From 4930da8e0cae801f340bfddd00db56eb97c9b18a Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 9 Jun 2022 19:27:22 +0200 Subject: [PATCH] C-Netz: Add capability of non-standard OgK channel(s) --- src/cnetz/cnetz.c | 188 ++++++++++++++++++++++++---------------- src/cnetz/cnetz.h | 6 +- src/cnetz/database.c | 22 +++-- src/cnetz/database.h | 4 +- src/cnetz/dsp.c | 4 +- src/cnetz/main.c | 8 +- src/cnetz/telegramm.c | 5 +- src/cnetz/transaction.c | 102 +++++++++++++++++++--- src/cnetz/transaction.h | 15 ++-- 9 files changed, 244 insertions(+), 110 deletions(-) diff --git a/src/cnetz/cnetz.c b/src/cnetz/cnetz.c index e276d62..7762331 100644 --- a/src/cnetz/cnetz.c +++ b/src/cnetz/cnetz.c @@ -159,6 +159,12 @@ #define CUT_OFF_EMPHASIS_CNETZ 796.0 /* 200 uS time constant */ +/* OgK list of alternative channels, NOT including 131 */ +cnetz_t *ogk_list[16]; +int ogk_list_count = 0; +int ogk_list_index = 0; + + /* Convert channel number to frequency number of base station. Set 'unterband' to 1 to get frequency of mobile station. */ double cnetz_kanal2freq(int kanal, int unterband) @@ -286,42 +292,38 @@ int cnetz_init(void) } /* Create transceiver instance and link to a list. */ -int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char *device, int use_sdr, enum demod_type demod, int samplerate, double rx_gain, double tx_gain, int challenge_valid, uint64_t challenge, int response_valid, uint64_t response, int warteschlange, int metering, double speech_deviation, 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(const char *kanal_name, enum cnetz_chan_type chan_type, const char *device, int use_sdr, enum demod_type demod, int samplerate, double rx_gain, double tx_gain, int challenge_valid, uint64_t challenge, int response_valid, uint64_t response, int warteschlange, int metering, double speech_deviation, 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; + int kanal; int rc; - if ((atoi(kanal) & 1) && (atoi(kanal) < 3 || atoi(kanal) > 1147)) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Channel ('Kanal') number %s invalid. For odd channel numbers, use channel 3 ... 1147.\n", kanal); + kanal = atoi(kanal_name); + if ((kanal & 1) && (kanal < 3 || kanal > 1147)) { + PDEBUG(DCNETZ, DEBUG_ERROR, "Channel ('Kanal') number %d invalid. For odd channel numbers, use channel 3 ... 1147.\n", kanal); return -EINVAL; } - if ((atoi(kanal) & 1) && atoi(kanal) > 947) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You defined an extended frequency channel %s, only newer phones support this!\n", kanal); + if ((kanal & 1) && kanal > 947) { + PDEBUG(DCNETZ, DEBUG_NOTICE, "You defined an extended frequency channel %d, only newer phones support this!\n", kanal); } - if (!(atoi(kanal) & 1) && (atoi(kanal) < 4 || atoi(kanal) > 918)) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Channel ('Kanal') number %s invalid. For even channel numbers, use channel 4 ... 918.\n", kanal); + if (!(kanal & 1) && (kanal < 4 || kanal > 918)) { + PDEBUG(DCNETZ, DEBUG_ERROR, "Channel ('Kanal') number %d invalid. For even channel numbers, use channel 4 ... 918.\n", kanal); return -EINVAL; } - if (!(atoi(kanal) & 1) && atoi(kanal) > 758) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You defined an extended frequency %s, only newer phones support this!\n", kanal); - } - - /* OgK must be on channel 131 */ - if ((chan_type == CHAN_TYPE_OGK || chan_type == CHAN_TYPE_OGK_SPK) && atoi(kanal) != CNETZ_OGK_KANAL) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You must use channel %d for calling channel ('Orga-Kanal') or for combined calling + traffic channel!\n", CNETZ_OGK_KANAL); - return -EINVAL; + if (!(kanal & 1) && kanal > 758) { + PDEBUG(DCNETZ, DEBUG_NOTICE, "You defined an extended frequency channel %d, only newer phones support this!\n", kanal); } /* SpK must be on channel other than 131 */ - if (chan_type == CHAN_TYPE_SPK && atoi(kanal) == CNETZ_OGK_KANAL) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You must not use channel %d for traffic channel!\n", CNETZ_OGK_KANAL); + if (chan_type == CHAN_TYPE_SPK && kanal == CNETZ_STD_OGK_KANAL) { + PDEBUG(DCNETZ, DEBUG_NOTICE, "You must not use channel %d for traffic channel!\n", CNETZ_STD_OGK_KANAL); return -EINVAL; } /* warn if we combine SpK and OgK, this is not supported by standard */ if (chan_type == CHAN_TYPE_OGK_SPK) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You selected channel %d ('Orga-Kanal') for combined calling + traffic channel. Some phones will reject this.\n", CNETZ_OGK_KANAL); + PDEBUG(DCNETZ, DEBUG_NOTICE, "You selected channel %d ('Orga-Kanal') for combined control + traffic channel. Some phones will reject this.\n", kanal); } for (sender = sender_head; sender; sender = sender->next) { @@ -338,11 +340,21 @@ int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char * return -ENOMEM; } - PDEBUG(DCNETZ, DEBUG_DEBUG, "Creating 'C-Netz' instance for 'Kanal' = %s (sample rate %d).\n", kanal, samplerate); + PDEBUG(DCNETZ, DEBUG_DEBUG, "Creating 'C-Netz' instance for 'Kanal' = %d (sample rate %d).\n", kanal, samplerate); + + cnetz->kanal = kanal; + if ((chan_type == CHAN_TYPE_OGK || chan_type == CHAN_TYPE_OGK_SPK) && kanal != CNETZ_STD_OGK_KANAL) { + if (ogk_list_count == 16) { + PDEBUG(DCNETZ, DEBUG_ERROR, "No more than 16 non-standard OGK are allowed!\n"); + rc = -EINVAL; + goto error; + } + ogk_list[ogk_list_count++] = cnetz; + } /* init general part of transceiver */ /* do not enable emphasis, since it is done by cnetz code, not by common sender code */ - rc = sender_create(&cnetz->sender, kanal, cnetz_kanal2freq(atoi(kanal), 0), cnetz_kanal2freq(atoi(kanal), 1), device, use_sdr, samplerate, rx_gain, tx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, PAGING_SIGNAL_NONE); + rc = sender_create(&cnetz->sender, kanal_name, cnetz_kanal2freq(kanal, 0), cnetz_kanal2freq(kanal, 1), device, use_sdr, samplerate, rx_gain, tx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, PAGING_SIGNAL_NONE); if (rc < 0) { PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to init transceiver process!\n"); goto error; @@ -403,13 +415,13 @@ int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char * cnetz_go_idle(cnetz); #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, NAN); trans->mo_call = 1; cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_K, (cnetz->sched_ts + 2) & 31); #else /* create transaction for speech channel loopback */ 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, NAN); trans->mo_call = 1; cnetz_set_dsp_mode(cnetz, DSP_MODE_SPK_K); cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_K, (cnetz->sched_ts + 1) & 31); @@ -419,20 +431,20 @@ int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char * #if 0 /* debug flushing transactions */ transaction_t *trans1, *trans2; - trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1); + trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1, NAN); destroy_transaction(trans1); - trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1); + trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1, NAN); destroy_transaction(trans1); - trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1); - trans2 = create_transaction(cnetz, 99, 2, 2, 22002, -1, -1); + trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1, NAN); + trans2 = create_transaction(cnetz, 99, 2, 2, 22002, -1, -1, NAN); unlink_transaction(trans1); link_transaction(trans1, cnetz); cnetz_flush_other_transactions(cnetz, trans1); - trans2 = create_transaction(cnetz, 99, 2, 2, 22002, -1, -1); + trans2 = create_transaction(cnetz, 99, 2, 2, 22002, -1, -1, NAN); cnetz_flush_other_transactions(cnetz, trans2); #endif - PDEBUG(DCNETZ, DEBUG_NOTICE, "Created 'Kanal' #%s of type '%s' = %s\n", kanal, chan_type_short_name(chan_type), chan_type_long_name(chan_type)); + PDEBUG(DCNETZ, DEBUG_NOTICE, "Created 'Kanal' #%d of type '%s' = %s\n", kanal, chan_type_short_name(chan_type), chan_type_long_name(chan_type)); const char *name, *station; name = get_station_name(si.fuz_nat, si.fuz_fuvst, si.fuz_rest, &station); PDEBUG(DNMT, DEBUG_NOTICE, " -> Using cell ID: Nat=%d FuVst=%d Rest=%d Name='%s' (%s)\n", si.fuz_nat, si.fuz_fuvst, si.fuz_rest, name, station); @@ -473,9 +485,9 @@ static cnetz_t *search_free_spk(int extended) cnetz = (cnetz_t *) sender; /* ignore extended frequency, if not supported */ if (!extended) { - if ((atoi(sender->kanal) & 1) && atoi(sender->kanal) > 947) + if ((cnetz->kanal & 1) && cnetz->kanal > 947) continue; - if (!(atoi(sender->kanal) & 1) && atoi(sender->kanal) > 758) + if (!(cnetz->kanal & 1) && cnetz->kanal > 758) continue; } /* ignore busy channel */ @@ -492,7 +504,7 @@ static cnetz_t *search_free_spk(int extended) return ogk_spk; } -static cnetz_t *search_ogk(void) +static cnetz_t *search_ogk(int kanal) { sender_t *sender; cnetz_t *cnetz; @@ -502,6 +514,8 @@ static cnetz_t *search_ogk(void) /* ignore busy channel */ if (cnetz->state != CNETZ_IDLE) continue; + if (cnetz->kanal != kanal) + continue; if (cnetz->chan_type == CHAN_TYPE_OGK) return cnetz; if (cnetz->chan_type == CHAN_TYPE_OGK_SPK) @@ -514,7 +528,6 @@ static cnetz_t *search_ogk(void) /* 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) @@ -533,18 +546,17 @@ void cnetz_go_idle(cnetz_t *cnetz) /* set scheduler to OgK or turn off SpK */ if (cnetz->dsp_mode == DSP_MODE_SPK_K || cnetz->dsp_mode == DSP_MODE_SPK_V) { /* switch next frame after distributed signaling boundary (multiple of 8 slots) */ - cnetz_set_sched_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, (cnetz->sched_ts + 8) & 24); + cnetz_set_sched_dsp_mode(cnetz, (cnetz->chan_type == CHAN_TYPE_OGK || cnetz->chan_type == CHAN_TYPE_OGK_SPK) ? DSP_MODE_OGK : DSP_MODE_OFF, (cnetz->sched_ts + 8) & 24); } else { /* 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_sched_dsp_mode(cnetz, (cnetz->chan_type == CHAN_TYPE_OGK || cnetz->chan_type == CHAN_TYPE_OGK_SPK) ? DSP_MODE_OGK : DSP_MODE_OFF, (cnetz->sched_ts + 1) & 31); + cnetz_set_dsp_mode(cnetz, (cnetz->chan_type == CHAN_TYPE_OGK || cnetz->chan_type == CHAN_TYPE_OGK_SPK) ? 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); + trans = search_transaction_queue(); if (trans) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Now channel available for queued subscriber '%s'.\n", transaction2rufnummer(trans)); + PDEBUG(DCNETZ, DEBUG_NOTICE, "Now channel is 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); @@ -585,14 +597,14 @@ void call_down_clock(void) {} int call_down_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; + cnetz_t *ogk, *spk; int rc; int extended; transaction_t *trans; uint8_t futln_nat; uint8_t futln_fuvst; int futln_rest; /* use int for checking size > 65535 */ + int ogk_kanal; /* 1. split number into elements */ futln_nat = dialing[0] - '0'; @@ -605,28 +617,22 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id, } /* 2. check if the subscriber is attached */ - rc = find_db(futln_nat, futln_fuvst, futln_rest, NULL, &extended); + rc = find_db(futln_nat, futln_fuvst, futln_rest, &ogk_kanal, NULL, &extended); if (rc < 0) { PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call to not attached subscriber, rejecting!\n"); return -CAUSE_OUTOFORDER; } /* 3. check if given number is already in a call, return BUSY */ - for (sender = sender_head; sender; sender = sender->next) { - cnetz = (cnetz_t *) sender; - /* search transaction for this number */ - trans = search_transaction_number(cnetz, futln_nat, futln_fuvst, futln_rest); - if (trans) - break; - } - if (sender) { + trans = search_transaction_number_global(futln_nat, futln_fuvst, futln_rest); + if (trans) { PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call to busy number, rejecting!\n"); return -CAUSE_BUSY; } /* 4. check if we have no OgK, return NOCHANNEL */ - cnetz = search_ogk(); - if (!cnetz) { + ogk = search_ogk(ogk_kanal); + if (!ogk) { PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call, but OgK is currently busy, rejecting!\n"); return -CAUSE_NOCHANNEL; } @@ -634,17 +640,17 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id, /* 5. check if all senders are busy, return NOCHANNEL */ spk = search_free_spk(extended); if (!spk) { - if (!cnetz->warteschlange) { + if (!ogk->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); + PDEBUG(DCNETZ, DEBUG_INFO, "Call to mobile station, paging station id '%s'\n", dialing); /* 6. trying to page mobile station */ - trans = create_transaction(cnetz, (spk) ? TRANS_VAK : TRANS_WSK, futln_nat, futln_fuvst, futln_rest, -1, -1); + trans = create_transaction(ogk, (spk) ? TRANS_VAK : TRANS_WSK, futln_nat, futln_fuvst, futln_rest, -1, -1, NAN); if (!trans) { PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); return -CAUSE_TEMPFAIL; @@ -750,17 +756,17 @@ void call_down_release(int callref, int cause) } } -int cnetz_meldeaufruf(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest) +int cnetz_meldeaufruf(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int ogk_kanal) { cnetz_t *cnetz; transaction_t *trans; - cnetz = search_ogk(); + cnetz = search_ogk(ogk_kanal); if (!cnetz) { PDEBUG(DCNETZ, DEBUG_NOTICE, "'Meldeaufruf', but OgK is currently busy!\n"); return -CAUSE_NOCHANNEL; } - trans = create_transaction(cnetz, TRANS_MA, futln_nat, futln_fuvst, futln_rest, -1, -1); + trans = create_transaction(cnetz, TRANS_MA, futln_nat, futln_fuvst, futln_rest, -1, -1, NAN); if (!trans) { PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); return -CAUSE_TEMPFAIL; @@ -992,7 +998,7 @@ const telegramm_t *cnetz_transmit_telegramm_rufblock(cnetz_t *cnetz) telegramm.grenzwert_fuer_umschalten = si.grenz_umschalten; telegramm.grenze_fuer_ausloesen = si.grenz_ausloesen; - trans = search_transaction(cnetz, TRANS_EM | TRANS_UM | TRANS_WBN | TRANS_WBP | TRANS_VAG | TRANS_VAK | TRANS_ATQ | TRANS_VA | TRANS_WSK); + trans = search_transaction(cnetz, TRANS_EM | TRANS_UM | TRANS_WBN | TRANS_WBP | TRANS_VAG | TRANS_VAK | TRANS_ATQ | TRANS_ATQ_IDLE | TRANS_VA | TRANS_WSK); if (trans) { telegramm.futln_nationalitaet = trans->futln_nat; telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst; @@ -1057,14 +1063,14 @@ vak: break; } if (spk == cnetz) { - PDEBUG(DCNETZ, DEBUG_INFO, "Staying on combined calling + traffic channel %s\n", spk->sender.kanal); + PDEBUG(DCNETZ, DEBUG_INFO, "Staying on combined control + traffic channel %s\n", spk->sender.kanal); } else { PDEBUG(DCNETZ, DEBUG_INFO, "Assigning phone to traffic channel %s\n", spk->sender.kanal); /* sync RX time to current OgK time */ fsk_copy_sync(&spk->fsk_demod, &cnetz->fsk_demod); } /* set channel */ - telegramm.frequenz_nr = atoi(spk->sender.kanal); + telegramm.frequenz_nr = spk->kanal; /* change state to busy */ cnetz_new_state(spk, CNETZ_BUSY); /* schedule switching two slots ahead */ @@ -1076,6 +1082,7 @@ vak: cnetz_flush_other_transactions(spk, trans); break; case TRANS_ATQ: + case TRANS_ATQ_IDLE: 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); @@ -1117,7 +1124,13 @@ const telegramm_t *cnetz_transmit_telegramm_meldeblock(cnetz_t *cnetz) telegramm.ogk_verkehrsanteil = 0; /* must be 0 or phone might not respond to messages in different slot */ telegramm.teilnehmergruppensperre = si.teilnehmergruppensperre; telegramm.anzahl_gesperrter_teilnehmergruppen = si.anzahl_gesperrter_teilnehmergruppen; - telegramm.ogk_vorschlag = CNETZ_OGK_KANAL; + if (ogk_list_count) { + /* if we have alternative OGKs, we cycle through the list and indicate their channels */ + telegramm.ogk_vorschlag = ogk_list[ogk_list_index]->kanal; + if (++ogk_list_index == ogk_list_count) + ogk_list_index = 0; + } else + telegramm.ogk_vorschlag = CNETZ_STD_OGK_KANAL; telegramm.fuz_rest_nr = si.fuz_rest; trans = search_transaction(cnetz, TRANS_VWG | TRANS_MA); @@ -1171,11 +1184,12 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo PDEBUG(DCNETZ, DEBUG_NOTICE, "Ignoring Attachment from subscriber '%s', because we are busy becoming SpK.\n", rufnummer); break; } - trans = create_transaction(cnetz, TRANS_EM, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, telegramm->chipkarten_futelg_bit, telegramm->erweitertes_frequenzbandbit); + trans = create_transaction(cnetz, TRANS_EM, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, telegramm->chipkarten_futelg_bit, telegramm->erweitertes_frequenzbandbit, cnetz->rf_level_db); if (!trans) { PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); break; } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ valid_frame = 1; break; case OPCODE_UM_R: @@ -1192,11 +1206,12 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo PDEBUG(DCNETZ, DEBUG_NOTICE, "Ignoring Roaming from subscriber '%s', because we are busy becoming SpK.\n", rufnummer); break; } - trans = create_transaction(cnetz, TRANS_UM, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, telegramm->chipkarten_futelg_bit, telegramm->erweitertes_frequenzbandbit); + trans = create_transaction(cnetz, TRANS_UM, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, telegramm->chipkarten_futelg_bit, telegramm->erweitertes_frequenzbandbit, cnetz->rf_level_db); if (!trans) { PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); break; } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ valid_frame = 1; break; case OPCODE_UWG_R: @@ -1208,29 +1223,33 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo break; case OPCODE_VWG_R: case OPCODE_SRG_R: + case OPCODE_NUG_R: if (!match_fuz(telegramm)) break; rufnummer = telegramm2rufnummer(telegramm); if (opcode == OPCODE_VWG_R) PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received outgoing Call 'Verbindungswunsch gehend' message from Subscriber '%s'\n", rufnummer); - else + else if (opcode == OPCODE_SRG_R) PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received outgoing emergency Call 'Sonderruf gehend' message from Subscriber '%s'\n", rufnummer); + else + PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received outgoing Call 'Verbindungswunsch gehend bei Nachbarschaftsunterstuetzung' message from Subscriber '%s'\n", rufnummer); if (cnetz->state != CNETZ_IDLE) { PDEBUG(DCNETZ, DEBUG_NOTICE, "Ignoring Call from subscriber '%s', because we are busy becoming SpK.\n", rufnummer); break; } - trans = create_transaction(cnetz, TRANS_VWG, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, -1, telegramm->erweitertes_frequenzbandbit); + trans = create_transaction(cnetz, TRANS_VWG, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, -1, telegramm->erweitertes_frequenzbandbit, cnetz->rf_level_db); if (!trans) { PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); break; } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ trans->try = 1; valid_frame = 1; break; case OPCODE_WUE_M: 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"); + PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received dialing digits 'Wahluebertragung' message without transaction (on this OgK), ignoring!\n"); break; } rufnummer = transaction2rufnummer(trans); @@ -1246,17 +1265,30 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo 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); + trans = search_transaction_number_global(telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr); if (!trans) { + PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "There is no transaction, so we assume that the phone did not receive previous release.\n"); /* 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, -1, -1); + trans = create_transaction(cnetz, TRANS_ATQ_IDLE, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, -1, -1, cnetz->rf_level_db); if (!trans) { PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); break; } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ } else { - timer_stop(&trans->timer); - trans_new_state(trans, TRANS_ATQ); + if (cnetz == trans->cnetz) { + timer_stop(&trans->timer); + trans_new_state(trans, TRANS_ATQ); + } else + if (trans->state == TRANS_ATQ_IDLE) { + trans = create_transaction(cnetz, TRANS_ATQ_IDLE, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, -1, -1, cnetz->rf_level_db); + if (!trans) { + PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); + break; + } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ + } else + PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received release 'Ausloesen des FuTelG im OgK-Betrieb bei WS' message without transaction (on this OgK), ignoring!\n"); } valid_frame = 1; break; @@ -1265,7 +1297,7 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo 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"); + PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received acknowledge 'Meldung Funktelefonteilnehmer' message without transaction (on this OgK), ignoring!\n"); break; } rufnummer = transaction2rufnummer(trans); @@ -1295,7 +1327,9 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz) { static telegramm_t telegramm; transaction_t *trans = cnetz->trans_list; + int ogk_kanal; cnetz_t *ogk; + int rc; if (!trans) return NULL; @@ -1311,7 +1345,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz) telegramm.futln_nationalitaet = trans->futln_nat; telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst; telegramm.futln_rest_nr = trans->futln_rest; - telegramm.frequenz_nr = atoi(cnetz->sender.kanal); + telegramm.frequenz_nr = cnetz->kanal; telegramm.bedingte_genauigkeit_der_fufst = si.genauigkeit; telegramm.zufallszahl = cnetz->challenge; @@ -1426,9 +1460,15 @@ no_auth: /* idle channel */ cnetz_go_idle(cnetz); /* alloc ogk again */ - ogk = search_ogk(); + rc = find_db(trans->futln_nat, trans->futln_fuvst, trans->futln_rest, &ogk_kanal, NULL, NULL); + if (rc < 0) { + PDEBUG(DCNETZ, DEBUG_NOTICE, "Cannot find subscriber in database anymore, releasing!\n"); + goto no_ogk; + } + ogk = search_ogk(ogk_kanal); if (!ogk) { PDEBUG(DCNETZ, DEBUG_NOTICE, "Cannot retry, because currently no OgK available (busy)\n"); +no_ogk: cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); if (trans->callref) call_up_release(trans->callref, CAUSE_NOCHANNEL); @@ -1634,7 +1674,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_v(cnetz_t *cnetz) telegramm.futln_nationalitaet = trans->futln_nat; telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst; telegramm.futln_rest_nr = trans->futln_rest; - telegramm.frequenz_nr = atoi(cnetz->sender.kanal); + telegramm.frequenz_nr = cnetz->kanal; telegramm.entfernung = si.entfernung; telegramm.bedingte_genauigkeit_der_fufst = si.genauigkeit; telegramm.gueltigkeit_des_gebuehrenstandes = 0; diff --git a/src/cnetz/cnetz.h b/src/cnetz/cnetz.h index 3d074b8..db00eb9 100644 --- a/src/cnetz/cnetz.h +++ b/src/cnetz/cnetz.h @@ -6,7 +6,7 @@ typedef struct cnetz cnetz_t; #include "fsk_demod.h" #include "transaction.h" -#define CNETZ_OGK_KANAL 131 +#define CNETZ_STD_OGK_KANAL 131 /* dsp modes of transmission */ enum dsp_mode { @@ -66,6 +66,7 @@ struct clock_speed { /* instance of cnetz sender */ struct cnetz { sender_t sender; + int kanal; /* channel number */ enum cnetz_chan_type chan_type; /* channel type */ scrambler_t scrambler_tx; /* mirror what we transmit to MS */ scrambler_t scrambler_rx; /* mirror what we receive from MS */ @@ -99,6 +100,7 @@ struct cnetz { /* dsp states */ enum dsp_mode dsp_mode; /* current mode: audio, "Telegramm", .... */ + double rf_level_db; /* current RF level or nan, if not applicable */ iir_filter_t lp; /* low pass filter to eliminate noise above 5280 Hz */ fsk_fm_demod_t fsk_demod; /* demod process */ double fsk_deviation; /* deviation of FSK signal on sound card */ @@ -144,7 +146,7 @@ int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char * void cnetz_destroy(sender_t *sender); void cnetz_go_idle(cnetz_t *cnetz); void cnetz_sync_frame(cnetz_t *cnetz, double sync, int ts); -int cnetz_meldeaufruf(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest); +int cnetz_meldeaufruf(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int ogk_kanal); const struct telegramm *cnetz_transmit_telegramm_rufblock(cnetz_t *cnetz); const struct telegramm *cnetz_transmit_telegramm_meldeblock(cnetz_t *cnetz); void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, struct telegramm *telegramm, int block); diff --git a/src/cnetz/database.c b/src/cnetz/database.c index 86cc8ff..2645191 100644 --- a/src/cnetz/database.c +++ b/src/cnetz/database.c @@ -37,6 +37,7 @@ typedef struct cnetz_database { struct cnetz_database *next; + int ogk_kanal; /* available on which channel */ uint8_t futln_nat; /* who ... */ uint8_t futln_fuvst; uint16_t futln_rest; @@ -81,7 +82,7 @@ static void db_timeout(struct timer *timer) PDEBUG(DDB, DEBUG_INFO, "Check, if subscriber '%d,%d,%05d' is still available.\n", db->futln_nat, db->futln_fuvst, db->futln_rest); - rc = cnetz_meldeaufruf(db->futln_nat, db->futln_fuvst, db->futln_rest); + rc = cnetz_meldeaufruf(db->futln_nat, db->futln_fuvst, db->futln_rest, db->ogk_kanal); if (rc < 0) { /* OgK is used for speech, but this never happens in a real * network. We just assume that the phone has responded and @@ -93,7 +94,7 @@ static void db_timeout(struct timer *timer) } /* create/update db entry */ -int update_db(cnetz_t __attribute__((unused)) *cnetz, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *futelg_bit, int *extended, int busy, int failed) +int update_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int ogk_kanal, int *futelg_bit, int *extended, int busy, int failed) { cnetz_db_t *db, **dbp; @@ -128,6 +129,9 @@ int update_db(cnetz_t __attribute__((unused)) *cnetz, uint8_t futln_nat, uint8_t PDEBUG(DDB, DEBUG_INFO, "Adding subscriber '%d,%d,%05d' to database.\n", db->futln_nat, db->futln_fuvst, db->futln_rest); } + if (ogk_kanal) + db->ogk_kanal = ogk_kanal; + if (futelg_bit && *futelg_bit >= 0) db->futelg_bit = *futelg_bit; @@ -136,17 +140,17 @@ int update_db(cnetz_t __attribute__((unused)) *cnetz, uint8_t futln_nat, uint8_t db->busy = busy; if (busy) { - PDEBUG(DDB, DEBUG_INFO, "Subscriber '%d,%d,%05d' busy now.\n", db->futln_nat, db->futln_fuvst, db->futln_rest); + PDEBUG(DDB, DEBUG_INFO, "Subscriber '%d,%d,%05d' on OGK channel #%d is busy now.\n", db->futln_nat, db->futln_fuvst, db->futln_rest, db->ogk_kanal); timer_stop(&db->timer); } else if (!failed) { - PDEBUG(DDB, DEBUG_INFO, "Subscriber '%d,%d,%05d' idle now.\n", db->futln_nat, db->futln_fuvst, db->futln_rest); + PDEBUG(DDB, DEBUG_INFO, "Subscriber '%d,%d,%05d' on OGK channel #%d is idle now.\n", db->futln_nat, db->futln_fuvst, db->futln_rest, db->ogk_kanal); timer_start(&db->timer, MELDE_INTERVAL); /* when to check avaiability (again) */ db->retry = 0; db->eingebucht = 1; db->last_seen = get_time(); } else { db->retry++; - PDEBUG(DDB, DEBUG_NOTICE, "Paging subscriber '%d,%d,%05d' failed (try %d of %d).\n", db->futln_nat, db->futln_fuvst, db->futln_rest, db->retry, MELDE_MAXIMAL); + PDEBUG(DDB, DEBUG_NOTICE, "Paging subscriber '%d,%d,%05d' on OGK channel #%d failed (try %d of %d).\n", db->futln_nat, db->futln_fuvst, db->futln_rest, db->ogk_kanal, db->retry, MELDE_MAXIMAL); if (db->retry == MELDE_MAXIMAL) { PDEBUG(DDB, DEBUG_INFO, "Marking subscriber as gone.\n"); db->eingebucht = 0; @@ -162,7 +166,7 @@ int update_db(cnetz_t __attribute__((unused)) *cnetz, uint8_t futln_nat, uint8_t return 0; } -int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *futelg_bit, int *extended) +int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *ogk_kanal, int *futelg_bit, int *extended) { cnetz_db_t *db = cnetz_db_head; @@ -171,6 +175,8 @@ int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *fu && db->futln_nat == futln_nat && db->futln_fuvst == futln_fuvst && db->futln_rest == futln_rest) { + if (ogk_kanal) + *ogk_kanal = db->ogk_kanal; if (futelg_bit) *futelg_bit = db->futelg_bit; if (extended) @@ -193,6 +199,7 @@ void dump_db(void) cnetz_db_t *db = cnetz_db_head; double now = get_time(); int last; + char attached[16]; PDEBUG(DDB, DEBUG_NOTICE, "Dump of subscriber database:\n"); if (!db) { @@ -204,7 +211,8 @@ void dump_db(void) PDEBUG(DDB, DEBUG_NOTICE, "-------------------------------------------------------------------------------\n"); while (db) { last = (db->busy) ? 0 : (uint32_t)(now - db->last_seen); - PDEBUG(DDB, DEBUG_NOTICE, "%d,%d,%05d\t%s\t\t%s\t\t%02d:%02d:%02d \t%d/%d\n", db->futln_nat, db->futln_fuvst, db->futln_rest, (db->eingebucht) ? "YES" : "-no-", (db->busy) ? "YES" : "-no-", last / 3600, (last / 60) % 60, last % 60, db->retry, MELDE_MAXIMAL); + sprintf(attached, "YES (OGK %d)", db->ogk_kanal); + PDEBUG(DDB, DEBUG_NOTICE, "%d,%d,%05d\t%s\t%s\t\t%02d:%02d:%02d \t%d/%d\n", db->futln_nat, db->futln_fuvst, db->futln_rest, (db->eingebucht) ? attached : "-no-\t", (db->busy) ? "YES" : "-no-", last / 3600, (last / 60) % 60, last % 60, db->retry, MELDE_MAXIMAL); db = db->next; } } diff --git a/src/cnetz/database.h b/src/cnetz/database.h index a1339a0..7cd1c16 100644 --- a/src/cnetz/database.h +++ b/src/cnetz/database.h @@ -1,6 +1,6 @@ -int update_db(cnetz_t *cnetz, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *futelg_bit, int *extended, int busy, int failed); -int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *futelg_bit, int *extended); +int update_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int ogk_kanal, int *futelg_bit, int *extended, int busy, int failed); +int find_db(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int *ogk_kanal, int *futelg_bit, int *extended); void flush_db(void); void dump_db(void); diff --git a/src/cnetz/dsp.c b/src/cnetz/dsp.c index eb36323..082a98f 100644 --- a/src/cnetz/dsp.c +++ b/src/cnetz/dsp.c @@ -568,10 +568,12 @@ static int fsk_distributed_encode(cnetz_t *cnetz, const char *bits) /* decode samples and hut for bit changes * use deviation to find greatest slope of the signal (bit change) */ -void sender_receive(sender_t *sender, sample_t *samples, int length, double __attribute__((unused)) rf_level_db) +void sender_receive(sender_t *sender, sample_t *samples, int length, double rf_level_db) { cnetz_t *cnetz = (cnetz_t *) sender; + cnetz->rf_level_db = rf_level_db; + /* measure rx sample speed */ calc_clock_speed(cnetz, length, 0, 0); diff --git a/src/cnetz/main.c b/src/cnetz/main.c index 1c4dbba..dfe161d 100644 --- a/src/cnetz/main.c +++ b/src/cnetz/main.c @@ -82,6 +82,10 @@ void print_help(const char *arg0) /* - - */ printf(" -T --channel-type | list\n"); printf(" Give channel type, use 'list' to get a list. (default = '%s')\n", chan_type_short_name(chan_type[0])); + printf(" You must define at least one OgK at channel 131. This channel may be a\n"); + printf(" a combined OgK+SpK channel, but this works with older phones only.\n"); + printf(" You must define additionally one or more SpK, in order to make calls.\n"); + printf(" You may define alternative OgK, the phones will attach to it then.\n"); printf(" -M --measure-speed\n"); printf(" Measures clock speed. THIS IS REQUIRED! See documentation!\n"); printf(" -C --clock-speed ,\n"); @@ -524,7 +528,7 @@ int main(int argc, char *argv[]) } if (!num_kanal) { - printf("No channel (\"Kanal\") is specified, I suggest channel %d.\n\n", CNETZ_OGK_KANAL); + printf("No channel (\"Kanal\") is specified, I suggest channel %d.\n\n", CNETZ_STD_OGK_KANAL); mandatory = 1; } if (use_sdr) { @@ -585,7 +589,7 @@ int main(int argc, char *argv[]) init_coding(); cnetz_init(); - /* check for mandatory OgK */ + /* check for mandatory standard OgK */ for (i = 0; i < num_kanal; i++) { if (chan_type[i] == CHAN_TYPE_OGK || chan_type[i] == CHAN_TYPE_OGK_SPK) break; diff --git a/src/cnetz/telegramm.c b/src/cnetz/telegramm.c index 51b78d6..e9959a7 100644 --- a/src/cnetz/telegramm.c +++ b/src/cnetz/telegramm.c @@ -1499,10 +1499,9 @@ void cnetz_decode_telegramm(cnetz_t *cnetz, const char *bits, double level, doub return; } + PDEBUG_CHAN(DDSP, DEBUG_INFO, "RF level: %.1f dB RX Level: %.0f%% Standard deviation: %.0f%% Sync Time: %.2f (TS %.2f) %s\n", cnetz->rf_level_db, fabs(level) / cnetz->fsk_deviation * 100.0, stddev / fabs(level) * 100.0, sync_time, sync_time / 396.0, (level < 0) ? "NEGATIVE (phone's mode)" : "POSITIVE (base station's mode)"); if (bit_errors) - PDEBUG_CHAN(DDSP, DEBUG_INFO, "RX Level: %.0f%% Standard deviation: %.0f%% Sync Time: %.2f (TS %.2f) Bit errors: %d %s\n", fabs(level) / cnetz->fsk_deviation * 100.0, stddev / fabs(level) * 100.0, sync_time, sync_time / 396.0, bit_errors, (level < 0) ? "NEGATIVE (phone's mode)" : "POSITIVE (base station's mode)"); - else - PDEBUG_CHAN(DDSP, DEBUG_INFO, "RX Level: %.0f%% Standard deviation: %.0f%% Sync Time: %.2f (TS %.2f) %s\n", fabs(level) / cnetz->fsk_deviation * 100.0, stddev / fabs(level) * 100.0, sync_time, sync_time / 396.0, (level < 0) ? "NEGATIVE (phone's mode)" : "POSITIVE (base station's mode)"); + PDEBUG_CHAN(DDSP, DEBUG_INFO, " -> Frame has %d bit errors.\n", bit_errors); disassemble_telegramm(&telegramm, bits, si.authentifikationsbit); opcode = telegramm.opcode; diff --git a/src/cnetz/transaction.c b/src/cnetz/transaction.c index cf5dbef..b0a4989 100644 --- a/src/cnetz/transaction.c +++ b/src/cnetz/transaction.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "../libsample/sample.h" #include "../libdebug/debug.h" #include "../libmobile/call.h" @@ -28,6 +29,8 @@ #include "telegramm.h" #include "database.h" +static int new_cueue_position = 0; + const char *transaction2rufnummer(transaction_t *trans) { static char rufnummer[32]; /* make GCC happy (overflow check) */ @@ -38,24 +41,34 @@ const char *transaction2rufnummer(transaction_t *trans) } /* create transaction */ -transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int futelg_bit, 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 futelg_bit, int extended, double rf_level_db) { - sender_t *sender; - transaction_t *trans = NULL; - cnetz_t *search_cnetz; + transaction_t *trans; - /* search transaction for this subscriber */ - for (sender = sender_head; sender; sender = sender->next) { - search_cnetz = (cnetz_t *) sender; - /* search transaction for this callref */ - trans = search_transaction_number(search_cnetz, futln_nat, futln_fuvst, futln_rest); - if (trans) - break; - } + trans = search_transaction_number_global(futln_nat, futln_fuvst, futln_rest); if (trans) { const char *rufnummer = transaction2rufnummer(trans); int old_callref = trans->callref; cnetz_t *old_cnetz = trans->cnetz; + /* both states must be the same and one of the give selection */ + if ((trans->state & state & (TRANS_EM | TRANS_UM | TRANS_VWG | TRANS_ATQ_IDLE))) { + if (!isnan(trans->rf_level_db) && !isnan(rf_level_db) && trans->cnetz->kanal != cnetz->kanal) { + if (rf_level_db > trans->rf_level_db) { + PDEBUG(DTRANS, DEBUG_NOTICE, "Found already pending transaction for subscriber '%s' on channel #%d, but this message on channel #%d is stronger, so we move to that channel!\n", rufnummer, trans->cnetz->kanal, cnetz->kanal); + trans->rf_level_db = rf_level_db; + unlink_transaction(trans); + link_transaction(trans, cnetz); + update_db(trans->futln_nat, trans->futln_fuvst, trans->futln_rest, cnetz->kanal, NULL, NULL, 1, 0); + return trans; + } + if (rf_level_db < trans->rf_level_db) { + PDEBUG(DTRANS, DEBUG_NOTICE, "Found already pending transaction for subscriber '%s' on channel #%d, but this message on channel #%d is weaker, so we ignore that channel!\n", rufnummer, trans->cnetz->kanal, cnetz->kanal); + return trans; + } + } + PDEBUG(DTRANS, DEBUG_NOTICE, "Found already pending transaction for subscriber '%s' on channel #%d, but this message on channel #%d is also received. Try to avoid multiple OgK channels!\n", rufnummer, trans->cnetz->kanal, cnetz->kanal); + return trans; + } PDEBUG(DTRANS, DEBUG_NOTICE, "Found already pending transaction for subscriber '%s', deleting!\n", rufnummer); destroy_transaction(trans); if (old_cnetz) /* should be... */ @@ -88,10 +101,12 @@ transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_ link_transaction(trans, cnetz); /* update database: now busy */ - update_db(cnetz, futln_nat, futln_fuvst, futln_rest, &futelg_bit, &extended, 1, 0); + update_db(futln_nat, futln_fuvst, futln_rest, cnetz->kanal, &futelg_bit, &extended, 1, 0); trans->futelg_bit = futelg_bit; trans->extended = extended; + trans->rf_level_db = rf_level_db; + return trans; } @@ -99,7 +114,7 @@ transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_ void destroy_transaction(transaction_t *trans) { /* update database: now idle */ - update_db(trans->cnetz, trans->futln_nat, trans->futln_fuvst, trans->futln_rest, NULL, NULL, 0, trans->page_failed); + update_db(trans->futln_nat, trans->futln_fuvst, trans->futln_rest, 0, NULL, NULL, 0, trans->page_failed); unlink_transaction(trans); @@ -182,6 +197,23 @@ transaction_t *search_transaction_number(cnetz_t *cnetz, uint8_t futln_nat, uint return NULL; } +transaction_t *search_transaction_number_global(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest) +{ + sender_t *sender; + cnetz_t *cnetz; + transaction_t *trans = NULL; + + /* search transaction for this subscriber */ + for (sender = sender_head; sender; sender = sender->next) { + cnetz = (cnetz_t *) sender; + /* search transaction for this callref */ + trans = search_transaction_number(cnetz, futln_nat, futln_fuvst, futln_rest); + if (trans) + break; + } + + return trans; +} transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref) { transaction_t *trans = cnetz->trans_list; @@ -201,6 +233,42 @@ transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref) return NULL; } +/* get oldest transaction in queue: + * + * oldest means that the queue number is the smallest. + * all candidates (transactions) must be in queue state. + */ +transaction_t *search_transaction_queue(void) +{ + sender_t *sender; + transaction_t *trans, *found = NULL; + cnetz_t *cnetz; + int queue_max = 0; + + for (sender = sender_head; sender; sender = sender->next) { + cnetz = (cnetz_t *) sender; + trans = cnetz->trans_list; + while (trans) { + if ((trans->state & (TRANS_MO_QUEUE | TRANS_MT_QUEUE))) { + /* select if first or lower number */ + if (!found || trans->queue_position < queue_max) { + queue_max = trans->queue_position; + found = trans; + } + } + trans = trans->next; + } + } + + if (found) { + const char *rufnummer = transaction2rufnummer(found); + PDEBUG(DTRANS, DEBUG_DEBUG, "Found oldest transaction in queue for subscriber '%s'\n", rufnummer); + return found; + } + + return NULL; +} + static const char *trans_state_name(uint64_t state) { switch (state) { @@ -252,6 +320,8 @@ static const char *trans_state_name(uint64_t state) return "AT"; case TRANS_ATQ: return "ATQ"; + case TRANS_ATQ_IDLE: + return "ATQ_IDLE"; case TRANS_MO_QUEUE: return "MO_QUEUE"; case TRANS_MT_QUEUE: @@ -301,6 +371,7 @@ const char *trans_short_state_name(uint64_t state) case TRANS_AF: case TRANS_AT: case TRANS_ATQ: + case TRANS_ATQ_IDLE: return "RELEASE"; case TRANS_MO_QUEUE: case TRANS_MO_DELAY: @@ -317,6 +388,9 @@ void trans_new_state(transaction_t *trans, uint64_t 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; + /* in case of a queue, set new positon */ + if (!trans->queue_position && (state == TRANS_MO_QUEUE || state == TRANS_MT_QUEUE)) + trans->queue_position = ++new_cueue_position; cnetz_display_status(); } diff --git a/src/cnetz/transaction.h b/src/cnetz/transaction.h index ad77037..0c1e86c 100644 --- a/src/cnetz/transaction.h +++ b/src/cnetz/transaction.h @@ -29,11 +29,12 @@ #define TRANS_AF (1 << 20) /* release connection by base station (SpK) */ #define TRANS_AT (1 << 21) /* release connection by mobile station */ #define TRANS_ATQ (1 << 22) /* acknowledge release of MO call in queue */ +#define TRANS_ATQ_IDLE (1 << 23) /* repeat, if call has been released already (mobile sends again) */ /* queue */ -#define TRANS_MO_QUEUE (1 << 23) /* MO queue */ -#define TRANS_MT_QUEUE (1 << 24) /* MT queue */ -#define TRANS_MO_DELAY (1 << 25) /* delay to be sure the channel is free again */ -#define TRANS_MT_DELAY (1 << 26) +#define TRANS_MO_QUEUE (1 << 24) /* MO queue */ +#define TRANS_MT_QUEUE (1 << 25) /* MT queue */ +#define TRANS_MO_DELAY (1 << 26) /* delay to be sure the channel is free again */ +#define TRANS_MT_DELAY (1 << 27) typedef struct transaction { struct transaction *next; /* pointer to next node in list */ @@ -54,16 +55,20 @@ typedef struct transaction { 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) */ + int queue_position; /* to find next transaction in queue */ + double rf_level_db; /* level of first contact, so we can detect correct channel at multiple receptions */ } transaction_t; const char *transaction2rufnummer(transaction_t *trans); -transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int futelg_bit, 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 futelg_bit, int extended, double rf_level_db); 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, 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_number_global(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest); transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref); +transaction_t *search_transaction_queue(void); 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);