Added bridgin support for GSM and SIP
[lcr.git] / ss5.cpp
diff --git a/ss5.cpp b/ss5.cpp
index 0d453e4..a12f936 100644 (file)
--- a/ss5.cpp
+++ b/ss5.cpp
@@ -333,6 +333,7 @@ class Pss5 *ss5_hunt_line(struct mISDNport *mISDNport)
        return NULL;
 }
 
+int queue_event(struct lcr_work *work, void *instance, int index);
 
 /*
  * constructor
@@ -346,13 +347,14 @@ Pss5::Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_se
        p_m_s_digit_i = 0;
        p_m_s_pulsecount = 0;
        p_m_s_last_digit = ' ';
+       p_m_s_last_digit_used = ' ';
        p_m_s_signal_loss = 0;
        p_m_s_decoder_count = 0;
        //p_m_s_decoder_buffer;
        p_m_s_sample_nr = 0;
        p_m_s_recog = 0;
-       p_m_s_timer = 0.0;
-       p_m_s_timer_fn = NULL;
+       memset(&p_m_s_queue, 0, sizeof(p_m_s_queue));
+       add_work(&p_m_s_queue, queue_event, this, 0);
        p_m_s_answer = 0;
        p_m_s_busy_flash = 0;
        p_m_s_clear_back = 0;
@@ -371,6 +373,7 @@ Pss5::Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_se
  */
 Pss5::~Pss5()
 {
+       del_work(&p_m_s_queue);
 }
 
 
@@ -382,7 +385,47 @@ void Pss5::_new_ss5_state(int state, const char *func, int line)
        PDEBUG(DEBUG_SS5, "%s(%s:%d): changing SS5 state from %s to %s\n", p_name, func, line, ss5_state_name[p_m_s_state], ss5_state_name[state]);
        p_m_s_state = state;
        p_m_s_signal = SS5_SIGNAL_NULL;
+
+       if (p_m_s_state == SS5_STATE_IDLE && (p_m_s_answer || p_m_s_busy_flash || p_m_s_clear_back))
+               trigger_work(&p_m_s_queue);
 }
