X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=blobdiff_plain;f=ss5.cpp;h=2a09bede9362cfba99b9e0d62977b884bbfb8d65;hp=0d453e48786c9fea32a8e27af03e36e46cd8ca51;hb=034d3a91404addedc1c7a3494862c79532b0b878;hpb=ab670ecfdc8c7e299bc1b9ddea014980ad7637fa diff --git a/ss5.cpp b/ss5.cpp index 0d453e4..2a09bed 100644 --- a/ss5.cpp +++ b/ss5.cpp @@ -24,6 +24,7 @@ * - PORT_STATE_OUT_SETUP: the seizing procedure is started. * - PORT_STATE_OUT_OVERLAP: the transmitter is sending the digits. * - PORT_STATE_OUT_PROCEEDING: the digits are sent, we wait until someone answers. + * - PORT_STATE_OUT_DISCONNECT: a clear-back is sent, after DISCONNECT was received * - PORT_STATE_CONNECT: a call is answered on either side. * - PORT_STATE_IN_SETUP: the seizing is received, we wait for the first digit. * - PORT_STATE_IN_OVERLAP: the digits are received. @@ -127,7 +128,8 @@ const char *ss5_signal_name[] = { #define BELL_TIMER_RECOG_END (300*8) /* recognize end of digit */ /* ss5 timers */ -#define SS5_TIMER_OVERLAP 5.0 /* timeout for overlap digits received on outgoing exchange */ +#define SS5_TIMER_OVERLAP 10 /* timeout for overlap digits received on incomming exchange */ +#define SS5_TIMER_RELEASE 20 /* timeout after disconnect on incomming exchange */ /* @@ -156,6 +158,8 @@ enum { /* even values are indications, odd values are requests */ SS5_DIALING_REQ, SS5_FORWARD_TRANSFER_IND, SS5_FORWARD_TRANSFER_REQ, + SS5_TIMEOUT_IND, + SS5_QUALITY_IND, }; static struct isdn_message { const char *name; @@ -183,6 +187,8 @@ static struct isdn_message { {"DIALING SENDING", SS5_DIALING_REQ}, {"FORWARD-TRANSFER RECEIVED", SS5_FORWARD_TRANSFER_IND}, {"FORWARD-TRANSFER SENDING", SS5_FORWARD_TRANSFER_REQ}, + {"TIMEOUT", SS5_TIMEOUT_IND}, + {"QUALITY REPORT", SS5_QUALITY_IND}, {NULL, 0}, }; static void ss5_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned int msg, int channel) @@ -252,7 +258,7 @@ void ss5_create_channel(struct mISDNport *mISDNport, int i) memset(&port_settings, 0, sizeof(port_settings)); SCPY(port_settings.tones_dir, options.tones_dir); - ss5port = new Pss5(PORT_TYPE_SS5_IDLE, mISDNport, portname, &port_settings, i + (i>=15) + 1, 1, B_MODE_TRANSPARENT); + ss5port = new Pss5(PORT_TYPE_SS5_IDLE, mISDNport, portname, &port_settings, mISDNport->ifport->interface, i + (i>=15) + 1, 1, B_MODE_TRANSPARENT); if (!ss5port) FATAL("No memory for Pss5 class.\n"); if (!ss5port->p_m_b_channel) @@ -333,11 +339,28 @@ class Pss5 *ss5_hunt_line(struct mISDNport *mISDNport) return NULL; } +static int timeout(struct lcr_timer *timer, void *instance, int i) +{ + class Pss5 *ss5 = (class Pss5 *)instance; + + ss5->register_timeout(); + + return 0; +} + +int queue_event(struct lcr_work *work, void *instance, int index) +{ + class Pss5 *ss5port = (class Pss5 *)instance; + + ss5port->process_queue(); + + return 0; +} /* * constructor */ -Pss5::Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode) +Pss5::Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, struct interface *interface, int channel, int exclusive, int mode) : PmISDN(type, mISDNport, portname, settings, interface, channel, exclusive, mode) { p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN; p_m_s_state = SS5_STATE_IDLE; @@ -346,18 +369,21 @@ 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_quality_value = 0; + p_m_s_quality_count = 0; p_m_s_recog = 0; - p_m_s_timer = 0.0; - p_m_s_timer_fn = NULL; - p_m_s_answer = 0; - p_m_s_busy_flash = 0; - p_m_s_clear_back = 0; + memset(&p_m_s_queue, 0, sizeof(p_m_s_queue)); + add_work(&p_m_s_queue, queue_event, this, 0); + p_m_s_queued_signal = 0; memset(p_m_s_delay_digits, ' ', sizeof(p_m_s_delay_digits)); memset(p_m_s_delay_mute, ' ', sizeof(p_m_s_delay_mute)); + memset(&p_m_s_timer, 0, sizeof(p_m_s_timer)); + add_timer(&p_m_s_timer, timeout, this, 0); /* turn on signalling receiver */ inband_receive_on(); @@ -371,10 +397,64 @@ Pss5::Pss5(int type, struct mISDNport *mISDNport, char *portname, struct port_se */ Pss5::~Pss5() { + del_timer(&p_m_s_timer); + del_work(&p_m_s_queue); } /* + * timeout trigger + */ +void Pss5::register_timeout(void) +{ + ss5_trace_header(p_m_mISDNport, this, SS5_TIMEOUT_IND, p_m_b_channel); + end_trace(); + switch(p_state) { + case PORT_STATE_IN_SETUP: + PDEBUG(DEBUG_SS5, "%s: timeout after seize\n", p_name); + do_release(CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, SS5_CLEAR_BACK_REQ); + break; + case PORT_STATE_IN_OVERLAP: + PDEBUG(DEBUG_SS5, "%s: timeout during dialing\n", p_name); + do_release(CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, SS5_CLEAR_BACK_REQ); + break; + case PORT_STATE_OUT_DISCONNECT: + PDEBUG(DEBUG_SS5, "%s: timeout after sending busy flash / clear forward\n", p_name); + /* always send clear forward, because release guard only works as a reply to clear forward */ + do_release(CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, SS5_CLEAR_FORWARD_REQ); + break; + } +} + +/* + * change port state + */ +void Pss5::new_state(int state) +{ + switch(state) { + case PORT_STATE_IN_SETUP: + case PORT_STATE_IN_OVERLAP: + if (SS5_TIMER_OVERLAP == 0) + break; + PDEBUG(DEBUG_SS5, "%s: starting timeout timer with %d seconds\n", p_name, SS5_TIMER_OVERLAP); + schedule_timer(&p_m_s_timer, SS5_TIMER_OVERLAP, 0); + break; + case PORT_STATE_OUT_DISCONNECT: + if (p_type != PORT_TYPE_SS5_IN) + break; + if (SS5_TIMER_RELEASE == 0) + break; + PDEBUG(DEBUG_SS5, "%s: starting timeout timer with %d seconds\n", p_name, SS5_TIMER_RELEASE); + schedule_timer(&p_m_s_timer, SS5_TIMER_RELEASE, 0); + break; + default: + PDEBUG(DEBUG_SS5, "%s: stopping timeout timer\n", p_name); + unsched_timer(&p_m_s_timer); + } + Port::new_state(state); +} + +/* * change ss5 states */ void Pss5::_new_ss5_state(int state, const char *func, int line) @@ -382,13 +462,61 @@ 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_queued_signal) + trigger_work(&p_m_s_queue); } + +void Pss5::process_queue(void) +{ + /* when clear forward is scheduled, we abort current state */ + if (p_m_s_queued_signal == SS5_CLEAR_FORWARD_REQ) + new_ss5_state(SS5_STATE_IDLE); + + /* if there is an ongoing signal, we wait until done */ + if (p_m_s_state != SS5_STATE_IDLE) + return; + + /* this shoud not happen */ + if (!p_m_s_queued_signal) + return; + + /* start signal */ + ss5_trace_header(p_m_mISDNport, this, p_m_s_queued_signal, p_m_b_channel); + end_trace(); + switch(p_m_s_queued_signal) { + case SS5_ANSWER_REQ: + /* start answer */ + p_m_s_queued_signal = 0; /* prevent trigger loop */ + start_signal(SS5_STATE_ANSWER); + break; + case SS5_BUSY_FLASH_REQ: + /* busy flash */ + p_m_s_queued_signal = 0; /* prevent trigger loop */ + start_signal(SS5_STATE_BUSY_FLASH); + break; + case SS5_CLEAR_BACK_REQ: + /* clear back */ + p_m_s_queued_signal = 0; /* prevent trigger loop */ + start_signal(SS5_STATE_CLEAR_BACK); + break; + case SS5_CLEAR_FORWARD_REQ: + /* clear forward */ + p_m_s_queued_signal = 0; /* prevent trigger loop */ + start_signal(SS5_STATE_CLEAR_FORWARD); + break; + default: + PERROR("unhandled event %d\n", p_m_s_queued_signal); + p_m_s_queued_signal = 0; + } +} + void Pss5::_new_ss5_signal(int signal, const char *func, int line) { if (p_m_s_signal) - PDEBUG(DEBUG_SS5, "%s(%s:%d): changing SS5 signal state from %s to %s\n", p_name, func, line, ss5_signal_name[p_m_s_signal], ss5_signal_name[signal]); + PDEBUG(DEBUG_SS5, "%s: changing SS5 signal state from %s to %s\n", p_name, ss5_signal_name[p_m_s_signal], ss5_signal_name[signal]); else - PDEBUG(DEBUG_SS5, "%s(%s:%d): changing SS5 signal state to %s\n", p_name, func, line, ss5_signal_name[signal]); + PDEBUG(DEBUG_SS5, "%s: changing SS5 signal state to %s\n", p_name, ss5_signal_name[signal]); p_m_s_signal = signal; } @@ -402,6 +530,8 @@ void Pss5::inband_receive(unsigned char *buffer, int len) { int count = 0, tocopy, space; char digit; + double quality; + int mute = 0; again: /* how much to copy ? */ @@ -420,15 +550,31 @@ void Pss5::inband_receive(unsigned char *buffer, int len) return; /* decode one frame */ - digit = ss5_decode(p_m_s_decoder_buffer, SS5_DECODER_NPOINTS); + digit = ss5_decode(p_m_s_decoder_buffer, SS5_DECODER_NPOINTS, &quality); p_m_s_decoder_count = 0; + /* indicate quality of received digit */ + if ((p_m_mISDNport->ss5 & SS5_FEATURE_QUALITY)) { + if (digit != ' ') { + p_m_s_quality_value += quality; + p_m_s_quality_count++; + } else if (p_m_s_quality_count) { + ss5_trace_header(p_m_mISDNport, this, SS5_QUALITY_IND, p_m_b_channel); + add_trace("digit", NULL, "%c", p_m_s_last_digit); + quality = p_m_s_quality_value/p_m_s_quality_count; + add_trace("quality", NULL, "%3d%%", (int)(quality*100.0)); + end_trace(); + p_m_s_quality_value = 0; + p_m_s_quality_count = 0; + } + } + #ifdef DEBUG_DETECT if (p_m_s_last_digit != digit && digit != ' ') 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,28 +606,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; } } - - /* update mute */ - if ((p_m_mISDNport->ss5 & SS5_FEATURE_SUPPRESS)) { - int mdigit; - memcpy(p_m_s_delay_mute, p_m_s_delay_mute+1, sizeof(p_m_s_delay_mute)-1); - p_m_s_delay_mute[sizeof(p_m_s_delay_mute)-1] = digit; - mdigit = p_m_s_delay_mute[0]; - if (p_m_mute) { - /* mute is on */ - if (mdigit != 'A' && mdigit != 'B' && mdigit != 'C') - mute_off(); - } else { - /* mute is off */ - if (mdigit == 'A' || mdigit == 'B' || mdigit == 'C') - mute_on(); - } - } + p_m_s_last_digit_used = digit; /* delay decoded tones */ if ((p_m_mISDNport->ss5 & SS5_FEATURE_DELAY)) { @@ -900,6 +1037,42 @@ void Pss5::inband_receive(unsigned char *buffer, int len) break; } + /* update mute on RX */ + if ((p_m_mISDNport->ss5 & SS5_FEATURE_MUTE_RX)) { + int mdigit; + memcpy(p_m_s_delay_mute, p_m_s_delay_mute+1, sizeof(p_m_s_delay_mute)-1); + p_m_s_delay_mute[sizeof(p_m_s_delay_mute)-1] = digit; + mdigit = p_m_s_delay_mute[0]; + if (mdigit == 'A' || mdigit == 'B' || mdigit == 'C') + mute = 1; + } + + /* mute when TX */ + if ((p_m_mISDNport->ss5 & SS5_FEATURE_MUTE_TX)) { + switch(p_m_s_signal) { + case SS5_SIGNAL_SEND_ON_RECOG: + case SS5_SIGNAL_RECEIVE_RECOG: + if (p_m_s_recog > SS5_DELAY_MUTE) + mute = 1; + break; + case SS5_SIGNAL_SEND_OFF: + case SS5_SIGNAL_RECEIVE: + mute = 1; + break; + } + } + + /* apply mute state */ + if (p_m_mute) { + /* mute is on */ + if (!mute) + mute_off(); + } else { + /* mute is off */ + if (mute) + mute_on(); + } + /* something more to decode ? */ if (count != len) goto again; @@ -950,7 +1123,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, SS5_CLEAR_FORWARD_REQ); break; } new_ss5_state(SS5_STATE_DELAY); @@ -1347,7 +1520,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); } @@ -1383,16 +1556,9 @@ void Pss5::pulse_ind(int on) add_trace("digit", NULL, "%s", dial+1); add_trace("pulses", NULL, "%d", p_m_s_pulsecount); end_trace(); - /* special star release feature */ - if ((p_m_mISDNport->ss5 & SS5_FEATURE_STAR_RELEASE) && dial[1] == '*') { - ss5_trace_header(p_m_mISDNport, this, SS5_DIALING_IND, p_m_b_channel); - add_trace("star", NULL, "releases call"); - end_trace(); - goto star_release; - } 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 */ @@ -1415,7 +1581,6 @@ void Pss5::pulse_ind(int on) ss5_trace_header(p_m_mISDNport, this, SS5_DIALING_IND, p_m_b_channel); add_trace("longtone", NULL, "releases call"); end_trace(); - star_release: /* long pulse is gone, release current connection, if any */ while(p_epointlist) { message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); @@ -1593,7 +1758,7 @@ void Pss5::double_seizure_ind(void) /* * shuts down by sending a clear forward and releasing endpoint */ -void Pss5::do_release(int cause, int location) +void Pss5::do_release(int cause, int location, int signal) { struct lcr_msg *message; @@ -1606,25 +1771,28 @@ void Pss5::do_release(int cause, int location) free_epointlist(p_epointlist); } - /* start clear-forward */ - ss5_trace_header(p_m_mISDNport, this, SS5_CLEAR_FORWARD_REQ, p_m_b_channel); - end_trace(); - start_signal(SS5_STATE_CLEAR_FORWARD); - - new_state(PORT_STATE_RELEASE); +// if (p_state != PORT_STATE_RELEASE) { + p_m_s_queued_signal = signal; + if (signal == SS5_CLEAR_FORWARD_REQ) { + new_state(PORT_STATE_RELEASE); + set_tone("", "noise"); + } else + new_state(PORT_STATE_OUT_DISCONNECT); + trigger_work(&p_m_s_queue); +// } } /* * 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; @@ -1643,8 +1811,7 @@ void Pss5::do_setup(char *dial) FATAL("Incoming call but already got an endpoint.\n"); if (!(epoint = new Endpoint(p_serial, 0))) FATAL("No memory for Endpoint instance\n"); - if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming - FATAL("No memory for Endpoint Application instance\n"); + epoint->ep_app = new_endpointapp(epoint, 0, p_m_mISDNport->ifport->interface->app); //incoming epointlist_new(epoint->ep_serial); /* send setup message to endpoit */ @@ -1661,52 +1828,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 +1856,8 @@ void Pss5::message_setup(unsigned int epoint_id, int message_id, union parameter memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo)); memcpy(&p_redirinfo, ¶m->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 */ @@ -1904,8 +2025,9 @@ void Pss5::message_connect(unsigned int epoint_id, int message_id, union paramet memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo)); if (p_state != PORT_STATE_CONNECT) { + p_m_s_queued_signal = SS5_ANSWER_REQ; new_state(PORT_STATE_CONNECT); - p_m_s_answer = 1; + trigger_work(&p_m_s_queue); } set_tone("", NULL); @@ -1914,27 +2036,35 @@ void Pss5::message_connect(unsigned int epoint_id, int message_id, union paramet /* MESSAGE_DISCONNECT */ void Pss5::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param) { - /* disconnect and clear forward (release guard) */ -// if ((p_type==PORT_TYPE_SS5_IN && !p_m_mISDNport->tones) /* incomming exchange with no tones */ -if (0 || p_type==PORT_TYPE_SS5_OUT) { /* outgoing exchange */ - do_release(param->disconnectinfo.cause, param->disconnectinfo.location); + /* release and clear forward */ + if (p_type==PORT_TYPE_SS5_OUT) { /* outgoing exchange */ + do_release(param->disconnectinfo.cause, param->disconnectinfo.location, SS5_CLEAR_FORWARD_REQ); + return; + } + /* release and clear back */ + if ((p_m_mISDNport->ss5 & SS5_FEATURE_RELEASE)) { + do_release(param->disconnectinfo.cause, param->disconnectinfo.location, SS5_CLEAR_BACK_REQ); return; } - ss5_trace_header(p_m_mISDNport, this, SS5_CLEAR_BACK_REQ, p_m_b_channel); - end_trace(); - start_signal(SS5_STATE_CLEAR_BACK); - - new_state(PORT_STATE_OUT_DISCONNECT); + /* disconnect by sending clear back (after answer) or busy flash (before answer) */ + if (p_state != PORT_STATE_OUT_DISCONNECT) { + if (p_state == PORT_STATE_CONNECT) + p_m_s_queued_signal = SS5_CLEAR_BACK_REQ; + else + p_m_s_queued_signal = SS5_BUSY_FLASH_REQ; + new_state(PORT_STATE_OUT_DISCONNECT); + trigger_work(&p_m_s_queue); + } } /* MESSAGE_RELEASE */ void Pss5::message_release(unsigned int epoint_id, int message_id, union parameter *param) { - do_release(param->disconnectinfo.cause, param->disconnectinfo.location); + /* always send clear forward, because release guard only works as a reply to clear forward */ + do_release(param->disconnectinfo.cause, param->disconnectinfo.location, SS5_CLEAR_FORWARD_REQ); } - /* * endpoint sends messages to the port */