C-Netz: At correct timeslot switch channel mode

Without this, the first BQ(K) message came to early, so that BSA 51
released when receiving ZFZ(K) one frame too early.
This commit is contained in:
Andreas Eversberg 2020-06-01 21:07:49 +02:00
parent a98b05beb0
commit 7189984bbb
4 changed files with 54 additions and 44 deletions

View File

@ -377,21 +377,23 @@ int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char *
goto error; goto error;
/* go into idle state */ /* go into idle state */
cnetz_set_dsp_mode(cnetz, DSP_MODE_OGK); if (chan_type == CHAN_TYPE_OGK || chan_type == CHAN_TYPE_OGK_SPK)
cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_OGK, 0); cnetz_set_dsp_mode(cnetz, DSP_MODE_OGK);
else
cnetz_set_dsp_mode(cnetz, DSP_MODE_OFF);
cnetz_go_idle(cnetz); cnetz_go_idle(cnetz);
#ifdef DEBUG_SPK #ifdef DEBUG_SPK
transaction_t *trans = create_transaction(cnetz, TRANS_DS, 2, 2, 22002, -1, -1); transaction_t *trans = create_transaction(cnetz, TRANS_DS, 2, 2, 22002, -1, -1);
trans->mo_call = 1; trans->mo_call = 1;
cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_K, 2); cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_K, (cnetz->sched_ts + 2) & 31);
#else #else
/* create transaction for speech channel loopback */ /* create transaction for speech channel loopback */
if (loopback && chan_type == CHAN_TYPE_SPK) { if (loopback && chan_type == CHAN_TYPE_SPK) {
transaction_t *trans = create_transaction(cnetz, TRANS_VHQ_K, 2, 2, 22002, -1, -1); transaction_t *trans = create_transaction(cnetz, TRANS_VHQ_K, 2, 2, 22002, -1, -1);
trans->mo_call = 1; trans->mo_call = 1;
cnetz_set_dsp_mode(cnetz, DSP_MODE_SPK_K); cnetz_set_dsp_mode(cnetz, DSP_MODE_SPK_K);
cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_K, 0); cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_K, (cnetz->sched_ts + 1) & 31);
} }
#endif #endif
@ -509,10 +511,11 @@ void cnetz_go_idle(cnetz_t *cnetz)
/* set scheduler to OgK or turn off SpK */ /* set scheduler to OgK or turn off SpK */
if (cnetz->dsp_mode == DSP_MODE_SPK_K || cnetz->dsp_mode == DSP_MODE_SPK_V) { if (cnetz->dsp_mode == DSP_MODE_SPK_K || cnetz->dsp_mode == DSP_MODE_SPK_V) {
/* go idle after next frame/slot */ /* switch next frame after distributed signaling boundary (mutliple of 8 slots) */
cnetz_set_sched_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, 1); cnetz_set_sched_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, (cnetz->sched_ts + 8) & 24);
} else { } else {
cnetz_set_sched_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, 0); /* switch next frame */
cnetz_set_sched_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, (cnetz->sched_ts + 1) & 31);
cnetz_set_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF); cnetz_set_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF);
} }
@ -533,7 +536,7 @@ static void cnetz_release(transaction_t *trans, uint8_t cause)
trans_new_state(trans, (trans->cnetz->dsp_mode == DSP_MODE_OGK) ? TRANS_VA : TRANS_AF); trans_new_state(trans, (trans->cnetz->dsp_mode == DSP_MODE_OGK) ? TRANS_VA : TRANS_AF);
trans->repeat = 0; trans->repeat = 0;
trans->release_cause = cause; trans->release_cause = cause;
trans->cnetz->sched_switch_mode = 0; trans->cnetz->sched_dsp_mode_ts = -1;
timer_stop(&trans->timer); timer_stop(&trans->timer);
} }
@ -1068,7 +1071,7 @@ vak:
/* change state to busy */ /* change state to busy */
cnetz_new_state(spk, CNETZ_BUSY); cnetz_new_state(spk, CNETZ_BUSY);
/* schedule switching two slots ahead */ /* schedule switching two slots ahead */
cnetz_set_sched_dsp_mode(spk, DSP_MODE_SPK_K, 2); cnetz_set_sched_dsp_mode(spk, DSP_MODE_SPK_K, (cnetz->sched_ts + 2) & 31);
/* relink */ /* relink */
unlink_transaction(trans); unlink_transaction(trans);
link_transaction(trans, spk); link_transaction(trans, spk);
@ -1384,7 +1387,7 @@ no_auth:
/* next sub frame */ /* next sub frame */
trans_new_state(trans, TRANS_VHQ_V); trans_new_state(trans, TRANS_VHQ_V);
trans->repeat = 0; trans->repeat = 0;
cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_V, 1); cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_V, (cnetz->sched_ts + 1) & 31);
#ifndef DEBUG_SPK #ifndef DEBUG_SPK
timer_start(&trans->timer, 0.075 + 0.6 * F_VHQ); /* one slot + F_VHQ frames */ timer_start(&trans->timer, 0.075 + 0.6 * F_VHQ); /* one slot + F_VHQ frames */
#endif #endif
@ -1401,7 +1404,7 @@ no_auth:
/* next sub frame */ /* next sub frame */
trans_new_state(trans, TRANS_VHQ_V); trans_new_state(trans, TRANS_VHQ_V);
trans->repeat = 0; trans->repeat = 0;
cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_V, 1); cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_V, (cnetz->sched_ts + 1) & 31);
timer_start(&trans->timer, 0.075 + 0.6 * F_VHQ); /* one slot + F_VHQ frames */ timer_start(&trans->timer, 0.075 + 0.6 * F_VHQ); /* one slot + F_VHQ frames */
} }
break; break;

