[GSM_BS] Added DTMF support.
[lcr.git] / gsm_bs.cpp
index 10d1e8c..584b7e2 100644 (file)
@@ -10,6 +10,7 @@
 \*****************************************************************************/ 
 
 #include "main.h"
+#include "config.h"
 
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
@@ -24,6 +25,7 @@ extern "C" {
 #include <osmocore/talloc.h>
 #include <openbsc/mncc.h>
 #include <openbsc/trau_frame.h>
+#include <openbsc/osmo_msc.h>
 //#include <osmocom/vty/command.h>
 struct gsm_network *bsc_gsmnet = 0;
 extern int ipacc_rtp_direct;
@@ -38,6 +40,7 @@ int bts_model_unknown_init(void);
 int bts_model_bs11_init(void);
 int bts_model_nanobts_init(void);
 static struct log_target *stderr_target;
+extern const char *openbsc_copyright;
 
 /* timer to store statistics */
 #define DB_SYNC_INTERVAL       60, 0
@@ -47,18 +50,23 @@ static struct timer_list db_sync_timer;
 struct vty_app_info {
        const char *name;
        const char *version;
-       char *copyright;
+       const char *copyright;
        void *tall_ctx;
        int (*go_parent_cb)(struct vty *vty);
+       int (*is_config_node)(struct vty *vty, int node);
 };
+
 extern int bsc_vty_go_parent(struct vty *vty);
+extern int bsc_vty_is_config_node(struct vty *vty, int node);
 static struct vty_app_info vty_info = {
        "OpenBSC",
        PACKAGE_VERSION,
        NULL,
        NULL,
        bsc_vty_go_parent,
+       bsc_vty_is_config_node,
 };
+
 void vty_init(struct vty_app_info *app_info);
 int bsc_vty_init(void);
 
@@ -78,11 +86,42 @@ static void db_sync_timer_cb(void *data)
 }
 
 /*
+ * DTMF stuff
+ */
+unsigned char dtmf_samples[16][8000];
+static int dtmf_x[4] = { 1209, 1336, 1477, 1633 };
+static int dtmf_y[4] = { 697, 770, 852, 941 };
+
+void generate_dtmf(void)
+{
+       double fx, fy, sample;
+       int i, x, y;
+       unsigned char *law;
+
+       for (y = 0; y < 4; y++) {
+               fy = 2 * 3.1415927 * ((double)dtmf_y[y]) / 8000.0;
+               for (x = 0; x < 4; x++) {
+                       fx = 2 * 3.1415927 * ((double)dtmf_x[x]) / 8000.0;
+                       law = dtmf_samples[y << 2 | x];
+                       for (i = 0; i < 8000; i++) {
+                               sample = sin(fy * ((double)i)) * 0.251 * 32767.0; /* -6 dB */
+                               sample += sin(fx * ((double)i)) * 0.158 * 32767.0; /* -8 dB */
+                               *law++ = audio_s16_to_law[(int)sample & 0xffff];
+                       }
+               }
+       }
+}
+
+
+/*
  * constructor
  */
 Pgsm_bs::Pgsm_bs(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : Pgsm(type, mISDNport, portname, settings, channel, exclusive, mode)
 {
        p_m_g_instance = gsm->network;
+       p_m_g_dtmf = NULL;
+       p_m_g_dtmf_index = 0;
+
        PDEBUG(DEBUG_GSM, "Created new GSMBSPort(%s).\n", portname);
 }
 
@@ -97,7 +136,7 @@ Pgsm_bs::~Pgsm_bs()
 /* DTMF INDICATION */
 void Pgsm_bs::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
 {
-       struct lcr_msg *message;
+//     struct lcr_msg *message;
        struct gsm_mncc *resp;
 
        gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
@@ -114,10 +153,37 @@ void Pgsm_bs::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct
        resp->keypad = mncc->keypad;
        send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
 
+#if 0
        /* send dialing information */
        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION);
        memcpy(&message->param.information, &p_dialinginfo, sizeof(struct dialing_info));
        message_put(message);
+#endif
+
+       /* generate DTMF tones */
+       switch (mncc->keypad) {
+               case '1': p_m_g_dtmf = dtmf_samples[0]; break;
+               case '2': p_m_g_dtmf = dtmf_samples[1]; break;
+               case '3': p_m_g_dtmf = dtmf_samples[2]; break;
+               case 'a':
+               case 'A': p_m_g_dtmf = dtmf_samples[3]; break;
+               case '4': p_m_g_dtmf = dtmf_samples[4]; break;
+               case '5': p_m_g_dtmf = dtmf_samples[5]; break;
+               case '6': p_m_g_dtmf = dtmf_samples[6]; break;
+               case 'b':
+               case 'B': p_m_g_dtmf = dtmf_samples[7]; break;
+               case '7': p_m_g_dtmf = dtmf_samples[8]; break;
+               case '8': p_m_g_dtmf = dtmf_samples[9]; break;
+               case '9': p_m_g_dtmf = dtmf_samples[10]; break;
+               case 'c':
+               case 'C': p_m_g_dtmf = dtmf_samples[11]; break;
+               case '*': p_m_g_dtmf = dtmf_samples[12]; break;
+               case '0': p_m_g_dtmf = dtmf_samples[13]; break;
+               case '#': p_m_g_dtmf = dtmf_samples[14]; break;
+               case 'd':
+               case 'D': p_m_g_dtmf = dtmf_samples[15]; break;
+       }
+       p_m_g_dtmf_index = 0;
 }
 void Pgsm_bs::stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
 {
@@ -134,6 +200,9 @@ void Pgsm_bs::stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct
        resp = create_mncc(MNCC_STOP_DTMF_RSP, p_m_g_callref);
        resp->keypad = mncc->keypad;
        send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
+       
+       /* stop DTMF */
+       p_m_g_dtmf = NULL;
 }
 
 /* HOLD INDICATION */
