layer23: Add mobile support for sending / receiving voice frame through MNCC
authorAndreas.Eversberg <jolly@eversberg.eu>
Thu, 28 Jul 2011 18:54:42 +0000 (20:54 +0200)
committerSylvain Munaut <tnt@246tNt.com>
Thu, 28 Jul 2011 19:30:51 +0000 (21:30 +0200)
Support GSM FR codec only so far.

Written-by: Andreas Eversberg <jolly@eversberg.eu>
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
15 files changed:
src/Makefile
src/host/layer23/configure.ac
src/host/layer23/include/osmocom/bb/common/l1ctl.h
src/host/layer23/include/osmocom/bb/common/osmocom_data.h
src/host/layer23/include/osmocom/bb/mobile/gsm48_cc.h
src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h
src/host/layer23/include/osmocom/bb/mobile/voice.h [new file with mode: 0644]
src/host/layer23/src/common/l1ctl.c
src/host/layer23/src/misc/Makefile.am
src/host/layer23/src/misc/app_cbch_sniff.c
src/host/layer23/src/mobile/Makefile.am
src/host/layer23/src/mobile/app_mobile.c
src/host/layer23/src/mobile/gsm48_cc.c
src/host/layer23/src/mobile/gsm48_rr.c
src/host/layer23/src/mobile/voice.c [new file with mode: 0644]

index 7dba3bd..de1435d 100644 (file)
@@ -13,9 +13,11 @@ TOPDIR=$(shell pwd)
 OSMOCORE_CONFIGURE_ENV= LIBOSMOCORE_LIBS=$(TOPDIR)/shared/libosmocore/build-host/src/.libs/libosmocore.a \
                         LIBOSMOVTY_LIBS=$(TOPDIR)/shared/libosmocore/build-host/src/vty/.libs/libosmovty.a \
                        LIBOSMOGSM_LIBS=$(TOPDIR)/shared/libosmocore/build-host/src/gsm/.libs/libosmogsm.a \
+                       LIBOSMOCODEC_LIBS=$(TOPDIR)/shared/libosmocore/build-host/src/codec/.libs/libosmocodec.a \
                        LIBOSMOCORE_CFLAGS=-I$(TOPDIR)/shared/libosmocore/include \
                        LIBOSMOVTY_CFLAGS=-I$(TOPDIR)/shared/libosmocore/include \
-                       LIBOSMOGSM_CFLAGS=-I$(TOPDIR)/shared/libosmocore/include
+                       LIBOSMOGSM_CFLAGS=-I$(TOPDIR)/shared/libosmocore/include \
+                       LIBOSMOCODEC_CFLAGS=-I$(TOPDIR)/shared/libosmocore/include
 
 all: libosmocore-target nofirmware firmware mtk-firmware
 nofirmware: libosmocore-host layer23 osmocon gsmmap
index 0a67fab..b50868a 100644 (file)
@@ -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
index faa12d5..5ebea96 100644 (file)
@@ -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);
index d387c91..6ad89cd 100644 (file)
@@ -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 {
index d6ea575..8cdd1c4 100644 (file)
@@ -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);
index cccf279..756d302 100644 (file)
@@ -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 (file)
index 0000000..a052418
--- /dev/null
@@ -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 */
index a249ed7..e3ab4c9 100644 (file)
@@ -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);
index 15d46a8..0b59f38 100644 (file)
@@ -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
 
index 4a4c918..fb043db 100644 (file)
@@ -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);
        }
 }
 
index fb0423e..e5cf76a 100644 (file)
@@ -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
 
index 164f3ed..8b3b552 100644 (file)
@@ -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;
 }
index 5abf3f8..07ee2d9 100644 (file)
@@ -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;
                }
                
index 9d014d6..7722a42 100644 (file)
@@ -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 (file)
index 0000000..b767833
--- /dev/null
@@ -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;
+}