+
+int queue_event(struct lcr_work *work, void *instance, int index)
+{
+       class Pss5 *ss5port = (class Pss5 *)instance;
+
+       if (ss5port->p_m_s_state == SS5_STATE_IDLE) {
+               /* if answer signal is queued */
+               if (ss5port->p_m_s_answer) {
+                       ss5port->p_m_s_answer = 0;
+                       /* start answer */
+                       ss5_trace_header(ss5port->p_m_mISDNport, ss5port, SS5_ANSWER_REQ, ss5port->p_m_b_channel);
+                       end_trace();
+                       ss5port->start_signal(SS5_STATE_ANSWER);
+               }
+
+               /* if busy-flash signal is queued */
+               if (ss5port->p_m_s_busy_flash) {
+                       ss5port->p_m_s_busy_flash = 0;
+                       /* start busy-flash */
+                       ss5_trace_header(ss5port->p_m_mISDNport, ss5port, SS5_BUSY_FLASH_REQ, ss5port->p_m_b_channel);
+                       end_trace();
+                       ss5port->start_signal(SS5_STATE_BUSY_FLASH);
+               }
+
+               /* if clear-back signal is queued */
+               if (ss5port->p_m_s_clear_back) {
+                       ss5port->p_m_s_clear_back = 0;
+                       /* start clear-back */
+                       ss5_trace_header(ss5port->p_m_mISDNport, ss5port, SS5_CLEAR_BACK_REQ, ss5port->p_m_b_channel);
+                       end_trace();
+                       ss5port->start_signal(SS5_STATE_CLEAR_BACK);
+               }
+       }
+
+       return 0;
+}
+
 void Pss5::_new_ss5_signal(int signal, const char *func, int line)
 {
        if (p_m_s_signal)
@@ -428,7 +471,7 @@ void Pss5::inband_receive(unsigned char *buffer, int len)
                PDEBUG(DEBUG_SS5, "%s: detecting signal '%c' start (state=%s signal=%s)\n", p_name, digit, ss5_state_name[p_m_s_state], ss5_signal_name[p_m_s_signal]);
 #endif
 
-       /* ignore short loss of signal */
+       /* ignore short loss of signal, or change within one decode window */
        if (p_m_s_signal_loss) {
                if (digit == ' ') {
                        /* still lost */
@@ -460,11 +503,19 @@ void Pss5::inband_receive(unsigned char *buffer, int len)
                        p_m_s_last_digit = digit;
                        /* starting to loose signal */
                        p_m_s_signal_loss = SS5_DECODER_NPOINTS;
+               } else if (digit != p_m_s_last_digit) {
+                       /* digit changes, but we keep old digit until it is detected twice */
+#ifdef DEBUG_DETECT
+                       PDEBUG(DEBUG_SS5, "%s: signal '%c' changes to '%c'\n", p_name, p_m_s_last_digit, digit);
+#endif
+                       p_m_s_last_digit = digit;
+                       digit = p_m_s_last_digit_used;
                } else {
                        /* storing last signal, in case it is lost */
                        p_m_s_last_digit = digit;
                }
        }
+       p_m_s_last_digit_used = digit;
 
        /* update mute */
        if ((p_m_mISDNport->ss5 & SS5_FEATURE_SUPPRESS)) {
@@ -950,7 +1001,7 @@ int Pss5::inband_send(unsigned char *buffer, int len)
                if (duration > 0 && p_m_s_sample_nr >= duration) {
                        PDEBUG(DEBUG_SS5, "%s: sending tone '%c' complete, starting delay\n", p_name, digit);
                        if (p_m_s_state == SS5_STATE_DOUBLE_SEIZE) {
-                               do_release(CAUSE_NOCHANNEL, LOCATION_BEYOND);
+                               do_release(CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL);
                                break;
                        }
                        new_ss5_state(SS5_STATE_DELAY);
@@ -1347,7 +1398,7 @@ void Pss5::digit_ind(char digit)
        end_trace();
        new_ss5_state(SS5_STATE_IDLE);
 
-       do_setup(dial);
+       do_setup(dial, 1);
        new_state(PORT_STATE_IN_PROCEEDING);
 }
 
@@ -1392,7 +1443,7 @@ void Pss5::pulse_ind(int on)
                        }
                        if (p_state == PORT_STATE_IN_SETUP) {
                                /* sending digit as setup */
-                               do_setup(dial); /* include 'a' == KP1 */
+                               do_setup(dial, 0); /* include 'a' == KP1 */
                                new_state(PORT_STATE_IN_OVERLAP);
                        } else {
                                /* sending digit as information */
@@ -1618,13 +1669,13 @@ void Pss5::do_release(int cause, int location)
 /*
  * create endpoint and send setup
  */
-void Pss5::do_setup(char *dial)
+void Pss5::do_setup(char *dial, int complete)
 {
        class Endpoint *epoint;
        struct lcr_msg *message;
 
        SCPY(p_dialinginfo.id, dial);
-       p_dialinginfo.sending_complete = 1;
+       p_dialinginfo.sending_complete = complete;
        p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
        p_callerinfo.screen = INFO_SCREEN_NETWORK;
        p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
@@ -1661,52 +1712,6 @@ void Pss5::do_setup(char *dial)
 }
 
 
-/*
- * handler
- */
-int Pss5::handler(void)
-{
-       int ret;
-
-       if ((ret = PmISDN::handler()))
-               return(ret);
-
-       /* handle timer */
-       if (p_m_s_timer && p_m_s_timer < now) {
-               p_m_s_timer = 0.0;
-               (this->*(p_m_s_timer_fn))();
-       }
-
-       /* if answer signal is queued */
-       if (p_m_s_answer && p_m_s_state == SS5_STATE_IDLE) {
-               p_m_s_answer = 0;
-               /* start answer */
-               ss5_trace_header(p_m_mISDNport, this, SS5_ANSWER_REQ, p_m_b_channel);
-               end_trace();
-               start_signal(SS5_STATE_ANSWER);
-       }
-
-       /* if busy-flash signal is queued */
-       if (p_m_s_busy_flash && p_m_s_state == SS5_STATE_IDLE) {
-               p_m_s_busy_flash = 0;
-               /* start busy-flash */
-               ss5_trace_header(p_m_mISDNport, this, SS5_BUSY_FLASH_REQ, p_m_b_channel);
-               end_trace();
-               start_signal(SS5_STATE_BUSY_FLASH);
-       }
-
-       /* if clear-back signal is queued */
-       if (p_m_s_clear_back && p_m_s_state == SS5_STATE_IDLE) {
-               p_m_s_clear_back = 0;
-               /* start clear-back */
-               ss5_trace_header(p_m_mISDNport, this, SS5_CLEAR_BACK_REQ, p_m_b_channel);
-               end_trace();
-               start_signal(SS5_STATE_CLEAR_BACK);
-       }
-
-       return(0);
-}
-
 
 /*
  * handles all messages from endpoint
@@ -1735,8 +1740,8 @@ void Pss5::message_setup(unsigned int epoint_id, int message_id, union parameter
        memcpy(&p_capainfo, &param->setup.capainfo, sizeof(p_capainfo));
        memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
        /* screen outgoing caller id */
-       do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface);
-       do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface);
+       do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface->name);
+       do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface->name);
 
        /* parse dial string  */
        dash = 0; /* dash must be used next time */
@@ -1906,6 +1911,7 @@ void Pss5::message_connect(unsigned int epoint_id, int message_id, union paramet
        if (p_state != PORT_STATE_CONNECT) {
                new_state(PORT_STATE_CONNECT);
                p_m_s_answer = 1;
+               trigger_work(&p_m_s_queue);
        }
 
        set_tone("", NULL);
@@ -1934,6 +1940,10 @@ void Pss5::message_release(unsigned int epoint_id, int message_id, union paramet
        do_release(param->disconnectinfo.cause, param->disconnectinfo.location);
 }
 
+void Pss5::register_timeout(void)
+{
+       do_release(CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL);
+}
 
 /*
  * endpoint sends messages to the port