C-Netz: retry call setup messages up to 3 times

This commit is contained in:
Andreas Eversberg 2016-08-01 09:27:37 +02:00
parent b84a64f872
commit 664f8c7ac0
3 changed files with 94 additions and 24 deletions

View File

@ -236,6 +236,22 @@ int cnetz_create(int kanal, enum cnetz_chan_type chan_type, const char *sounddev
}
#endif
#if 0
/* debug flushing transactions */
transaction_t *trans1, *trans2;
trans1 = create_transaction(cnetz, 99, 6, 2, 15784);
destroy_transaction(trans1);
trans1 = create_transaction(cnetz, 99, 6, 2, 15784);
destroy_transaction(trans1);
trans1 = create_transaction(cnetz, 99, 6, 2, 15784);
trans2 = create_transaction(cnetz, 99, 2, 2, 22002);
unlink_transaction(trans1);
link_transaction(trans1, cnetz);
cnetz_flush_other_transactions(cnetz, trans1);
trans2 = create_transaction(cnetz, 99, 2, 2, 22002);
cnetz_flush_other_transactions(cnetz, trans2);
#endif
return 0;
error:
@ -272,9 +288,10 @@ static void cnetz_go_idle(cnetz_t *cnetz)
cnetz->sender.callref = 0;
}
/* set scheduler to OgK */
PDEBUG(DCNETZ, DEBUG_INFO, "Entering IDLE state on channel %d.\n", cnetz->sender.kanal);
cnetz_new_state(cnetz, CNETZ_IDLE);
/* set scheduler to OgK or turn off SpK */
if (cnetz->dsp_mode == DSP_MODE_SPK_K || cnetz->dsp_mode == DSP_MODE_SPK_V) {
/* go idle after next frame/slot */
cnetz_set_sched_dsp_mode(cnetz, (cnetz->sender.kanal == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, 1);
@ -288,9 +305,9 @@ static void cnetz_go_idle(cnetz_t *cnetz)
static void cnetz_release(transaction_t *trans, uint8_t cause)
{
trans_new_state(trans, TRANS_AF);
trans->repeat = 0;
trans->release_cause = cause;
trans->cnetz->sched_switch_mode = 0;
trans->count = 0;
timer_stop(&trans->timer);
}
@ -341,6 +358,7 @@ cnetz_t *search_ogk(void)
for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender;
/* if callref is set, we ignore busy channel with this callref */
if (cnetz->state != CNETZ_IDLE)
continue;
if (cnetz->chan_type == CHAN_TYPE_OGK)
@ -426,6 +444,7 @@ inval:
sender->callref = 0;
return -CAUSE_TEMPFAIL;
}
trans->try = 1;
return 0;
}
@ -625,21 +644,30 @@ void transaction_timeout(struct timer *timer)
switch (trans->state) {
case TRANS_WAF:
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after dialing request 'Wahlaufforderung'\n");
if (++trans->count == 3) {
if (trans->try == N) {
/* no response to dialing is like MA failed */
trans->ma_failed = 1;
trans_new_state(trans, TRANS_WBN);
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
break;
}
trans->try++;
trans_new_state(trans, TRANS_VWG);
break;
case TRANS_BQ:
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after channel allocation 'Belegung Quittung'\n");
if (trans->mt_call) {
call_in_release(cnetz->sender.callref, CAUSE_OUTOFORDER);
cnetz->sender.callref = 0;
#if 0
if (trans->try == N) {
if (trans->mt_call) {
call_in_release(cnetz->sender.callref, CAUSE_OUTOFORDER);
cnetz->sender.callref = 0;
}
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
break;
}
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
#endif
trans_new_state(trans, TRANS_AF);
trans->repeat = 0;
break;
case TRANS_VHQ:
if (cnetz->dsp_mode != DSP_MODE_SPK_V)
@ -795,7 +823,7 @@ wbn:
telegramm.opcode = OPCODE_VAK_R;
}
trans_new_state(trans, TRANS_BQ);
trans->count = 0;
trans->repeat = 0;
timer_start(&trans->timer, 0.150 + 0.0375 * F_BQ); /* two slots + F_BQ frames */
/* select channel */
spk = search_free_spk();
@ -859,7 +887,7 @@ const telegramm_t *cnetz_transmit_telegramm_meldeblock(cnetz_t *cnetz)
telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst;
telegramm.futln_rest_nr = trans->futln_rest;
trans_new_state(trans, TRANS_WAF);
timer_start(&trans->timer, 4.0); /* Wait two slot cycles until resending */
timer_start(&trans->timer, 1.0); /* Wait two slot cycles until resending */
break;
case TRANS_MA:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending keepalive request 'Meldeaufruf'\n");
@ -868,7 +896,7 @@ const telegramm_t *cnetz_transmit_telegramm_meldeblock(cnetz_t *cnetz)
telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst;
telegramm.futln_rest_nr = trans->futln_rest;
trans_new_state(trans, TRANS_MFT);
timer_start(&trans->timer, 4.0); /* Wait two slot cycles until timeout */
timer_start(&trans->timer, 1.0); /* Wait two slot cycles until timeout */
break;
default:
; /* MLR */
@ -940,6 +968,7 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo
PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n");
break;
}
trans->try = 1;
spk = search_free_spk();
if (!spk) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "Rejecting call from subscriber '%s', because we have no free channel.\n", rufnummer);
@ -959,6 +988,7 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received dialing digits 'Wahluebertragung' message from Subscriber '%s' to Number '%s'\n", rufnummer, trans->dialing);
timer_stop(&trans->timer);
trans_new_state(trans, TRANS_WBP);
trans->try = 1; /* try */
valid_frame = 1;
break;
case OPCODE_MFT_M:
@ -994,6 +1024,8 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz)
{
static telegramm_t telegramm;
transaction_t *trans = cnetz->trans_list;
cnetz_t *ogk;
int callref;
memset(&telegramm, 0, sizeof(telegramm));
if (!trans)
@ -1015,9 +1047,9 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz)
case TRANS_BQ:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Belegungsquittung' on traffic channel\n");
telegramm.opcode = OPCODE_BQ_K;
if (++trans->count >= 8 && !timer_running(&trans->timer)) {
if (++trans->repeat >= 8 && !timer_running(&trans->timer)) {
trans_new_state(trans, TRANS_VHQ);
trans->count = 0;
trans->repeat = 0;
timer_start(&trans->timer, 0.0375 * F_VHQK); /* F_VHQK frames */
}
break;
@ -1038,13 +1070,13 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz)
}
cnetz->sender.callref = callref;
trans_new_state(trans, TRANS_DS);
trans->count = 0;
trans->repeat = 0;
timer_start(&trans->timer, 0.0375 * F_DS); /* F_DS frames */
}
if (trans->mt_call) {
trans_new_state(trans, TRANS_RTA);
timer_start(&trans->timer, 0.0375 * F_RTA); /* F_RTA frames */
trans->count = 0;
trans->repeat = 0;
call_in_alerting(cnetz->sender.callref);
}
}
@ -1055,7 +1087,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz)
if ((cnetz->sched_ts & 7) == 7 && cnetz->sched_r_m && !timer_running(&trans->timer)) {
/* next sub frame */
trans_new_state(trans, TRANS_VHQ);
trans->count = 0;
trans->repeat = 0;
cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_V, 1);
#ifndef DEBUG_SPK
timer_start(&trans->timer, 0.075 + 0.6 * F_VHQ); /* one slot + F_VHQ frames */
@ -1072,7 +1104,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz)
if ((cnetz->sched_ts & 7) == 7 && cnetz->sched_r_m) {
/* next sub frame */
trans_new_state(trans, TRANS_VHQ);
trans->count = 0;
trans->repeat = 0;
cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_V, 1);
timer_start(&trans->timer, 0.075 + 0.6 * F_VHQ); /* one slot + F_VHQ frames */
}
@ -1081,15 +1113,50 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz)
call_failed:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Ausloesen durch FuFSt' on traffic channel\n");
telegramm.opcode = OPCODE_AF_K;
if (++trans->count == N_AFKT) {
if (++trans->repeat < N_AFKT)
break;
if (!trans->try) {
/* no retry */
destroy_transaction(trans);
cnetz_go_idle(cnetz);
break;
}
if (trans->try == N) {
PDEBUG(DCNETZ, DEBUG_INFO, "Maximum retries, removing transaction\n");
destroy_transaction(trans);
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
cnetz_go_idle(cnetz);
break;
}
/* remove call from SpK (or OgK) */
unlink_transaction(trans);
callref = cnetz->sender.callref;
cnetz->sender.callref = 0;
/* idle channel */
cnetz_go_idle(cnetz);
/* alloc ogk again */
ogk = search_ogk();
if (!ogk) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "Cannot retry, because currently no OgK available (busy)\n");
destroy_transaction(trans);
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
break;
}
PDEBUG(DCNETZ, DEBUG_INFO, "Retry to assign channel.\n");
/* attach call to OgK */
ogk->sender.callref = callref;
link_transaction(trans, ogk);
/* change state */
if (trans->mo_call)
trans_new_state(trans, TRANS_WBP);
if (trans->mt_call)
trans_new_state(trans, TRANS_VAK);
trans->try++;
break;
case TRANS_AT:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Auslosen durch FuTln' on traffic channel\n");
telegramm.opcode = OPCODE_AF_K;
if (++trans->count == 1) {
if (++trans->repeat == 1) {
destroy_transaction(trans);
cnetz_go_idle(cnetz);
}
@ -1122,6 +1189,7 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm)
if (trans->state != TRANS_BQ)
break;
timer_stop(&trans->timer);
trans->try = 0;
break;
case OPCODE_DSQ_K:
if (!match_fuz(cnetz, telegramm, cnetz->cell_nr)) {
@ -1177,7 +1245,7 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm)
break;
cnetz->scrambler = telegramm->betriebs_art;
trans_new_state(trans, TRANS_AHQ);
trans->count = 0;
trans->repeat = 0;
timer_stop(&trans->timer);
call_in_answer(cnetz->sender.callref, transaction2rufnummer(trans));
break;
@ -1194,7 +1262,7 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm)
if (trans->state == TRANS_AT || trans->state == TRANS_AF)
break;
trans_new_state(trans, TRANS_AT);
trans->count = 0;
trans->repeat = 0;
timer_stop(&trans->timer);
if (cnetz->sender.callref) {
call_in_release(cnetz->sender.callref, CAUSE_NORMAL);
@ -1246,7 +1314,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_v(cnetz_t *cnetz)
case TRANS_AF:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Ausloesen durch FuFSt' on traffic channel\n");
telegramm.opcode = OPCODE_AF_V;
if (++trans->count == N_AFV) {
if (++trans->repeat == N_AFV) {
destroy_transaction(trans);
cnetz_go_idle(cnetz);
}
@ -1254,7 +1322,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_v(cnetz_t *cnetz)
case TRANS_AT:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Auslosen durch FuTln' on traffic channel\n");
telegramm.opcode = OPCODE_AF_V;
if (++trans->count == 1) {
if (++trans->repeat == 1) {
destroy_transaction(trans);
cnetz_go_idle(cnetz);
}
@ -1303,7 +1371,7 @@ void cnetz_receive_telegramm_spk_v(cnetz_t *cnetz, telegramm_t *telegramm)
break;
cnetz->scrambler = telegramm->betriebs_art;
trans_new_state(trans, TRANS_AT);
trans->count = 0;
trans->repeat = 0;
timer_stop(&trans->timer);
if (cnetz->sender.callref) {
call_in_release(cnetz->sender.callref, CAUSE_NORMAL);

View File

@ -36,6 +36,7 @@ enum cnetz_state {
#define F_RTA 16 /* number of not received frames at RTA state */
#define N_AFKT 6 /* number of release frames to send during concentrated signaling */
#define N_AFV 4 /* number of release frames to send during distributed signaling */
#define N 3 /* now many times we repeat a message on OgK */
/* clear causes */
#define CNETZ_CAUSE_TEILNEHMERBESETZT 0 /* subscriber busy */

View File

@ -33,7 +33,8 @@ typedef struct transaction {
char dialing[17]; /* number dialed by the phone */
int32_t state; /* state of transaction */
int8_t release_cause; /* reason for release, (c-netz coding) */
int count; /* counts resending things */
int try; /* counts resending messages */
int repeat; /* counts repeating messages */
struct timer timer; /* for varous timeouts */
int mo_call; /* flags a moile originating call */
int mt_call; /* flags a moile terminating call */