Add BCCH message to PH-/MPH-/TCH-SAP interface
This first part moves BCCH message primitives from osmo-bts-sysmo to common part. A new file "common/l1sap.c" is introduced to implement handling of layer 1 messages from/to BTS model.
This commit is contained in:
parent
1eaa3d72ea
commit
5e90f2a809
|
@ -49,4 +49,6 @@ int bts_model_oml_estab(struct gsm_bts *bts);
|
||||||
int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm);
|
int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm);
|
||||||
int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan);
|
int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan);
|
||||||
|
|
||||||
|
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,4 +8,4 @@ libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \
|
||||||
load_indication.c pcu_sock.c handover.c msg_utils.c \
|
load_indication.c pcu_sock.c handover.c msg_utils.c \
|
||||||
load_indication.c pcu_sock.c handover.c msg_utils.c \
|
load_indication.c pcu_sock.c handover.c msg_utils.c \
|
||||||
tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \
|
tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \
|
||||||
cbch.c
|
l1sap.c cbch.c
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
/* L1 SAP primitives */
|
||||||
|
|
||||||
|
/* (C) 2011 by Harald Welte <laforge@gnumonks.org>
|
||||||
|
* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/msgb.h>
|
||||||
|
#include <osmocom/gsm/l1sap.h>
|
||||||
|
#include <osmocom/core/gsmtap.h>
|
||||||
|
#include <osmocom/core/gsmtap_util.h>
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
|
||||||
|
#include <osmocom/trau/osmo_ortp.h>
|
||||||
|
|
||||||
|
#include <osmo-bts/logging.h>
|
||||||
|
#include <osmo-bts/gsm_data.h>
|
||||||
|
#include <osmo-bts/l1sap.h>
|
||||||
|
#include <osmo-bts/pcu_if.h>
|
||||||
|
#include <osmo-bts/measurement.h>
|
||||||
|
#include <osmo-bts/bts.h>
|
||||||
|
#include <osmo-bts/rsl.h>
|
||||||
|
#include <osmo-bts/bts_model.h>
|
||||||
|
|
||||||
|
static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
|
||||||
|
|
||||||
|
static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = {
|
||||||
|
0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B,
|
||||||
|
0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B,
|
||||||
|
0x2B, 0x2B, 0x2B
|
||||||
|
};
|
||||||
|
|
||||||
|
/* allocate a msgb containing a osmo_phsap_prim + optional l2 data
|
||||||
|
* in order to wrap femtobts header arround l2 data, there must be enough space
|
||||||
|
* in front and behind data pointer */
|
||||||
|
struct msgb *l1sap_msgb_alloc(unsigned int l2_len)
|
||||||
|
{
|
||||||
|
struct msgb *msg = msgb_alloc_headroom(512, 128, "l1sap_prim");
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
msg->l1h = msgb_put(msg, sizeof(struct osmo_phsap_prim));
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PH-RTS-IND prim recevied from bts model */
|
||||||
|
static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx,
|
||||||
|
struct osmo_phsap_prim *l1sap, struct ph_data_param *rts_ind)
|
||||||
|
{
|
||||||
|
struct msgb *msg = l1sap->oph.msg;
|
||||||
|
struct gsm_time g_time;
|
||||||
|
uint8_t chan_nr, link_id;
|
||||||
|
uint8_t tn;
|
||||||
|
uint32_t fn;
|
||||||
|
uint8_t *p, *si;
|
||||||
|
|
||||||
|
chan_nr = rts_ind->chan_nr;
|
||||||
|
link_id = rts_ind->link_id;
|
||||||
|
fn = rts_ind->fn;
|
||||||
|
tn = L1SAP_CHAN2TS(chan_nr);
|
||||||
|
|
||||||
|
gsm_fn2gsmtime(&g_time, fn);
|
||||||
|
|
||||||
|
DEBUGP(DL1P, "Rx PH-RTS.ind %02u/%02u/%02u chan_nr=%d link_id=%d\n",
|
||||||
|
g_time.t1, g_time.t2, g_time.t3, chan_nr, link_id);
|
||||||
|
|
||||||
|
/* reuse PH-RTS.ind for PH-DATA.req */
|
||||||
|
if (!msg) {
|
||||||
|
LOGP(DL1P, LOGL_FATAL, "RTS without msg to be reused. Please "
|
||||||
|
"fix!\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
msgb_trim(msg, sizeof(*l1sap));
|
||||||
|
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA, PRIM_OP_REQUEST,
|
||||||
|
msg);
|
||||||
|
msg->l2h = msg->l1h + sizeof(*l1sap);
|
||||||
|
|
||||||
|
if (L1SAP_IS_CHAN_BCCH(chan_nr)) {
|
||||||
|
p = msgb_put(msg, GSM_MACBLOCK_LEN);
|
||||||
|
/* get them from bts->si_buf[] */
|
||||||
|
si = bts_sysinfo_get(trx->bts, &g_time);
|
||||||
|
if (si)
|
||||||
|
memcpy(p, si, GSM_MACBLOCK_LEN);
|
||||||
|
else
|
||||||
|
memcpy(p, fill_frame, GSM_MACBLOCK_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGP(DL1P, "Tx PH-DATA.req %02u/%02u/%02u chan_nr=%d link_id=%d\n",
|
||||||
|
g_time.t1, g_time.t2, g_time.t3, chan_nr, link_id);
|
||||||
|
|
||||||
|
l1sap_down(trx, l1sap);
|
||||||
|
|
||||||
|
/* don't free, because we forwarded data */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* any L1 prim received from bts model */
|
||||||
|
int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
||||||
|
{
|
||||||
|
struct msgb *msg = l1sap->oph.msg;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
switch (OSMO_PRIM_HDR(&l1sap->oph)) {
|
||||||
|
case OSMO_PRIM(PRIM_PH_RTS, PRIM_OP_INDICATION):
|
||||||
|
rc = l1sap_ph_rts_ind(trx, l1sap, &l1sap->u.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGP(DL1P, LOGL_NOTICE, "unknown prim %d op %d\n",
|
||||||
|
l1sap->oph.primitive, l1sap->oph.operation);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special return value '1' means: do not free */
|
||||||
|
if (rc != 1)
|
||||||
|
msgb_free(msg);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* any L1 prim sent to bts model */
|
||||||
|
static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
||||||
|
{
|
||||||
|
return bts_model_l1sap_down(trx, l1sap);
|
||||||
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
#include <osmo-bts/handover.h>
|
#include <osmo-bts/handover.h>
|
||||||
#include <osmo-bts/cbch.h>
|
#include <osmo-bts/cbch.h>
|
||||||
#include <osmo-bts/bts_model.h>
|
#include <osmo-bts/bts_model.h>
|
||||||
|
#include <osmo-bts/l1sap.h>
|
||||||
|
|
||||||
#include <sysmocom/femtobts/superfemto.h>
|
#include <sysmocom/femtobts/superfemto.h>
|
||||||
#include <sysmocom/femtobts/gsml1prim.h>
|
#include <sysmocom/femtobts/gsml1prim.h>
|
||||||
|
@ -422,8 +423,135 @@ static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = {
|
||||||
0x2B, 0x2B, 0x2B
|
0x2B, 0x2B, 0x2B
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
|
||||||
|
struct osmo_phsap_prim *l1sap)
|
||||||
|
{
|
||||||
|
struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx);
|
||||||
|
uint32_t u32Fn;
|
||||||
|
uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi;
|
||||||
|
uint8_t chan_nr, link_id;
|
||||||
|
GsmL1_Prim_t *l1p;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (!msg) {
|
||||||
|
LOGP(DL1C, LOGL_FATAL, "PH-DATA.req without msg. "
|
||||||
|
"Please fix!\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
chan_nr = l1sap->u.data.chan_nr;
|
||||||
|
link_id = l1sap->u.data.link_id;
|
||||||
|
u32Fn = l1sap->u.data.fn;
|
||||||
|
u8Tn = L1SAP_CHAN2TS(chan_nr);
|
||||||
|
subCh = 0x1f;
|
||||||
|
if (L1SAP_IS_CHAN_BCCH(chan_nr)) {
|
||||||
|
sapi = GsmL1_Sapi_Bcch;
|
||||||
|
} else {
|
||||||
|
LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d "
|
||||||
|
"chan_nr %d link_id %d\n", l1sap->oph.primitive,
|
||||||
|
l1sap->oph.operation, chan_nr, link_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pull and trim msg to start of payload */
|
||||||
|
msgb_pull(msg, sizeof(*l1sap));
|
||||||
|
len = msg->len;
|
||||||
|
msgb_trim(msg, 0);
|
||||||
|
|
||||||
|
/* convert l1sap message to GsmL1 primitive, keep payload */
|
||||||
|
if (len) {
|
||||||
|
/* data request */
|
||||||
|
GsmL1_PhDataReq_t *data_req;
|
||||||
|
GsmL1_MsgUnitParam_t *msu_param;
|
||||||
|
uint8_t *temp;
|
||||||
|
|
||||||
|
/* wrap zeroed l1p structure arrount payload
|
||||||
|
* this must be done in three steps, since the actual
|
||||||
|
* payload is not at the end but inside the l1p structure. */
|
||||||
|
temp = l1p->u.phDataReq.msgUnitParam.u8Buffer;
|
||||||
|
msgb_push(msg, temp - (uint8_t *)l1p);
|
||||||
|
memset(msg->data, 0, msg->len);
|
||||||
|
msgb_put(msg, len);
|
||||||
|
memset(msg->tail, 0, sizeof(*l1p) - msg->len);
|
||||||
|
msgb_put(msg, sizeof(*l1p) - msg->len);
|
||||||
|
msg->l1h = msg->data;
|
||||||
|
|
||||||
|
l1p = msgb_l1prim(msg);
|
||||||
|
l1p->id = GsmL1_PrimId_PhDataReq;
|
||||||
|
data_req = &l1p->u.phDataReq;
|
||||||
|
data_req->hLayer1 = fl1->hLayer1;
|
||||||
|
data_req->u8Tn = u8Tn;
|
||||||
|
data_req->u32Fn = u32Fn;
|
||||||
|
data_req->sapi = sapi;
|
||||||
|
data_req->subCh = subCh;
|
||||||
|
data_req->u8BlockNbr = u8BlockNbr;
|
||||||
|
msu_param = &data_req->msgUnitParam;
|
||||||
|
msu_param->u8Size = len;
|
||||||
|
} else {
|
||||||
|
/* empty frame */
|
||||||
|
GsmL1_PhEmptyFrameReq_t *empty_req;
|
||||||
|
|
||||||
|
/* put l1p structure */
|
||||||
|
msgb_put(msg, sizeof(*l1p));
|
||||||
|
memset(msg->data, 0, msg->len);
|
||||||
|
msg->l1h = msg->data;
|
||||||
|
|
||||||
|
l1p = msgb_l1prim(msg);
|
||||||
|
l1p->id = GsmL1_PrimId_PhEmptyFrameReq;
|
||||||
|
empty_req = &l1p->u.phEmptyFrameReq;
|
||||||
|
empty_req->hLayer1 = fl1->hLayer1;
|
||||||
|
empty_req->u8Tn = u8Tn;
|
||||||
|
empty_req->u32Fn = u32Fn;
|
||||||
|
empty_req->sapi = sapi;
|
||||||
|
empty_req->subCh = subCh;
|
||||||
|
empty_req->u8BlockNbr = u8BlockNbr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send message to DSP's queue */
|
||||||
|
osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], msg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* primitive from common part */
|
||||||
|
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
||||||
|
{
|
||||||
|
struct msgb *msg = l1sap->oph.msg;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
switch (OSMO_PRIM_HDR(&l1sap->oph)) {
|
||||||
|
case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST):
|
||||||
|
rc = ph_data_req(trx, msg, l1sap);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d\n",
|
||||||
|
l1sap->oph.primitive, l1sap->oph.operation);
|
||||||
|
rc = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
msgb_free(msg);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan,
|
||||||
|
GsmL1_Sapi_t sapi, GsmL1_SubCh_t subCh,
|
||||||
|
uint8_t u8Tn, uint32_t u32Fn)
|
||||||
|
{
|
||||||
|
uint8_t cbits = 0;
|
||||||
|
switch (sapi) {
|
||||||
|
case GsmL1_Sapi_Bcch:
|
||||||
|
cbits = 0x10;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cbits << 3) | u8Tn;
|
||||||
|
}
|
||||||
|
|
||||||
static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
|
static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
|
||||||
GsmL1_PhReadyToSendInd_t *rts_ind)
|
GsmL1_PhReadyToSendInd_t *rts_ind,
|
||||||
|
struct msgb *l1p_msg)
|
||||||
{
|
{
|
||||||
struct gsm_bts_trx *trx = fl1->priv;
|
struct gsm_bts_trx *trx = fl1->priv;
|
||||||
struct gsm_bts *bts = trx->bts;
|
struct gsm_bts *bts = trx->bts;
|
||||||
|
@ -434,9 +562,31 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
|
||||||
struct gsm_lchan *lchan;
|
struct gsm_lchan *lchan;
|
||||||
struct gsm_time g_time;
|
struct gsm_time g_time;
|
||||||
uint32_t t3p;
|
uint32_t t3p;
|
||||||
uint8_t *si;
|
|
||||||
struct osmo_phsap_prim pp;
|
struct osmo_phsap_prim pp;
|
||||||
int rc;
|
int rc;
|
||||||
|
struct osmo_phsap_prim *l1sap;
|
||||||
|
uint8_t chan_nr, link_id;
|
||||||
|
uint32_t fn;
|
||||||
|
|
||||||
|
|
||||||
|
/* check if primitive should be handled by common part */
|
||||||
|
chan_nr = chan_nr_by_sapi(trx->ts[rts_ind->u8Tn].pchan, rts_ind->sapi,
|
||||||
|
rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn);
|
||||||
|
if (chan_nr) {
|
||||||
|
fn = rts_ind->u32Fn;
|
||||||
|
link_id = 0;
|
||||||
|
rc = msgb_trim(l1p_msg, sizeof(*l1sap));
|
||||||
|
if (rc < 0)
|
||||||
|
MSGB_ABORT(l1p_msg, "No room for primitive\n");
|
||||||
|
l1sap = msgb_l1sap_prim(l1p_msg);
|
||||||
|
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS,
|
||||||
|
PRIM_OP_INDICATION, l1p_msg);
|
||||||
|
l1sap->u.data.link_id = link_id;
|
||||||
|
l1sap->u.data.chan_nr = chan_nr;
|
||||||
|
l1sap->u.data.fn = fn;
|
||||||
|
|
||||||
|
return l1sap_up(trx, l1sap);
|
||||||
|
}
|
||||||
|
|
||||||
gsm_fn2gsmtime(&g_time, rts_ind->u32Fn);
|
gsm_fn2gsmtime(&g_time, rts_ind->u32Fn);
|
||||||
|
|
||||||
|
@ -515,14 +665,6 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
|
||||||
msu_param->u8Buffer[2] = (g_time.t1 << 7) | (g_time.t2 << 2) | (t3p >> 1);
|
msu_param->u8Buffer[2] = (g_time.t1 << 7) | (g_time.t2 << 2) | (t3p >> 1);
|
||||||
msu_param->u8Buffer[3] = (t3p & 1);
|
msu_param->u8Buffer[3] = (t3p & 1);
|
||||||
break;
|
break;
|
||||||
case GsmL1_Sapi_Bcch:
|
|
||||||
/* get them from bts->si_buf[] */
|
|
||||||
si = bts_sysinfo_get(bts, &g_time);
|
|
||||||
if (si)
|
|
||||||
memcpy(msu_param->u8Buffer, si, GSM_MACBLOCK_LEN);
|
|
||||||
else
|
|
||||||
memcpy(msu_param->u8Buffer, fill_frame, GSM_MACBLOCK_LEN);
|
|
||||||
break;
|
|
||||||
case GsmL1_Sapi_Sacch:
|
case GsmL1_Sapi_Sacch:
|
||||||
/* resolve the L2 entity using rts_ind->hLayer2 */
|
/* resolve the L2 entity using rts_ind->hLayer2 */
|
||||||
lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2);
|
lchan = l1if_hLayer_to_lchan(trx, rts_ind->hLayer2);
|
||||||
|
@ -613,6 +755,7 @@ tx:
|
||||||
msgb_free(resp_msg);
|
msgb_free(resp_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msgb_free(l1p_msg);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
empty_frame:
|
empty_frame:
|
||||||
|
@ -975,8 +1118,8 @@ static int l1if_handle_ind(struct femtol1_hdl *fl1, struct msgb *msg)
|
||||||
case GsmL1_PrimId_PhConnectInd:
|
case GsmL1_PrimId_PhConnectInd:
|
||||||
break;
|
break;
|
||||||
case GsmL1_PrimId_PhReadyToSendInd:
|
case GsmL1_PrimId_PhReadyToSendInd:
|
||||||
rc = handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd);
|
return handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd,
|
||||||
break;
|
msg);
|
||||||
case GsmL1_PrimId_PhDataInd:
|
case GsmL1_PrimId_PhDataInd:
|
||||||
rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg);
|
rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -40,6 +40,8 @@ int bts_model_rsl_chan_mod(struct gsm_lchan *lchan)
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
|
void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl,
|
||||||
unsigned int rtp_pl_len) {}
|
unsigned int rtp_pl_len) {}
|
||||||
|
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
int l1if_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn,
|
int l1if_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn,
|
||||||
uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len)
|
uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len)
|
||||||
|
|
Loading…
Reference in New Issue