View File

@ -94,8 +94,8 @@ struct cnetz {
int sched_ts; /* current time slot */ int sched_ts; /* current time slot */
int sched_last_ts; /* last timeslot we transmitted, to sync time of the receiver */ int sched_last_ts; /* last timeslot we transmitted, to sync time of the receiver */
int sched_r_m; /* Rufblock (0) / Meldeblock (1) */ int sched_r_m; /* Rufblock (0) / Meldeblock (1) */
int sched_switch_mode; /* counts slots until mode is switched */ enum dsp_mode sched_dsp_mode; /* what mode shall be switched to */
enum dsp_mode sched_dsp_mode; /* what mode shall be switched to */ int sched_dsp_mode_ts; /* time slot when to switch mode (-1 = don't switch) */
/* dsp states */ /* dsp states */
enum dsp_mode dsp_mode; /* current mode: audio, "Telegramm", .... */ enum dsp_mode dsp_mode; /* current mode: audio, "Telegramm", .... */

View File

@ -54,6 +54,27 @@ scrambler_t scrambler_test_scrambler1;
scrambler_t scrambler_test_scrambler2; scrambler_t scrambler_test_scrambler2;
#endif #endif
const char *cnetz_dsp_mode_name(enum dsp_mode mode)
{
static char invalid[16];
switch (mode) {
case DSP_SCHED_NONE:
return "SCHED_NONE";
case DSP_MODE_OFF:
return "OFF";
case DSP_MODE_OGK:
return "OGK";
case DSP_MODE_SPK_K:
return "SPK_K";
case DSP_MODE_SPK_V:
return "SPK_V";
}
sprintf(invalid, "invalid(%d)", mode);
return invalid;
}
static sample_t ramp_up[256], ramp_down[256]; static sample_t ramp_up[256], ramp_down[256];
void dsp_init(void) void dsp_init(void)
@ -166,6 +187,8 @@ int dsp_init_sender(cnetz_t *cnetz, int measure_speed, double clock_speed[2], en
scrambler_setup(&scrambler_test_scrambler2, cnetz->sender.samplerate); scrambler_setup(&scrambler_test_scrambler2, cnetz->sender.samplerate);
#endif #endif
cnetz->sched_dsp_mode_ts = -1;
return 0; return 0;
error: error:
@ -636,10 +659,11 @@ again:
} }
/* switch to speech channel */ /* switch to speech channel */
if (cnetz->sched_switch_mode && cnetz->sched_r_m == 0) { if (cnetz->sched_dsp_mode_ts >= 0 && cnetz->sched_r_m == 0) {
if (--cnetz->sched_switch_mode == 0) { if (cnetz->sched_dsp_mode_ts == cnetz->sched_ts) {
/* OgK / SpK(K) / SpK(V) */ /* OgK / SpK(K) / SpK(V) */
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Switching channel (mode)\n"); PDEBUG_CHAN(DDSP, DEBUG_INFO, "Now switchting channel mode to %s at timeslot %d\n", cnetz_dsp_mode_name(cnetz->sched_dsp_mode), cnetz->sched_dsp_mode_ts);
cnetz->sched_dsp_mode_ts = -1;
cnetz_set_dsp_mode(cnetz, cnetz->sched_dsp_mode); cnetz_set_dsp_mode(cnetz, cnetz->sched_dsp_mode);
} }
} }
@ -843,39 +867,22 @@ void unshrink_speech(cnetz_t *cnetz, sample_t *speech_buffer, int count)
cnetz->sender.rxbuf_pos = pos; cnetz->sender.rxbuf_pos = pos;
} }
const char *cnetz_dsp_mode_name(enum dsp_mode mode)
{
static char invalid[16];
switch (mode) {
case DSP_SCHED_NONE:
return "SCHED_NONE";
case DSP_MODE_OFF:
return "OFF";
case DSP_MODE_OGK:
return "OGK";
case DSP_MODE_SPK_K:
return "SPK_K";
case DSP_MODE_SPK_V:
return "SPK_V";
}
sprintf(invalid, "invalid(%d)", mode);
return invalid;
}
void cnetz_set_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode) void cnetz_set_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode)
{ {
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "DSP mode %s -> %s\n", cnetz_dsp_mode_name(cnetz->dsp_mode), cnetz_dsp_mode_name(mode)); if (mode != cnetz->dsp_mode) {
cnetz->dsp_mode = mode; PDEBUG_CHAN(DDSP, DEBUG_INFO, "DSP mode %s -> %s\n", cnetz_dsp_mode_name(cnetz->dsp_mode), cnetz_dsp_mode_name(mode));
cnetz->dsp_mode = mode;
}
/* we must get rid of partly received frame */ /* we must get rid of partly received frame */
fsk_demod_reset(&cnetz->fsk_demod); fsk_demod_reset(&cnetz->fsk_demod);
} }
void cnetz_set_sched_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode, int frames_ahead) void cnetz_set_sched_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode, int timeslot)
{ {
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, " Schedule DSP mode %s -> %s in %d frames\n", cnetz_dsp_mode_name(cnetz->dsp_mode), cnetz_dsp_mode_name(mode), frames_ahead); if (mode != cnetz->dsp_mode) {
cnetz->sched_dsp_mode = mode; PDEBUG_CHAN(DDSP, DEBUG_INFO, "Schedule DSP mode %s -> %s at timeslot %d\n", cnetz_dsp_mode_name(cnetz->dsp_mode), cnetz_dsp_mode_name(mode), timeslot);
cnetz->sched_switch_mode = frames_ahead; cnetz->sched_dsp_mode = mode;
cnetz->sched_dsp_mode_ts = timeslot;
}
} }

View File

@ -5,5 +5,5 @@ void dsp_cleanup_sender(cnetz_t *cnetz);
void calc_clock_speed(cnetz_t *cnetz, double samples, int tx, int result); void calc_clock_speed(cnetz_t *cnetz, double samples, int tx, int result);
void unshrink_speech(cnetz_t *cnetz, sample_t *speech_buffer, int count); void unshrink_speech(cnetz_t *cnetz, sample_t *speech_buffer, int count);
void cnetz_set_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode); void cnetz_set_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode);
void cnetz_set_sched_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode, int frames_ahead); void cnetz_set_sched_dsp_mode(cnetz_t *cnetz, enum dsp_mode mode, int timeslot);