C-Netz: Work on system informations, metering and call queues

- Make system informations configurable
- Simulate call mertering
- Support for call queues on busy voice channels
This commit is contained in:
Andreas Eversberg
2017-08-26 17:48:13 +02:00
parent 3bfba37fff
commit dfdad21e3f
11 changed files with 573 additions and 192 deletions

View File

@@ -39,6 +39,12 @@
* created. The transaction is linked to OgK. When the scheduler schedules
* VAK(R), the SpK is allocated and the transaction is linked to it.
*
* If no SpK is available, the call is rejected. If queue (Warteschlange) is
* enabled, WSK(R) is scheduled. After transmission, the state changes to
* TRANS_MT_QUEUE. Upon timeout (no channel becomes available), the call is
* rejected by scheduling VA(R). Upon available channel the call proceeeds with
* VAK(R) as described above.
*
* If an MO (mobile originating) call is made (received VWG(K)), a transaction
* with callref is created. The transaction is linked to OgK. When the
* scheduler schedules WAF(M), the process waits for WUE(M). If not received,
@@ -47,6 +53,12 @@
* then schedules VAG(R), the SpK is allocated and the transaction is linked to
* it.
*
* If no SpK is available, the call is rejected by scheduling WBN(R). If queue
* (Warteschlange) is enabled, WWBP(R) is scheduled. After transmission, the
* state is changed to TRANS_MO_QUEUE. Upon timeout (no channel becomes
* available), the call is rejected by scheduling VA(R). Upon available channel
* the call proceeeds with VAG(R) as described above.
*
* Switching to SpK is performed two time slots after transmitting VAK(R) or
* VAG(R). The timer is started. The schedulers schedules 8 times BQ(K) and
* awaits at least one BEL(K). If BEK(K) is received, the timer is stoped. If
@@ -129,6 +141,7 @@
#include <string.h>
#include <errno.h>
#include <math.h>
#include <inttypes.h>
#include "../common/sample.h"
#include "../common/debug.h"
#include "../common/timer.h"
@@ -231,7 +244,7 @@ int cnetz_init(void)
}
/* Create transceiver instance and link to a list. */
int cnetz_create(int kanal, enum cnetz_chan_type chan_type, const char *audiodev, int use_sdr, enum demod_type demod, int samplerate, double rx_gain, int auth, int ms_power, int measure_speed, double clock_speed[2], int polarity, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback)
int cnetz_create(int kanal, enum cnetz_chan_type chan_type, const char *audiodev, int use_sdr, enum demod_type demod, int samplerate, double rx_gain, int auth, int warteschlange, int metering, int ms_power, int measure_speed, double clock_speed[2], int polarity, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback)
{
sender_t *sender;
cnetz_t *cnetz;
@@ -313,6 +326,8 @@ int cnetz_create(int kanal, enum cnetz_chan_type chan_type, const char *audiodev
cnetz->chan_type = chan_type;
cnetz->auth = auth;
cnetz->warteschlange = warteschlange;
cnetz->metering = metering;
cnetz->ms_power = ms_power;
switch (polarity) {
@@ -409,63 +424,7 @@ void cnetz_destroy(sender_t *sender)
free(cnetz);
}
/* Abort connection, if any and send idle broadcast */
void cnetz_go_idle(cnetz_t *cnetz)
{
if (cnetz->state == CNETZ_IDLE)
return;
if (cnetz->trans_list) {
PDEBUG(DCNETZ, DEBUG_ERROR, "Releasing but still having transaction, please fix!\n");
if (cnetz->trans_list->callref)
call_in_release(cnetz->trans_list->callref, CAUSE_NORMAL);
destroy_transaction(cnetz->trans_list);
}
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);
} else {
cnetz_set_sched_dsp_mode(cnetz, (cnetz->sender.kanal == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, 0);
cnetz_set_dsp_mode(cnetz, (cnetz->sender.kanal == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF);
}
}
/* Initiate release connection on speech channel */
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;
timer_stop(&trans->timer);
}
/* Receive audio from call instance. */
void call_rx_audio(int callref, sample_t *samples, int count)
{
sender_t *sender;
cnetz_t *cnetz;
for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender;
if (cnetz->trans_list && cnetz->trans_list->callref == callref)
break;
}
if (!sender)
return;
if (cnetz->dsp_mode == DSP_MODE_SPK_V) {
/* store as is, since we convert rate when processing FSK frames */
jitter_save(&cnetz->sender.dejitter, samples, count);
}
}
cnetz_t *search_free_spk(int extended)
static cnetz_t *search_free_spk(int extended)
{
sender_t *sender;
cnetz_t *cnetz, *ogk_spk = NULL;
@@ -493,7 +452,7 @@ cnetz_t *search_free_spk(int extended)
return ogk_spk;
}
cnetz_t *search_ogk(void)
static cnetz_t *search_ogk(void)
{
sender_t *sender;
cnetz_t *cnetz;
@@ -512,10 +471,80 @@ cnetz_t *search_ogk(void)
return NULL;
}
int call_out_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing)
/* Abort connection, if any and send idle broadcast */
void cnetz_go_idle(cnetz_t *cnetz)
{
cnetz_t *ogk;
transaction_t *trans;
if (cnetz->state == CNETZ_IDLE)
return;
if (cnetz->trans_list) {
PDEBUG(DCNETZ, DEBUG_ERROR, "Releasing but still having transaction, please fix!\n");
if (cnetz->trans_list->callref)
call_in_release(cnetz->trans_list->callref, CAUSE_NORMAL);
destroy_transaction(cnetz->trans_list);
}
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);
} else {
cnetz_set_sched_dsp_mode(cnetz, (cnetz->sender.kanal == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, 0);
cnetz_set_dsp_mode(cnetz, (cnetz->sender.kanal == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF);
}
/* check for first phone in queue and trigger completion of call (becoming idle means that SpK is now available) */
ogk = search_ogk();
trans = search_transaction(ogk, TRANS_MT_QUEUE | TRANS_MO_QUEUE);
if (trans) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "Now channel available for queued subscriber '%s'.\n", transaction2rufnummer(trans));
trans_new_state(trans, (trans->state == TRANS_MT_QUEUE) ? TRANS_MT_DELAY : TRANS_MO_DELAY);
timer_stop(&trans->timer);
timer_start(&trans->timer, 2.0);
}
}
/* Initiate release connection on speech channel */
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->repeat = 0;
trans->release_cause = cause;
trans->cnetz->sched_switch_mode = 0;
timer_stop(&trans->timer);
}
/* Receive audio from call instance. */
void call_rx_audio(int callref, sample_t *samples, int count)
{
sender_t *sender;
cnetz_t *cnetz;
for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender;
if (cnetz->trans_list && cnetz->trans_list->callref == callref)
break;
}
if (!sender)
return;
if (cnetz->dsp_mode == DSP_MODE_SPK_V) {
/* store as is, since we convert rate when processing FSK frames */
jitter_save(&cnetz->sender.dejitter, samples, count);
}
}
int call_out_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing)
{
sender_t *sender;
cnetz_t *cnetz, *spk;
int extended;
transaction_t *trans;
uint8_t futln_nat;
uint8_t futln_fuvst;
@@ -544,7 +573,8 @@ inval:
futln_rest = atoi(dialing + 2);
/* 2. check if the subscriber is attached */
if (!find_db(futln_nat, futln_fuvst, futln_rest)) {
extended = find_db(futln_nat, futln_fuvst, futln_rest);
if (extended < 0) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call to not attached subscriber, rejecting!\n");
return -CAUSE_OUTOFORDER;
}
@@ -562,23 +592,27 @@ inval:
return -CAUSE_BUSY;
}
/* 4. check if all senders are busy, return NOCHANNEL */
if (!search_free_spk(1)) { // FIXME: maybe lookup database for extended frequency band before calling subscriber
PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call, but no free channel, rejecting!\n");
return -CAUSE_NOCHANNEL;
}
/* 5. check if we have no OgK, return NOCHANNEL */
/* 4. check if we have no OgK, return NOCHANNEL */
cnetz = search_ogk();
if (!cnetz) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call, but OgK is currently busy, rejecting!\n");
return -CAUSE_NOCHANNEL;
}
/* 5. check if all senders are busy, return NOCHANNEL */
spk = search_free_spk(extended);
if (!spk) {
if (!cnetz->warteschlange) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call, but no free channel, rejecting!\n");
return -CAUSE_NOCHANNEL;
} else
PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call, but no free channel, queuing call!\n");
}
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Call to mobile station, paging station id '%s'\n", dialing);
/* 6. trying to page mobile station */
trans = create_transaction(cnetz, TRANS_VAK, dialing[0] - '0', dialing[1] - '0', atoi(dialing + 2), -1);
trans = create_transaction(cnetz, (spk) ? TRANS_VAK : TRANS_WSK, dialing[0] - '0', dialing[1] - '0', atoi(dialing + 2), -1);
if (!trans) {
PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n");
return -CAUSE_TEMPFAIL;
@@ -632,8 +666,13 @@ void call_out_disconnect(int callref, int cause)
default:
PDEBUG(DCNETZ, DEBUG_INFO, "Call control disconnects on organisation channel, removing transaction.\n");
call_in_release(callref, cause);
destroy_transaction(trans);
cnetz_go_idle(cnetz);
trans->callref = 0;
if (trans->state == TRANS_MT_QUEUE || trans->state == TRANS_MT_DELAY) {
cnetz_release(trans, cnetz_cause_isdn2cnetz(cause));
} else {
destroy_transaction(trans);
cnetz_go_idle(cnetz);
}
}
}
@@ -670,8 +709,12 @@ void call_out_release(int callref, int cause)
break;
default:
PDEBUG(DCNETZ, DEBUG_INFO, "Call control releases on organisation channel, removing transaction.\n");
destroy_transaction(trans);
cnetz_go_idle(cnetz);
if (trans->state == TRANS_MT_QUEUE) {
cnetz_release(trans, cnetz_cause_isdn2cnetz(cause));
} else {
destroy_transaction(trans);
cnetz_go_idle(cnetz);
}
}
}
@@ -767,6 +810,22 @@ void transaction_timeout(struct timer *timer)
trans->try++;
trans_new_state(trans, TRANS_VWG);
break;
case TRANS_MT_QUEUE:
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Phone in queue, but still no channel available, releasing call!\n");
call_in_release(trans->callref, CAUSE_NOCHANNEL);
trans->callref = 0;
cnetz_release(trans, CNETZ_CAUSE_GASSENBESETZT);
break;
case TRANS_MO_QUEUE:
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Phone in queue, but still no channel available, releasing!\n");
cnetz_release(trans, CNETZ_CAUSE_GASSENBESETZT);
break;
case TRANS_MT_DELAY:
trans_new_state(trans, TRANS_VAK);
break;
case TRANS_MO_DELAY:
trans_new_state(trans, TRANS_VAG);
break;
case TRANS_BQ:
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after channel allocation 'Belegung Quittung'\n");
trans_new_state(trans, TRANS_AF);
@@ -808,7 +867,7 @@ void transaction_timeout(struct timer *timer)
destroy_transaction(trans);
break;
default:
PDEBUG_CHAN(DCNETZ, DEBUG_ERROR, "Timeout unhandled in state %d\n", trans->state);
PDEBUG_CHAN(DCNETZ, DEBUG_ERROR, "Timeout unhandled in state %" PRIu64 "\n", trans->state);
}
}
@@ -869,13 +928,13 @@ const telegramm_t *cnetz_transmit_telegramm_rufblock(cnetz_t *cnetz)
telegramm.zeitschlitz_nr = cnetz->sched_ts;
telegramm.grenzwert_fuer_einbuchen_und_umbuchen = si[cnetz->cell_nr].grenz_einbuchen;
telegramm.authentifikationsbit = cnetz->auth;
telegramm.vermittlungstechnische_sperren = si[cnetz->cell_nr].sperre;
telegramm.ws_kennung = 0;
telegramm.vermittlungstechnische_sperren = si[cnetz->cell_nr].vermittlungstechnische_sperren;
telegramm.ws_kennung = si[cnetz->cell_nr].ws_kennung;
telegramm.reduzierungsfaktor = si[cnetz->cell_nr].reduzierung;
telegramm.fuz_nationalitaet = si[cnetz->cell_nr].fuz_nat;
telegramm.fuz_fuvst_nr = si[cnetz->cell_nr].fuz_fuvst;
telegramm.fuz_rest_nr = si[cnetz->cell_nr].fuz_rest;
telegramm.kennung_fufst = si[cnetz->cell_nr].fufst_prio;
telegramm.kennung_fufst = si[cnetz->cell_nr].kennung_fufst;
telegramm.nachbarschafts_prioritaets_bit = si[cnetz->cell_nr].nachbar_prio;
telegramm.bewertung_nach_pegel_und_entfernung = si[cnetz->cell_nr].bewertung;
telegramm.entfernungsangabe_der_fufst = si[cnetz->cell_nr].entfernung;
@@ -884,11 +943,12 @@ const telegramm_t *cnetz_transmit_telegramm_rufblock(cnetz_t *cnetz)
telegramm.grenzwert_fuer_umschalten = si[cnetz->cell_nr].grenz_umschalten;
telegramm.grenze_fuer_ausloesen = si[cnetz->cell_nr].grenz_ausloesen;
trans = search_transaction(cnetz, TRANS_EM | TRANS_UM | TRANS_WBN | TRANS_WBP | TRANS_VAG | TRANS_VAK);
trans = search_transaction(cnetz, TRANS_EM | TRANS_UM | TRANS_WBN | TRANS_WBP | TRANS_VAG | TRANS_VAK | TRANS_ATQ | TRANS_VA | TRANS_WSK);
if (trans) {
telegramm.futln_nationalitaet = trans->futln_nat;
telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst;
telegramm.futln_rest_nr = trans->futln_rest;
telegramm.ausloesegrund = trans->release_cause;
switch (trans->state) {
case TRANS_EM:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending acknowledgment 'Einbuchquittung' to Attachment request.\n");
@@ -909,16 +969,26 @@ wbn:
break;
case TRANS_WBP:
spk = search_free_spk(trans->extended);
if (!spk) {
/* Accept call if channel available, otherwise reject or queue call */
if (spk) {
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending call accept 'Wahlbestaetigung positiv'.\n");
telegramm.opcode = OPCODE_WBP_R;
trans_new_state(trans, TRANS_VAG);
} else if (cnetz->warteschlange) {
/* queue call if no channel is available, but queue allowed */
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "No free channel, sending call accept in queue 'Wahlbestaetigung positiv in Warteschlage'.\n");
telegramm.opcode = OPCODE_WWBP_R;
trans_new_state(trans, TRANS_MO_QUEUE);
timer_start(&trans->timer, T_VAG2); /* Maximum time to hold queue */
} else {
PDEBUG(DCNETZ, DEBUG_NOTICE, "No free channel anymore, rejecting call!\n");
trans_new_state(trans, TRANS_WBN);
goto wbn;
}
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending call accept 'Wahlbestaetigung positiv'.\n");
telegramm.opcode = OPCODE_WBP_R;
trans_new_state(trans, TRANS_VAG);
break;
case TRANS_VAG:
case TRANS_VAK:
vak:
if (trans->state == TRANS_VAG) {
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending channel assignment 'Verbindungsaufbau gehend'.\n");
telegramm.opcode = OPCODE_VAG_R;
@@ -956,6 +1026,28 @@ wbn:
/* flush all other transactions, if any (in case of OgK/SpK) */
cnetz_flush_other_transactions(spk, trans);
break;
case TRANS_ATQ:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending acknowledgment 'Quittung fuer Ausloesen des FuTelG im OgK-Betrieb' to release request.\n");
telegramm.opcode = OPCODE_ATQ_R;
destroy_transaction(trans);
break;
case TRANS_VA:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Vorzeitiges Ausloesen' to queued mobile station\n");
telegramm.opcode = OPCODE_VA_R;
destroy_transaction(trans);
break;
case TRANS_WSK:
spk = search_free_spk(trans->extended);
/* if channel becomes free before we send the queue information, we proceed with channel assignment */
if (spk) {
trans_new_state(trans, TRANS_VAK);
goto vak;
}
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "No free channel, sending incoming call in queue 'Warteschglange kommend'.\n");
telegramm.opcode = OPCODE_WSK_R;
trans_new_state(trans, TRANS_MT_QUEUE);
timer_start(&trans->timer, T_VAK); /* Maximum time to hold queue */
call_in_alerting(trans->callref);
default:
; /* LR */
}
@@ -974,8 +1066,8 @@ const telegramm_t *cnetz_transmit_telegramm_meldeblock(cnetz_t *cnetz)
telegramm.opcode = OPCODE_MLR_M;
telegramm.max_sendeleistung = cnetz->ms_power;
telegramm.ogk_verkehrsanteil = 0; /* must be 0 or phone might not respond to messages in different slot */
telegramm.teilnehmersperre = 0;
telegramm.anzahl_gesperrter_teilnehmergruppen = 0;
telegramm.teilnehmergruppensperre = si[cnetz->cell_nr].teilnehmergruppensperre;
telegramm.anzahl_gesperrter_teilnehmergruppen = si[cnetz->cell_nr].anzahl_gesperrter_teilnehmergruppen;
telegramm.ogk_vorschlag = CNETZ_OGK_KANAL;
telegramm.fuz_rest_nr = si[cnetz->cell_nr].fuz_rest;
@@ -1014,7 +1106,6 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo
int valid_frame = 0;
transaction_t *trans;
const char *rufnummer;
cnetz_t *spk;
switch (opcode) {
case OPCODE_EM_R:
@@ -1059,6 +1150,13 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo
}
valid_frame = 1;
break;
case OPCODE_UWG_R:
case OPCODE_UWK_R:
if (!match_fuz(cnetz, telegramm, cnetz->cell_nr))
break;
rufnummer = telegramm2rufnummer(telegramm);
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received Roaming request 'Umbuchantrag' message from Subscriber '%s' on queue\n", rufnummer);
break;
case OPCODE_VWG_R:
case OPCODE_SRG_R:
if (!match_fuz(cnetz, telegramm, cnetz->cell_nr))
@@ -1075,16 +1173,10 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo
break;
}
trans->try = 1;
spk = search_free_spk(trans->extended);
if (!spk) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "Rejecting call from subscriber '%s', because we have no free channel. (or not supported by phone)\n", rufnummer);
trans_new_state(trans, TRANS_WBN);
break;
}
valid_frame = 1;
break;
case OPCODE_WUE_M:
trans = search_transaction(cnetz, TRANS_WAF | TRANS_WBP | TRANS_VAG);
trans = search_transaction(cnetz, TRANS_WAF | TRANS_WBP | TRANS_VAG | TRANS_MO_QUEUE);
if (!trans) {
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received dialing digits 'Wahluebertragung' message without transaction, ignoring!\n");
break;
@@ -1097,7 +1189,28 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo
trans->try = 1; /* try */
valid_frame = 1;
break;
case OPCODE_ATO_R:
if (!match_fuz(cnetz, telegramm, cnetz->cell_nr))
break;
rufnummer = telegramm2rufnummer(telegramm);
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received release 'Ausloesen des FuTelG im OgK-Betrieb bei WS' message from Subscriber '%s'\n", rufnummer);
trans = search_transaction_number(cnetz, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr);
if (!trans) {
/* create transaction, in case the phone repeats the release after we have acked it */
trans = create_transaction(cnetz, TRANS_ATQ, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, telegramm->erweitertes_frequenzbandbit);
if (!trans) {
PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n");
break;
}
} else {
timer_stop(&trans->timer);
trans_new_state(trans, TRANS_ATQ);
}
valid_frame = 1;
break;
case OPCODE_MFT_M:
if (!match_fuz(cnetz, telegramm, cnetz->cell_nr))
break;
trans = search_transaction_number(cnetz, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr);
if (!trans) {
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received acknowledge 'Meldung Funktelefonteilnehmer' message without transaction, ignoring!\n");
@@ -1392,15 +1505,23 @@ const telegramm_t *cnetz_transmit_telegramm_spk_v(cnetz_t *cnetz)
{
static telegramm_t telegramm;
transaction_t *trans = cnetz->trans_list;
int meter = 0;
memset(&telegramm, 0, sizeof(telegramm));
if (!trans)
return &telegramm;
if (cnetz->metering) {
double now = get_time();
if (!trans->call_start)
trans->call_start = now;
meter = (now - trans->call_start) / (double)cnetz->metering + 1;
}
telegramm.max_sendeleistung = cnetz->ms_power;
telegramm.sendeleistungsanpassung = 1;
telegramm.ankuendigung_gespraechsende = 0;
telegramm.gebuehren_stand = 0;
telegramm.gebuehren_stand = meter;
telegramm.fuz_nationalitaet = si[cnetz->cell_nr].fuz_nat;
telegramm.fuz_fuvst_nr = si[cnetz->cell_nr].fuz_fuvst;
telegramm.fuz_rest_nr = si[cnetz->cell_nr].fuz_rest;
@@ -1456,6 +1577,8 @@ void cnetz_receive_telegramm_spk_v(cnetz_t *cnetz, telegramm_t *telegramm)
switch (opcode) {
case OPCODE_VH_V:
case OPCODE_USAI_V:
case OPCODE_USAE_V:
if (!match_fuz(cnetz, telegramm, cnetz->cell_nr)) {
break;
}
@@ -1465,7 +1588,17 @@ void cnetz_receive_telegramm_spk_v(cnetz_t *cnetz, telegramm_t *telegramm)
if (trans->state != TRANS_VHQ)
break;
timer_start(&trans->timer, 0.6 * F_VHQ); /* F_VHQ frames */
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received supervisory frame 'Verbindung halten' message.\n");
switch (opcode) {
case OPCODE_VH_V:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received supervisory frame 'Verbindung halten' message%s.\n", (telegramm->test_telefonteilnehmer_geraet) ? ", phone is a test-phone" : "");
break;
case OPCODE_USAI_V:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received internal handover request frame 'Umschaltantrag intern' message%s.\n", (telegramm->test_telefonteilnehmer_geraet) ? ", phone is a test-phone" : "");
break;
case OPCODE_USAE_V:
PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received external handover request frame 'Umschaltantrag extern' message%s.\n", (telegramm->test_telefonteilnehmer_geraet) ? ", phone is a test-phone" : "");
break;
}
valid_frame = 1;
cnetz->scrambler = telegramm->betriebs_art;
break;

View File

@@ -37,6 +37,8 @@ enum cnetz_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 */
#define T_VAG2 180 /* time on outgoing queue */
#define T_VAK 60 /* time on incoming queue */
/* clear causes */
#define CNETZ_CAUSE_GASSENBESETZT 0 /* network congested */
@@ -71,6 +73,8 @@ typedef struct cnetz {
/* cell config */
int ms_power; /* power level of MS, use 0..3 */
int auth; /* authentication support of the cell */
int warteschlange; /* use queue */
int metering; /* use metering pulses in seconds 0 = off */
/* all cnetz states */
enum cnetz_state state; /* main state of sender */
@@ -127,7 +131,7 @@ int cnetz_channel_by_short_name(const char *short_name);
const char *chan_type_short_name(enum cnetz_chan_type chan_type);
const char *chan_type_long_name(enum cnetz_chan_type chan_type);
int cnetz_init(void);
int cnetz_create(int kanal, enum cnetz_chan_type chan_type, const char *audiodev, int use_sdr, enum demod_type demod, int samplerate, double rx_gain, int auth, int ms_power, int measure_speed, double clock_speed[2], int polarity, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback);
int cnetz_create(int kanal, enum cnetz_chan_type chan_type, const char *audiodev, int use_sdr, enum demod_type demod, int samplerate, double rx_gain, int auth, int warteschlange, int metering, int ms_power, int measure_speed, double clock_speed[2], int polarity, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback);
void cnetz_destroy(sender_t *sender);
void cnetz_go_idle(cnetz_t *cnetz);
void cnetz_sync_frame(cnetz_t *cnetz, double sync, int ts);

View File

@@ -36,6 +36,7 @@
#define MELDE_MAXIMAL 3
typedef struct cnetz_database {
struct cnetz_database *next;
uint8_t futln_nat; /* who ... */
uint8_t futln_fuvst;
@@ -154,10 +155,10 @@ int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest)
if (db->futln_nat == futln_nat
&& db->futln_fuvst == futln_fuvst
&& db->futln_rest == futln_rest)
return 1;
return db->extended;
db = db->next;
}
return 0;
return -1;
}
void flush_db(void)

View File

@@ -47,7 +47,27 @@ int set_clock_speed = 0;
const char *flip_polarity = "auto";
int ms_power = 0; /* 0..3 */
int auth = 0;
int warteschlange = 1;
uint8_t fuz_nat = 1;
uint8_t fuz_fuvst = 1;
uint8_t fuz_rest = 38;
uint8_t kennung_fufst = 1; /* normal prio */
uint8_t ws_kennung = 0; /* no queue */
uint8_t fuvst_sperren = 0; /* no blocking registration/calls */
uint8_t grenz_einbuchen = 1; /* > 15 SNR */
uint8_t grenz_umschalten = 15; /* < 18 SNR */
uint8_t grenz_ausloesen = 15; /* < 18 SNR */
uint8_t mittel_umschalten = 5; /* 64 Frames */
uint8_t mittel_ausloesen = 5; /* 64 Frames */
uint8_t genauigkeit = 1; /* limited accuracy */
uint8_t bewertung = 1; /* rating by level */
uint8_t entfernung = 3; /* 3km */
uint8_t reduzierung = 0; /* factor 4 */
uint8_t nachbar_prio = 0;
int8_t futln_sperre_start = -1; /* no blocking */
int8_t futln_sperre_end = -1; /* no range */
enum demod_type demod = FSK_DEMOD_AUTO;
int metering = 20;
void print_help(const char *arg0)
{
@@ -57,7 +77,7 @@ void print_help(const char *arg0)
printf(" Give channel type, use 'list' to get a list. (default = '%s')\n", chan_type_short_name(chan_type[0]));
printf(" -M --measure-speed\n");
printf(" Measures clock speed. THIS IS REQUIRED! See documentation!\n");
printf(" -S --clock-speed <rx ppm>,<tx ppm>\n");
printf(" -C --clock-speed <rx ppm>,<tx ppm>\n");
printf(" Correct speed of sound card's clock. Use '-M' to measure speed for\n");
printf(" some hours after temperature has settled. The use these results to\n");
printf(" correct signal processing speed. After adjustment, the clock must match\n");
@@ -69,6 +89,7 @@ void print_help(const char *arg0)
printf(" base station generates two virtual base stations with both polarities.\n");
printf(" Once a mobile registers, the correct polarity is selected and used.\n");
printf(" (default = %s)\n", flip_polarity);
printf(" Note: This has no effect with SDR.\n");
printf(" -P --ms-power <power level>\n");
printf(" Give power level of the mobile station 0..3. (default = '%d')\n", ms_power);
printf(" 0 = 50-125 mW; 1 = 0.5-1 W; 2 = 4-8 W; 3 = 10-20 W\n");
@@ -76,6 +97,90 @@ void print_help(const char *arg0)
printf(" Enable authentication on the base station. Since we cannot\n");
printf(" authenticate, because we don't know the secret key and the algorithm,\n");
printf(" we just accept any card. With this we get the vendor IDs of the phone.\n");
printf(" -Q --queue | --warteschlange 1 | 0\n");
printf(" Enable queue support. If no channel is available, calls will be kept\n");
printf(" in a queue for maximum of 60 seconds. (default = %d)\n", warteschlange);
printf(" -G --gebuehren <seconds> | 0\n");
printf(" Increment metering counter every given number of seconds.\n");
printf(" To turn off, use 0. (default = %d)\n", metering);
printf(" -S --sysinfo fuz-nat=<nat>\n");
printf(" Set country ID of base station. All IDs were used inside Germany only.\n");
printf(" (default = %d)\n", fuz_nat);
printf(" -S --sysinfo fuz-fuvst=<id>\n");
printf(" Set switching center ID of base station. (default = %d)\n", fuz_fuvst);
printf(" -S --sysinfo fuz-rest=<id>\n");
printf(" Set cell ID of base station. (default = %d)\n", fuz_rest);
printf(" -S --sysinfo kennung-fufst=<id>\n");
printf(" Set priority for selecting base station. (default = %d)\n", kennung_fufst);
printf(" 0 = Test (Only special mobile stations may register.)\n");
printf(" 1 = Normal priority base station.\n");
printf(" 2 = Higher priority base station.\n");
printf(" 3 = Highest priority base station.\n");
printf(" Note: Priority has no effect, because there is only one base station.\n");
printf(" -S --sysinfo ws-kennung=<value>\n");
printf(" Queue setting of base station. (default = %d)\n", ws_kennung);
printf(" 0 = No queue, calls will be handled directly.\n");
printf(" 1 = Queue on outgoing calls.\n");
printf(" 2 = Queue blocked, no calls allowed.\n");
printf(" 3 = Reserved, don't use!\n");
printf(" -S --sysinfo fuvst-sperren=<value>\n");
printf(" Blocking registration and outgoing calls. (default = %d)\n", fuvst_sperren);
printf(" 0 = Registration and outgoing calls allowed.\n");
printf(" 1 = Only registration alloweed.\n");
printf(" 2 = Only outgoing calls allowed. (Cannot work without registration!)\n");
printf(" 3 = No registration and no outgoing calls allowed.\n");
printf(" -S --sysinfo grenz-einbuchen=<value>\n");
printf(" Minimum SNR to allow registration of mobile (default = %d)\n", grenz_einbuchen);
printf(" 0 = No limit; 1 = >15 dB; 2 = >17 dB; 3 = >19 dB\n");
printf(" 4 = >21 dB; 5 = >25 dB; 6 = >28 dB; 7 = >32 dB\n");
printf(" -S --sysinfo grenz-umschalten=<value>\n");
printf(" Minimum SNR before phone requests handover (default = %d)\n", grenz_umschalten);
printf(" 15 = 18 dB ... 0 = 26 dB (external)\n");
printf(" 13 = 16 dB ... 0 = 22 dB (internal)\n");
printf(" -S --sysinfo grenz-ausloesen=<value>\n");
printf(" Minimum SNR before phone releases of call (default = %d)\n", grenz_ausloesen);
printf(" 15 = 18 dB ... 0 = 26 dB\n");
printf(" -S --sysinfo mittel-umschalten=<value>\n");
printf(" Number of frames to measure for handover criterium (default = %d)\n", mittel_umschalten);
printf(" 0 = 2 measurements; 1 = 4 measurements; 2 = 8 measurememnts\n");
printf(" 3 = 16 measurements; 4 = 32 measurements; 5 = 64 measurememnts\n");
printf(" -S --sysinfo mittel-ausloesen=<value>\n");
printf(" Number of frames to measure for release criterium (default = %d)\n", mittel_ausloesen);
printf(" 0 = 2 measurements; 1 = 4 measurements; 2 = 8 measurememnts\n");
printf(" 3 = 16 measurements; 4 = 32 measurements; 5 = 64 measurememnts\n");
printf(" -S --sysinfo genauigkeit=<value>\n");
printf(" Accuracy of base station (default = %d)\n", genauigkeit);
printf(" 0 = full accuracy; 1 = limited accuracy\n");
printf(" Note: This has no effect, because there is only one base station.\n");
printf(" -S --sysinfo bewertung=<value>\n");
printf(" Rating of base station (default = %d)\n", bewertung);
printf(" 0 = by relative distance; 1 = by received level\n");
printf(" Note: This has no effect, because there is only one base station.\n");
printf(" -S --sysinfo entfernung=<value>\n");
printf(" Base station size (default = %d)\n", entfernung);
printf(" 0 = 1.5km; 1 = 2km; 2 = 2.5km; 3 = 3km; 4 = 5km; 5 = 5km\n");
printf(" 6 = 6km; 7 = 7km; 8 = 8km; 9 = 10km; 10 = 12km; 11 = 14km\n");
printf(" 12 = 16km; 13 = 17km; 14 = 23km; 15 = 30km\n");
printf(" Note: This has no effect, because there is only one base station.\n");
printf(" -S --sysinfo reduzierung=<value>\n");
printf(" See specs value 'y' (default = %d)\n", reduzierung);
printf(" 0 = 4; 1 = 3; 2 = 2; 3 = 1\n");
printf(" Note: This has no effect, because there is only one base station.\n");
printf(" -S --sysinfo nachbar-prio=<value>\n");
printf(" See specs value 'g' (default = %d)\n", nachbar_prio);
printf(" Note: This has no effect, because there is only one base station.\n");
printf(" -S --sysinfo futln-sperre=<value>[-<value>]\n");
printf(" Blocking registration and outgoing calls for selected mobile stations.\n");
printf(" The 4 least significant bits of the subscriber number can be given to\n");
printf(" block all matching phones. Alternatively the phone number may be given\n");
printf(" here, so that the 4 bits get calculated automatically. The optional\n");
printf(" second value can be given, to define a range - in the same way.\n");
if (futln_sperre_start < 0)
printf(" (default = no value given)\n");
else if (futln_sperre_end < 0)
printf(" (default = %d)\n", futln_sperre_start);
else
printf(" (default = %d-%d)\n", futln_sperre_start, futln_sperre_end);
printf(" -D --demod auto | slope | level\n");
printf(" Adjust demodulation algorithm. Use 'slope' to detect a level change\n");
printf(" by finding the highest slope of a bit transition. It is useful, if\n");
@@ -91,6 +196,27 @@ void print_help(const char *arg0)
printf("Press 'i' key to dump list of currently attached subscribers.\n");
}
static int atoi_limit(const char *p, int l1, int l2)
{
int value = atoi(p);
if (l1 < l2) {
if (value < l1)
value = l1;
if (value > l2)
value = l2;
} else {
if (value < l2)
value = l2;
if (value > l1)
value = l1;
}
return value;
}
#define OPT_WARTESCHLANGE 256
static int handle_options(int argc, char **argv)
{
int skip_args = 0;
@@ -100,15 +226,19 @@ static int handle_options(int argc, char **argv)
static struct option long_options_special[] = {
{"channel-type", 1, 0, 'T'},
{"measure-speed", 0, 0, 'M'},
{"clock-speed", 1, 0, 'S'},
{"clock-speed", 1, 0, 'C'},
{"flip-polarity", 1, 0, 'F'},
{"ms-power", 1, 0, 'P'},
{"authentication", 0, 0, 'A'},
{"queue", 1, 0, 'Q'},
{"warteschlange", 1, 0, OPT_WARTESCHLANGE},
{"gebuehren", 1, 0, 'G'},
{"sysinfo", 1, 0, 'S'},
{"demod", 1, 0, 'D'},
{0, 0, 0, 0}
};
set_options_common("T:MS:F:N:P:AD:", long_options_special);
set_options_common("T:MC:F:P:AQ:G:S:D:", long_options_special);
while (1) {
int option_index = 0, c;
@@ -136,7 +266,7 @@ static int handle_options(int argc, char **argv)
measure_speed = 1;
skip_args++;
break;
case 'S':
case 'C':
p = strchr(optarg, ',');
if (!p) {
fprintf(stderr, "Illegal clock speed, use two values, seperated by comma and no spaces!\n");
@@ -161,17 +291,97 @@ static int handle_options(int argc, char **argv)
skip_args += 2;
break;
case 'P':
ms_power = atoi(optarg);
if (ms_power > 3)
ms_power = 3;
if (ms_power < 0)
ms_power = 0;
ms_power = atoi_limit(optarg, 0, 3);
skip_args += 2;
break;
case 'A':
auth = 1;
skip_args += 1;
break;
case 'Q':
case OPT_WARTESCHLANGE:
warteschlange = atoi_limit(optarg, 0, 1);;
skip_args += 2;
break;
case 'G':
metering = atoi(optarg);
skip_args += 2;
break;
case 'S':
p = strchr(optarg, '=');
if (!p) {
fprintf(stderr, "Given sysinfo parameter '%s' requires '=' character to set value, see help!\n", optarg);
exit(0);
}
p++;
if (!strncasecmp(optarg, "fuz-nat=", p - optarg)) {
fuz_nat = atoi_limit(p, 0, 7);
} else
if (!strncasecmp(optarg, "fuz-fuvst=", p - optarg)) {
fuz_fuvst = atoi_limit(p, 0, 32);
} else
if (!strncasecmp(optarg, "fuz-rest=", p - optarg)) {
fuz_rest = atoi_limit(p, 0, 255);
} else
if (!strncasecmp(optarg, "kennung-fufst=", p - optarg)) {
kennung_fufst = atoi_limit(p, 0, 3);
} else
if (!strncasecmp(optarg, "ws-kennung=", p - optarg)) {
ws_kennung = atoi_limit(p, 0, 3);
} else
if (!strncasecmp(optarg, "fuvst-sperren=", p - optarg)) {
fuvst_sperren = atoi_limit(p, 0, 3);
} else
if (!strncasecmp(optarg, "grenz-einbuchen=", p - optarg)) {
grenz_einbuchen = atoi_limit(p, 0, 7);
} else
if (!strncasecmp(optarg, "grenz-umschalten=", p - optarg)) {
grenz_umschalten = atoi_limit(p, 0, 15);
} else
if (!strncasecmp(optarg, "grenz-ausloesen=", p - optarg)) {
grenz_ausloesen = atoi_limit(p, 0, 15);
} else
if (!strncasecmp(optarg, "mittel-umschalten=", p - optarg)) {
mittel_umschalten = atoi_limit(p, 0, 5);
} else
if (!strncasecmp(optarg, "mittel-ausloesen=", p - optarg)) {
mittel_ausloesen = atoi_limit(p, 0, 5);
} else
if (!strncasecmp(optarg, "genauigkeit=", p - optarg)) {
genauigkeit = atoi_limit(p, 0, 1);
} else
if (!strncasecmp(optarg, "bewertung=", p - optarg)) {
bewertung = atoi_limit(p, 0, 1);
} else
if (!strncasecmp(optarg, "entfernung=", p - optarg)) {
entfernung = atoi_limit(p, 0, 15);
} else
if (!strncasecmp(optarg, "nachbar-prio=", p - optarg)) {
nachbar_prio = atoi_limit(p, 0, 1);
} else
if (!strncasecmp(optarg, "futln-sperre=", p - optarg)) {
char value[128], *v, *q;
strncpy(value, p, sizeof(value) - 1);
value[sizeof(value) - 1] = '\0';
v = value;
q = strchr(value, '-');
if (q)
*q++ = '\0';
if (strlen(v) > 5)
v += strlen(v) - 5;
futln_sperre_start = atoi(v) & 0xf;
if (q) {
if (strlen(q) > 5)
q += strlen(q) - 5;
futln_sperre_end = atoi(q) & 0xf;
}
} else
{
fprintf(stderr, "Given sysinfo parameter '%s' unknown, see help!\n", optarg);
exit(0);
}
skip_args += 2;
break;
case 'D':
if (!strcasecmp(optarg, "auto"))
demod = FSK_DEMOD_AUTO;
@@ -202,6 +412,8 @@ int main(int argc, char *argv[])
const char *station_id = "";
int mandatory = 0;
int polarity;
int teilnehmergruppensperre = 0;
int anzahl_gesperrter_teilnehmergruppen = 0;
int i;
/* init common tones */
@@ -266,7 +478,16 @@ int main(int argc, char *argv[])
/* init functions */
scrambler_init();
init_sysinfo();
if (futln_sperre_start >= 0) {
teilnehmergruppensperre = futln_sperre_start;
if (futln_sperre_end >= 0)
anzahl_gesperrter_teilnehmergruppen = ((futln_sperre_end - futln_sperre_start) & 0xf) + 1;
else
anzahl_gesperrter_teilnehmergruppen = 1;
}
if (anzahl_gesperrter_teilnehmergruppen)
printf("Blocked subscriber with number's last 4 bits from 0x%x to 0x%x\n", teilnehmergruppensperre, (teilnehmergruppensperre + anzahl_gesperrter_teilnehmergruppen - 1) & 0xf);
init_sysinfo(fuz_nat, fuz_fuvst, fuz_rest, kennung_fufst, ws_kennung, fuvst_sperren, grenz_einbuchen, grenz_umschalten, grenz_ausloesen, mittel_umschalten, mittel_ausloesen, genauigkeit, bewertung, entfernung, reduzierung, nachbar_prio, teilnehmergruppensperre, anzahl_gesperrter_teilnehmergruppen);
dsp_init();
rc = init_telegramm();
if (rc < 0) {
@@ -336,7 +557,7 @@ int main(int argc, char *argv[])
/* create transceiver instance */
for (i = 0; i < num_kanal; i++) {
rc = cnetz_create(kanal[i], chan_type[i], audiodev[i], use_sdr, demod, samplerate, rx_gain, auth, ms_power, (i == 0) ? measure_speed : 0, clock_speed, polarity, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback);
rc = cnetz_create(kanal[i], chan_type[i], audiodev[i], use_sdr, demod, samplerate, rx_gain, auth, warteschlange, metering, ms_power, (i == 0) ? measure_speed : 0, clock_speed, polarity, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback);
if (rc < 0) {
fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n");
goto fail;

View File

@@ -4,61 +4,57 @@
cnetz_si si[2];
void init_sysinfo(void)
void init_sysinfo(uint8_t fuz_nat, uint8_t fuz_fuvst, uint8_t fuz_rest, uint8_t kennung_fufst, uint8_t ws_kennung, uint8_t vermittlungstechnische_sperren, uint8_t grenz_einbuchen, uint8_t grenz_umschalten, uint8_t grenz_ausloesen, uint8_t mittel_umschalten, uint8_t mittel_ausloesen, uint8_t genauigkeit, uint8_t bewertung, uint8_t entfernung, uint8_t reduzierung, uint8_t nachbar_prio, int8_t teilnehmergruppensperre, uint8_t anzahl_gesperrter_teilnehmergruppen)
{
memset(&si, 0, sizeof(si));
memset(&si[0], 0, sizeof(cnetz_si));
/* polarity of TX signal */
si[0].flip_polarity = 0;
/* ID of base station */
si[0].fuz_nat = fuz_nat;
si[0].fuz_fuvst = fuz_fuvst;
si[0].fuz_rest = fuz_rest;
/* a low value causes quicker measurement results */
si[0].mittel_umschalten = mittel_umschalten; /* 0..5 */
/* a high value is tollerant to bad quality */
si[0].grenz_umschalten = grenz_umschalten; /* 0..15 */
/* a low value causes quicker measurement results */
si[0].mittel_ausloesen = mittel_ausloesen; /* 0..5 */
/* a high value is tollerant to bad quality */
si[0].grenz_ausloesen = grenz_ausloesen; /* 0..15 */
si[0].vermittlungstechnische_sperren = vermittlungstechnische_sperren;
si[0].genauigkeit = genauigkeit; /* 1 = bedingte Genauigkeit */
si[0].entfernung = entfernung;
/* a low value is tollerant to bad quality */
si[0].grenz_einbuchen = grenz_einbuchen; /* 1..7 */
si[0].kennung_fufst = kennung_fufst;
si[0].ws_kennung = ws_kennung;
si[0].nachbar_prio = nachbar_prio;
si[0].bewertung = bewertung; /* 0 = relative entfernung, 1 = pegel */
si[0].reduzierung = reduzierung;
/* deny group of subscribers. (used to balance subscribers between base stations) */
si[0].teilnehmergruppensperre = teilnehmergruppensperre;
si[0].anzahl_gesperrter_teilnehmergruppen = anzahl_gesperrter_teilnehmergruppen;
/* second cell uses flipped polarity. different station ID is used to
* detect what cell (and what polarity) the mobile responses to. */
memcpy(&si[1], &si[0], sizeof(cnetz_si));
si[1].flip_polarity = 1;
si[0].fuz_nat = 1;
si[1].fuz_nat = 1;
si[0].fuz_fuvst = 1;
si[1].fuz_fuvst = 1;
si[0].fuz_rest = 38;
si[1].fuz_rest = 39;
/* a low value causes quicker measurement results */
si[0].mittel_umschalten = 5; /* 0..5 */
si[1].mittel_umschalten = 5;
/* a low value is tollerant to bad quality */
si[0].grenz_umschalten = 0; /* 0..13 */
si[1].grenz_umschalten = 0; /* 0..13 */
/* a low value causes quicker measurement results */
si[0].mittel_ausloesen = 5; /* 0..5 */
si[1].mittel_ausloesen = 5;
/* a low value is tollerant to bad quality */
si[0].grenz_ausloesen = 0; /* 0..13 */
si[1].grenz_ausloesen = 0; /* 0..13 */
si[0].sperre = 0;
si[1].sperre = 0;
si[0].genauigkeit = 1; /* bedingte Genauigkeit */
si[1].genauigkeit = 1; /* bedingte Genauigkeit */
si[0].entfernung = 3;
si[1].entfernung = 3;
/* a low value is tollerant to bad quality */
si[0].grenz_einbuchen = 1; /* 1..7 */
si[1].grenz_einbuchen = 1;
si[0].fufst_prio = 1; /* normal pio */
si[1].fufst_prio = 1; /* normal pio */
si[0].nachbar_prio = 0;
si[1].nachbar_prio = 0;
si[0].bewertung = 1; /* pegel */
si[1].bewertung = 1; /* pegel */
si[0].reduzierung = 0;
si[1].reduzierung = 0;
si[1].fuz_rest = si[0].fuz_rest + 1;
}

View File

@@ -8,17 +8,20 @@ typedef struct system_information {
uint8_t grenz_umschalten;
uint8_t mittel_ausloesen;
uint8_t grenz_ausloesen;
uint8_t sperre;
uint8_t vermittlungstechnische_sperren;
uint8_t genauigkeit;
uint8_t entfernung;
uint8_t grenz_einbuchen;
uint8_t fufst_prio; /* prio of base station */
uint8_t kennung_fufst; /* prio of base station */
uint8_t ws_kennung; /* queue setting sof base station */
uint8_t nachbar_prio;
uint8_t bewertung;
uint8_t reduzierung;
int8_t teilnehmergruppensperre;
int8_t anzahl_gesperrter_teilnehmergruppen;
} cnetz_si;
extern cnetz_si si[];
void init_sysinfo(void);
void init_sysinfo(uint8_t fuz_nat, uint8_t fuz_fuvst, uint8_t fuz_rest, uint8_t kennung_fufst, uint8_t ws_kennung, uint8_t vermittlungstechnische_sperren, uint8_t grenz_einbuchen, uint8_t grenz_umschalten, uint8_t grenz_ausloesen, uint8_t mittel_umschalten, uint8_t mittel_ausloesen, uint8_t genauigkeit, uint8_t bewertung, uint8_t entfernung, uint8_t reduzierung, uint8_t nachbar_prio, int8_t teilnehmergruppensperre, uint8_t anzahl_gesperrter_teilnehmergruppen);

View File

@@ -114,7 +114,7 @@ static const char *param_genauigkeit[] = {
};
static const char *param_grenzwert[] = {
"Illegaler Parameter 0",
"No limit",
"> 15 dB S/N",
"> 17 dB S/N",
"> 19 dB S/N",
@@ -272,7 +272,7 @@ static struct definition_parameter {
{ 'U',"FuTln-Heimmat FuVSt-Nr.", 5, NULL },
{ 'V',"Sicherungs-Code", 16, NULL },
{ 'W',"WS-Kennung", 2, param_wskennung },
{ 'X',"Wahlziffer beliebig 16 Ziffer", 64, NULL },
{ 'X',"Wahlziffer beliebig 16 Ziffern", 64, NULL },
{ 'Z',"Zeitschlitz-Nr.", 5, NULL },
{ 'a',"Grenzert fuer Ausloesen", 4, param_ausloesen },
{ 'b',"Chipkarten-FuTelG-Bit", 1, param_chipkarte },
@@ -363,7 +363,7 @@ static struct definition_opcode {
{ "________________________________________________________________", NULL, "opcode 34",BLOCK_I,"Illegaler Opcode" },
{ "PPdZZZZZ----------------IIIAAAAAFFFFFFFFNNNUUUUUTTTTTTTTTTTTTTTT", NULL, "EBQ(R)", BLOCK_R,"Einbuchquittung" },
{ "PPdZZZZZ----------------IIIAAAAAFFFFFFFFNNNUUUUUTTTTTTTTTTTTTTTT", NULL, "UBQ(R)", BLOCK_R,"Umbuchquittung" },
{ "PPdZZZZZ----------------IIIAAAAAFFFFFFFFNNNUUUUUTTTTTTTTTTTTTTTT", NULL, "WSK(R)", BLOCK_R,"Wartescglange kommend" },
{ "PPdZZZZZ----------------IIIAAAAAFFFFFFFFNNNUUUUUTTTTTTTTTTTTTTTT", NULL, "WSK(R)", BLOCK_R,"Warteschglange kommend" },
{ "PP-MMMMMDDDDEEEE------HHHHHHHHHHFFFFFFFF------------------------", NULL, "MLR(M)", BLOCK_M,"Melde-Leer-Ruf" },
{ "PPdZZZZZffflvvWW------yyIIIAAAAAFFFFFFFFkkgprrrrmmmmnnnnuuuuaaaa", NULL, "LR(R)", BLOCK_R,"Leer-Ruf" },
{ "PPdZZZZZ----------------IIIAAAAAFFFFFFFFNNNUUUUUTTTTTTTTTTTTTTTT", NULL, "ATQ(R)", BLOCK_R,"Quittung fuer Ausloesen des FuTelG im OgK-Betrieb" },
@@ -655,7 +655,7 @@ static char *assemble_telegramm(const telegramm_t *telegramm, int debug)
value = telegramm->ankuendigung_gespraechsende;
break;
case 'D':
value = telegramm->teilnehmersperre;
value = telegramm->teilnehmergruppensperre;
break;
case 'E':
value = telegramm->anzahl_gesperrter_teilnehmergruppen;
@@ -868,7 +868,7 @@ static void disassemble_telegramm(telegramm_t *telegramm, const char *bits, int
telegramm->ankuendigung_gespraechsende = value;
break;
case 'D':
telegramm->teilnehmersperre = value;
telegramm->teilnehmergruppensperre = value;
break;
case 'E':
telegramm->anzahl_gesperrter_teilnehmergruppen = value;
@@ -1533,7 +1533,7 @@ selected:
nr = 1;
goto selected;
} else {
PDEBUG(DFRAME, DEBUG_NOTICE, "Received Telegramm with no cell number, ignoring!\n");
PDEBUG(DFRAME, DEBUG_NOTICE, "Received Telegramm with unknown cell number, ignoring!\n");
return;
}
}

View File

@@ -67,7 +67,7 @@ typedef struct telegramm {
uint8_t fuz_fuvst_nr;
uint8_t betriebs_art;
uint8_t ankuendigung_gespraechsende;
uint8_t teilnehmersperre;
uint8_t teilnehmergruppensperre;
uint8_t anzahl_gesperrter_teilnehmergruppen;
uint8_t fuz_rest_nr;
uint16_t gebuehren_stand;

View File

@@ -39,7 +39,7 @@ const char *transaction2rufnummer(transaction_t *trans)
}
/* create transaction */
transaction_t *create_transaction(cnetz_t *cnetz, uint32_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int extended)
transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int extended)
{
sender_t *sender;
transaction_t *trans = NULL;
@@ -80,7 +80,7 @@ transaction_t *create_transaction(cnetz_t *cnetz, uint32_t state, uint8_t futln_
if (state == TRANS_VWG)
trans->mo_call = 1;
if (state == TRANS_VAK)
if (state == TRANS_VAK || state == TRANS_WSK)
trans->mt_call = 1;
const char *rufnummer = transaction2rufnummer(trans);
@@ -147,7 +147,7 @@ void unlink_transaction(transaction_t *trans)
cnetz_display_status();
}
transaction_t *search_transaction(cnetz_t *cnetz, uint32_t state_mask)
transaction_t *search_transaction(cnetz_t *cnetz, uint64_t state_mask)
{
transaction_t *trans = cnetz->trans_list;
@@ -200,7 +200,7 @@ transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref)
return NULL;
}
static const char *trans_state_name(int state)
static const char *trans_state_name(uint64_t state)
{
switch (state) {
case 0:
@@ -223,6 +223,8 @@ static const char *trans_state_name(int state)
return "WBN";
case TRANS_VAG:
return "VAG";
case TRANS_WSK:
return "WSK";
case TRANS_VAK:
return "VAK";
case TRANS_BQ:
@@ -235,16 +237,28 @@ static const char *trans_state_name(int state)
return "DS";
case TRANS_AHQ:
return "AHQ";
case TRANS_VA:
return "VA";
case TRANS_AF:
return "AF";
case TRANS_AT:
return "AT";
case TRANS_ATQ:
return "ATQ";
case TRANS_MO_QUEUE:
return "MO_QUEUE";
case TRANS_MT_QUEUE:
return "MT_QUEUE";
case TRANS_MO_DELAY:
return "MO_DELAY";
case TRANS_MT_DELAY:
return "MT_DELAY";
default:
return "<invald transaction state>";
}
}
const char *trans_short_state_name(int state)
const char *trans_short_state_name(uint64_t state)
{
switch (state) {
case 0:
@@ -279,9 +293,9 @@ const char *trans_short_state_name(int state)
}
}
void trans_new_state(transaction_t *trans, int state)
void trans_new_state(transaction_t *trans, uint64_t state)
{
PDEBUG(DTRANS, DEBUG_INFO, "Transaction state %s -> %s\n", trans_state_name(trans->state), trans_state_name(state));
PDEBUG(DTRANS, DEBUG_INFO, "Transaction (%s) state %s -> %s\n", transaction2rufnummer(trans), trans_state_name(trans->state), trans_state_name(state));
trans->state = state;
cnetz_display_status();
}

View File

@@ -13,16 +13,24 @@
#define TRANS_WBN (1 << 7) /* dialing received, waiting for time slot to reject call */
#define TRANS_VAG (1 << 8) /* establishment of call sent, switching channel */
/* mobile terminated call */
#define TRANS_VAK (1 << 9) /* establishment of call sent, switching channel */
#define TRANS_WSK (1 << 9) /* incomming call in queue */
#define TRANS_VAK (1 << 10) /* establishment of call sent, switching channel */
/* traffic channel */
#define TRANS_BQ (1 << 10) /* accnowledge channel */
#define TRANS_VHQ (1 << 11) /* hold call */
#define TRANS_RTA (1 << 12) /* hold call and make the phone ring */
#define TRANS_DS (1 << 13) /* establish speech connection */
#define TRANS_AHQ (1 << 14) /* establish speech connection after answer */
#define TRANS_BQ (1 << 11) /* accnowledge channel */
#define TRANS_VHQ (1 << 12) /* hold call */
#define TRANS_RTA (1 << 13) /* hold call and make the phone ring */
#define TRANS_DS (1 << 14) /* establish speech connection */
#define TRANS_AHQ (1 << 15) /* establish speech connection after answer */
/* release */
#define TRANS_AF (1 << 15) /* release connection by base station */
#define TRANS_AT (1 << 16) /* release connection by mobile station */
#define TRANS_VA (1 << 16) /* release call in queue by base station (OgK) */
#define TRANS_AF (1 << 17) /* release connection by base station (SpK) */
#define TRANS_AT (1 << 18) /* release connection by mobile station */
#define TRANS_ATQ (1 << 19) /* acknowledge release of MO call in queue */
/* queue */
#define TRANS_MO_QUEUE (1 << 20) /* MO queue */
#define TRANS_MT_QUEUE (1 << 21) /* MT queue */
#define TRANS_MO_DELAY (1 << 22) /* delay to be sure the channel is free again */
#define TRANS_MT_DELAY (1 << 23)
typedef struct transaction {
struct transaction *next; /* pointer to next node in list */
@@ -33,7 +41,7 @@ typedef struct transaction {
uint16_t futln_rest;
int extended; /* extended frequency capability */
char dialing[17]; /* number dialed by the phone */
int32_t state; /* state of transaction */
int64_t state; /* state of transaction */
int8_t release_cause; /* reason for release, (c-netz coding) */
int try; /* counts resending messages */
int repeat; /* counts repeating messages */
@@ -41,18 +49,19 @@ typedef struct transaction {
int mo_call; /* flags a moile originating call */
int mt_call; /* flags a moile terminating call */
int page_failed; /* failed to get a response from MS */
double call_start; /* when did the call start? (used for metering) */
} transaction_t;
const char *transaction2rufnummer(transaction_t *trans);
transaction_t *create_transaction(cnetz_t *cnetz, uint32_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int extended);
transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int extended);
void destroy_transaction(transaction_t *trans);
void link_transaction(transaction_t *trans, cnetz_t *cnetz);
void unlink_transaction(transaction_t *trans);
transaction_t *search_transaction(cnetz_t *cnetz, uint32_t state_mask);
transaction_t *search_transaction(cnetz_t *cnetz, uint64_t state_mask);
transaction_t *search_transaction_number(cnetz_t *cnetz, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest);
transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref);
void trans_new_state(transaction_t *trans, int state);
void trans_new_state(transaction_t *trans, uint64_t state);
void cnetz_flush_other_transactions(cnetz_t *cnetz, transaction_t *trans);
void transaction_timeout(struct timer *timer);
const char *trans_short_state_name(int state);
const char *trans_short_state_name(uint64_t state);