@@ -427,8 +496,22 @@ static int message_bsc(struct gsm_network *net, int msg_type, void *arg)
        }
 
        if (msg_type == GSM_TCHF_FRAME) {
-               if (port)
-                       pgsm_bs->frame_receive((struct gsm_trau_frame *)arg);
+               if (port) {
+                       /* inject DTMF, if enabled */
+                       if (pgsm_bs->p_m_g_dtmf) {
+                               unsigned char data[160];
+                               int i;
+
+                               for (i = 0; i < 160; i++) {
+                                       data[i] = pgsm_bs->p_m_g_dtmf[pgsm_bs->p_m_g_dtmf_index++];
+                                       if (pgsm_bs->p_m_g_dtmf_index == 8000)
+                                               pgsm_bs->p_m_g_dtmf_index = 0;
+                               }
+                               /* send */
+                               pgsm_bs->bchannel_send(PH_DATA_REQ, 0, data, 160);
+                       } else
+                               pgsm_bs->frame_receive(arg);
+               }
                return 0;
        }
 
@@ -775,6 +858,8 @@ int gsm_bs_init(void)
         mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
        int pcapfd, rc;
 
+       vty_info.copyright = openbsc_copyright;
+
        log_init(&log_info);
        tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
        talloc_ctx_init();
@@ -791,6 +876,10 @@ int gsm_bs_init(void)
        /* enable filters */
        log_set_all_filter(stderr_target, 1);
 
+       /* Init VTY (need to preceed options) */
+       vty_init(&vty_info);
+       bsc_vty_init();
+
        /* set debug */
        if (gsm->conf.debug[0])
                log_parse_category_mask(stderr_target, gsm->conf.debug);
@@ -812,6 +901,19 @@ int gsm_bs_init(void)
        /* use RTP proxy for audio streaming */
        ipacc_rtp_direct = 0;
 
+       /* bootstrap network */
+       if (gsm->conf.openbsc_cfg[0] == '/')
+               SCPY(cfg, gsm->conf.openbsc_cfg);
+       else
+               SPRINT(cfg, "%s/%s", CONFIG_DATA, gsm->conf.openbsc_cfg);
+       rc = bsc_bootstrap_network(&message_bsc, cfg);
+       if (rc < 0) {
+               PERROR("Failed to bootstrap GSM network.\n");
+               return gsm_exit(-1);
+       }
+       bsc_api_init(bsc_gsmnet, msc_bsc_api());
+       gsm->network = bsc_gsmnet;
+
        /* init database */
        if (gsm->conf.hlr[0] == '/')
                SCPY(hlr, gsm->conf.hlr);
@@ -833,21 +935,7 @@ int gsm_bs_init(void)
        db_sync_timer.data = NULL;
        bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
 
-       /* Init VTY */
-       vty_init(&vty_info);
-       bsc_vty_init();
-
-       /* bootstrap network */
-       if (gsm->conf.openbsc_cfg[0] == '/')
-               SCPY(cfg, gsm->conf.openbsc_cfg);
-       else
-               SPRINT(cfg, "%s/%s", CONFIG_DATA, gsm->conf.openbsc_cfg);
-       rc = bsc_bootstrap_network(&message_bsc, cfg);
-       if (rc < 0) {
-               PERROR("Failed to bootstrap GSM network.\n");
-               return gsm_exit(-1);
-       }
-       gsm->network = bsc_gsmnet;
+       generate_dtmf();
 
        return 0;
 }