VIRT-PHY: coding style / API usage cleanup
This is the result of my manual clean-up of the many coding style issues found in the stumpf/virt-phy branch of OsmocomBB. Some may remain, but it's much closer to what we're used to in the Osmocom world now. Change-Id: I3aa95dbef75d7749d490aad0237d074528527e8b
This commit is contained in:
parent
020186009c
commit
7e65a1483f
|
@ -1,12 +1,12 @@
|
|||
/* GSMTAP layer1 is transmits gsmtap messages over a virtual layer 1.*/
|
||||
|
||||
/* (C) 2016 Sebastian Stumpf
|
||||
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
|
@ -14,7 +14,7 @@
|
|||
* 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
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
@ -40,47 +40,45 @@
|
|||
|
||||
static struct l1_model_ms *l1_model_ms = NULL;
|
||||
|
||||
// for debugging
|
||||
static const struct value_string gsmtap_channels[22] = {
|
||||
{GSMTAP_CHANNEL_UNKNOWN, "UNKNOWN"},
|
||||
{GSMTAP_CHANNEL_BCCH, "BCCH"},
|
||||
{GSMTAP_CHANNEL_CCCH, "CCCH"},
|
||||
{GSMTAP_CHANNEL_RACH, "RACH"},
|
||||
{GSMTAP_CHANNEL_AGCH, "AGCH"},
|
||||
{GSMTAP_CHANNEL_PCH, "PCH"},
|
||||
{GSMTAP_CHANNEL_SDCCH, "SDCCH"},
|
||||
{GSMTAP_CHANNEL_SDCCH4, "SDCCH/4"},
|
||||
{GSMTAP_CHANNEL_SDCCH8, "SDCCH/8"},
|
||||
{GSMTAP_CHANNEL_TCH_F, "TCH/F/FACCH/F"},
|
||||
{GSMTAP_CHANNEL_TCH_H, "TCH/H/FACCH/H"},
|
||||
{GSMTAP_CHANNEL_PACCH, "PACCH"},
|
||||
{GSMTAP_CHANNEL_CBCH52, "CBCH"},
|
||||
{GSMTAP_CHANNEL_PDCH, "PDCH"},
|
||||
{GSMTAP_CHANNEL_PTCCH, "PTTCH"},
|
||||
{GSMTAP_CHANNEL_CBCH51, "CBCH"},
|
||||
{GSMTAP_CHANNEL_ACCH |
|
||||
GSMTAP_CHANNEL_SDCCH, "LSACCH"},
|
||||
{GSMTAP_CHANNEL_ACCH |
|
||||
GSMTAP_CHANNEL_SDCCH4, "SACCH/4"},
|
||||
{GSMTAP_CHANNEL_ACCH |
|
||||
GSMTAP_CHANNEL_SDCCH8, "SACCH/8"},
|
||||
{GSMTAP_CHANNEL_ACCH |
|
||||
GSMTAP_CHANNEL_TCH_F, "SACCH/F"},
|
||||
{GSMTAP_CHANNEL_ACCH |
|
||||
GSMTAP_CHANNEL_TCH_H, "SACCH/H"},
|
||||
{0, NULL}, };
|
||||
// for debugging
|
||||
static const struct value_string gsmtap_types[10] = {{
|
||||
GSMTAP_TYPE_UM,
|
||||
"GSM Um (MS<->BTS)"}, {GSMTAP_TYPE_ABIS, "GSM Abis (BTS<->BSC)"}, {
|
||||
GSMTAP_TYPE_UM_BURST,
|
||||
"GSM Um burst (MS<->BTS)"}, {GSMTAP_TYPE_SIM, "SIM"}, {
|
||||
GSMTAP_TYPE_TETRA_I1,
|
||||
"TETRA V+D"}, {GSMTAP_TYPE_WMX_BURST, "WiMAX burst"}, {
|
||||
GSMTAP_TYPE_GMR1_UM,
|
||||
"GMR-1 air interfeace (MES-MS<->GTS)"}, {
|
||||
GSMTAP_TYPE_UMTS_RLC_MAC,
|
||||
"UMTS RLC/MAC"}, {GSMTAP_TYPE_UMTS_RRC, "UMTS RRC"}, {0, NULL}, };
|
||||
/* for debugging */
|
||||
static const struct value_string gsmtap_channels[] = {
|
||||
{ GSMTAP_CHANNEL_UNKNOWN, "UNKNOWN" },
|
||||
{ GSMTAP_CHANNEL_BCCH, "BCCH" },
|
||||
{ GSMTAP_CHANNEL_CCCH, "CCCH" },
|
||||
{ GSMTAP_CHANNEL_RACH, "RACH" },
|
||||
{ GSMTAP_CHANNEL_AGCH, "AGCH" },
|
||||
{ GSMTAP_CHANNEL_PCH, "PCH" },
|
||||
{ GSMTAP_CHANNEL_SDCCH, "SDCCH" },
|
||||
{ GSMTAP_CHANNEL_SDCCH4, "SDCCH/4" },
|
||||
{ GSMTAP_CHANNEL_SDCCH8, "SDCCH/8" },
|
||||
{ GSMTAP_CHANNEL_TCH_F, "TCH/F/FACCH/F" },
|
||||
{ GSMTAP_CHANNEL_TCH_H, "TCH/H/FACCH/H" },
|
||||
{ GSMTAP_CHANNEL_PACCH, "PACCH" },
|
||||
{ GSMTAP_CHANNEL_CBCH52, "CBCH" },
|
||||
{ GSMTAP_CHANNEL_PDCH, "PDCH" } ,
|
||||
{ GSMTAP_CHANNEL_PTCCH, "PTTCH" },
|
||||
{ GSMTAP_CHANNEL_CBCH51, "CBCH" },
|
||||
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH, "LSACCH" },
|
||||
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH4, "SACCH/4" },
|
||||
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH8, "SACCH/8" },
|
||||
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_TCH_F, "SACCH/F" },
|
||||
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_TCH_H, "SACCH/H" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* for debugging */
|
||||
static const struct value_string gsmtap_types[10] = {
|
||||
{ GSMTAP_TYPE_UM, "GSM Um (MS<->BTS)" },
|
||||
{ GSMTAP_TYPE_ABIS, "GSM Abis (BTS<->BSC)" },
|
||||
{ GSMTAP_TYPE_UM_BURST, "GSM Um burst (MS<->BTS)" },
|
||||
{ GSMTAP_TYPE_SIM, "SIM Card" },
|
||||
{ GSMTAP_TYPE_TETRA_I1, "TETRA V+D" },
|
||||
{ GSMTAP_TYPE_WMX_BURST, "WiMAX burst" },
|
||||
{ GSMTAP_TYPE_GMR1_UM, "GMR-1 air interfeace (MES-MS<->GTS)"},
|
||||
{ GSMTAP_TYPE_UMTS_RLC_MAC, "UMTS RLC/MAC" },
|
||||
{ GSMTAP_TYPE_UMTS_RRC, "UMTS RRC" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
void gsmtapl1_init(struct l1_model_ms *model)
|
||||
{
|
||||
|
@ -91,48 +89,46 @@ void gsmtapl1_init(struct l1_model_ms *model)
|
|||
* Replace l11 header of given msgb by a gsmtap header and send it over the virt um.
|
||||
*/
|
||||
void gsmtapl1_tx_to_virt_um_inst(uint32_t fn, struct virt_um_inst *vui,
|
||||
struct msgb *msg)
|
||||
struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
|
||||
struct gsmtap_hdr *gh;
|
||||
struct msgb *outmsg; // msg to send with gsmtap header prepended
|
||||
uint16_t arfcn = l1_model_ms->state->serving_cell.arfcn; // arfcn of the cell we currently camp on
|
||||
uint8_t signal_dbm = 63; // signal strength, 63 is best
|
||||
uint8_t snr = 63; // signal noise ratio, 63 is best
|
||||
uint8_t *data = msgb_l2(msg); // data to transmit (whole message without l1 header)
|
||||
uint8_t data_len = msgb_l2len(msg); // length of data
|
||||
struct msgb *outmsg; /* msg to send with gsmtap header prepended */
|
||||
uint16_t arfcn = l1_model_ms->state->serving_cell.arfcn; /* arfcn of the cell we currently camp on */
|
||||
uint8_t signal_dbm = 63; /* signal strength */
|
||||
uint8_t snr = 63; /* signal noise ratio, 63 is best */
|
||||
uint8_t *data = msgb_l2(msg); /* data to transmit (whole message without l1 header) */
|
||||
uint8_t data_len = msgb_l2len(msg); /* length of data */
|
||||
|
||||
uint8_t rsl_chantype; // rsl chan type (8.58, 9.3.1)
|
||||
uint8_t subslot; // multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51)
|
||||
uint8_t timeslot; // tdma timeslot to send in (0-7)
|
||||
uint8_t gsmtap_chan; // the gsmtap channel
|
||||
uint8_t rsl_chantype; /* rsl chan type (8.58, 9.3.1) */
|
||||
uint8_t subslot; /* multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51) */
|
||||
uint8_t timeslot; /* tdma timeslot to send in (0-7) */
|
||||
uint8_t gsmtap_chan; /* the gsmtap channel */
|
||||
|
||||
rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, ×lot);
|
||||
gsmtap_chan = chantype_rsl2gsmtap(rsl_chantype, ul->link_id);
|
||||
|
||||
// arfcn needs to be flagged to be able to distinguish between uplink and downlink
|
||||
/* arfcn needs to be flagged to be able to distinguish between uplink and downlink */
|
||||
outmsg = gsmtap_makemsg(arfcn | GSMTAP_ARFCN_F_UPLINK, timeslot,
|
||||
gsmtap_chan, subslot, fn, signal_dbm, snr, data,
|
||||
data_len);
|
||||
gsmtap_chan, subslot, fn, signal_dbm, snr, data,
|
||||
data_len);
|
||||
if (outmsg) {
|
||||
outmsg->l1h = msgb_data(outmsg);
|
||||
gh = msgb_l1(outmsg);
|
||||
if (virt_um_write_msg(l1_model_ms->vui, outmsg) == -1) {
|
||||
LOGP(DVIRPHY,
|
||||
LOGL_ERROR,
|
||||
"Gsmtap msg could not send to virt um - (arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
|
||||
LOGP(DVIRPHY, LOGL_ERROR, "Gsmtap msg could not send to virt um - "
|
||||
"(arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
|
||||
gh->arfcn, gh->type, gh->sub_type, gh->timeslot,
|
||||
gh->sub_slot);
|
||||
} else {
|
||||
DEBUGP(DVIRPHY,
|
||||
"Sending gsmtap msg to virt um - (arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
|
||||
DEBUGP(DVIRPHY, "Sending gsmtap msg to virt um - "
|
||||
"(arfcn=%u, type=%u, subtype=%u, timeslot=%u, subslot=%u)\n",
|
||||
gh->arfcn, gh->type, gh->sub_type, gh->timeslot,
|
||||
gh->sub_slot);
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
LOGP(DVIRPHY, LOGL_ERROR, "Gsmtap msg could not be created!\n");
|
||||
}
|
||||
|
||||
/* free message */
|
||||
msgb_free(msg);
|
||||
|
@ -166,96 +162,89 @@ extern uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev);
|
|||
* - if in MS_STATE_IDLE_SEARCHING
|
||||
*/
|
||||
void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
|
||||
struct msgb *msg)
|
||||
struct msgb *msg)
|
||||
{
|
||||
if (!msg) {
|
||||
if (!msg)
|
||||
return;
|
||||
}
|
||||
|
||||
struct gsmtap_hdr *gh = msgb_l1(msg);
|
||||
uint32_t fn = ntohl(gh->frame_number); // frame number of the rcv msg
|
||||
uint16_t arfcn = ntohs(gh->arfcn); // arfcn of the received msg
|
||||
uint8_t gsmtap_chantype = gh->sub_type; // gsmtap channel type
|
||||
uint8_t signal_dbm = dbm2rxlev(prim_pm_set_sig_strength(arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM)); // Power measurement with each received massage
|
||||
uint8_t snr = gh->snr_db; // signal noise ratio, 63 is best
|
||||
uint8_t subslot = gh->sub_slot; // multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51)
|
||||
uint8_t timeslot = gh->timeslot; // tdma timeslot to send in (0-7)
|
||||
uint8_t rsl_chantype; // rsl chan type (8.58, 9.3.1)
|
||||
uint8_t link_id; // rsl link id tells if this is an ssociated or dedicated link
|
||||
uint8_t chan_nr; // encoded rsl channel type, timeslot and mf subslot
|
||||
uint32_t fn = ntohl(gh->frame_number); /* frame number of the rcv msg */
|
||||
uint16_t arfcn = ntohs(gh->arfcn); /* arfcn of the received msg */
|
||||
uint8_t gsmtap_chantype = gh->sub_type; /* gsmtap channel type */
|
||||
uint8_t signal_dbm = dbm2rxlev(prim_pm_set_sig_strength(arfcn & GSMTAP_ARFCN_MASK, MAX_SIG_LEV_DBM)); /* Power measurement with each received massage */
|
||||
uint8_t snr = gh->snr_db; /* signal noise ratio */
|
||||
uint8_t subslot = gh->sub_slot; /* multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51) */
|
||||
uint8_t timeslot = gh->timeslot; /* tdma timeslot to send in (0-7) */
|
||||
uint8_t rsl_chantype; /* rsl chan type (8.58, 9.3.1) */
|
||||
uint8_t link_id; /* rsl link id tells if this is an ssociated or dedicated link */
|
||||
uint8_t chan_nr; /* encoded rsl channel type, timeslot and mf subslot */
|
||||
|
||||
// generally ignore all uplink messages received
|
||||
/* generally ignore all uplink messages received */
|
||||
if (arfcn & GSMTAP_ARFCN_F_UPLINK) {
|
||||
LOGP(DVIRPHY, LOGL_NOTICE,
|
||||
"Ignoring gsmtap msg from virt um - uplink flag set!\n");
|
||||
LOGP(DVIRPHY, LOGL_NOTICE, "Ignoring gsmtap msg from virt um - uplink flag set!\n");
|
||||
goto freemsg;
|
||||
}
|
||||
|
||||
// we do not forward messages to l23 if we are in network search state
|
||||
if (l1_model_ms->state->state == MS_STATE_IDLE_SEARCHING) {
|
||||
/* we do not forward messages to l23 if we are in network search state */
|
||||
if (l1_model_ms->state->state == MS_STATE_IDLE_SEARCHING)
|
||||
goto freemsg;
|
||||
}
|
||||
|
||||
// forward downlink msg to fbsb sync routine if we are in sync state
|
||||
/* forward downlink msg to fbsb sync routine if we are in sync state */
|
||||
if (l1_model_ms->state->state == MS_STATE_IDLE_SYNCING) {
|
||||
prim_fbsb_sync(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// generally ignore all messages coming from another arfcn than the camped one
|
||||
/* generally ignore all messages coming from another arfcn than the camped one */
|
||||
if (l1_model_ms->state->serving_cell.arfcn != arfcn) {
|
||||
LOGP(DVIRPHY,
|
||||
LOGL_NOTICE,
|
||||
LOGP(DVIRPHY, LOGL_NOTICE,
|
||||
"Ignoring gsmtap msg from virt um - msg arfcn=%d not equal synced arfcn=%d!\n",
|
||||
arfcn,
|
||||
l1_model_ms->state->serving_cell.arfcn);
|
||||
arfcn, l1_model_ms->state->serving_cell.arfcn);
|
||||
goto freemsg;
|
||||
}
|
||||
|
||||
msg->l2h = msgb_pull(msg, sizeof(*gh));
|
||||
chantype_gsmtap2rsl(gsmtap_chantype, &rsl_chantype, &link_id);
|
||||
// see GSM 8.58 -> 9.3.1 for channel number encoding
|
||||
/* see TS 08.58 -> 9.3.1 for channel number encoding */
|
||||
chan_nr = rsl_enc_chan_nr(rsl_chantype, subslot, timeslot);
|
||||
|
||||
gsm_fn2gsmtime(&l1_model_ms->state->downlink_time, fn);
|
||||
virt_l1_sched_sync_time(l1_model_ms->state->downlink_time, 0);
|
||||
virt_l1_sched_execute(fn);
|
||||
|
||||
DEBUGP(DVIRPHY,
|
||||
"Receiving gsmtap msg from virt um - (arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u, rsl_chan_type=0x%2x, link_id=0x%2x, chan_nr=0x%2x)\n",
|
||||
DEBUGP(DVIRPHY, "Receiving gsmtap msg from virt um - "
|
||||
"(arfcn=%u, framenumber=%u, type=%s, subtype=%s, timeslot=%u, subslot=%u, rsl_chan_type=0x%2x, link_id=0x%2x, chan_nr=0x%2x)\n",
|
||||
arfcn, fn, get_value_string(gsmtap_types, gh->type),
|
||||
get_value_string(gsmtap_channels, gsmtap_chantype), timeslot,
|
||||
subslot, rsl_chantype, link_id, chan_nr);
|
||||
|
||||
// switch case with removed acch flag
|
||||
/* switch case with removed ACCH flag */
|
||||
switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) {
|
||||
case GSMTAP_CHANNEL_TCH_H:
|
||||
case GSMTAP_CHANNEL_TCH_F:
|
||||
#if(0)
|
||||
// TODO: handle msgs on TCH that are neither FACCH nor TCH/ACCH
|
||||
if(!facch && ! tch_acch) {
|
||||
#if 0
|
||||
/* TODO: handle voice */
|
||||
if (!facch && !tch_acch) {
|
||||
l1ctl_tx_traffic_ind(msg, arfcn, link_id, chan_nr, fn,
|
||||
snr, signal_dbm, 0, 0);
|
||||
snr, signal_dbm, 0, 0);
|
||||
}
|
||||
#endif
|
||||
case GSMTAP_CHANNEL_SDCCH4:
|
||||
case GSMTAP_CHANNEL_SDCCH8:
|
||||
// only forward messages on dedicated channels to l2, if the timeslot and subslot is fitting
|
||||
if(l1_model_ms->state->dedicated.tn == timeslot && l1_model_ms->state->dedicated.subslot == subslot) {
|
||||
l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr,
|
||||
signal_dbm, 0, 0);
|
||||
/* only forward messages on dedicated channels to l2, if
|
||||
* the timeslot and subslot is fitting */
|
||||
if (l1_model_ms->state->dedicated.tn == timeslot
|
||||
&& l1_model_ms->state->dedicated.subslot == subslot) {
|
||||
l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr, signal_dbm, 0, 0);
|
||||
}
|
||||
break;
|
||||
case GSMTAP_CHANNEL_AGCH:
|
||||
case GSMTAP_CHANNEL_PCH:
|
||||
case GSMTAP_CHANNEL_BCCH:
|
||||
// save to just forward here, as upper layer ignores messages that do not fit the current state (e.g. gsm48_rr.c:2159)
|
||||
l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr,
|
||||
signal_dbm, 0, 0);
|
||||
/* save to just forward here, as upper layer ignores messages that
|
||||
* do not fit the current state (e.g. gsm48_rr.c:2159) */
|
||||
l1ctl_tx_data_ind(msg, arfcn, link_id, chan_nr, fn, snr, signal_dbm, 0, 0);
|
||||
break;
|
||||
case GSMTAP_CHANNEL_RACH:
|
||||
LOGP(DVIRPHY,
|
||||
LOGL_NOTICE,
|
||||
LOGP(DVIRPHY, LOGL_NOTICE,
|
||||
"Ignoring gsmtap msg from virt um - channel type is uplink only!\n");
|
||||
break;
|
||||
case GSMTAP_CHANNEL_SDCCH:
|
||||
|
@ -265,19 +254,16 @@ void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst *vui,
|
|||
case GSMTAP_CHANNEL_PTCCH:
|
||||
case GSMTAP_CHANNEL_CBCH51:
|
||||
case GSMTAP_CHANNEL_CBCH52:
|
||||
LOGP(DVIRPHY,
|
||||
LOGL_NOTICE,
|
||||
LOGP(DVIRPHY, LOGL_NOTICE,
|
||||
"Ignoring gsmtap msg from virt um - channel type not supported!\n");
|
||||
break;
|
||||
default:
|
||||
LOGP(DVIRPHY,
|
||||
LOGL_NOTICE,
|
||||
LOGP(DVIRPHY, LOGL_NOTICE,
|
||||
"Ignoring gsmtap msg from virt um - channel type unknown.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
freemsg:
|
||||
// handle memory deallocation
|
||||
freemsg:
|
||||
talloc_free(msg);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
/* L1CTL SAP implementation. */
|
||||
|
||||
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
@ -23,12 +43,10 @@ static struct l1_model_ms *l1_model_ms = NULL;
|
|||
|
||||
static void l1_model_tch_mode_set(uint8_t tch_mode)
|
||||
{
|
||||
if (tch_mode == GSM48_CMODE_SPEECH_V1
|
||||
|| tch_mode == GSM48_CMODE_SPEECH_EFR) {
|
||||
if (tch_mode == GSM48_CMODE_SPEECH_V1 || tch_mode == GSM48_CMODE_SPEECH_EFR)
|
||||
l1_model_ms->state->tch_mode = tch_mode;
|
||||
|
||||
} else {
|
||||
// set default value if no proper mode was assigned by l23
|
||||
else {
|
||||
/* set default value if no proper mode was assigned by l23 */
|
||||
l1_model_ms->state->tch_mode = GSM48_CMODE_SIGN;
|
||||
}
|
||||
}
|
||||
|
@ -51,13 +69,11 @@ void l1ctl_sap_init(struct l1_model_ms *model)
|
|||
*
|
||||
* Enqueues the message into the rx queue.
|
||||
*/
|
||||
void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi,
|
||||
struct msgb *msg)
|
||||
void l1ctl_sap_rx_from_l23_inst_cb(struct l1ctl_sock_inst *lsi, struct msgb *msg)
|
||||
{
|
||||
// check if the received msg is not empty
|
||||
/* check if the received msg is not empty */
|
||||
if (msg) {
|
||||
DEBUGP(DL1C, "Message incoming from layer 2: %s\n",
|
||||
osmo_hexdump(msg->data, msg->len));
|
||||
DEBUGP(DL1C, "Message incoming from layer 2: %s\n", osmo_hexdump(msg->data, msg->len));
|
||||
l1ctl_sap_handler(msg);
|
||||
}
|
||||
}
|
||||
|
@ -76,10 +92,8 @@ void l1ctl_sap_rx_from_l23(struct msgb *msg)
|
|||
*/
|
||||
void l1ctl_sap_tx_to_l23_inst(struct l1ctl_sock_inst *lsi, struct msgb *msg)
|
||||
{
|
||||
uint16_t *len;
|
||||
/* prepend 16bit length before sending */
|
||||
len = (uint16_t *)msgb_push(msg, sizeof(*len));
|
||||
*len = htons(msg->len - sizeof(*len));
|
||||
msgb_push_u16(msg, msg->len);
|
||||
l1ctl_sock_write_msg(lsi, msg);
|
||||
}
|
||||
|
||||
|
@ -108,15 +122,11 @@ struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
|
|||
{
|
||||
struct msgb *msg;
|
||||
struct l1ctl_hdr *l1h;
|
||||
msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
|
||||
if (!msg) {
|
||||
while (1) {
|
||||
puts("OOPS. Out of buffers...\n");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
l1h = (struct l1ctl_hdr *)msgb_put(msg, sizeof(*l1h));
|
||||
msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
|
||||
OSMO_ASSERT(msg);
|
||||
|
||||
l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
|
||||
l1h->msg_type = msg_type;
|
||||
l1h->flags = 0;
|
||||
|
||||
|
@ -142,13 +152,12 @@ struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
|
|||
* [l1ctl_info_dl] : initialized with params. msgb->data points here.
|
||||
* [spare-bytes] : L3_MSG_DATA bytes reserved for data. msgb->tail points here.
|
||||
*/
|
||||
struct msgb *l1ctl_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
|
||||
uint16_t arfcn)
|
||||
struct msgb *l1ctl_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr, uint16_t arfcn)
|
||||
{
|
||||
struct l1ctl_info_dl *dl;
|
||||
struct msgb *msg = l1ctl_msgb_alloc(msg_type);
|
||||
|
||||
dl = (struct l1ctl_info_dl *)msgb_put(msg, sizeof(*dl));
|
||||
dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
|
||||
dl->frame_nr = htonl(fn);
|
||||
dl->snr = htons(snr);
|
||||
dl->band_arfcn = htons(arfcn);
|
||||
|
@ -160,21 +169,18 @@ struct msgb *l1ctl_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
|
|||
* @brief General handler for incoming L1CTL messages from layer 2/3.
|
||||
*
|
||||
* This handler will call the specific routine dependent on the L1CTL message type.
|
||||
*
|
||||
*/
|
||||
void l1ctl_sap_handler(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h;
|
||||
|
||||
if (!msg) {
|
||||
if (!msg)
|
||||
return;
|
||||
}
|
||||
|
||||
l1h = (struct l1ctl_hdr *)msg->data;
|
||||
l1h = (struct l1ctl_hdr *) msg->data;
|
||||
|
||||
if (sizeof(*l1h) > msg->len) {
|
||||
LOGP(DL1C, LOGL_NOTICE, "Malformed message: too short. %u\n",
|
||||
msg->len);
|
||||
LOGP(DL1C, LOGL_NOTICE, "Malformed message: too short. %u\n", msg->len);
|
||||
goto exit_msgbfree;
|
||||
}
|
||||
|
||||
|
@ -226,8 +232,11 @@ void l1ctl_sap_handler(struct msgb *msg)
|
|||
break;
|
||||
}
|
||||
|
||||
exit_msgbfree: msgb_free(msg);
|
||||
exit_nofree: return; /* msg is scheduled for uplink and mustn't be freed here */
|
||||
exit_msgbfree:
|
||||
msgb_free(msg);
|
||||
|
||||
exit_nofree:
|
||||
return; /* msg is scheduled for uplink and mustn't be freed here */
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
|
@ -248,17 +257,15 @@ void l1ctl_sap_handler(struct msgb *msg)
|
|||
*/
|
||||
void l1ctl_rx_dm_est_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
|
||||
struct l1ctl_dm_est_req *est_req =
|
||||
(struct l1ctl_dm_est_req *)ul->payload;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
|
||||
struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
|
||||
uint8_t rsl_chantype, subslot, timeslot;
|
||||
|
||||
rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, ×lot);
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received and handled from l23 - L1CTL_DM_EST_REQ (chan_nr=0x%02x, tn=%u, ss=%u)\n",
|
||||
ul->chan_nr, timeslot, subslot);
|
||||
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_DM_EST_REQ (chan_nr=0x%02x, tn=%u, ss=%u)\n",
|
||||
ul->chan_nr, timeslot, subslot);
|
||||
|
||||
l1_model_ms->state->dedicated.chan_type = rsl_chantype;
|
||||
l1_model_ms->state->dedicated.tn = timeslot;
|
||||
|
@ -266,12 +273,12 @@ void l1ctl_rx_dm_est_req(struct msgb *msg)
|
|||
l1_model_ms->state->state = MS_STATE_DEDICATED;
|
||||
|
||||
/* TCH config */
|
||||
if (rsl_chantype == RSL_CHAN_Bm_ACCHs
|
||||
|| rsl_chantype == RSL_CHAN_Lm_ACCHs) {
|
||||
if (rsl_chantype == RSL_CHAN_Bm_ACCHs || rsl_chantype == RSL_CHAN_Lm_ACCHs) {
|
||||
l1_model_ms->state->tch_mode = est_req->tch_mode;
|
||||
l1_model_tch_mode_set(est_req->tch_mode);
|
||||
l1_model_ms->state->audio_mode = est_req->audio_mode;
|
||||
// TODO: configure audio hardware for encoding / decoding / recording / playing voice
|
||||
/* TODO: configure audio hardware for encoding /
|
||||
* decoding / recording / playing voice */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,15 +295,12 @@ void l1ctl_rx_dm_est_req(struct msgb *msg)
|
|||
*/
|
||||
void l1ctl_rx_dm_freq_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
|
||||
struct l1ctl_dm_freq_req *freq_req =
|
||||
(struct l1ctl_dm_freq_req *)ul->payload;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
|
||||
struct l1ctl_dm_freq_req *freq_req = (struct l1ctl_dm_freq_req *) ul->payload;
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received and ignored from l23 - L1CTL_DM_FREQ_REQ (arfcn0=%u, hsn=%u, maio=%u)\n",
|
||||
ntohs(freq_req->h0.band_arfcn), freq_req->h1.hsn,
|
||||
freq_req->h1.maio);
|
||||
DEBUGP(DL1C, "Received and ignored from l23 - L1CTL_DM_FREQ_REQ (arfcn0=%u, hsn=%u, maio=%u)\n",
|
||||
ntohs(freq_req->h0.band_arfcn), freq_req->h1.hsn, freq_req->h1.maio);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -315,23 +319,21 @@ void l1ctl_rx_dm_freq_req(struct msgb *msg)
|
|||
*/
|
||||
void l1ctl_rx_crypto_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
|
||||
struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *)ul->payload;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
|
||||
struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
|
||||
uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received and handled from l23 - L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n",
|
||||
cr->algo, key_len);
|
||||
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n",
|
||||
cr->algo, key_len);
|
||||
|
||||
if (cr->algo && key_len != A5_KEY_LEN) {
|
||||
DEBUGP(DL1C, "L1CTL_CRYPTO_REQ -> Invalid key\n");
|
||||
LOGP(DL1C, LOGL_ERROR, "L1CTL_CRYPTO_REQ -> Invalid key\n");
|
||||
return;
|
||||
}
|
||||
|
||||
l1_model_ms->crypto_inf->algo = cr->algo;
|
||||
memcpy(l1_model_ms->crypto_inf->key, cr->key,
|
||||
sizeof(uint8_t) * A5_KEY_LEN);
|
||||
memcpy(l1_model_ms->crypto_inf->key, cr->key, sizeof(uint8_t) * A5_KEY_LEN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -354,8 +356,8 @@ void l1ctl_rx_dm_rel_req(struct msgb *msg)
|
|||
l1_model_ms->state->tch_mode = GSM48_CMODE_SIGN;
|
||||
l1_model_ms->state->state = MS_STATE_IDLE_CAMPING;
|
||||
|
||||
// TODO: disable ciphering
|
||||
// TODO: disable audio recording / playing
|
||||
/* TODO: disable ciphering */
|
||||
/* TODO: disable audio recording / playing */
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -375,9 +377,8 @@ void l1ctl_rx_param_req(struct msgb *msg)
|
|||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
|
||||
struct l1ctl_par_req *par_req = (struct l1ctl_par_req *)ul->payload;
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received and ignored from l23 - L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n",
|
||||
par_req->ta, par_req->tx_power);
|
||||
DEBUGP(DL1C, "Received and ignored from l23 - L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n",
|
||||
par_req->ta, par_req->tx_power);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -395,26 +396,23 @@ void l1ctl_rx_param_req(struct msgb *msg)
|
|||
*/
|
||||
void l1ctl_rx_reset_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_reset *reset_req = (struct l1ctl_reset *)l1h->data;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_reset *reset_req = (struct l1ctl_reset *) l1h->data;
|
||||
|
||||
switch (reset_req->type) {
|
||||
case L1CTL_RES_T_FULL:
|
||||
DEBUGP(DL1C,
|
||||
"Received and handled from l23 - L1CTL_RESET_REQ (type=FULL)\n");
|
||||
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RESET_REQ (type=FULL)\n");
|
||||
l1_model_ms->state->state = MS_STATE_IDLE_SEARCHING;
|
||||
virt_l1_sched_stop();
|
||||
l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
|
||||
break;
|
||||
case L1CTL_RES_T_SCHED:
|
||||
virt_l1_sched_restart(l1_model_ms->state->downlink_time);
|
||||
DEBUGP(DL1C,
|
||||
"Received and handled from l23 - L1CTL_RESET_REQ (type=SCHED)\n");
|
||||
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RESET_REQ (type=SCHED)\n");
|
||||
l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
|
||||
break;
|
||||
default:
|
||||
LOGP(DL1C, LOGL_ERROR,
|
||||
"Received and ignored from l23 - L1CTL_RESET_REQ (type=unknown)\n");
|
||||
LOGP(DL1C, LOGL_ERROR, "Received and ignored from l23 - L1CTL_RESET_REQ (type=unknown)\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -434,16 +432,15 @@ void l1ctl_rx_reset_req(struct msgb *msg)
|
|||
*/
|
||||
void l1ctl_rx_ccch_mode_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_ccch_mode_req *ccch_mode_req =
|
||||
(struct l1ctl_ccch_mode_req *)l1h->data;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_ccch_mode_req *ccch_mode_req = (struct l1ctl_ccch_mode_req *) l1h->data;
|
||||
uint8_t ccch_mode = ccch_mode_req->ccch_mode;
|
||||
|
||||
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_CCCH_MODE_REQ\n");
|
||||
|
||||
l1_model_ms->state->serving_cell.ccch_mode = ccch_mode;
|
||||
|
||||
// check if more has to be done here
|
||||
/* check if more has to be done here */
|
||||
l1ctl_tx_ccch_mode_conf(ccch_mode);
|
||||
}
|
||||
|
||||
|
@ -460,21 +457,18 @@ void l1ctl_rx_ccch_mode_req(struct msgb *msg)
|
|||
*/
|
||||
void l1ctl_rx_tch_mode_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_tch_mode_req *tch_mode_req =
|
||||
(struct l1ctl_tch_mode_req *)l1h->data;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_tch_mode_req *tch_mode_req = (struct l1ctl_tch_mode_req *) l1h->data;
|
||||
|
||||
l1_model_tch_mode_set(tch_mode_req->tch_mode);
|
||||
l1_model_ms->state->audio_mode = tch_mode_req->audio_mode;
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received and handled from l23 - L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n",
|
||||
tch_mode_req->tch_mode, tch_mode_req->audio_mode);
|
||||
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n",
|
||||
tch_mode_req->tch_mode, tch_mode_req->audio_mode);
|
||||
|
||||
// TODO: configure audio hardware for encoding / decoding / recording / playing voice
|
||||
/* TODO: configure audio hardware for encoding / decoding / recording / playing voice */
|
||||
|
||||
l1ctl_tx_tch_mode_conf(l1_model_ms->state->tch_mode,
|
||||
l1_model_ms->state->audio_mode);
|
||||
l1ctl_tx_tch_mode_conf(l1_model_ms->state->tch_mode, l1_model_ms->state->audio_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -492,13 +486,11 @@ void l1ctl_rx_tch_mode_req(struct msgb *msg)
|
|||
*/
|
||||
void l1ctl_rx_neigh_pm_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_neigh_pm_req *pm_req =
|
||||
(struct l1ctl_neigh_pm_req *)l1h->data;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_neigh_pm_req *pm_req = (struct l1ctl_neigh_pm_req *) l1h->data;
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received and ignored from l23 - L1CTL_NEIGH_PM_REQ new list with %u entries\n",
|
||||
pm_req->n);
|
||||
DEBUGP(DL1C, "Received and ignored from l23 - L1CTL_NEIGH_PM_REQ new list with %u entries\n",
|
||||
pm_req->n);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -525,9 +517,8 @@ void l1ctl_rx_sim_req(struct msgb *msg)
|
|||
uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
|
||||
uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received and ignored from l23 - SIM Request length: %u, data: %s: ",
|
||||
len, osmo_hexdump(data, sizeof(data)));
|
||||
LOGP(DL1C, LOGL_ERROR, "Received and ignored from l23 - SIM Request length: %u, data: %s\n",
|
||||
len, osmo_hexdump(data, sizeof(data)));
|
||||
|
||||
}
|
||||
|
||||
|
@ -548,12 +539,11 @@ void l1ctl_rx_sim_req(struct msgb *msg)
|
|||
void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
|
||||
{
|
||||
struct msgb *msg = l1ctl_msgb_alloc(msg_type);
|
||||
struct l1ctl_reset *reset_resp;
|
||||
reset_resp = (struct l1ctl_reset *)msgb_put(msg, sizeof(*reset_resp));
|
||||
reset_resp->type = reset_type;
|
||||
struct l1ctl_reset *reset_resp = (struct l1ctl_reset *) msgb_put(msg, sizeof(*reset_resp));
|
||||
|
||||
reset_resp->type = reset_type;
|
||||
DEBUGP(DL1C, "Sending to l23 - %s (reset_type: %u)\n", getL1ctlPrimName(msg_type), reset_type);
|
||||
|
||||
DEBUGP(DL1C, "Sending to l23 - %s (reset_type: %u)\n",
|
||||
getL1ctlPrimName(msg_type), reset_type);
|
||||
l1ctl_sap_tx_to_l23(msg);
|
||||
}
|
||||
|
||||
|
@ -570,12 +560,11 @@ void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
|
|||
{
|
||||
struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
|
||||
struct l1ctl_ccch_mode_conf *mode_conf;
|
||||
mode_conf = (struct l1ctl_ccch_mode_conf *)msgb_put(msg,
|
||||
sizeof(*mode_conf));
|
||||
|
||||
mode_conf = (struct l1ctl_ccch_mode_conf *) msgb_put(msg, sizeof(*mode_conf));
|
||||
mode_conf->ccch_mode = ccch_mode;
|
||||
|
||||
DEBUGP(DL1C, "Sending to l23 - L1CTL_CCCH_MODE_CONF (mode: %u)\n",
|
||||
ccch_mode);
|
||||
DEBUGP(DL1C, "Sending to l23 - L1CTL_CCCH_MODE_CONF (mode: %u)\n", ccch_mode);
|
||||
l1ctl_sap_tx_to_l23(msg);
|
||||
}
|
||||
|
||||
|
@ -593,56 +582,53 @@ void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode)
|
|||
{
|
||||
struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
|
||||
struct l1ctl_tch_mode_conf *mode_conf;
|
||||
mode_conf = (struct l1ctl_tch_mode_conf *)msgb_put(msg,
|
||||
sizeof(*mode_conf));
|
||||
|
||||
mode_conf = (struct l1ctl_tch_mode_conf *) msgb_put(msg, sizeof(*mode_conf));
|
||||
mode_conf->tch_mode = tch_mode;
|
||||
mode_conf->audio_mode = audio_mode;
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Sending to l23 - L1CTL_TCH_MODE_CONF (tch_mode: %u, audio_mode: %u)\n",
|
||||
tch_mode, audio_mode);
|
||||
DEBUGP(DL1C, "Sending to l23 - L1CTL_TCH_MODE_CONF (tch_mode: %u, audio_mode: %u)\n",
|
||||
tch_mode, audio_mode);
|
||||
l1ctl_sap_tx_to_l23(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the scheduled fn for a msg depending on its chan_nr and link_id.
|
||||
*/
|
||||
uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
||||
uint8_t link_id)
|
||||
uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr, uint8_t link_id)
|
||||
{
|
||||
uint8_t chan_type, chan_ss, chan_ts;
|
||||
rsl_dec_chan_nr(chan_nr, &chan_type, &chan_ss, &chan_ts);
|
||||
|
||||
uint32_t sched_fn = cur_time.fn;
|
||||
uint16_t mod_102 = cur_time.fn % 2 * 51;
|
||||
|
||||
rsl_dec_chan_nr(chan_nr, &chan_type, &chan_ss, &chan_ts);
|
||||
|
||||
/* TODO: Replace this spaghetti monster with some lookup table */
|
||||
switch (chan_type) {
|
||||
case RSL_CHAN_Bm_ACCHs:
|
||||
switch (link_id) {
|
||||
case LID_DEDIC:
|
||||
// dl=[0...11,13...24] ul=[0...11,13...24]
|
||||
// skip idle frames and frames reserved for TCH_ACCH
|
||||
if(cur_time.t2 == 12 || cur_time.t2 == 25) {
|
||||
/* dl=[0...11,13...24] ul=[0...11,13...24]
|
||||
* skip idle frames and frames reserved for TCH_ACCH */
|
||||
if (cur_time.t2 == 12 || cur_time.t2 == 25)
|
||||
sched_fn++;
|
||||
}
|
||||
break;
|
||||
// dl=42, ul=42+15
|
||||
/* dl=42, ul=42+15 */
|
||||
case LID_SACCH:
|
||||
if((chan_ts & 1)) {
|
||||
// Odd traffic channel timeslot -> dl=[25] ul=[25]
|
||||
// TCH_ACCH always at the end of tch multiframe (mod 26)
|
||||
if ((chan_ts & 1)) {
|
||||
/* Odd traffic channel timeslot -> dl=[25] ul=[25]
|
||||
* TCH_ACCH always at the end of tch multiframe (mod 26) */
|
||||
sched_fn -= cur_time.t2;
|
||||
sched_fn += 25;
|
||||
}
|
||||
else {
|
||||
// Even traffic channel timeslot -> dl=[12] ul=[12]
|
||||
if(cur_time.t2 <= 12) {
|
||||
} else {
|
||||
/* Even traffic channel timeslot -> dl=[12] ul=[12] */
|
||||
if (cur_time.t2 <= 12) {
|
||||
sched_fn -= cur_time.t2;
|
||||
sched_fn += 12;
|
||||
} else {
|
||||
sched_fn -= cur_time.t2;
|
||||
sched_fn += 26 + 12;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -653,9 +639,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
switch (chan_ss) {
|
||||
case 0:
|
||||
switch (link_id) {
|
||||
// dl=22, ul=22+15
|
||||
/* dl=22, ul=22+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 22 + 15) {
|
||||
if (cur_time.t3 <= 22 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 22 + 15;
|
||||
} else {
|
||||
|
@ -663,9 +649,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 22 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=42, ul=42+15
|
||||
/* dl=42, ul=42+15 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 42 + 15) {
|
||||
if (mod_102 <= 42 + 15) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 42 + 15;
|
||||
} else {
|
||||
|
@ -677,9 +663,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 1:
|
||||
switch (link_id) {
|
||||
// dl=26, ul=26+15
|
||||
/* dl=26, ul=26+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 26 + 15) {
|
||||
if (cur_time.t3 <= 26 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 26 + 15;
|
||||
} else {
|
||||
|
@ -687,9 +673,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 26 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=46, ul=46+15
|
||||
/* dl=46, ul=46+15 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 46 + 15) {
|
||||
if (mod_102 <= 46 + 15) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 46 + 15;
|
||||
} else {
|
||||
|
@ -701,9 +687,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 2:
|
||||
switch (link_id) {
|
||||
// dl=32, ul=32+15
|
||||
/* dl=32, ul=32+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 32 + 15) {
|
||||
if (cur_time.t3 <= 32 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 32 + 15;
|
||||
} else {
|
||||
|
@ -711,9 +697,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 32 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=51+42, ul=51+42+15
|
||||
/* dl=51+42, ul=51+42+15 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 51 + 42 + 15) {
|
||||
if (mod_102 <= 51 + 42 + 15) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 51 + 42 + 15;
|
||||
} else {
|
||||
|
@ -725,9 +711,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 3:
|
||||
switch (link_id) {
|
||||
// dl=36, ul=36+15
|
||||
/* dl=36, ul=36+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 36 + 15) {
|
||||
if (cur_time.t3 <= 36 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 36 + 15;
|
||||
} else {
|
||||
|
@ -735,9 +721,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 36 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=51+46, ul=51+46+15
|
||||
/* dl=51+46, ul=51+46+15 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 51 + 46 + 15) {
|
||||
if (mod_102 <= 51 + 46 + 15) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 51 + 46 + 15;
|
||||
} else {
|
||||
|
@ -753,9 +739,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
switch (chan_ss) {
|
||||
case 0:
|
||||
switch (link_id) {
|
||||
// dl=0, ul=0+15
|
||||
/* dl=0, ul=0+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 0 + 15) {
|
||||
if (cur_time.t3 <= 0 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 0 + 15;
|
||||
} else {
|
||||
|
@ -763,9 +749,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 0 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=32, ul=32+15
|
||||
/* dl=32, ul=32+15 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 32 + 15) {
|
||||
if (mod_102 <= 32 + 15) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 32 + 15;
|
||||
} else {
|
||||
|
@ -777,9 +763,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 1:
|
||||
switch (link_id) {
|
||||
// dl=4, ul=4+15
|
||||
/* dl=4, ul=4+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 4 + 15) {
|
||||
if (cur_time.t3 <= 4 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 4 + 15;
|
||||
} else {
|
||||
|
@ -787,9 +773,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 4 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=36, ul=36+15
|
||||
/* dl=36, ul=36+15 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 36 + 15) {
|
||||
if (mod_102 <= 36 + 15) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 36 + 15;
|
||||
} else {
|
||||
|
@ -801,9 +787,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 2:
|
||||
switch (link_id) {
|
||||
// dl=8, ul=8+15
|
||||
/* dl=8, ul=8+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 8 + 15) {
|
||||
if (cur_time.t3 <= 8 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 8 + 15;
|
||||
} else {
|
||||
|
@ -811,9 +797,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 8 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=40, ul=40+15
|
||||
/* dl=40, ul=40+15 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 40 + 15) {
|
||||
if (mod_102 <= 40 + 15) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 40 + 15;
|
||||
} else {
|
||||
|
@ -825,9 +811,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 3:
|
||||
switch (link_id) {
|
||||
// dl=12, ul=12+15
|
||||
/* dl=12, ul=12+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 12 + 15) {
|
||||
if (cur_time.t3 <= 12 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 12 + 15;
|
||||
} else {
|
||||
|
@ -835,9 +821,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 12 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=44, ul=44+15
|
||||
/* dl=44, ul=44+15 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 44 + 15) {
|
||||
if (mod_102 <= 44 + 15) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 44 + 15;
|
||||
} else {
|
||||
|
@ -849,9 +835,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 4:
|
||||
switch (link_id) {
|
||||
// dl=16, ul=16+15
|
||||
/* dl=16, ul=16+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 16 + 15) {
|
||||
if (cur_time.t3 <= 16 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 16 + 15;
|
||||
} else {
|
||||
|
@ -859,9 +845,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 16 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=51+32, ul=51+32+15
|
||||
/* dl=51+32, ul=51+32+15 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 51 + 32 + 15) {
|
||||
if (mod_102 <= 51 + 32 + 15) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 51 + 32 + 15;
|
||||
} else {
|
||||
|
@ -873,9 +859,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 5:
|
||||
switch (link_id) {
|
||||
// dl=20, ul=36+15
|
||||
/* dl=20, ul=36+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 20 + 15) {
|
||||
if (cur_time.t3 <= 20 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 20 + 15;
|
||||
} else {
|
||||
|
@ -883,9 +869,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 20 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=51+36, ul=51+36+15 ==> 0
|
||||
/* dl=51+36, ul=51+36+15 ==> 0 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 0) {
|
||||
if (mod_102 <= 0) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 0;
|
||||
} else {
|
||||
|
@ -897,9 +883,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 6:
|
||||
switch (link_id) {
|
||||
// dl=24, ul=24+15
|
||||
/* dl=24, ul=24+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 24 + 15) {
|
||||
if (cur_time.t3 <= 24 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 24 + 15;
|
||||
} else {
|
||||
|
@ -907,9 +893,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 24 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=51+40, ul=51+40+15 ==> 4
|
||||
/* dl=51+40, ul=51+40+15 ==> 4 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 4) {
|
||||
if (mod_102 <= 4) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 4;
|
||||
} else {
|
||||
|
@ -921,9 +907,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
break;
|
||||
case 7:
|
||||
switch (link_id) {
|
||||
// dl=28, ul=28+15
|
||||
/* dl=28, ul=28+15 */
|
||||
case LID_DEDIC:
|
||||
if(cur_time.t3 <= 28 + 15) {
|
||||
if (cur_time.t3 <= 28 + 15) {
|
||||
sched_fn -= cur_time.t3;
|
||||
sched_fn += 28 + 15;
|
||||
} else {
|
||||
|
@ -931,9 +917,9 @@ uint32_t sched_fn_ul(struct gsm_time cur_time, uint8_t chan_nr,
|
|||
sched_fn += 51 + 28 + 15;
|
||||
}
|
||||
break;
|
||||
// dl=51+44, ul=51+44+15 ==> 8
|
||||
/* dl=51+44, ul=51+44+15 ==> 8 */
|
||||
case LID_SACCH:
|
||||
if(mod_102 <= 8) {
|
||||
if (mod_102 <= 8) {
|
||||
sched_fn -= mod_102;
|
||||
sched_fn += 8;
|
||||
} else {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/* Socket based Layer1 <-> Layer23 communication over L1CTL primitives. */
|
||||
|
||||
/* (C) 2016 Sebastian Stumpf
|
||||
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
|
@ -14,7 +14,7 @@
|
|||
* 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
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
@ -61,36 +61,39 @@
|
|||
static int l1ctl_sock_data_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
{
|
||||
struct l1ctl_sock_inst *lsi = ofd->data;
|
||||
// Check if request is really read request
|
||||
if (what & BSC_FD_READ) {
|
||||
struct msgb *msg = msgb_alloc(L1CTL_SOCK_MSGB_SIZE,
|
||||
"L1CTL sock rx");
|
||||
int rc;
|
||||
uint16_t len;
|
||||
struct l1ctl_hdr *l1h;
|
||||
// read length of the message first and convert to host byte order
|
||||
rc = read(ofd->fd, &len, sizeof(len));
|
||||
if (rc < sizeof(len)) {
|
||||
goto ERR;
|
||||
}
|
||||
// convert to host byte order
|
||||
len = ntohs(len);
|
||||
if (len <= 0 || len > L1CTL_SOCK_MSGB_SIZE) {
|
||||
goto ERR;
|
||||
}
|
||||
rc = read(ofd->fd, msgb_data(msg), len);
|
||||
struct l1ctl_hdr *l1h;
|
||||
struct msgb *msg;
|
||||
uint16_t len;
|
||||
int rc;
|
||||
|
||||
if (rc == len) {
|
||||
msgb_put(msg, rc);
|
||||
l1h = (void *) msgb_data(msg);
|
||||
msg->l1h = l1h;
|
||||
lsi->recv_cb(lsi, msg);
|
||||
return 0;
|
||||
}
|
||||
ERR: perror(
|
||||
"Failed to receive msg from l2. Connection will be closed.\n");
|
||||
l1ctl_sock_disconnect(lsi);
|
||||
/* Check if request is really read request */
|
||||
if (!(what & BSC_FD_READ))
|
||||
return 0;
|
||||
|
||||
msg = msgb_alloc(L1CTL_SOCK_MSGB_SIZE, "L1CTL sock rx");
|
||||
|
||||
/* read length of the message first and convert to host byte order */
|
||||
rc = read(ofd->fd, &len, sizeof(len));
|
||||
if (rc < sizeof(len))
|
||||
goto err_close;
|
||||
|
||||
/* convert to host byte order */
|
||||
len = ntohs(len);
|
||||
if (len <= 0 || len > L1CTL_SOCK_MSGB_SIZE)
|
||||
goto err_close;
|
||||
|
||||
rc = read(ofd->fd, msgb_data(msg), len);
|
||||
if (rc == len) {
|
||||
msgb_put(msg, rc);
|
||||
l1h = (void *) msgb_data(msg);
|
||||
msg->l1h = l1h;
|
||||
lsi->recv_cb(lsi, msg);
|
||||
return 0;
|
||||
}
|
||||
err_close:
|
||||
perror("Failed to receive msg from l2. Connection will be closed.\n");
|
||||
l1ctl_sock_disconnect(lsi);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -142,8 +145,7 @@ struct l1ctl_sock_inst *l1ctl_sock_init(
|
|||
strcpy(local_addr.sun_path, path);
|
||||
unlink(local_addr.sun_path);
|
||||
|
||||
if ((rc = bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr)))
|
||||
!= 0) {
|
||||
if ((rc = bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr))) != 0) {
|
||||
fprintf(stderr, "Failed to bind the unix domain socket. '%s'\n",
|
||||
local_addr.sun_path);
|
||||
return NULL;
|
||||
|
@ -161,7 +163,7 @@ struct l1ctl_sock_inst *l1ctl_sock_init(
|
|||
lsi->ofd.fd = fd;
|
||||
lsi->ofd.when = BSC_FD_READ;
|
||||
lsi->ofd.cb = l1ctl_sock_accept_cb;
|
||||
// no connection -> invalid filedescriptor and not 0 (==std_in)
|
||||
/* no connection -> invalid filedescriptor and not 0 (==std_in) */
|
||||
lsi->connection.fd = -1;
|
||||
lsi->l1ctl_sock_path = path;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Logging/Debug support of the virtual physical layer */
|
||||
|
||||
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
|
@ -57,20 +58,27 @@ const char* l1ctlPrimNames[] = {
|
|||
"L1CTL_TRAFFIC_CONF",
|
||||
"L1CTL_TRAFFIC_IND"};
|
||||
|
||||
static const struct log_info_cat default_categories[] = {[DL1C] = {
|
||||
.name = "DL1C",
|
||||
.description = "Layer 1 Control",
|
||||
.color = "\033[1;31m",
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_DEBUG, }, [DVIRPHY] = {
|
||||
.name = "DVIRPHY",
|
||||
.description = "Virtual Layer 1 Interface",
|
||||
.color = "\033[1;31m",
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_DEBUG, }};
|
||||
static const struct log_info_cat default_categories[] = {
|
||||
[DL1C] = {
|
||||
.name = "DL1C",
|
||||
.description = "Layer 1 Control",
|
||||
.color = "\033[1;31m",
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_DEBUG, },
|
||||
[DVIRPHY] = {
|
||||
.name = "DVIRPHY",
|
||||
.description = "Virtual Layer 1 Interface",
|
||||
.color = "\033[1;31m",
|
||||
.enabled = 1,
|
||||
.loglevel = LOGL_DEBUG,
|
||||
}
|
||||
};
|
||||
|
||||
const struct log_info ms_log_info = {.filter_fn = NULL, .cat =
|
||||
default_categories, .num_cat = ARRAY_SIZE(default_categories), };
|
||||
const struct log_info ms_log_info = {
|
||||
.filter_fn = NULL,
|
||||
.cat = default_categories,
|
||||
.num_cat = ARRAY_SIZE(default_categories),
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the logging system for the virtual physical layer.
|
||||
|
@ -81,9 +89,9 @@ int ms_log_init(char *cat_mask)
|
|||
|
||||
log_init(&ms_log_info, NULL);
|
||||
stderr_target = log_target_create_stderr();
|
||||
if (!stderr) {
|
||||
if (!stderr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_add_target(stderr_target);
|
||||
log_set_all_filter(stderr_target, 1);
|
||||
//log_set_log_level(stderr_target, 1);
|
||||
|
@ -91,9 +99,9 @@ int ms_log_init(char *cat_mask)
|
|||
log_set_use_color(stderr_target, 0);
|
||||
log_set_print_timestamp(stderr_target, 1);
|
||||
log_set_print_category(stderr_target, 1);
|
||||
if (cat_mask) {
|
||||
if (cat_mask)
|
||||
log_parse_category_mask(stderr_target, cat_mask);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
|
||||
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <virtphy/virt_l1_model.h>
|
||||
#include <talloc.h>
|
||||
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <virtphy/virt_l1_sched.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <virtphy/virt_l1_model.h>
|
||||
|
@ -14,7 +33,7 @@ static uint32_t last_exec_fn = 0;
|
|||
/**
|
||||
* @brief Initialize schedulers data structures.
|
||||
*/
|
||||
void virt_l1_sched_init(struct l1_model_ms * model)
|
||||
void virt_l1_sched_init(struct l1_model_ms *model)
|
||||
{
|
||||
l1_model_ms = model;
|
||||
}
|
||||
|
@ -53,11 +72,10 @@ void virt_l1_sched_stop()
|
|||
struct virt_l1_sched_mframe_item *mi_next, *mi_tmp;
|
||||
|
||||
/* Empty tdma and mframe sched items lists */
|
||||
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry)
|
||||
{
|
||||
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry) {
|
||||
struct virt_l1_sched_tdma_item *ti_next, *ti_tmp;
|
||||
llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list, tdma_item_entry)
|
||||
{
|
||||
|
||||
llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list, tdma_item_entry) {
|
||||
talloc_free(ti_next->msg);
|
||||
llist_del(&ti_next->tdma_item_entry);
|
||||
}
|
||||
|
@ -74,32 +92,31 @@ void virt_l1_sched_execute(uint32_t fn)
|
|||
struct virt_l1_sched_mframe_item *mi_next, *mi_tmp;
|
||||
uint8_t hyperframe_restart = fn < last_exec_fn;
|
||||
|
||||
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry)
|
||||
{
|
||||
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry) {
|
||||
/* execute all registered handler for current mf sched item */
|
||||
uint8_t exec_now = mi_next->fn <= fn || (hyperframe_restart && mi_next->fn > last_exec_fn);
|
||||
/* break loop, as we have an ordered list in case the hyperframe had not been reset */
|
||||
uint8_t break_now = mi_next->fn > fn && !hyperframe_restart;
|
||||
|
||||
if(exec_now) {
|
||||
if (exec_now) {
|
||||
struct virt_l1_sched_tdma_item *ti_next, *ti_tmp;
|
||||
// run through all scheduled tdma sched items for that frame number
|
||||
llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list, tdma_item_entry)
|
||||
{
|
||||
// exec tdma sched item's handler callback
|
||||
// TODO: we do not have a tdma scheduler currently and execute alle scheduled tdma items here at once
|
||||
/* run through all scheduled tdma sched items for that frame number */
|
||||
llist_for_each_entry_safe(ti_next, ti_tmp, &mi_next->tdma_item_list,
|
||||
tdma_item_entry) {
|
||||
/* exec tdma sched item's handler callback */
|
||||
/* TODO: we do not have a TDMA scheduler currently and execute
|
||||
* all scheduled tdma items here at once */
|
||||
ti_next->handler_cb(mi_next->fn, ti_next->msg);
|
||||
// remove handled tdma sched item
|
||||
/* remove handled tdma sched item */
|
||||
llist_del(&ti_next->tdma_item_entry);
|
||||
}
|
||||
// remove handled mframe sched item
|
||||
/* remove handled mframe sched item */
|
||||
llist_del(&mi_next->mframe_item_entry);
|
||||
talloc_free(mi_next);
|
||||
}
|
||||
|
||||
if(break_now) {
|
||||
if (break_now)
|
||||
break;
|
||||
}
|
||||
}
|
||||
last_exec_fn = fn;
|
||||
}
|
||||
|
@ -110,36 +127,33 @@ void virt_l1_sched_execute(uint32_t fn)
|
|||
void virt_l1_sched_schedule(struct msgb * msg, uint32_t fn, uint8_t ts,
|
||||
virt_l1_sched_cb * handler_cb)
|
||||
{
|
||||
struct virt_l1_sched_mframe_item *mi_next = NULL, *mi_tmp = NULL,
|
||||
*mi_fn = NULL;
|
||||
struct virt_l1_sched_mframe_item *mi_next = NULL, *mi_tmp = NULL, *mi_fn = NULL;
|
||||
struct virt_l1_sched_tdma_item *ti_new = NULL;
|
||||
|
||||
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry)
|
||||
{
|
||||
llist_for_each_entry_safe(mi_next, mi_tmp, &mframe_item_list, mframe_item_entry) {
|
||||
if (mi_next->fn == fn) {
|
||||
mi_fn = mi_next;
|
||||
break;
|
||||
} else if (mi_next->fn > fn) {
|
||||
} else if (mi_next->fn > fn)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mi_fn) {
|
||||
// list did not contain mframe item with needed fn
|
||||
/* list did not contain mframe item with needed fn */
|
||||
mi_fn = talloc_zero(NULL, struct virt_l1_sched_mframe_item);
|
||||
mi_fn->fn = fn;
|
||||
// need to manually init the struct content.... no so happy
|
||||
/* need to manually init the struct content.... no so happy */
|
||||
mi_fn->tdma_item_list.prev = &mi_fn->tdma_item_list;
|
||||
mi_fn->tdma_item_list.next = &mi_fn->tdma_item_list;
|
||||
|
||||
// TODO: check if we get an error if list is empty...
|
||||
llist_add(&mi_fn->mframe_item_entry,
|
||||
mi_next->mframe_item_entry.prev);
|
||||
|
||||
/* TODO: check if we get an error if list is empty... */
|
||||
llist_add(&mi_fn->mframe_item_entry, mi_next->mframe_item_entry.prev);
|
||||
}
|
||||
|
||||
ti_new = talloc_zero(mi_fn, struct virt_l1_sched_tdma_item);
|
||||
ti_new->msg = msg;
|
||||
ti_new->handler_cb = handler_cb;
|
||||
ti_new->ts = ts;
|
||||
// simply add at end, no ordering for tdma sched items currently
|
||||
llist_add_tail(&ti_new->tdma_item_entry, &mi_fn->tdma_item_list); // TODO: ordered insert needed if tdma scheduler should be implemented
|
||||
/* simply add at end, no ordering for tdma sched items currently */
|
||||
llist_add_tail(&ti_new->tdma_item_entry, &mi_fn->tdma_item_list);
|
||||
/* TODO: ordered insert needed if tdma scheduler should be implemented */
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
|
||||
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
|
@ -79,9 +80,7 @@ void l1ctl_rx_data_req(struct msgb *msg)
|
|||
|
||||
msg->l2h = data_ind->data;
|
||||
|
||||
virt_l1_sched_schedule(msg, fn_sched, timeslot,
|
||||
&virt_l1_sched_handler_cb);
|
||||
|
||||
virt_l1_sched_schedule(msg, fn_sched, timeslot, &virt_l1_sched_handler_cb);
|
||||
}
|
||||
|
||||
void l1ctl_tx_data_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
|
||||
|
@ -103,16 +102,15 @@ void l1ctl_tx_data_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
|
|||
l1dl->frame_nr = htonl(fn);
|
||||
l1dl->snr = snr;
|
||||
l1dl->rx_level = signal_dbm;
|
||||
l1dl->num_biterr = 0; // no biterrors
|
||||
l1dl->num_biterr = 0; /* no biterrors */
|
||||
l1dl->fire_crc = 0;
|
||||
|
||||
// TODO: data decoding and decryption
|
||||
/* TODO: data decoding and decryption */
|
||||
|
||||
memcpy(l1di->data, msgb_data(msg), msgb_length(msg));
|
||||
|
||||
DEBUGP(DL1C, "Sending signaling-data to l23.\n");
|
||||
l1ctl_sap_tx_to_l23(l1ctl_msg);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -127,7 +125,7 @@ void l1ctl_tx_data_conf(uint32_t fn, uint16_t snr, uint16_t arfcn)
|
|||
{
|
||||
struct msgb * l1ctl_msg;
|
||||
l1ctl_msg = l1ctl_create_l2_msg(L1CTL_DATA_CONF, fn, snr, arfcn);
|
||||
// send confirm to layer23
|
||||
/* send confirm to layer23 */
|
||||
l1ctl_sap_tx_to_l23(l1ctl_msg);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
|
||||
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
|
||||
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -31,11 +54,10 @@ static uint16_t sync_count = 0;
|
|||
*/
|
||||
void l1ctl_rx_fbsb_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *)l1h->data;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received and handled from l23 - L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
|
||||
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
|
||||
ntohs(sync_req->band_arfcn), sync_req->flags);
|
||||
|
||||
l1_model_ms->state->state = MS_STATE_IDLE_SYNCING;
|
||||
|
@ -50,14 +72,15 @@ void l1ctl_rx_fbsb_req(struct msgb *msg)
|
|||
void prim_fbsb_sync(struct msgb *msg)
|
||||
{
|
||||
struct gsmtap_hdr *gh = msgb_l1(msg);
|
||||
uint32_t fn = ntohl(gh->frame_number); // frame number of the rcv msg
|
||||
uint16_t arfcn = ntohs(gh->arfcn); // arfcn of the received msg
|
||||
uint32_t fn = ntohl(gh->frame_number); /* frame number of the rcv msg */
|
||||
uint16_t arfcn = ntohs(gh->arfcn); /* arfcn of the received msg */
|
||||
|
||||
// ignore messages from other arfcns as the one requested to sync to by l23
|
||||
/* ignore messages from other arfcns as the one requested to sync to by l23 */
|
||||
if (l1_model_ms->state->fbsb.arfcn != arfcn) {
|
||||
talloc_free(msg);
|
||||
// cancel sync if we did not receive a msg on dl from the requested arfcn that we can sync to
|
||||
if(sync_count++ > 20) {
|
||||
/* cancel sync if we did not receive a msg on dl from
|
||||
* the requested arfcn that we can sync to */
|
||||
if (sync_count++ > 20) {
|
||||
sync_count = 0;
|
||||
l1_model_ms->state->state = MS_STATE_IDLE_SEARCHING;
|
||||
l1ctl_tx_fbsb_conf(1, (l1_model_ms->state->fbsb.arfcn));
|
||||
|
@ -92,10 +115,10 @@ void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn)
|
|||
{
|
||||
struct msgb *msg;
|
||||
struct l1ctl_fbsb_conf *resp;
|
||||
uint32_t fn = 0; // 0 should be okay here
|
||||
uint16_t snr = 40; // signal noise ratio > 40db is best signal (unused in virt)
|
||||
int16_t initial_freq_err = 0; // 0 means no error (unused in virt)
|
||||
uint8_t bsic = 0; // bsci can be read from sync burst (unused in virt)
|
||||
uint32_t fn = 0; /* 0 should be okay here */
|
||||
uint16_t snr = 40; /* signal noise ratio > 40db is best signal (unused in virt)*/
|
||||
int16_t initial_freq_err = 0; /* 0 means no error (unused in virt) */
|
||||
uint8_t bsic = 0; /* BSIC can be read from sync burst (unused in virt) */
|
||||
|
||||
msg = l1ctl_create_l2_msg(L1CTL_FBSB_CONF, fn, snr, arfcn);
|
||||
|
||||
|
@ -104,8 +127,7 @@ void l1ctl_tx_fbsb_conf(uint8_t res, uint16_t arfcn)
|
|||
resp->result = res;
|
||||
resp->bsic = bsic;
|
||||
|
||||
DEBUGP(DL1C, "Sending to l23 - %s (res: %u)\n",
|
||||
getL1ctlPrimName(L1CTL_FBSB_CONF), res);
|
||||
DEBUGP(DL1C, "Sending to l23 - %s (res: %u)\n", getL1ctlPrimName(L1CTL_FBSB_CONF), res);
|
||||
|
||||
l1ctl_sap_tx_to_l23(msg);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,26 @@
|
|||
|
||||
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
|
||||
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -22,19 +45,26 @@ static struct l1_model_ms *l1_model_ms = NULL;
|
|||
* @param [in] arfcn to change sig str for.
|
||||
* @param [in] sig_lev the measured signal level value.
|
||||
*/
|
||||
uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev) {
|
||||
if(l1_model_ms->state->pm.timeout_s > 0 || l1_model_ms->state->pm.timeout_us > 0) {
|
||||
osmo_timer_schedule(&l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[arfcn], l1_model_ms->state->pm.timeout_s, l1_model_ms->state->pm.timeout_us);
|
||||
uint16_t prim_pm_set_sig_strength(uint16_t arfcn, int16_t sig_lev)
|
||||
{
|
||||
if (l1_model_ms->state->pm.timeout_s > 0 || l1_model_ms->state->pm.timeout_us > 0) {
|
||||
osmo_timer_schedule(&l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[arfcn],
|
||||
l1_model_ms->state->pm.timeout_s,
|
||||
l1_model_ms->state->pm.timeout_us);
|
||||
}
|
||||
l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn] = sig_lev - l1_model_ms->state->pm.meas.arfcn_sig_lev_red_dbm[arfcn];
|
||||
DEBUGP(DL1C, "Power measurement set for arfcn %u. Set signal level to %d (== rxlev: %u).\n", arfcn, l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn], dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn]));
|
||||
l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn] =
|
||||
sig_lev - l1_model_ms->state->pm.meas.arfcn_sig_lev_red_dbm[arfcn];
|
||||
DEBUGP(DL1C, "Power measurement set for arfcn %u. Set signal level to %d (== rxlev: %u).\n",
|
||||
arfcn, l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn],
|
||||
dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn]));
|
||||
return l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn];
|
||||
}
|
||||
|
||||
void prim_pm_timer_cb(void *data) {
|
||||
// reset the signal level to bad value if no messages have been received from that rfcn for a given time
|
||||
DEBUGP(DL1C,
|
||||
"Timeout occurred for arfcn, signal level reset to worst value.\n");
|
||||
void prim_pm_timer_cb(void *data)
|
||||
{
|
||||
/* reset the signal level to bad value if no messages have been
|
||||
* received from that rfcn for a given time */
|
||||
DEBUGP(DL1C, "Timeout occurred for arfcn, signal level reset to worst value.\n");
|
||||
*((int16_t*)data) = MIN_SIG_LEV_DBM;
|
||||
}
|
||||
|
||||
|
@ -45,50 +75,47 @@ void prim_pm_timer_cb(void *data) {
|
|||
*
|
||||
* @param [in] msg the received message.
|
||||
*
|
||||
* Process power measurement for a given range of arfcns to calculate signal power and connection quality.
|
||||
*
|
||||
* Note: This should only be called after a certain time so some messages have already been received.
|
||||
* Process power measurement for a given range of arfcns to calculate
|
||||
* signal power and connection quality.
|
||||
*
|
||||
* Note: This should only be called after a certain time so some
|
||||
* messages have already been received.
|
||||
*/
|
||||
void l1ctl_rx_pm_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *)l1h->data;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
|
||||
struct msgb *resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
|
||||
uint16_t arfcn_next;
|
||||
// convert to host order
|
||||
|
||||
/* convert to host order */
|
||||
pm_req->range.band_arfcn_from = ntohs(pm_req->range.band_arfcn_from);
|
||||
pm_req->range.band_arfcn_to = ntohs(pm_req->range.band_arfcn_to);
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received from l23 - L1CTL_PM_REQ TYPE=%u, FROM=%d, TO=%d\n",
|
||||
pm_req->type, pm_req->range.band_arfcn_from,
|
||||
pm_req->range.band_arfcn_to);
|
||||
DEBUGP(DL1C, "Received from l23 - L1CTL_PM_REQ TYPE=%u, FROM=%d, TO=%d\n",
|
||||
pm_req->type, pm_req->range.band_arfcn_from, pm_req->range.band_arfcn_to);
|
||||
|
||||
for (arfcn_next = pm_req->range.band_arfcn_from;
|
||||
arfcn_next <= pm_req->range.band_arfcn_to;
|
||||
++arfcn_next) {
|
||||
struct l1ctl_pm_conf *pm_conf =
|
||||
(struct l1ctl_pm_conf *)msgb_put(resp_msg,
|
||||
sizeof(*pm_conf));
|
||||
arfcn_next <= pm_req->range.band_arfcn_to; ++arfcn_next) {
|
||||
struct l1ctl_pm_conf *pm_conf = (struct l1ctl_pm_conf *) msgb_put(resp_msg, sizeof(*pm_conf));
|
||||
pm_conf->band_arfcn = htons(arfcn_next);
|
||||
// set min and max to the value calculated for that arfcn (IGNORE UPLINKK AND PCS AND OTHER FLAGS)
|
||||
/* set min and max to the value calculated for that
|
||||
* arfcn (IGNORE UPLINKK AND PCS AND OTHER FLAGS) */
|
||||
pm_conf->pm[0] = dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]);
|
||||
pm_conf->pm[1] = dbm2rxlev(l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[arfcn_next & ARFCN_NO_FLAGS_MASK]);
|
||||
if (arfcn_next == pm_req->range.band_arfcn_to) {
|
||||
struct l1ctl_hdr *resp_l1h = msgb_l1(resp_msg);
|
||||
resp_l1h->flags |= L1CTL_F_DONE;
|
||||
}
|
||||
// no more space to hold mor pm info in msgb, flush to l23
|
||||
/* no more space to hold mor pm info in msgb, flush to l23 */
|
||||
if (msgb_tailroom(resp_msg) < sizeof(*pm_conf)) {
|
||||
l1ctl_sap_tx_to_l23(resp_msg);
|
||||
resp_msg = l1ctl_msgb_alloc(L1CTL_PM_CONF);
|
||||
}
|
||||
}
|
||||
// transmit the remaining part of pm response to l23
|
||||
if (resp_msg) {
|
||||
/* transmit the remaining part of pm response to l23 */
|
||||
if (resp_msg)
|
||||
l1ctl_sap_tx_to_l23(resp_msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,10 +127,10 @@ void prim_pm_init(struct l1_model_ms *model)
|
|||
{
|
||||
int i;
|
||||
l1_model_ms = model;
|
||||
// init the signal level of all arfcns with the lowest value possible
|
||||
memset (model->state->pm.meas.arfcn_sig_lev_dbm, MIN_SIG_LEV_DBM, sizeof (int16_t) * 1024);
|
||||
// init timers
|
||||
for(i = 0; i < 1024; ++i) {
|
||||
/* init the signal level of all arfcns with the lowest value possible */
|
||||
memset(model->state->pm.meas.arfcn_sig_lev_dbm, MIN_SIG_LEV_DBM, sizeof (int16_t) * 1024);
|
||||
/* init timers */
|
||||
for (i = 0; i < 1024; ++i) {
|
||||
l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[i].cb = prim_pm_timer_cb;
|
||||
l1_model_ms->state->pm.meas.arfcn_sig_lev_timers[i].data = &l1_model_ms->state->pm.meas.arfcn_sig_lev_dbm[i];
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
|
||||
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
|
@ -39,26 +40,28 @@
|
|||
static struct l1_model_ms *l1_model_ms = NULL;
|
||||
static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg);
|
||||
|
||||
// use if we have a combined uplink (RACH, SDCCH, ...) (see http://www.rfwireless-world.com/Terminology/GSM-combined-channel-configuration.html)
|
||||
// if we have no combined channel config, uplink consists of only RACH
|
||||
static uint8_t t3_to_rach_comb[51] = {
|
||||
/* use if we have a combined uplink (RACH, SDCCH, ...) (see
|
||||
* http://www.rfwireless-world.com/Terminology/GSM-combined-channel-configuration.html)
|
||||
* if we have no combined channel config, uplink consists of only RACH * */
|
||||
static const uint8_t t3_to_rach_comb[51] = {
|
||||
0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 25, 25,
|
||||
25, 25, 25, 25, 25, 26, 27, 27, 27, 27};
|
||||
static uint8_t rach_to_t3_comb[27] = {
|
||||
25, 25, 25, 25, 25, 26, 27, 27, 27, 27
|
||||
};
|
||||
static const uint8_t rach_to_t3_comb[27] = {
|
||||
4, 5, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35, 36, 45, 46};
|
||||
30, 31, 32, 33, 34, 35, 36, 45, 46
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Handler callback function for RACH request.
|
||||
*
|
||||
* @param [in] msg the msg to sent over virtual um.
|
||||
*/
|
||||
static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
|
||||
static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb *msg)
|
||||
{
|
||||
gsmtapl1_tx_to_virt_um(fn, msg);
|
||||
l1ctl_tx_rach_conf(fn,
|
||||
l1_model_ms->state->serving_cell.arfcn);
|
||||
l1ctl_tx_rach_conf(fn, l1_model_ms->state->serving_cell.arfcn);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,30 +76,29 @@ static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
|
|||
*/
|
||||
void l1ctl_rx_rach_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
|
||||
struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *)ul->payload;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
|
||||
struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
|
||||
uint32_t fn_sched;
|
||||
uint8_t ts = 1; //FIXME mostly, ts 1 is used for rach, where can i get that info? System info?
|
||||
uint8_t ts = 1; /* FIXME mostly, ts 1 is used for rach, where can i get that info? System info? */
|
||||
uint16_t offset = ntohs(rach_req->offset);
|
||||
|
||||
DEBUGP(DL1C,
|
||||
"Received and handled from l23 - L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
|
||||
rach_req->ra, offset, rach_req->combined);
|
||||
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
|
||||
rach_req->ra, offset, rach_req->combined);
|
||||
|
||||
if (rach_req->ra == 0x03) {
|
||||
if (rach_req->ra == 0x03)
|
||||
fn_sched = 42;
|
||||
}
|
||||
|
||||
// set ra data to msg (8bits, the 11bit option is not used)
|
||||
/* set ra data to msg (8bits, the 11bit option is not used for GSM) */
|
||||
msg->l2h = msgb_put(msg, sizeof(uint8_t));
|
||||
*msg->l2h = rach_req->ra;
|
||||
|
||||
// chan_nr need to be encoded here, as it is not set by l23 for the rach request, but needed by virt um
|
||||
/* chan_nr need to be encoded here, as it is not set by l23 for
|
||||
* the rach request, but needed by virt um */
|
||||
ul->chan_nr = rsl_enc_chan_nr(RSL_CHAN_RACH, 0, ts);
|
||||
ul->link_id = LID_DEDIC;
|
||||
|
||||
// sched fn calculation if we have a combined ccch channel configuration
|
||||
/* sched fn calculation if we have a combined ccch channel configuration */
|
||||
if (rach_req->combined) {
|
||||
/* add elapsed RACH slots to offset */
|
||||
offset += t3_to_rach_comb[l1_model_ms->state->current_time.t3];
|
||||
|
@ -104,12 +106,10 @@ void l1ctl_rx_rach_req(struct msgb *msg)
|
|||
fn_sched = l1_model_ms->state->current_time.fn - l1_model_ms->state->current_time.t3;
|
||||
fn_sched += offset / 27 * 51;
|
||||
fn_sched += rach_to_t3_comb[offset % 27];
|
||||
} else {
|
||||
} else
|
||||
fn_sched = l1_model_ms->state->current_time.fn + offset;
|
||||
}
|
||||
|
||||
virt_l1_sched_schedule(msg, fn_sched, ts, &virt_l1_sched_handler_cb);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
/* (C) 2010 by Dieter Spaar <spaar@mirider.augusta.de>
|
||||
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
|
@ -63,20 +64,18 @@ static void virt_l1_sched_handler_cb(uint32_t fn, struct msgb * msg)
|
|||
*/
|
||||
void l1ctl_rx_traffic_req(struct msgb *msg)
|
||||
{
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *)l1h->data;
|
||||
struct l1ctl_traffic_req *tr = (struct l1ctl_traffic_req *)ul->payload;
|
||||
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
|
||||
struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
|
||||
struct l1ctl_traffic_req *tr = (struct l1ctl_traffic_req *) ul->payload;
|
||||
uint8_t rsl_chantype, subslot, timeslot;
|
||||
uint32_t fn_sched = sched_fn_ul(l1_model_ms->state->current_time,
|
||||
ul->chan_nr, ul->link_id);
|
||||
uint32_t fn_sched = sched_fn_ul(l1_model_ms->state->current_time, ul->chan_nr, ul->link_id);
|
||||
|
||||
rsl_dec_chan_nr(ul->chan_nr, &rsl_chantype, &subslot, ×lot);
|
||||
DEBUGP(DL1C, "Received and handled from l23 - L1CTL_TRAFFIC_REQ\n");
|
||||
|
||||
msg->l2h = tr->data;
|
||||
|
||||
virt_l1_sched_schedule(msg, fn_sched, timeslot,
|
||||
&virt_l1_sched_handler_cb);
|
||||
virt_l1_sched_schedule(msg, fn_sched, timeslot, &virt_l1_sched_handler_cb);
|
||||
}
|
||||
|
||||
void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
|
||||
|
@ -89,10 +88,8 @@ void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
|
|||
struct l1ctl_info_dl * l1dl;
|
||||
uint8_t rsl_chan_type, subchan, timeslot;
|
||||
l1ctl_msg = l1ctl_msgb_alloc(L1CTL_TRAFFIC_IND);
|
||||
l1dl = (struct l1ctl_info_dl *)msgb_put(l1ctl_msg,
|
||||
sizeof(struct l1ctl_info_dl));
|
||||
l1ti = (struct l1ctl_traffic_ind *)msgb_put(
|
||||
l1ctl_msg, sizeof(struct l1ctl_traffic_ind));
|
||||
l1dl = (struct l1ctl_info_dl *) msgb_put(l1ctl_msg, sizeof(*l1dl));
|
||||
l1ti = (struct l1ctl_traffic_ind *) msgb_put(l1ctl_msg, sizeof(*l1ti));
|
||||
|
||||
rsl_dec_chan_nr(chan_nr, &rsl_chan_type, &subchan, ×lot);
|
||||
|
||||
|
@ -102,10 +99,10 @@ void l1ctl_tx_traffic_ind(struct msgb *msg, uint16_t arfcn, uint8_t link_id,
|
|||
l1dl->frame_nr = htonl(fn);
|
||||
l1dl->snr = snr;
|
||||
l1dl->rx_level = signal_dbm;
|
||||
l1dl->num_biterr = 0; // no biterrors
|
||||
l1dl->num_biterr = 0; /* no biterrors */
|
||||
l1dl->fire_crc = 0;
|
||||
|
||||
// TODO: traffic decoding and decryption
|
||||
/* TODO: traffic decoding and decryption */
|
||||
|
||||
memcpy(l1ti->data, msgb_data(msg), msgb_length(msg));
|
||||
DEBUGP(DL1C, "Sending to l23 - L1CTL_TRAFFIC_IND\n");
|
||||
|
@ -124,7 +121,7 @@ void l1ctl_tx_traffic_conf(uint32_t fn, uint16_t snr, uint16_t arfcn)
|
|||
{
|
||||
struct msgb * l1ctl_msg;
|
||||
l1ctl_msg = l1ctl_create_l2_msg(L1CTL_TRAFFIC_CONF, fn, snr, arfcn);
|
||||
// send confirm to layer23
|
||||
/* send confirm to layer23 */
|
||||
l1ctl_sap_tx_to_l23(l1ctl_msg);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,24 @@
|
|||
/* osmocom includes */
|
||||
|
||||
/* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <stdint.h>
|
||||
|
@ -18,13 +37,13 @@
|
|||
#define DEFAULT_MCAST_PORT 4729 /* IANA-registered port for GSMTAP */
|
||||
#define DEFAULT_LOG_MASK "DL1C,1:DVIRPHY,1"
|
||||
|
||||
static char* dl_rx_grp = DEFAULT_MS_MCAST_GROUP;
|
||||
static char* ul_tx_grp = DEFAULT_BTS_MCAST_GROUP;
|
||||
static char *dl_rx_grp = DEFAULT_MS_MCAST_GROUP;
|
||||
static char *ul_tx_grp = DEFAULT_BTS_MCAST_GROUP;
|
||||
static int port = DEFAULT_MCAST_PORT;
|
||||
static char* log_mask = DEFAULT_LOG_MASK;
|
||||
static char * l1ctl_sock_path = L1CTL_SOCK_PATH;
|
||||
static char * arfcn_sig_lev_red_mask = NULL;
|
||||
static char * pm_timeout = NULL;
|
||||
static char *log_mask = DEFAULT_LOG_MASK;
|
||||
static char *l1ctl_sock_path = L1CTL_SOCK_PATH;
|
||||
static char *arfcn_sig_lev_red_mask = NULL;
|
||||
static char *pm_timeout = NULL;
|
||||
|
||||
static void handle_options(int argc, char **argv)
|
||||
{
|
||||
|
@ -75,17 +94,16 @@ static void handle_options(int argc, char **argv)
|
|||
|
||||
void parse_pm_timeout(struct l1_model_ms *model, char *pm_timeout) {
|
||||
|
||||
if(!pm_timeout || (strcmp(pm_timeout, "") == 0)) {
|
||||
if (!pm_timeout || (strcmp(pm_timeout, "") == 0))
|
||||
return;
|
||||
}
|
||||
// seconds
|
||||
|
||||
/* seconds */
|
||||
char *buf = strtok(pm_timeout, ":");
|
||||
model->state->pm.timeout_s = atoi(buf);
|
||||
// microseconds
|
||||
/* microseconds */
|
||||
buf = strtok(NULL, ":");
|
||||
if(buf) {
|
||||
if (buf)
|
||||
model->state->pm.timeout_us = atoi(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,30 +111,30 @@ void parse_pm_timeout(struct l1_model_ms *model, char *pm_timeout) {
|
|||
*/
|
||||
void parse_arfcn_sig_lev_red(struct l1_model_ms *model, char * arfcn_sig_lev_red_mask) {
|
||||
|
||||
if(!arfcn_sig_lev_red_mask || (strcmp(arfcn_sig_lev_red_mask, "") == 0)) {
|
||||
if (!arfcn_sig_lev_red_mask || (strcmp(arfcn_sig_lev_red_mask, "") == 0))
|
||||
return;
|
||||
}
|
||||
|
||||
char *token = strtok(arfcn_sig_lev_red_mask, ":");
|
||||
do {
|
||||
char* colon = strstr(token, ",");
|
||||
uint16_t arfcn;
|
||||
uint8_t red;
|
||||
if(!colon) {
|
||||
if (!colon)
|
||||
continue;
|
||||
}
|
||||
|
||||
colon[0] = '\0';
|
||||
|
||||
arfcn = atoi(token);
|
||||
red = atoi(colon + 1);
|
||||
|
||||
//TODO: this may go wild if the token string is not properly formatted
|
||||
/* TODO: this may go wild if the token string is not properly formatted */
|
||||
model->state->pm.meas.arfcn_sig_lev_red_dbm[arfcn] = red;
|
||||
} while ((token = strtok(NULL, ":")));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// init loginfo
|
||||
/* init loginfo */
|
||||
static struct l1_model_ms *model;
|
||||
|
||||
handle_options(argc, argv);
|
||||
|
@ -136,7 +154,7 @@ int main(int argc, char *argv[])
|
|||
l1ctl_sap_init(model);
|
||||
virt_l1_sched_init(model);
|
||||
|
||||
// apply timeout and arfcn reduction value config to model
|
||||
/* apply timeout and arfcn reduction value config to model */
|
||||
parse_pm_timeout(model, pm_timeout);
|
||||
parse_arfcn_sig_lev_red(model, arfcn_sig_lev_red_mask);
|
||||
|
||||
|
@ -146,12 +164,12 @@ int main(int argc, char *argv[])
|
|||
l1ctl_sock_path);
|
||||
|
||||
while (1) {
|
||||
// handle osmocom fd READ events (l1ctl-unix-socket, virtual-um-mcast-socket)
|
||||
/* handle osmocom fd READ events (l1ctl-unix-socket, virtual-um-mcast-socket) */
|
||||
osmo_select_main(0);
|
||||
}
|
||||
|
||||
l1_model_ms_destroy(model);
|
||||
|
||||
// not reached
|
||||
/* not reached */
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue