From: Andreas.Eversberg Date: Thu, 28 Jul 2011 18:54:42 +0000 (+0200) Subject: layer23: Add mobile support for sending / receiving voice frame through MNCC X-Git-Url: http://git.rot13.org/?a=commitdiff_plain;h=1a5461fb2beb96bfa004245a102cd4c1422baa2a;hp=e042cbb29763f21fd2ed7076c15db87b037ce73a;p=osmocom-bb.git layer23: Add mobile support for sending / receiving voice frame through MNCC Support GSM FR codec only so far. Written-by: Andreas Eversberg Signed-off-by: Sylvain Munaut --- diff --git a/src/Makefile b/src/Makefile index 7dba3bd..de1435d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 diff --git a/src/host/layer23/configure.ac b/src/host/layer23/configure.ac index 0a67fab..b50868a 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 faa12d5..5ebea96 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 d387c91..6ad89cd 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 #include #include +#include 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 d6ea575..8cdd1c4 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 cccf279..756d302 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 0000000..a052418 --- /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 a249ed7..e3ab4c9 100644 --- a/src/host/layer23/src/common/l1ctl.c +++ b/src/host/layer23/src/common/l1ctl.c @@ -46,6 +46,7 @@ #include #include #include +#include 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 15d46a8..0b59f38 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 4a4c918..fb043db 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 fb0423e..e5cf76a 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 164f3ed..8b3b552 100644 --- a/src/host/layer23/src/mobile/app_mobile.c +++ b/src/host/layer23/src/mobile/app_mobile.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -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 5abf3f8..07ee2d9 100644 --- a/src/host/layer23/src/mobile/gsm48_cc.c +++ b/src/host/layer23/src/mobile/gsm48_cc.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include 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 9d014d6..7722a42 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 0000000..b767833 --- /dev/null +++ b/src/host/layer23/src/mobile/voice.c @@ -0,0 +1,78 @@ +/* + * (C) 2010 by Andreas Eversberg + * + * 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 + +#include + +#include +#include +#include + + +/* + * 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; +}