summaryrefslogtreecommitdiffstats
path: root/src/host/layer23
diff options
context:
space:
mode:
authorAndreas.Eversberg <jolly@eversberg.eu>2011-07-28 20:54:42 +0200
committerSylvain Munaut <tnt@246tNt.com>2011-07-28 21:30:51 +0200
commit1a5461fb2beb96bfa004245a102cd4c1422baa2a (patch)
tree71b3dce4ea3765b61610015b58c79c2322127456 /src/host/layer23
parente042cbb29763f21fd2ed7076c15db87b037ce73a (diff)
layer23: Add mobile support for sending / receiving voice frame through MNCC
Support GSM FR codec only so far. Written-by: Andreas Eversberg <jolly@eversberg.eu> Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Diffstat (limited to 'src/host/layer23')
-rw-r--r--src/host/layer23/configure.ac1
-rw-r--r--src/host/layer23/include/osmocom/bb/common/l1ctl.h10
-rw-r--r--src/host/layer23/include/osmocom/bb/common/osmocom_data.h14
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/gsm48_cc.h1
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h5
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/voice.h7
-rw-r--r--src/host/layer23/src/common/l1ctl.c130
-rw-r--r--src/host/layer23/src/misc/Makefile.am2
-rw-r--r--src/host/layer23/src/misc/app_cbch_sniff.c4
-rw-r--r--src/host/layer23/src/mobile/Makefile.am4
-rw-r--r--src/host/layer23/src/mobile/app_mobile.c18
-rw-r--r--src/host/layer23/src/mobile/gsm48_cc.c34
-rw-r--r--src/host/layer23/src/mobile/gsm48_rr.c60
-rw-r--r--src/host/layer23/src/mobile/voice.c78
14 files changed, 330 insertions, 38 deletions
diff --git a/src/host/layer23/configure.ac b/src/host/layer23/configure.ac
index 0a67fab9..b50868a5 100644
--- a/src/host/layer23/configure.ac
+++ b/src/host/layer23/configure.ac
@@ -16,6 +16,7 @@ dnl checks for libraries
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm)
+PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec)
AC_CHECK_LIB(gps, gps_waiting, CFLAGS+=" -D_HAVE_GPSD" LDFLAGS+=" -lgps",,)
dnl checks for header files
diff --git a/src/host/layer23/include/osmocom/bb/common/l1ctl.h b/src/host/layer23/include/osmocom/bb/common/l1ctl.h
index faa12d5b..5ebea96c 100644
--- a/src/host/layer23/include/osmocom/bb/common/l1ctl.h
+++ b/src/host/layer23/include/osmocom/bb/common/l1ctl.h
@@ -25,10 +25,10 @@ int l1ctl_tx_rach_req(struct osmocom_ms *ms, uint8_t ra, uint16_t offset,
/* Transmit L1CTL_DM_EST_REQ */
int l1ctl_tx_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
- uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode);
+ uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode, uint8_t audio_mode);
int l1ctl_tx_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
uint16_t *ma, uint8_t ma_len, uint8_t chan_nr, uint8_t tsc,
- uint8_t tch_mode);
+ uint8_t tch_mode, uint8_t audio_mode);
/* Transmit L1CTL_DM_FREQ_REQ */
int l1ctl_tx_dm_freq_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
@@ -48,7 +48,8 @@ int l1ctl_tx_fbsb_req(struct osmocom_ms *ms, uint16_t arfcn,
int l1ctl_tx_ccch_mode_req(struct osmocom_ms *ms, uint8_t ccch_mode);
/* Transmit TCH_MODE_REQ */
-int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode);
+int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode,
+ uint8_t audio_mode);
/* Transmit ECHO_REQ */
int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len);
@@ -62,6 +63,9 @@ int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
int l1ctl_tx_sim_req(struct osmocom_ms *ms, uint8_t *data, uint16_t length);
+/* Transmit L1CTL_VOICE_REQ */
+int l1ctl_tx_traffic_req(struct osmocom_ms *ms, struct msgb *msg,
+ uint8_t chan_nr, uint8_t link_id);
/* LAPDm wants to send a PH-* primitive to the physical layer (L1) */
int l1ctl_ph_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
diff --git a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
index d387c917..6ad89cd3 100644
--- a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
+++ b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h
@@ -19,11 +19,22 @@ struct osmocom_ms;
#include <osmocom/bb/mobile/gsm48_mm.h>
#include <osmocom/bb/mobile/gsm48_cc.h>
#include <osmocom/bb/common/sim.h>
+#include <osmocom/bb/common/l1ctl.h>
struct osmosap_entity {
osmosap_cb_t msg_handler;
};
+struct osmol1_entity {
+ int (*l1_traffic_ind)(struct osmocom_ms *ms, struct msgb *msg);
+};
+
+struct osmomncc_entity {
+ int (*mncc_recv)(struct osmocom_ms *ms, int msg_type, void *arg);
+ uint32_t ref;
+};
+
+
/* RX measurement statistics */
struct rx_meas_stat {
uint32_t last_fn;
@@ -45,6 +56,7 @@ struct osmocom_ms {
char name[32];
struct osmo_wqueue l2_wq, sap_wq;
uint16_t test_arfcn;
+ struct osmol1_entity l1_entity;
uint8_t deleting, shutdown, started;
struct gsm_support support;
@@ -59,6 +71,7 @@ struct osmocom_ms {
struct gsm322_cellsel cellsel;
struct gsm48_mmlayer mmlayer;
struct gsm48_cclayer cclayer;
+ struct osmomncc_entity mncc_entity;
struct llist_head trans_list;
};
@@ -104,6 +117,7 @@ struct osmobb_ccch_mode_conf {
struct osmobb_tch_mode_conf {
struct osmocom_ms *ms;
uint8_t tch_mode;
+ uint8_t audio_mode;
};
struct osmobb_neigh_pm_ind {
diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm48_cc.h b/src/host/layer23/include/osmocom/bb/mobile/gsm48_cc.h
index d6ea5756..8cdd1c4f 100644
--- a/src/host/layer23/include/osmocom/bb/mobile/gsm48_cc.h
+++ b/src/host/layer23/include/osmocom/bb/mobile/gsm48_cc.h
@@ -5,7 +5,6 @@ struct gsm48_cclayer {
struct osmocom_ms *ms;
struct llist_head mncc_upqueue;
- int (*mncc_recv)(struct osmocom_ms *, int, void *);
};
int gsm48_cc_init(struct osmocom_ms *ms);
diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
index cccf279a..756d302f 100644
--- a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
+++ b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
@@ -172,6 +172,9 @@ struct gsm48_rrlayer {
struct osmo_timer_list t_meas;
struct gsm48_rr_meas meas;
uint8_t monitor;
+
+ /* audio flow */
+ uint8_t audio_mode;
};
const char *get_rr_name(int value);
@@ -193,5 +196,7 @@ extern const char *gsm48_rr_state_names[];
int gsm48_rr_start_monitor(struct osmocom_ms *ms);
int gsm48_rr_stop_monitor(struct osmocom_ms *ms);
int gsm48_rr_alter_delay(struct osmocom_ms *ms);
+int gsm48_rr_tx_voice(struct osmocom_ms *ms, struct msgb *msg);
+int gsm48_rr_audio_mode(struct osmocom_ms *ms, uint8_t mode);
#endif /* _GSM48_RR_H */
diff --git a/src/host/layer23/include/osmocom/bb/mobile/voice.h b/src/host/layer23/include/osmocom/bb/mobile/voice.h
new file mode 100644
index 00000000..a0524183
--- /dev/null
+++ b/src/host/layer23/include/osmocom/bb/mobile/voice.h
@@ -0,0 +1,7 @@
+#ifndef _voice_h
+#define _voice_h
+
+int gsm_voice_init(struct osmocom_ms *ms);
+int gsm_send_voice(struct osmocom_ms *ms, struct gsm_data_frame *data);
+
+#endif /* _voice_h */
diff --git a/src/host/layer23/src/common/l1ctl.c b/src/host/layer23/src/common/l1ctl.c
index a249ed71..e3ab4c9c 100644
--- a/src/host/layer23/src/common/l1ctl.c
+++ b/src/host/layer23/src/common/l1ctl.c
@@ -46,6 +46,7 @@
#include <osmocom/bb/common/l1l2_interface.h>
#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
+#include <osmocom/codec/codec.h>
extern struct gsmtap_inst *gsmtap_inst;
@@ -67,6 +68,23 @@ static struct msgb *osmo_l1_alloc(uint8_t msg_type)
}
+static inline int msb_get_bit(uint8_t *buf, int bn)
+{
+ int pos_byte = bn >> 3;
+ int pos_bit = 7 - (bn & 7);
+
+ return (buf[pos_byte] >> pos_bit) & 1;
+}
+
+static inline void msb_set_bit(uint8_t *buf, int bn, int bit)
+{
+ int pos_byte = bn >> 3;
+ int pos_bit = 7 - (bn & 7);
+
+ buf[pos_byte] |= (bit << pos_bit);
+}
+
+
static int osmo_make_band_arfcn(struct osmocom_ms *ms, uint16_t arfcn)
{
/* TODO: Include the band */
@@ -356,7 +374,8 @@ int l1ctl_tx_ccch_mode_req(struct osmocom_ms *ms, uint8_t ccch_mode)
}
/* Transmit L1CTL_TCH_MODE_REQ */
-int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode)
+int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode,
+ uint8_t audio_mode)
{
struct msgb *msg;
struct l1ctl_tch_mode_req *req;
@@ -369,7 +388,7 @@ int l1ctl_tx_tch_mode_req(struct osmocom_ms *ms, uint8_t tch_mode)
req = (struct l1ctl_tch_mode_req *) msgb_put(msg, sizeof(*req));
req->tch_mode = tch_mode;
- req->audio_mode = AUDIO_TX_MICROPHONE | AUDIO_RX_SPEAKER;
+ req->audio_mode = audio_mode;
return osmo_send_l1(ms, msg);
}
@@ -440,7 +459,8 @@ int l1ctl_tx_rach_req(struct osmocom_ms *ms, uint8_t ra, uint16_t offset,
/* Transmit L1CTL_DM_EST_REQ */
int l1ctl_tx_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
- uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode)
+ uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode,
+ uint8_t audio_mode)
{
struct msgb *msg;
struct l1ctl_info_ul *ul;
@@ -462,14 +482,15 @@ int l1ctl_tx_dm_est_req_h0(struct osmocom_ms *ms, uint16_t band_arfcn,
req->h = 0;
req->h0.band_arfcn = htons(band_arfcn);
req->tch_mode = tch_mode;
- req->audio_mode = AUDIO_TX_MICROPHONE | AUDIO_RX_SPEAKER;
+ req->audio_mode = audio_mode;
return osmo_send_l1(ms, msg);
}
int l1ctl_tx_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
uint16_t *ma, uint8_t ma_len,
- uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode)
+ uint8_t chan_nr, uint8_t tsc, uint8_t tch_mode,
+ uint8_t audio_mode)
{
struct msgb *msg;
struct l1ctl_info_ul *ul;
@@ -496,7 +517,7 @@ int l1ctl_tx_dm_est_req_h1(struct osmocom_ms *ms, uint8_t maio, uint8_t hsn,
for (i = 0; i < ma_len; i++)
req->h1.ma[i] = htons(ma[i]);
req->tch_mode = tch_mode;
- req->audio_mode = AUDIO_TX_MICROPHONE | AUDIO_RX_SPEAKER;
+ req->audio_mode = audio_mode;
return osmo_send_l1(ms, msg);
}
@@ -732,12 +753,103 @@ static int rx_l1_tch_mode_conf(struct osmocom_ms *ms, struct msgb *msg)
LOGP(DL1C, LOGL_INFO, "TCH MODE CONF: mode=%u\n", conf->tch_mode);
mc.tch_mode = conf->tch_mode;
+ mc.audio_mode = conf->audio_mode;
mc.ms = ms;
osmo_signal_dispatch(SS_L1CTL, S_L1CTL_TCH_MODE_CONF, &mc);
return 0;
}
+/* Receive L1CTL_TRAFFIC_IND (Traffic Indication from L1) */
+static int rx_l1_traffic_ind(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct l1ctl_info_dl *dl;
+ struct l1ctl_traffic_ind *ti;
+ uint8_t fr[33];
+ int i, di, si;
+
+ /* Header handling */
+ dl = (struct l1ctl_info_dl *) msg->l1h;
+ msg->l2h = dl->payload;
+ ti = (struct l1ctl_traffic_ind *) msg->l2h;
+
+ memset(fr, 0x00, 33);
+ fr[0] = 0xd0;
+ for (i = 0; i < 260; i++) {
+ di = gsm610_bitorder[i];
+ si = (i > 181) ? i + 4 : i;
+ msb_set_bit(fr, 4 + di, msb_get_bit(ti->data, si));
+ }
+ memcpy(ti->data, fr, 33);
+
+ DEBUGP(DL1C, "TRAFFIC IND (%s)\n", osmo_hexdump(ti->data, 33));
+
+ /* distribute or drop */
+ if (ms->l1_entity.l1_traffic_ind) {
+ /* pull the L1 header from the msgb */
+ msgb_pull(msg, msg->l2h - (msg->l1h-sizeof(struct l1ctl_hdr)));
+ msg->l1h = NULL;
+
+ return ms->l1_entity.l1_traffic_ind(ms, msg);
+ }
+
+ msgb_free(msg);
+ return 0;
+}
+
+/* Transmit L1CTL_TRAFFIC_REQ (Traffic Request to L1) */
+int l1ctl_tx_traffic_req(struct osmocom_ms *ms, struct msgb *msg,
+ uint8_t chan_nr, uint8_t link_id)
+{
+ struct l1ctl_hdr *l1h;
+ struct l1ctl_info_ul *l1i_ul;
+ struct l1ctl_traffic_req *tr;
+ uint8_t fr[33];
+ int i, di, si;
+
+ /* Header handling */
+ tr = (struct l1ctl_traffic_req *) msg->l2h;
+
+ DEBUGP(DL1C, "TRAFFIC REQ (%s)\n",
+ osmo_hexdump(msg->l2h, msgb_l2len(msg)));
+
+ if (msgb_l2len(msg) != 33) {
+ LOGP(DL1C, LOGL_ERROR, "Traffic Request has incorrect length "
+ "(%u != 33)\n", msgb_l2len(msg));
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
+ if ((tr->data[0] >> 4) != 0xd) {
+ LOGP(DL1C, LOGL_ERROR, "Traffic Request has incorrect magic "
+ "(%u != 0xd)\n", tr->data[0] >> 4);
+ msgb_free(msg);
+ return -EINVAL;
+ }
+
+ memset(fr, 0x00, 33);
+ for (i = 0; i < 260; i++) {
+ si = gsm610_bitorder[i];
+ di = (i > 181) ? i + 4 : i;
+ msb_set_bit(fr, di, msb_get_bit(tr->data, 4 + si));
+ }
+ memcpy(tr->data, fr, 33);
+// printf("TX %s\n", osmo_hexdump(tr->data, 33));
+
+ /* prepend uplink info header */
+ l1i_ul = (struct l1ctl_info_ul *) msgb_push(msg, sizeof(*l1i_ul));
+
+ l1i_ul->chan_nr = chan_nr;
+ l1i_ul->link_id = link_id;
+
+ /* prepend l1 header */
+ msg->l1h = msgb_push(msg, sizeof(*l1h));
+ l1h = (struct l1ctl_hdr *) msg->l1h;
+ l1h->msg_type = L1CTL_TRAFFIC_REQ;
+
+ return osmo_send_l1(ms, msg);
+}
+
/* Transmit L1CTL_NEIGH_PM_REQ */
int l1ctl_tx_neigh_pm_req(struct osmocom_ms *ms, int num, uint16_t *arfcn)
{
@@ -837,6 +949,12 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
rc = rx_l1_neigh_pm_ind(ms, msg);
msgb_free(msg);
break;
+ case L1CTL_TRAFFIC_IND:
+ rc = rx_l1_traffic_ind(ms, msg);
+ break;
+ case L1CTL_TRAFFIC_CONF:
+ msgb_free(msg);
+ break;
default:
LOGP(DL1C, LOGL_ERROR, "Unknown MSG: %u\n", l1h->msg_type);
msgb_free(msg);
diff --git a/src/host/layer23/src/misc/Makefile.am b/src/host/layer23/src/misc/Makefile.am
index 15d46a8a..0b59f389 100644
--- a/src/host/layer23/src/misc/Makefile.am
+++ b/src/host/layer23/src/misc/Makefile.am
@@ -1,6 +1,6 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
-LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)
+LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS)
bin_PROGRAMS = bcch_scan ccch_scan echo_test cell_log cbch_sniff
diff --git a/src/host/layer23/src/misc/app_cbch_sniff.c b/src/host/layer23/src/misc/app_cbch_sniff.c
index 4a4c9188..fb043db1 100644
--- a/src/host/layer23/src/misc/app_cbch_sniff.c
+++ b/src/host/layer23/src/misc/app_cbch_sniff.c
@@ -58,12 +58,12 @@ static int try_cbch(struct osmocom_ms *ms, struct gsm48_sysinfo *s)
return l1ctl_tx_dm_est_req_h1(ms,
s->maio, s->hsn, s->hopping, s->hopp_len,
s->chan_nr, s->tsc,
- GSM48_CMODE_SIGN);
+ GSM48_CMODE_SIGN, 0);
} else {
LOGP(DRR, LOGL_INFO, "chan_nr = 0x%02x TSC = %d ARFCN = %d\n",
s->chan_nr, s->tsc, s->arfcn);
return l1ctl_tx_dm_est_req_h0(ms, s->arfcn,
- s->chan_nr, s->tsc, GSM48_CMODE_SIGN);
+ s->chan_nr, s->tsc, GSM48_CMODE_SIGN, 0);
}
}
diff --git a/src/host/layer23/src/mobile/Makefile.am b/src/host/layer23/src/mobile/Makefile.am
index fb0423e0..e5cf76a7 100644
--- a/src/host/layer23/src/mobile/Makefile.am
+++ b/src/host/layer23/src/mobile/Makefile.am
@@ -1,11 +1,11 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
-LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOGSM_LIBS)
+LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS)
noinst_LIBRARIES = libmobile.a
libmobile_a_SOURCES = gsm322.c gsm48_cc.c gsm48_mm.c gsm48_rr.c \
mnccms.c settings.c subscriber.c support.c \
- transaction.c vty_interface.c
+ transaction.c vty_interface.c voice.c
bin_PROGRAMS = mobile
diff --git a/src/host/layer23/src/mobile/app_mobile.c b/src/host/layer23/src/mobile/app_mobile.c
index 164f3edb..8b3b5524 100644
--- a/src/host/layer23/src/mobile/app_mobile.c
+++ b/src/host/layer23/src/mobile/app_mobile.c
@@ -35,6 +35,7 @@
#include <osmocom/bb/mobile/vty.h>
#include <osmocom/bb/mobile/app_mobile.h>
#include <osmocom/bb/mobile/mncc.h>
+#include <osmocom/bb/mobile/voice.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/core/msgb.h>
@@ -167,6 +168,7 @@ int mobile_init(struct osmocom_ms *ms)
gsm_sim_init(ms);
gsm48_cc_init(ms);
+ gsm_voice_init(ms);
gsm_subscr_init(ms);
gsm48_rr_init(ms);
gsm48_mm_init(ms);
@@ -191,13 +193,6 @@ int mobile_init(struct osmocom_ms *ms)
}
#endif
- if (mncc_recv_app)
- ms->cclayer.mncc_recv = mncc_recv_app;
- else if (ms->settings.ch_cap == GSM_CAP_SDCCH)
- ms->cclayer.mncc_recv = mncc_recv_dummy;
- else
- ms->cclayer.mncc_recv = mncc_recv_mobile;
-
gsm_random_imei(&ms->settings);
ms->shutdown = 0;
@@ -247,9 +242,12 @@ struct osmocom_ms *mobile_new(char *name)
mncc->msg_type = MS_NEW;
mncc_recv_app(ms, mncc->msg_type, mncc);
}
- ms->cclayer.mncc_recv = mncc_recv_app;
- } else
- ms->cclayer.mncc_recv = mncc_recv_dummy;
+ ms->mncc_entity.mncc_recv = mncc_recv_app;
+ } else if (ms->settings.ch_cap == GSM_CAP_SDCCH)
+ ms->mncc_entity.mncc_recv = mncc_recv_dummy;
+ else
+ ms->mncc_entity.mncc_recv = mncc_recv_mobile;
+
return ms;
}
diff --git a/src/host/layer23/src/mobile/gsm48_cc.c b/src/host/layer23/src/mobile/gsm48_cc.c
index 5abf3f8e..07ee2d9b 100644
--- a/src/host/layer23/src/mobile/gsm48_cc.c
+++ b/src/host/layer23/src/mobile/gsm48_cc.c
@@ -35,6 +35,8 @@
#include <osmocom/bb/mobile/mncc.h>
#include <osmocom/bb/mobile/transaction.h>
#include <osmocom/bb/mobile/gsm48_cc.h>
+#include <osmocom/bb/mobile/voice.h>
+#include <l1ctl_proto.h>
extern void *l23_ctx;
@@ -138,6 +140,9 @@ static const struct value_string gsm_mncc_names[] = {
{ MNCC_STOP_DTMF_REQ, "MNCC_STOP_DTMF_REQ" },
{ MNCC_HOLD_REQ, "MNCC_HOLD_REQ " },
{ MNCC_RETRIEVE_REQ, "MNCC_RETRIEVE_REQ" },
+ { MNCC_FRAME_RECV, "MNCC_FRAME_RECV" },
+ { MNCC_FRAME_DROP, "MNCC_FRAME_DROP" },
+ { MNCC_LCHAN_MODIFY, "MNCC_LCHAN_MODIFY" },
{ 0, NULL }
};
@@ -212,10 +217,10 @@ int mncc_dequeue(struct osmocom_ms *ms)
while ((msg = msgb_dequeue(&cc->mncc_upqueue))) {
mncc = (struct gsm_mncc *)msg->data;
- if (cc->mncc_recv)
- cc->mncc_recv(ms, mncc->msg_type, mncc);
+ if (ms->mncc_entity.mncc_recv)
+ ms->mncc_entity.mncc_recv(ms, mncc->msg_type, mncc);
work = 1; /* work done */
- talloc_free(msg);
+ msgb_free(msg);
}
return work;
@@ -364,6 +369,10 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans)
{
gsm48_stop_cc_timer(trans);
+ /* disable audio distribution */
+ if (trans->ms->mncc_entity.ref == trans->callref)
+ trans->ms->mncc_entity.ref = 0;
+
/* send release to L4, if callref still exists */
if (trans->callref) {
/* Ressource unavailable */
@@ -1944,8 +1953,19 @@ int mncc_send(struct osmocom_ms *ms, int msg_type, void *arg)
switch (msg_type) {
case GSM_TCHF_FRAME:
- printf("TCH/F frame ignored!\n");
- return -EINVAL;
+ return gsm_send_voice(ms, arg);
+ case MNCC_LCHAN_MODIFY:
+ return 0;
+ case MNCC_FRAME_RECV:
+ ms->mncc_entity.ref = trans->callref;
+ gsm48_rr_audio_mode(ms,
+ AUDIO_TX_TRAFFIC_REQ | AUDIO_RX_TRAFFIC_IND);
+ return 0;
+ case MNCC_FRAME_DROP:
+ if (ms->mncc_entity.ref == trans->callref)
+ ms->mncc_entity.ref = 0;
+ gsm48_rr_audio_mode(ms, AUDIO_TX_MICROPHONE | AUDIO_RX_SPEAKER);
+ return 0;
}
/* Find function for current state and message */
@@ -1954,8 +1974,8 @@ int mncc_send(struct osmocom_ms *ms, int msg_type, void *arg)
&& ((1 << trans->cc.state) & downstatelist[i].states))
break;
if (i == DOWNSLLEN) {
- LOGP(DCC, LOGL_NOTICE, "Message unhandled at this "
- "state.\n");
+ LOGP(DCC, LOGL_NOTICE, "Message %d unhandled at state "
+ "%d\n", msg_type, trans->cc.state);
return 0;
}
diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c
index 9d014d63..7722a42d 100644
--- a/src/host/layer23/src/mobile/gsm48_rr.c
+++ b/src/host/layer23/src/mobile/gsm48_rr.c
@@ -399,6 +399,7 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state)
memset(&rr->cd_now, 0, sizeof(rr->cd_now));
/* reset ciphering */
rr->cipher_on = 0;
+ /* reset audio mode */
/* tell cell selection process to return to idle mode
* NOTE: this must be sent unbuffered, because it will
* leave camping state, so it locks against subsequent
@@ -2927,14 +2928,15 @@ static int gsm48_rr_activate_channel(struct osmocom_ms *ms,
LOGP(DRR, LOGL_INFO, "establishing channel in dedicated mode\n");
rsl_dec_chan_nr(cd->chan_nr, &ch_type, &ch_subch, &ch_ts);
LOGP(DRR, LOGL_INFO, " Channel type %d, subch %d, ts %d, mode %d, "
- "cipher %d\n", ch_type, ch_subch, ch_ts, cd->mode,
- rr->cipher_type + 1);
+ "audio-mode %d, cipher %d\n", ch_type, ch_subch, ch_ts,
+ cd->mode, rr->audio_mode, rr->cipher_type + 1);
if (cd->h)
l1ctl_tx_dm_est_req_h1(ms, cd->maio, cd->hsn,
- ma, ma_len, cd->chan_nr, cd->tsc, cd->mode);
+ ma, ma_len, cd->chan_nr, cd->tsc, cd->mode,
+ rr->audio_mode);
else
l1ctl_tx_dm_est_req_h0(ms, cd->arfcn, cd->chan_nr, cd->tsc,
- cd->mode);
+ cd->mode, rr->audio_mode);
rr->dm_est = 1;
/* old SI 5/6 are not valid on a new dedicated channel */
@@ -3342,6 +3344,7 @@ static int gsm48_rr_rx_chan_rel(struct osmocom_ms *ms, struct msgb *msg)
static int gsm48_rr_set_mode(struct osmocom_ms *ms, uint8_t chan_nr,
uint8_t mode)
{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
uint8_t ch_type, ch_subch, ch_ts;
/* only apply mode to TCH/F or TCH/H */
@@ -3351,8 +3354,9 @@ static int gsm48_rr_set_mode(struct osmocom_ms *ms, uint8_t chan_nr,
return -ENOTSUP;
/* setting (new) timing advance */
- LOGP(DRR, LOGL_INFO, "setting TCH mode to %d\n", mode);
- l1ctl_tx_tch_mode_req(ms, mode);
+ LOGP(DRR, LOGL_INFO, "setting TCH mode to %d, audio mode to %d\n",
+ mode, rr->audio_mode);
+ l1ctl_tx_tch_mode_req(ms, mode, rr->audio_mode);
return 0;
}
@@ -5102,6 +5106,8 @@ int gsm48_rr_init(struct osmocom_ms *ms)
start_rr_t_meas(rr, 1, 0);
+ rr->audio_mode = AUDIO_TX_MICROPHONE | AUDIO_RX_SPEAKER;
+
return 0;
}
@@ -5214,3 +5220,45 @@ static int gsm48_rr_rand_acc_cnf_dedicated(struct osmocom_ms *ms, struct msgb *m
#endif
+int gsm48_rr_tx_voice(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ uint8_t ch_type, ch_subch, ch_ts;
+
+ if (!rr->dm_est) {
+ LOGP(DRR, LOGL_INFO, "Current channel is not active\n");
+ msgb_free(msg);
+ return -ENOTSUP;
+ }
+
+ rsl_dec_chan_nr(rr->cd_now.chan_nr, &ch_type, &ch_subch, &ch_ts);
+ if (ch_type != RSL_CHAN_Bm_ACCHs) {
+ LOGP(DRR, LOGL_INFO, "Current channel is not (yet) TCH/F\n");
+ msgb_free(msg);
+ return -ENOTSUP;
+ }
+
+ return l1ctl_tx_traffic_req(ms, msg, rr->cd_now.chan_nr,
+ rr->cd_now.link_id);
+}
+
+int gsm48_rr_audio_mode(struct osmocom_ms *ms, uint8_t mode)
+{
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
+ uint8_t ch_type, ch_subch, ch_ts;
+
+ LOGP(DRR, LOGL_INFO, "setting audio mode to %d\n", mode);
+
+ rr->audio_mode = mode;
+
+ if (!rr->dm_est)
+ return 0;
+
+ rsl_dec_chan_nr(rr->cd_now.chan_nr, &ch_type, &ch_subch, &ch_ts);
+ if (ch_type != RSL_CHAN_Bm_ACCHs
+ && ch_type != RSL_CHAN_Lm_ACCHs)
+ return 0;
+
+ return l1ctl_tx_tch_mode_req(ms, rr->cd_now.mode, mode);
+}
+
diff --git a/src/host/layer23/src/mobile/voice.c b/src/host/layer23/src/mobile/voice.c
new file mode 100644
index 00000000..b7678337
--- /dev/null
+++ b/src/host/layer23/src/mobile/voice.c
@@ -0,0 +1,78 @@
+/*
+ * (C) 2010 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 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 <stdlib.h>
+
+#include <osmocom/core/msgb.h>
+
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/mobile/mncc.h>
+#include <osmocom/bb/mobile/voice.h>
+
+
+/*
+ * receive voice
+ */
+
+static int gsm_recv_voice(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm_data_frame *mncc;
+
+ /* distribute and then free */
+ if (ms->mncc_entity.mncc_recv && ms->mncc_entity.ref) {
+ /* push mncc header in front of data */
+ mncc = (struct gsm_data_frame *)
+ msgb_push(msg, sizeof(struct gsm_data_frame));
+ mncc->msg_type = GSM_TCHF_FRAME;
+ mncc->callref = ms->mncc_entity.ref;
+ ms->mncc_entity.mncc_recv(ms, mncc->msg_type, mncc);
+ }
+
+ msgb_free(msg);
+ return 0;
+}
+
+/*
+ * send voice
+ */
+int gsm_send_voice(struct osmocom_ms *ms, struct gsm_data_frame *data)
+{
+ struct msgb *nmsg;
+
+ nmsg = msgb_alloc_headroom(33 + 64, 64, "TCH/F");
+ if (!nmsg)
+ return -ENOMEM;
+ nmsg->l2h = msgb_put(nmsg, 33);
+ memcpy(nmsg->l2h, data->data, 33);
+
+ return gsm48_rr_tx_voice(ms, nmsg);
+}
+
+/*
+ * init
+ */
+
+int gsm_voice_init(struct osmocom_ms *ms)
+{
+ ms->l1_entity.l1_traffic_ind = gsm_recv_voice;
+
+ return 0;
+}