2016-02-16 17:56:55 +00:00
/* C-Netz protocol handling
*
* ( C ) 2016 by Andreas Eversberg < jolly @ eversberg . eu >
* All Rights Reserved
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2016-08-01 17:17:13 +00:00
/* Notes on channel state an callref:
*
* If channel state is busy , it is used as SpK , also it has callref .
*
* Each transaction has callref , but callref is only assigned to channel
* in SpK mode , so voice frames are routed there .
*
*/
2016-08-13 06:12:48 +00:00
/* Notes on transaction state:
*
* The state is used to define what is scheduled next , what message is awaited ,
* what is done when timeout . The event ( scheduler , message , timeout ) is
* processed then and the state may change .
*/
/* Call control process:
*
* If an MT ( mobile terminating ) call is made , a transaction with callref is
* created . The transaction is linked to OgK . When the scheduler schedules
* VAK ( R ) , the SpK is allocated and the transaction is linked to it .
*
2017-08-26 15:48:13 +00:00
* 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 .
*
2016-08-13 06:12:48 +00:00
* 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 ,
* the process is repeated . After N times WBN ( R ) is scheduled and transaction
* is destroyed . If WUE ( M ) is received , the scheduler schedules WBP ( R ) and
* then schedules VAG ( R ) , the SpK is allocated and the transaction is linked to
* it .
*
2017-08-26 15:48:13 +00:00
* 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 .
*
2016-08-13 06:12:48 +00:00
* 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
* BQ ( K ) was sent at least 8 times and if timer is stopped , the scheduler
* schedules VHQ ( K ) . If no BEL ( K ) was received , AFK ( K ) is scheduled N_AFKT
* times , then the process on OgK ( WBP + VAG or VAK ) is repeated N times .
*
* Similar to BQ / BEL the DS / DSQ handing is performed . For MT calls , the BQ / BEL
* is followed by RTA / RTAQ handling . If the phone answers , the AT ( K ) is
* received and DS / DSQ handling is performed .
*
* After DS / DSQ handling , the SpK changes to distributed signalling mode .
* VHQ1 / VHQ2 ( V ) is transmitted and VH ( V ) is received . If VH ( V ) is not received
* F_VHQ times , the connection is terminated by sending AF ( K ) N_AFKT times .
* Transaction is released .
*
* If AT ( K ) or AT ( V ) is received , AF ( K ) or AF ( V ) is sent once and transaction
* is released .
*
* If call is released by upper layer , AF ( K ) is sent N_AFKT times or AF ( V ) is
* sent N_AFV times . The transaction is released .
*
* More details about the process can be read from the source code .
*
* Special timings and correct scheduling is defined in source code and can be
* read also in the C - Netz specs .
*/
2016-12-01 16:59:08 +00:00
/*
* Notes on switching from OgK to SpK
*
* Upon transmission of TRANS_VAG and TRANS_VAK , the SpK channel is allocated ,
* set to busy , scheduled to switch to SpK mode after two frames . The trans -
* action is relinked from OgK to SpK .
*
* In case of a combined OgK + SpK , the channel stays the same , but will change .
*
2019-07-15 19:14:52 +00:00
* See below for detailed processing .
2016-12-01 16:59:08 +00:00
*/
/*
* Notes on database ( subscriber )
*
* If a subscriber registers ( transaction is created ) , an instance of the
* subscriber database is created . A timer is running for each instance , so
* the subscriber is paged to check availability of the phone . If the paging
* fails , a retry counter is decreased until the subscriber is removed from
* database .
*
* See database . c for more information .
*/
2016-08-13 06:12:48 +00:00
/*
* Notes on the combined channel hack :
*
* For combined SpK + OgK hack , the channel is used as SpK as last choise . This
* allows to use only one transceiver for making C - Netz to work . Also it allows
* to use all transceivers for simultanious phone calls . Some phones may not
* work with that .
*/
2016-11-30 17:09:38 +00:00
/*
* Notes on sync :
*
* The encoder generates a precise clocked signal using correction value given
* by command line . For multichannel , the second sound card ' s channel ( slave ) is
* synced to the first one ( master ) , if calculation of signal phase might drift
2020-06-01 19:12:09 +00:00
* due to rounding errors .
2016-11-30 17:09:38 +00:00
*
* The decoder is synced to the phone , whenever it receives a valid frame .
*
* See dsp . c and fsk_fm_demod . c for code about syncing .
*/
2016-07-31 13:09:46 +00:00
# define CHAN cnetz->sender.kanal
2016-02-16 17:56:55 +00:00
# include <stdio.h>
# include <stdint.h>
# include <stdlib.h>
# include <string.h>
# include <errno.h>
# include <math.h>
2017-08-26 15:48:13 +00:00
# include <inttypes.h>
2017-11-18 07:06:06 +00:00
# include "../libsample/sample.h"
2017-11-18 07:58:57 +00:00
# include "../libdebug/debug.h"
2017-11-18 07:33:07 +00:00
# include "../libmobile/call.h"
2017-11-17 08:01:44 +00:00
# include "../libmncc/cause.h"
2016-02-16 17:56:55 +00:00
# include "cnetz.h"
2016-05-08 13:34:14 +00:00
# include "database.h"
2016-02-16 17:56:55 +00:00
# include "sysinfo.h"
# include "telegramm.h"
# include "dsp.h"
2019-11-24 17:26:38 +00:00
# include "stations.h"
2016-02-16 17:56:55 +00:00
2017-05-17 10:21:19 +00:00
/* uncomment this to do echo debugging (-l) on Speech Channel */
2016-02-16 17:56:55 +00:00
//#define DEBUG_SPK
2017-01-28 07:02:11 +00:00
# define CUT_OFF_EMPHASIS_CNETZ 796.0 /* 200 uS time constant */
2016-10-23 06:46:05 +00:00
2016-02-16 17:56:55 +00:00
/* Call reference for calls from mobile station to network
This offset of 0x400000000 is required for MNCC interface . */
static int new_callref = 0x40000000 ;
/* 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 )
{
double freq = 465.750 ;
2017-10-12 17:43:15 +00:00
if ( unterband = = 2 )
return - 10.000 * 1e6 ;
2016-02-16 17:56:55 +00:00
if ( ( kanal & 1 ) )
freq - = ( double ) ( kanal + 1 ) / 2.0 * 0.010 ;
else
freq - = ( double ) kanal / 2.0 * 0.0125 ;
if ( unterband )
2017-10-12 17:43:15 +00:00
freq - = 10.000 ;
2016-02-16 17:56:55 +00:00
2017-01-04 13:14:02 +00:00
return freq * 1e6 ;
2016-02-16 17:56:55 +00:00
}
2020-01-02 08:45:33 +00:00
/* convert power level to P-bits by selecting next higher level */
static uint8_t cnetz_power2bits ( int power )
{
switch ( power ) {
case 1 :
return 3 ;
case 2 :
case 3 :
return 2 ;
case 4 :
case 5 :
return 1 ;
case 6 :
case 7 :
case 8 :
default :
return 0 ;
}
}
2016-04-25 18:20:54 +00:00
const char * cnetz_state_name ( enum cnetz_state state )
{
static char invalid [ 16 ] ;
switch ( state ) {
case CNETZ_NULL :
return " (NULL) " ;
case CNETZ_IDLE :
return " IDLE " ;
case CNETZ_BUSY :
return " BUSY " ;
}
sprintf ( invalid , " invalid(%d) " , state ) ;
return invalid ;
}
2017-05-25 16:43:54 +00:00
void cnetz_display_status ( void )
{
sender_t * sender ;
cnetz_t * cnetz ;
transaction_t * trans ;
display_status_start ( ) ;
for ( sender = sender_head ; sender ; sender = sender - > next ) {
cnetz = ( cnetz_t * ) sender ;
display_status_channel ( cnetz - > sender . kanal , chan_type_short_name ( cnetz - > chan_type ) , cnetz_state_name ( cnetz - > state ) ) ;
for ( trans = cnetz - > trans_list ; trans ; trans = trans - > next )
display_status_subscriber ( transaction2rufnummer ( trans ) , trans_short_state_name ( trans - > state ) ) ;
}
display_status_end ( ) ;
}
2016-04-25 18:20:54 +00:00
static void cnetz_new_state ( cnetz_t * cnetz , enum cnetz_state new_state )
{
if ( cnetz - > state = = new_state )
return ;
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " State change: %s -> %s \n " , cnetz_state_name ( cnetz - > state ) , cnetz_state_name ( new_state ) ) ;
2016-04-25 18:20:54 +00:00
cnetz - > state = new_state ;
2017-05-25 16:43:54 +00:00
cnetz_display_status ( ) ;
2016-04-25 18:20:54 +00:00
}
2016-02-16 17:56:55 +00:00
/* Convert ISDN cause to 'Ausloesegrund' of C-Netz mobile station */
uint8_t cnetz_cause_isdn2cnetz ( int cause )
{
switch ( cause ) {
case CAUSE_NORMAL :
case CAUSE_BUSY :
case CAUSE_NOANSWER :
return CNETZ_CAUSE_TEILNEHMERBESETZT ;
case CAUSE_OUTOFORDER :
case CAUSE_INVALNUMBER :
case CAUSE_NOCHANNEL :
case CAUSE_TEMPFAIL :
default :
return CNETZ_CAUSE_GASSENBESETZT ;
}
}
/* global init */
int cnetz_init ( void )
{
return 0 ;
}
/* Create transceiver instance and link to a list. */
2020-06-14 18:59:41 +00:00
int cnetz_create ( const char * kanal , enum cnetz_chan_type chan_type , const char * audiodev , 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 )
2016-02-16 17:56:55 +00:00
{
2016-04-25 18:20:54 +00:00
sender_t * sender ;
2016-02-16 17:56:55 +00:00
cnetz_t * cnetz ;
int rc ;
2020-02-18 18:03:03 +00:00
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 ) ;
2016-02-16 17:56:55 +00:00
return - EINVAL ;
}
2019-07-20 16:11:17 +00:00
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 ) ;
2016-08-03 06:44:13 +00:00
}
2020-02-18 18:03:03 +00:00
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 ) ;
2016-02-16 17:56:55 +00:00
return - EINVAL ;
}
2019-07-20 16:11:17 +00:00
if ( ! ( atoi ( kanal ) & 1 ) & & atoi ( kanal ) > 758 ) {
PDEBUG ( DCNETZ , DEBUG_NOTICE , " You defined an extended frequency %s, only newer phones support this! \n " , kanal ) ;
2016-08-03 06:44:13 +00:00
}
2016-02-16 17:56:55 +00:00
2016-04-25 18:20:54 +00:00
/* OgK must be on channel 131 */
2019-07-20 16:11:17 +00:00
if ( ( chan_type = = CHAN_TYPE_OGK | | chan_type = = CHAN_TYPE_OGK_SPK ) & & atoi ( kanal ) ! = CNETZ_OGK_KANAL ) {
2016-04-25 18:20:54 +00:00
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 ;
}
/* SpK must be on channel other than 131 */
2019-07-20 16:11:17 +00:00
if ( chan_type = = CHAN_TYPE_SPK & & atoi ( kanal ) = = CNETZ_OGK_KANAL ) {
2016-04-25 18:20:54 +00:00
PDEBUG ( DCNETZ , DEBUG_NOTICE , " You must not use channel %d for traffic channel! \n " , CNETZ_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 ) ;
}
for ( sender = sender_head ; sender ; sender = sender - > next ) {
cnetz = ( cnetz_t * ) sender ;
2017-01-04 13:14:02 +00:00
if ( ! ! strcmp ( sender - > audiodev , audiodev ) ) {
2016-04-25 18:20:54 +00:00
PDEBUG ( DCNETZ , DEBUG_NOTICE , " To be able to sync multiple channels, all channels must be on the same sound device! \n " ) ;
return - EINVAL ;
}
2016-02-16 17:56:55 +00:00
}
cnetz = calloc ( 1 , sizeof ( cnetz_t ) ) ;
if ( ! cnetz ) {
PDEBUG ( DCNETZ , DEBUG_ERROR , " No memory! \n " ) ;
return - ENOMEM ;
}
2019-07-20 16:11:17 +00:00
PDEBUG ( DCNETZ , DEBUG_DEBUG , " Creating 'C-Netz' instance for 'Kanal' = %s (sample rate %d). \n " , kanal , samplerate ) ;
2016-02-16 17:56:55 +00:00
/* init general part of transceiver */
/* do not enable emphasis, since it is done by cnetz code, not by common sender code */
2020-06-14 18:59:41 +00:00
rc = sender_create ( & cnetz - > sender , kanal , cnetz_kanal2freq ( atoi ( kanal ) , 0 ) , cnetz_kanal2freq ( atoi ( kanal ) , 1 ) , audiodev , 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 ) ;
2016-02-16 17:56:55 +00:00
if ( rc < 0 ) {
PDEBUG ( DCNETZ , DEBUG_ERROR , " Failed to init transceiver process! \n " ) ;
goto error ;
}
2016-04-25 18:20:54 +00:00
#if 0
# warning hacking: applying different clock to slave
if ( & cnetz - > sender ! = sender_head ) {
clock_speed [ 0 ] = - 3 ;
clock_speed [ 1 ] = - 3 ;
}
# endif
2016-02-16 17:56:55 +00:00
/* init audio processing */
2019-12-05 07:33:08 +00:00
rc = dsp_init_sender ( cnetz , measure_speed , clock_speed , demod , speech_deviation ) ;
2016-02-16 17:56:55 +00:00
if ( rc < 0 ) {
PDEBUG ( DCNETZ , DEBUG_ERROR , " Failed to init signal processing! \n " ) ;
goto error ;
}
2016-04-25 18:20:54 +00:00
cnetz - > chan_type = chan_type ;
2019-06-29 05:49:28 +00:00
cnetz - > challenge_valid = challenge_valid ;
cnetz - > challenge = challenge ;
cnetz - > response_valid = response_valid ;
cnetz - > response = response ;
2017-08-26 15:48:13 +00:00
cnetz - > warteschlange = warteschlange ;
cnetz - > metering = metering ;
2016-02-16 17:56:55 +00:00
cnetz - > ms_power = ms_power ;
2016-05-10 17:25:07 +00:00
switch ( polarity ) {
case 1 :
/* select cell 0 for positive polarity */
2019-11-24 17:26:38 +00:00
cnetz - > negative_polarity = 0 ;
cnetz - > auto_polarity = 0 ;
2016-05-10 17:25:07 +00:00
break ;
2016-05-15 18:34:20 +00:00
case - 1 :
2016-05-10 17:25:07 +00:00
/* select cell 1 for negative polarity */
2019-11-24 17:26:38 +00:00
cnetz - > negative_polarity = 1 ;
cnetz - > auto_polarity = 0 ;
2016-05-10 17:25:07 +00:00
break ;
default :
/* send two cells and select by the first message from mobile */
2019-11-24 17:26:38 +00:00
cnetz - > negative_polarity = 0 ;
cnetz - > auto_polarity = 1 ;
2016-05-10 17:25:07 +00:00
}
2016-02-16 17:56:55 +00:00
cnetz - > pre_emphasis = pre_emphasis ;
cnetz - > de_emphasis = de_emphasis ;
2018-01-20 14:49:19 +00:00
rc = init_emphasis ( & cnetz - > estate , samplerate , CUT_OFF_EMPHASIS_CNETZ , CUT_OFF_HIGHPASS_DEFAULT , CUT_OFF_LOWPASS_DEFAULT ) ;
2016-02-16 17:56:55 +00:00
if ( rc < 0 )
goto error ;
/* go into idle state */
2020-06-01 19:07:49 +00:00
if ( chan_type = = CHAN_TYPE_OGK | | chan_type = = CHAN_TYPE_OGK_SPK )
cnetz_set_dsp_mode ( cnetz , DSP_MODE_OGK ) ;
else
cnetz_set_dsp_mode ( cnetz , DSP_MODE_OFF ) ;
2016-02-16 17:56:55 +00:00
cnetz_go_idle ( cnetz ) ;
# ifdef DEBUG_SPK
2019-06-29 05:49:28 +00:00
transaction_t * trans = create_transaction ( cnetz , TRANS_DS , 2 , 2 , 22002 , - 1 , - 1 ) ;
2016-02-16 17:56:55 +00:00
trans - > mo_call = 1 ;
2020-06-01 19:07:49 +00:00
cnetz_set_sched_dsp_mode ( cnetz , DSP_MODE_SPK_K , ( cnetz - > sched_ts + 2 ) & 31 ) ;
2016-04-25 18:20:54 +00:00
# else
/* create transaction for speech channel loopback */
if ( loopback & & chan_type = = CHAN_TYPE_SPK ) {
2019-06-29 05:49:28 +00:00
transaction_t * trans = create_transaction ( cnetz , TRANS_VHQ_K , 2 , 2 , 22002 , - 1 , - 1 ) ;
2016-04-25 18:20:54 +00:00
trans - > mo_call = 1 ;
2016-06-04 13:14:20 +00:00
cnetz_set_dsp_mode ( cnetz , DSP_MODE_SPK_K ) ;
2020-06-01 19:07:49 +00:00
cnetz_set_sched_dsp_mode ( cnetz , DSP_MODE_SPK_K , ( cnetz - > sched_ts + 1 ) & 31 ) ;
2016-04-25 18:20:54 +00:00
}
2016-02-16 17:56:55 +00:00
# endif
2016-08-01 07:27:37 +00:00
#if 0
/* debug flushing transactions */
transaction_t * trans1 , * trans2 ;
2019-06-29 05:49:28 +00:00
trans1 = create_transaction ( cnetz , 99 , 6 , 2 , 15784 , - 1 , - 1 ) ;
2016-08-01 07:27:37 +00:00
destroy_transaction ( trans1 ) ;
2019-06-29 05:49:28 +00:00
trans1 = create_transaction ( cnetz , 99 , 6 , 2 , 15784 , - 1 , - 1 ) ;
2016-08-01 07:27:37 +00:00
destroy_transaction ( trans1 ) ;
2019-06-29 05:49:28 +00:00
trans1 = create_transaction ( cnetz , 99 , 6 , 2 , 15784 , - 1 , - 1 ) ;
trans2 = create_transaction ( cnetz , 99 , 2 , 2 , 22002 , - 1 , - 1 ) ;
2016-08-01 07:27:37 +00:00
unlink_transaction ( trans1 ) ;
link_transaction ( trans1 , cnetz ) ;
cnetz_flush_other_transactions ( cnetz , trans1 ) ;
2019-06-29 05:49:28 +00:00
trans2 = create_transaction ( cnetz , 99 , 2 , 2 , 22002 , - 1 , - 1 ) ;
2016-08-01 07:27:37 +00:00
cnetz_flush_other_transactions ( cnetz , trans2 ) ;
# endif
2019-07-20 16:11:17 +00:00
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 ) ) ;
2020-01-02 17:54:20 +00:00
PDEBUG ( DNMT , DEBUG_NOTICE , " -> Using cell ID: Nat=%d FuVst=%d Rest=%d Name='%s' \n " , si . fuz_nat , si . fuz_fuvst , si . fuz_rest , get_station_name ( si . fuz_nat , si . fuz_fuvst , si . fuz_rest ) ) ;
2017-02-05 07:36:51 +00:00
2016-02-16 17:56:55 +00:00
return 0 ;
error :
cnetz_destroy ( & cnetz - > sender ) ;
return rc ;
}
/* Destroy transceiver instance and unlink from list. */
void cnetz_destroy ( sender_t * sender )
{
cnetz_t * cnetz = ( cnetz_t * ) sender ;
transaction_t * trans ;
2019-07-20 16:11:17 +00:00
PDEBUG ( DCNETZ , DEBUG_DEBUG , " Destroying 'C-Netz' instance for 'Kanal' = %s. \n " , sender - > kanal ) ;
2016-02-16 17:56:55 +00:00
while ( ( trans = search_transaction ( cnetz , ~ 0 ) ) ) {
const char * rufnummer = transaction2rufnummer ( trans ) ;
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Removing pending transaction for subscriber '%s' \n " , rufnummer ) ;
destroy_transaction ( trans ) ;
}
dsp_cleanup_sender ( cnetz ) ;
sender_destroy ( & cnetz - > sender ) ;
free ( cnetz ) ;
}
2017-08-26 15:48:13 +00:00
static cnetz_t * search_free_spk ( int extended )
{
sender_t * sender ;
cnetz_t * cnetz , * ogk_spk = NULL ;
for ( sender = sender_head ; sender ; sender = sender - > next ) {
cnetz = ( cnetz_t * ) sender ;
/* ignore extended frequency, if not supported */
if ( ! extended ) {
2019-07-20 16:11:17 +00:00
if ( ( atoi ( sender - > kanal ) & 1 ) & & atoi ( sender - > kanal ) > 947 )
2017-08-26 15:48:13 +00:00
continue ;
2019-07-20 16:11:17 +00:00
if ( ! ( atoi ( sender - > kanal ) & 1 ) & & atoi ( sender - > kanal ) > 758 )
2017-08-26 15:48:13 +00:00
continue ;
}
/* ignore busy channel */
if ( cnetz - > state ! = CNETZ_IDLE )
continue ;
/* return first free SpK */
if ( cnetz - > chan_type = = CHAN_TYPE_SPK )
return cnetz ;
/* remember OgK/SpK combined channel as second alternative */
if ( cnetz - > chan_type = = CHAN_TYPE_OGK_SPK )
ogk_spk = cnetz ;
}
return ogk_spk ;
}
static cnetz_t * search_ogk ( void )
{
sender_t * sender ;
cnetz_t * cnetz ;
for ( sender = sender_head ; sender ; sender = sender - > next ) {
cnetz = ( cnetz_t * ) sender ;
/* ignore busy channel */
if ( cnetz - > state ! = CNETZ_IDLE )
continue ;
if ( cnetz - > chan_type = = CHAN_TYPE_OGK )
return cnetz ;
if ( cnetz - > chan_type = = CHAN_TYPE_OGK_SPK )
return cnetz ;
}
return NULL ;
}
2016-02-16 17:56:55 +00:00
/* Abort connection, if any and send idle broadcast */
2017-05-26 05:27:30 +00:00
void cnetz_go_idle ( cnetz_t * cnetz )
2016-02-16 17:56:55 +00:00
{
2017-08-26 15:48:13 +00:00
cnetz_t * ogk ;
transaction_t * trans ;
2016-08-21 07:36:55 +00:00
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 )
2017-10-28 05:11:40 +00:00
call_up_release ( cnetz - > trans_list - > callref , CAUSE_NORMAL ) ;
2016-08-21 07:36:55 +00:00
destroy_transaction ( cnetz - > trans_list ) ;
2016-02-16 17:56:55 +00:00
}
2019-07-20 16:11:17 +00:00
PDEBUG ( DCNETZ , DEBUG_INFO , " Entering IDLE state on channel %s. \n " , cnetz - > sender . kanal ) ;
2016-04-25 18:20:54 +00:00
cnetz_new_state ( cnetz , CNETZ_IDLE ) ;
2016-08-01 07:27:37 +00:00
/* set scheduler to OgK or turn off SpK */
2016-02-16 17:56:55 +00:00
if ( cnetz - > dsp_mode = = DSP_MODE_SPK_K | | cnetz - > dsp_mode = = DSP_MODE_SPK_V ) {
2020-06-01 19:07:49 +00:00
/* switch next frame after distributed signaling boundary (mutliple of 8 slots) */
cnetz_set_sched_dsp_mode ( cnetz , ( atoi ( cnetz - > sender . kanal ) = = CNETZ_OGK_KANAL ) ? DSP_MODE_OGK : DSP_MODE_OFF , ( cnetz - > sched_ts + 8 ) & 24 ) ;
2016-02-16 17:56:55 +00:00
} else {
2020-06-01 19:07:49 +00:00
/* 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 ) ;
2019-07-20 16:11:17 +00:00
cnetz_set_dsp_mode ( cnetz , ( atoi ( cnetz - > sender . kanal ) = = CNETZ_OGK_KANAL ) ? DSP_MODE_OGK : DSP_MODE_OFF ) ;
2016-02-16 17:56:55 +00:00
}
2017-08-26 15:48:13 +00:00
/* 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 ) ;
}
2016-02-16 17:56:55 +00:00
}
/* Initiate release connection on speech channel */
static void cnetz_release ( transaction_t * trans , uint8_t cause )
{
2017-08-26 15:48:13 +00:00
trans_new_state ( trans , ( trans - > cnetz - > dsp_mode = = DSP_MODE_OGK ) ? TRANS_VA : TRANS_AF ) ;
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2016-02-16 17:56:55 +00:00
trans - > release_cause = cause ;
2020-06-01 19:07:49 +00:00
trans - > cnetz - > sched_dsp_mode_ts = - 1 ;
2016-02-16 17:56:55 +00:00
timer_stop ( & trans - > timer ) ;
}
/* Receive audio from call instance. */
2017-10-28 05:11:40 +00:00
void call_down_audio ( int callref , sample_t * samples , int count )
2016-02-16 17:56:55 +00:00
{
sender_t * sender ;
cnetz_t * cnetz ;
for ( sender = sender_head ; sender ; sender = sender - > next ) {
cnetz = ( cnetz_t * ) sender ;
2016-08-21 07:36:55 +00:00
if ( cnetz - > trans_list & & cnetz - > trans_list - > callref = = callref )
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! sender )
return ;
if ( cnetz - > dsp_mode = = DSP_MODE_SPK_V ) {
/* store as is, since we convert rate when processing FSK frames */
2017-01-04 13:14:02 +00:00
jitter_save ( & cnetz - > sender . dejitter , samples , count ) ;
2016-02-16 17:56:55 +00:00
}
}
2020-01-12 06:54:25 +00:00
void call_down_clock ( void ) { }
2017-10-28 05:11:40 +00:00
int call_down_setup ( int callref , const char __attribute__ ( ( unused ) ) * caller_id , enum number_type __attribute__ ( ( unused ) ) caller_type , const char * dialing )
2016-02-16 17:56:55 +00:00
{
sender_t * sender ;
2017-08-26 15:48:13 +00:00
cnetz_t * cnetz , * spk ;
2019-06-29 05:49:28 +00:00
int rc ;
2017-08-26 15:48:13 +00:00
int extended ;
2016-02-16 17:56:55 +00:00
transaction_t * trans ;
uint8_t futln_nat ;
uint8_t futln_fuvst ;
2020-05-10 04:43:08 +00:00
int futln_rest ; /* use int for checking size > 65535 */
int len ;
2016-02-16 17:56:55 +00:00
int i ;
/* 1. check if number is invalid, return INVALNUMBER */
2020-05-10 04:43:08 +00:00
len = strlen ( dialing ) ;
if ( len > = 11 & & ! strncmp ( dialing , " 0161 " , 4 ) ) {
2016-02-16 17:56:55 +00:00
dialing + = 4 ;
2020-05-10 04:43:08 +00:00
len - = 4 ;
}
if ( len < 7 | | len > 8 ) {
2016-02-16 17:56:55 +00:00
inval :
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Outgoing call to invalid number '%s', rejecting! \n " , dialing ) ;
return - CAUSE_INVALNUMBER ;
}
2020-05-10 04:43:08 +00:00
for ( i = 0 ; i < len ; i + + ) {
2016-02-16 17:56:55 +00:00
if ( dialing [ i ] < ' 0 ' | | dialing [ i ] > ' 9 ' )
goto inval ;
}
futln_nat = dialing [ 0 ] - ' 0 ' ;
2020-05-10 04:43:08 +00:00
if ( len = = 7 )
futln_fuvst = dialing [ 1 ] - ' 0 ' ;
else {
futln_fuvst = ( dialing [ 1 ] - ' 0 ' ) * 10 + ( dialing [ 2 ] - ' 0 ' ) ;
if ( futln_fuvst > 31 ) {
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Digit 2 and 3 '%02d' must not exceed '31', but they do! \n " , futln_fuvst ) ;
goto inval ;
}
}
futln_rest = atoi ( dialing + len - 5 ) ;
if ( futln_rest > 65535 ) {
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Last 5 digits '%05d' must not exceed '65535', but they do! \n " , futln_rest ) ;
goto inval ;
}
2016-02-16 17:56:55 +00:00
2016-05-08 13:34:14 +00:00
/* 2. check if the subscriber is attached */
2019-06-29 05:49:28 +00:00
rc = find_db ( futln_nat , futln_fuvst , futln_rest , NULL , & extended ) ;
if ( rc < 0 ) {
2016-05-08 13:34:14 +00:00
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 */
2016-02-16 17:56:55 +00:00
for ( sender = sender_head ; sender ; sender = sender - > next ) {
cnetz = ( cnetz_t * ) sender ;
/* search transaction for this number */
2016-06-12 08:50:11 +00:00
trans = search_transaction_number ( cnetz , futln_nat , futln_fuvst , futln_rest ) ;
2016-02-16 17:56:55 +00:00
if ( trans )
break ;
}
if ( sender ) {
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Outgoing call to busy number, rejecting! \n " ) ;
return - CAUSE_BUSY ;
}
2017-08-26 15:48:13 +00:00
/* 4. check if we have no OgK, return NOCHANNEL */
2016-04-25 18:20:54 +00:00
cnetz = search_ogk ( ) ;
if ( ! cnetz ) {
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Outgoing call, but OgK is currently busy, rejecting! \n " ) ;
return - CAUSE_NOCHANNEL ;
}
2017-08-26 15:48:13 +00:00
/* 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 " ) ;
}
2016-12-09 15:34:33 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Call to mobile station, paging station id '%s' \n " , dialing ) ;
2016-02-16 17:56:55 +00:00
2016-05-08 13:34:14 +00:00
/* 6. trying to page mobile station */
2019-06-29 05:49:28 +00:00
trans = create_transaction ( cnetz , ( spk ) ? TRANS_VAK : TRANS_WSK , dialing [ 0 ] - ' 0 ' , dialing [ 1 ] - ' 0 ' , atoi ( dialing + 2 ) , - 1 , - 1 ) ;
2016-02-16 17:56:55 +00:00
if ( ! trans ) {
PDEBUG ( DCNETZ , DEBUG_ERROR , " Failed to create transaction \n " ) ;
return - CAUSE_TEMPFAIL ;
}
2016-08-01 17:17:13 +00:00
trans - > callref = callref ;
2016-08-01 07:27:37 +00:00
trans - > try = 1 ;
2016-02-16 17:56:55 +00:00
return 0 ;
}
2017-10-28 05:11:40 +00:00
void call_down_answer ( int __attribute__ ( ( unused ) ) callref )
2017-08-06 09:30:39 +00:00
{
}
2016-02-16 17:56:55 +00:00
/* Call control sends disconnect (with tones).
* An active call stays active , so tones and annoucements can be received
* by mobile station .
*/
2017-10-28 05:11:40 +00:00
void call_down_disconnect ( int callref , int cause )
2016-02-16 17:56:55 +00:00
{
sender_t * sender ;
cnetz_t * cnetz ;
transaction_t * trans ;
PDEBUG ( DCNETZ , DEBUG_INFO , " Call has been disconnected by network. \n " ) ;
for ( sender = sender_head ; sender ; sender = sender - > next ) {
cnetz = ( cnetz_t * ) sender ;
2016-08-01 17:17:13 +00:00
/* search transaction for this callref */
trans = search_transaction_callref ( cnetz , callref ) ;
if ( trans )
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! sender ) {
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Outgoing disconnect, but no callref! \n " ) ;
2017-10-28 05:11:40 +00:00
call_up_release ( callref , CAUSE_INVALCALLREF ) ;
2016-02-16 17:56:55 +00:00
return ;
}
/* Release when not active */
switch ( cnetz - > dsp_mode ) {
case DSP_MODE_SPK_V :
return ;
case DSP_MODE_SPK_K :
PDEBUG ( DCNETZ , DEBUG_INFO , " Call control disconnects on speech channel, releasing towards mobile station. \n " ) ;
cnetz_release ( trans , cnetz_cause_isdn2cnetz ( cause ) ) ;
2017-10-28 05:11:40 +00:00
call_up_release ( callref , cause ) ;
2016-08-01 17:17:13 +00:00
trans - > callref = 0 ;
2016-02-16 17:56:55 +00:00
break ;
default :
PDEBUG ( DCNETZ , DEBUG_INFO , " Call control disconnects on organisation channel, removing transaction. \n " ) ;
2017-10-28 05:11:40 +00:00
call_up_release ( callref , cause ) ;
2017-08-26 15:48:13 +00:00
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 ) ;
}
2016-02-16 17:56:55 +00:00
}
}
/* Call control releases call toward mobile station. */
2017-10-28 05:11:40 +00:00
void call_down_release ( int callref , int cause )
2016-02-16 17:56:55 +00:00
{
sender_t * sender ;
cnetz_t * cnetz ;
transaction_t * trans ;
PDEBUG ( DCNETZ , DEBUG_INFO , " Call has been released by network, releasing call. \n " ) ;
for ( sender = sender_head ; sender ; sender = sender - > next ) {
cnetz = ( cnetz_t * ) sender ;
2016-08-01 17:17:13 +00:00
/* search transaction for this callref */
trans = search_transaction_callref ( cnetz , callref ) ;
if ( trans )
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! sender ) {
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Outgoing release, but no callref! \n " ) ;
/* don't send release, because caller already released */
return ;
}
2016-08-01 17:17:13 +00:00
trans - > callref = 0 ;
2016-02-16 17:56:55 +00:00
switch ( cnetz - > dsp_mode ) {
case DSP_MODE_SPK_K :
case DSP_MODE_SPK_V :
PDEBUG ( DCNETZ , DEBUG_INFO , " Call control releases on speech channel, releasing towards mobile station. \n " ) ;
cnetz_release ( trans , cnetz_cause_isdn2cnetz ( cause ) ) ;
break ;
default :
PDEBUG ( DCNETZ , DEBUG_INFO , " Call control releases on organisation channel, removing transaction. \n " ) ;
2017-08-26 15:48:13 +00:00
if ( trans - > state = = TRANS_MT_QUEUE ) {
cnetz_release ( trans , cnetz_cause_isdn2cnetz ( cause ) ) ;
} else {
destroy_transaction ( trans ) ;
cnetz_go_idle ( cnetz ) ;
}
2016-02-16 17:56:55 +00:00
}
}
2016-05-08 13:34:14 +00:00
int cnetz_meldeaufruf ( uint8_t futln_nat , uint8_t futln_fuvst , uint16_t futln_rest )
{
cnetz_t * cnetz ;
transaction_t * trans ;
cnetz = search_ogk ( ) ;
if ( ! cnetz ) {
2016-05-15 18:35:20 +00:00
PDEBUG ( DCNETZ , DEBUG_NOTICE , " 'Meldeaufruf', but OgK is currently busy! \n " ) ;
2016-05-08 13:34:14 +00:00
return - CAUSE_NOCHANNEL ;
}
2019-06-29 05:49:28 +00:00
trans = create_transaction ( cnetz , TRANS_MA , futln_nat , futln_fuvst , futln_rest , - 1 , - 1 ) ;
2016-05-08 13:34:14 +00:00
if ( ! trans ) {
PDEBUG ( DCNETZ , DEBUG_ERROR , " Failed to create transaction \n " ) ;
return - CAUSE_TEMPFAIL ;
}
return 0 ;
}
2016-04-25 18:20:54 +00:00
static struct cnetz_channels {
enum cnetz_chan_type chan_type ;
const char * short_name ;
const char * long_name ;
} cnetz_channels [ ] = {
2017-02-05 07:36:51 +00:00
{ CHAN_TYPE_OGK_SPK , " OgK/SpK " , " combined control & voice channel " } ,
{ CHAN_TYPE_OGK , " OgK " , " control channel " } ,
{ CHAN_TYPE_SPK , " SpK " , " voice channel " } ,
2016-04-25 18:20:54 +00:00
{ 0 , NULL , NULL }
} ;
void cnetz_channel_list ( void )
{
int i ;
printf ( " Type \t Description \n " ) ;
printf ( " ------------------------------------------------------------------------ \n " ) ;
for ( i = 0 ; cnetz_channels [ i ] . long_name ; i + + )
printf ( " %s \t %s \n " , cnetz_channels [ i ] . short_name , cnetz_channels [ i ] . long_name ) ;
}
int cnetz_channel_by_short_name ( const char * short_name )
{
int i ;
for ( i = 0 ; cnetz_channels [ i ] . short_name ; i + + ) {
2017-02-05 07:36:51 +00:00
if ( ! strcasecmp ( cnetz_channels [ i ] . short_name , short_name ) )
2016-04-25 18:20:54 +00:00
return cnetz_channels [ i ] . chan_type ;
}
return - 1 ;
}
const char * chan_type_short_name ( enum cnetz_chan_type chan_type )
{
int i ;
for ( i = 0 ; cnetz_channels [ i ] . short_name ; i + + ) {
if ( cnetz_channels [ i ] . chan_type = = chan_type )
return cnetz_channels [ i ] . short_name ;
}
return " invalid " ;
}
const char * chan_type_long_name ( enum cnetz_chan_type chan_type )
{
int i ;
for ( i = 0 ; cnetz_channels [ i ] . long_name ; i + + ) {
if ( cnetz_channels [ i ] . chan_type = = chan_type )
return cnetz_channels [ i ] . long_name ;
}
return " invalid " ;
}
2016-02-16 17:56:55 +00:00
/* Timeout handling */
2016-06-12 08:50:11 +00:00
void transaction_timeout ( struct timer * timer )
2016-02-16 17:56:55 +00:00
{
transaction_t * trans = ( transaction_t * ) timer - > priv ;
cnetz_t * cnetz = trans - > cnetz ;
switch ( trans - > state ) {
case TRANS_WAF :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " No response after dialing request 'Wahlaufforderung' \n " ) ;
2016-08-01 07:27:37 +00:00
if ( trans - > try = = N ) {
2016-02-16 17:56:55 +00:00
trans_new_state ( trans , TRANS_WBN ) ;
break ;
}
2016-08-01 07:27:37 +00:00
trans - > try + + ;
2016-02-16 17:56:55 +00:00
trans_new_state ( trans , TRANS_VWG ) ;
break ;
2017-08-26 15:48:13 +00:00
case TRANS_MT_QUEUE :
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Phone in queue, but still no channel available, releasing call! \n " ) ;
2017-10-28 05:11:40 +00:00
call_up_release ( trans - > callref , CAUSE_NOCHANNEL ) ;
2017-08-26 15:48:13 +00:00
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 ;
2016-02-16 17:56:55 +00:00
case TRANS_BQ :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " No response after channel allocation 'Belegung Quittung' \n " ) ;
2016-08-01 07:27:37 +00:00
trans_new_state ( trans , TRANS_AF ) ;
trans - > repeat = 0 ;
2016-02-16 17:56:55 +00:00
break ;
2019-06-29 05:49:28 +00:00
case TRANS_ZFZ :
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " No response after sending random number 'Zufallszahl' \n " ) ;
if ( trans - > callref ) {
call_up_release ( trans - > callref , CAUSE_TEMPFAIL ) ;
trans - > callref = 0 ;
}
cnetz_release ( trans , CNETZ_CAUSE_FUNKTECHNISCH ) ;
break ;
case TRANS_AP :
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " No response after waiting for challenge response 'Autorisierungsparameter' \n " ) ;
if ( trans - > callref ) {
call_up_release ( trans - > callref , CAUSE_TEMPFAIL ) ;
trans - > callref = 0 ;
}
cnetz_release ( trans , CNETZ_CAUSE_FUNKTECHNISCH ) ;
break ;
case TRANS_VHQ_K :
case TRANS_VHQ_V :
2016-02-16 17:56:55 +00:00
if ( cnetz - > dsp_mode ! = DSP_MODE_SPK_V )
2016-08-01 17:17:13 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " No response while holding call 'Quittung Verbindung halten' \n " ) ;
2016-02-16 17:56:55 +00:00
else
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Lost signal from 'FuTln' (mobile station) \n " ) ;
2016-08-01 17:17:13 +00:00
if ( trans - > callref ) {
2017-10-28 05:11:40 +00:00
call_up_release ( trans - > callref , CAUSE_TEMPFAIL ) ;
2016-08-01 17:17:13 +00:00
trans - > callref = 0 ;
2016-02-16 17:56:55 +00:00
}
cnetz_release ( trans , CNETZ_CAUSE_FUNKTECHNISCH ) ;
break ;
case TRANS_DS :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " No response after connect 'Durchschalten' \n " ) ;
2017-10-28 05:11:40 +00:00
call_up_release ( trans - > callref , CAUSE_TEMPFAIL ) ;
2016-08-01 17:17:13 +00:00
trans - > callref = 0 ;
2016-02-16 17:56:55 +00:00
cnetz_release ( trans , CNETZ_CAUSE_FUNKTECHNISCH ) ;
break ;
case TRANS_RTA :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " No response after ringing order 'Rufton anschalten' \n " ) ;
2017-10-28 05:11:40 +00:00
call_up_release ( trans - > callref , CAUSE_TEMPFAIL ) ;
2016-08-01 17:17:13 +00:00
trans - > callref = 0 ;
2016-02-16 17:56:55 +00:00
cnetz_release ( trans , CNETZ_CAUSE_FUNKTECHNISCH ) ;
break ;
case TRANS_AHQ :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " No response after answer 'Abhebequittung' \n " ) ;
2017-10-28 05:11:40 +00:00
call_up_release ( trans - > callref , CAUSE_TEMPFAIL ) ;
2016-08-01 17:17:13 +00:00
trans - > callref = 0 ;
2016-02-16 17:56:55 +00:00
cnetz_release ( trans , CNETZ_CAUSE_FUNKTECHNISCH ) ;
break ;
2016-05-08 13:34:14 +00:00
case TRANS_MFT :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " No response after keepalive order 'Meldeaufruf' \n " ) ;
2016-10-23 09:50:02 +00:00
/* no response to availability check */
trans - > page_failed = 1 ;
2016-05-08 13:34:14 +00:00
destroy_transaction ( trans ) ;
break ;
2016-02-16 17:56:55 +00:00
default :
2017-08-26 15:48:13 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_ERROR , " Timeout unhandled in state % " PRIu64 " \n " , trans - > state ) ;
2016-02-16 17:56:55 +00:00
}
}
/*
* sync to phone
*
* because we don ' t know the actual delay on sound card , we need to sync
* to the phone , that is synced to us .
*
* if block is given , we can set sync to absolute position in super frame .
* if not , we just sync to the nearest block .
*/
void cnetz_sync_frame ( cnetz_t * cnetz , double sync , int block )
{
double offset ;
if ( block > = 0 ) {
/* offset is the actual sync relative to bit_time */
offset = fmod ( sync - BITS_PER_BLOCK * ( double ) block + BITS_PER_SUPERFRAME , BITS_PER_SUPERFRAME ) ;
if ( offset > BITS_PER_SUPERFRAME / 2 )
offset - = BITS_PER_SUPERFRAME ;
} else {
/* sync to the nearest block */
/* offset is the actual sync relative to bit_time */
offset = fmod ( sync , BITS_PER_BLOCK ) ;
if ( offset > BITS_PER_BLOCK / 2 )
offset - = BITS_PER_BLOCK ;
}
/* if more than +- one bit out of sync */
if ( offset < - 0.5 | | offset > 0.5 ) {
2016-12-09 15:34:33 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Frame sync offset = %.2f, correcting! \n " , offset ) ;
2016-10-07 06:55:18 +00:00
fsk_correct_sync ( & cnetz - > fsk_demod , offset ) ;
2016-02-16 17:56:55 +00:00
return ;
}
/* resync by some fraction of received sync error */
2016-12-09 15:34:33 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_DEBUG , " Frame sync offset = %.2f, correcting. \n " , offset ) ;
2016-10-07 06:55:18 +00:00
fsk_correct_sync ( & cnetz - > fsk_demod , offset / 2.0 ) ;
2016-02-16 17:56:55 +00:00
}
/*
* OgK handling
*/
/* transmit rufblock */
const telegramm_t * cnetz_transmit_telegramm_rufblock ( cnetz_t * cnetz )
{
static telegramm_t telegramm ;
transaction_t * trans ;
2016-04-25 18:20:54 +00:00
cnetz_t * spk ;
2016-02-16 17:56:55 +00:00
memset ( & telegramm , 0 , sizeof ( telegramm ) ) ;
telegramm . opcode = OPCODE_LR_R ;
2020-01-02 08:45:33 +00:00
telegramm . max_sendeleistung = cnetz_power2bits ( cnetz - > ms_power ) ;
2019-11-24 17:26:38 +00:00
telegramm . bedingte_genauigkeit_der_fufst = si . genauigkeit ;
2016-02-16 17:56:55 +00:00
telegramm . zeitschlitz_nr = cnetz - > sched_ts ;
2019-11-24 17:26:38 +00:00
telegramm . grenzwert_fuer_einbuchen_und_umbuchen = si . grenz_einbuchen ;
telegramm . authentifikationsbit = si . authentifikationsbit ;
telegramm . vermittlungstechnische_sperren = si . vermittlungstechnische_sperren ;
telegramm . ws_kennung = si . ws_kennung ;
telegramm . reduzierungsfaktor = si . reduzierung ;
telegramm . fuz_nationalitaet = si . fuz_nat ;
telegramm . fuz_fuvst_nr = si . fuz_fuvst ;
telegramm . fuz_rest_nr = si . fuz_rest ;
telegramm . kennung_fufst = si . kennung_fufst ;
telegramm . nachbarschafts_prioritaets_bit = si . nachbar_prio ;
telegramm . bewertung_nach_pegel_und_entfernung = si . bewertung ;
telegramm . entfernungsangabe_der_fufst = si . entfernung ;
telegramm . mittelungsfaktor_fuer_ausloesen = si . mittel_ausloesen ;
telegramm . mittelungsfaktor_fuer_umschalten = si . mittel_umschalten ;
telegramm . grenzwert_fuer_umschalten = si . grenz_umschalten ;
telegramm . grenze_fuer_ausloesen = si . grenz_ausloesen ;
2016-02-16 17:56:55 +00:00
2017-08-26 15:48:13 +00:00
trans = search_transaction ( cnetz , TRANS_EM | TRANS_UM | TRANS_WBN | TRANS_WBP | TRANS_VAG | TRANS_VAK | TRANS_ATQ | TRANS_VA | TRANS_WSK ) ;
2016-02-16 17:56:55 +00:00
if ( trans ) {
telegramm . futln_nationalitaet = trans - > futln_nat ;
telegramm . futln_heimat_fuvst_nr = trans - > futln_fuvst ;
telegramm . futln_rest_nr = trans - > futln_rest ;
2017-08-26 15:48:13 +00:00
telegramm . ausloesegrund = trans - > release_cause ;
2016-02-16 17:56:55 +00:00
switch ( trans - > state ) {
case TRANS_EM :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending acknowledgment 'Einbuchquittung' to Attachment request. \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_EBQ_R ;
destroy_transaction ( trans ) ;
break ;
case TRANS_UM :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending acknowledgment 'Umbuchquittung' to Roaming requuest. \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_UBQ_R ;
destroy_transaction ( trans ) ;
break ;
case TRANS_WBN :
2016-04-25 18:20:54 +00:00
wbn :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending call reject 'Wahlbestaetigung negativ'. \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_WBN_R ;
destroy_transaction ( trans ) ;
cnetz_go_idle ( cnetz ) ;
break ;
case TRANS_WBP :
2016-08-03 06:44:13 +00:00
spk = search_free_spk ( trans - > extended ) ;
2017-08-26 15:48:13 +00:00
/* 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 {
2016-04-25 18:20:54 +00:00
PDEBUG ( DCNETZ , DEBUG_NOTICE , " No free channel anymore, rejecting call! \n " ) ;
2017-08-26 15:48:13 +00:00
trans_new_state ( trans , TRANS_WBN ) ;
2016-04-25 18:20:54 +00:00
goto wbn ;
}
2016-02-16 17:56:55 +00:00
break ;
case TRANS_VAG :
case TRANS_VAK :
2017-08-26 15:48:13 +00:00
vak :
2016-02-16 17:56:55 +00:00
if ( trans - > state = = TRANS_VAG ) {
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending channel assignment 'Verbindungsaufbau gehend'. \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_VAG_R ;
} else {
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending channel assignment 'Verbindungsaufbau kommend'. \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_VAK_R ;
}
trans_new_state ( trans , TRANS_BQ ) ;
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2016-02-16 17:56:55 +00:00
timer_start ( & trans - > timer , 0.150 + 0.0375 * F_BQ ) ; /* two slots + F_BQ frames */
2016-04-25 18:20:54 +00:00
/* select channel */
2016-08-03 06:44:13 +00:00
spk = search_free_spk ( trans - > extended ) ;
2016-06-12 08:50:11 +00:00
if ( ! spk ) {
2016-08-01 17:17:13 +00:00
PDEBUG ( DCNETZ , DEBUG_NOTICE , " No free channel anymore, rejecting call! \n " ) ;
2016-06-12 08:50:11 +00:00
destroy_transaction ( trans ) ;
cnetz_go_idle ( cnetz ) ;
2016-06-18 06:05:18 +00:00
break ;
2016-06-12 08:50:11 +00:00
}
2016-04-25 18:20:54 +00:00
if ( spk = = cnetz ) {
2019-07-20 16:11:17 +00:00
PDEBUG ( DCNETZ , DEBUG_INFO , " Staying on combined calling + traffic channel %s \n " , spk - > sender . kanal ) ;
2016-04-25 18:20:54 +00:00
} else {
2019-07-20 16:11:17 +00:00
PDEBUG ( DCNETZ , DEBUG_INFO , " Assigning phone to traffic channel %s \n " , spk - > sender . kanal ) ;
2016-04-25 18:20:54 +00:00
/* sync RX time to current OgK time */
2016-12-01 16:59:08 +00:00
fsk_copy_sync ( & spk - > fsk_demod , & cnetz - > fsk_demod ) ;
2016-04-25 18:20:54 +00:00
}
2016-06-18 06:05:18 +00:00
/* set channel */
2019-07-20 16:11:17 +00:00
telegramm . frequenz_nr = atoi ( spk - > sender . kanal ) ;
2016-06-18 06:05:18 +00:00
/* change state to busy */
2016-04-25 18:20:54 +00:00
cnetz_new_state ( spk , CNETZ_BUSY ) ;
2016-02-16 17:56:55 +00:00
/* schedule switching two slots ahead */
2020-06-01 19:07:49 +00:00
cnetz_set_sched_dsp_mode ( spk , DSP_MODE_SPK_K , ( cnetz - > sched_ts + 2 ) & 31 ) ;
2016-06-18 06:05:18 +00:00
/* relink */
2016-04-25 18:20:54 +00:00
unlink_transaction ( trans ) ;
link_transaction ( trans , spk ) ;
/* flush all other transactions, if any (in case of OgK/SpK) */
cnetz_flush_other_transactions ( spk , trans ) ;
2016-02-16 17:56:55 +00:00
break ;
2017-08-26 15:48:13 +00:00
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 */
2017-10-28 05:11:40 +00:00
call_up_alerting ( trans - > callref ) ;
2016-02-16 17:56:55 +00:00
default :
; /* LR */
}
}
return & telegramm ;
}
/* transmit meldeblock */
const telegramm_t * cnetz_transmit_telegramm_meldeblock ( cnetz_t * cnetz )
{
static telegramm_t telegramm ;
transaction_t * trans ;
memset ( & telegramm , 0 , sizeof ( telegramm ) ) ;
telegramm . opcode = OPCODE_MLR_M ;
2020-01-02 08:45:33 +00:00
telegramm . max_sendeleistung = cnetz_power2bits ( cnetz - > ms_power ) ;
2016-02-16 17:56:55 +00:00
telegramm . ogk_verkehrsanteil = 0 ; /* must be 0 or phone might not respond to messages in different slot */
2019-11-24 17:26:38 +00:00
telegramm . teilnehmergruppensperre = si . teilnehmergruppensperre ;
telegramm . anzahl_gesperrter_teilnehmergruppen = si . anzahl_gesperrter_teilnehmergruppen ;
2016-02-16 17:56:55 +00:00
telegramm . ogk_vorschlag = CNETZ_OGK_KANAL ;
2019-11-24 17:26:38 +00:00
telegramm . fuz_rest_nr = si . fuz_rest ;
2016-02-16 17:56:55 +00:00
2016-05-08 13:34:14 +00:00
trans = search_transaction ( cnetz , TRANS_VWG | TRANS_MA ) ;
2016-02-16 17:56:55 +00:00
if ( trans ) {
switch ( trans - > state ) {
case TRANS_VWG :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending acknowledgment 'Wahlaufforderung' to outging call \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_WAF_M ;
telegramm . futln_nationalitaet = trans - > futln_nat ;
telegramm . futln_heimat_fuvst_nr = trans - > futln_fuvst ;
telegramm . futln_rest_nr = trans - > futln_rest ;
trans_new_state ( trans , TRANS_WAF ) ;
2016-08-01 07:27:37 +00:00
timer_start ( & trans - > timer , 1.0 ) ; /* Wait two slot cycles until resending */
2016-02-16 17:56:55 +00:00
break ;
2016-05-08 13:34:14 +00:00
case TRANS_MA :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending keepalive request 'Meldeaufruf' \n " ) ;
2016-05-08 13:34:14 +00:00
telegramm . opcode = OPCODE_MA_M ;
telegramm . futln_nationalitaet = trans - > futln_nat ;
telegramm . futln_heimat_fuvst_nr = trans - > futln_fuvst ;
telegramm . futln_rest_nr = trans - > futln_rest ;
trans_new_state ( trans , TRANS_MFT ) ;
2016-08-01 07:27:37 +00:00
timer_start ( & trans - > timer , 1.0 ) ; /* Wait two slot cycles until timeout */
2016-05-08 13:34:14 +00:00
break ;
2016-02-16 17:56:55 +00:00
default :
; /* MLR */
}
}
return & telegramm ;
}
void cnetz_receive_telegramm_ogk ( cnetz_t * cnetz , telegramm_t * telegramm , int block )
{
uint8_t opcode = telegramm - > opcode ;
int valid_frame = 0 ;
transaction_t * trans ;
const char * rufnummer ;
switch ( opcode ) {
case OPCODE_EM_R :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) )
2016-02-16 17:56:55 +00:00
break ;
rufnummer = telegramm2rufnummer ( telegramm ) ;
2019-11-24 17:26:38 +00:00
if ( si . authentifikationsbit & & telegramm - > chipkarten_futelg_bit )
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received Attachment 'Einbuchen' message from Subscriber '%s' with chip card's ID %d (vendor id %d, hardware version %d, software version %d) \n " , rufnummer , telegramm - > kartenkennung , telegramm - > herstellerkennung , telegramm - > hardware_des_futelg , telegramm - > software_des_futelg ) ;
2016-02-16 17:56:55 +00:00
else
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received Attachment 'Einbuchen' message from Subscriber '%s' with %s card's security code %d \n " , rufnummer , ( telegramm - > chipkarten_futelg_bit ) ? " chip " : " magnet " , telegramm - > sicherungs_code ) ;
2016-08-03 06:44:13 +00:00
if ( telegramm - > erweitertes_frequenzbandbit )
2020-06-01 19:12:09 +00:00
PDEBUG ( DCNETZ , DEBUG_INFO , " -> Phone supports extended frequency band \n " ) ;
2016-02-16 17:56:55 +00:00
if ( cnetz - > state ! = CNETZ_IDLE ) {
2016-04-25 18:20:54 +00:00
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Ignoring Attachment from subscriber '%s', because we are busy becoming SpK. \n " , rufnummer ) ;
2016-02-16 17:56:55 +00:00
break ;
}
2019-06-29 05:49:28 +00:00
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 ) ;
2016-02-16 17:56:55 +00:00
if ( ! trans ) {
PDEBUG ( DCNETZ , DEBUG_ERROR , " Failed to create transaction \n " ) ;
break ;
}
valid_frame = 1 ;
break ;
case OPCODE_UM_R :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) )
2016-02-16 17:56:55 +00:00
break ;
rufnummer = telegramm2rufnummer ( telegramm ) ;
2019-11-24 17:26:38 +00:00
if ( si . authentifikationsbit & & telegramm - > chipkarten_futelg_bit )
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received Roaming 'Umbuchen' message from Subscriber '%s' with chip card's ID %d (vendor id %d, hardware version %d, software version %d) \n " , rufnummer , telegramm - > kartenkennung , telegramm - > herstellerkennung , telegramm - > hardware_des_futelg , telegramm - > software_des_futelg ) ;
2016-02-16 17:56:55 +00:00
else
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received Roaming 'Umbuchen' message from Subscriber '%s' with %s card's security code %d \n " , rufnummer , ( telegramm - > chipkarten_futelg_bit ) ? " chip " : " magnet " , telegramm - > sicherungs_code ) ;
2016-08-03 06:44:13 +00:00
if ( telegramm - > erweitertes_frequenzbandbit )
2020-06-01 19:12:09 +00:00
PDEBUG ( DCNETZ , DEBUG_INFO , " -> Phone supports extended frequency band \n " ) ;
2016-02-16 17:56:55 +00:00
if ( cnetz - > state ! = CNETZ_IDLE ) {
2016-04-25 18:20:54 +00:00
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Ignoring Roaming from subscriber '%s', because we are busy becoming SpK. \n " , rufnummer ) ;
2016-02-16 17:56:55 +00:00
break ;
}
2019-06-29 05:49:28 +00:00
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 ) ;
2016-02-16 17:56:55 +00:00
if ( ! trans ) {
PDEBUG ( DCNETZ , DEBUG_ERROR , " Failed to create transaction \n " ) ;
break ;
}
valid_frame = 1 ;
break ;
2017-08-26 15:48:13 +00:00
case OPCODE_UWG_R :
case OPCODE_UWK_R :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) )
2017-08-26 15:48:13 +00:00
break ;
rufnummer = telegramm2rufnummer ( telegramm ) ;
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received Roaming request 'Umbuchantrag' message from Subscriber '%s' on queue \n " , rufnummer ) ;
break ;
2016-02-16 17:56:55 +00:00
case OPCODE_VWG_R :
case OPCODE_SRG_R :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) )
2016-02-16 17:56:55 +00:00
break ;
rufnummer = telegramm2rufnummer ( telegramm ) ;
2019-11-17 09:07:07 +00:00
if ( opcode = = OPCODE_VWG_R )
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received outgoing Call 'Verbindungswunsch gehend' message from Subscriber '%s' \n " , rufnummer ) ;
else
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received outgoing emergency Call 'Sonderruf gehend' message from Subscriber '%s' \n " , rufnummer ) ;
2016-02-16 17:56:55 +00:00
if ( cnetz - > state ! = CNETZ_IDLE ) {
2016-04-25 18:20:54 +00:00
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Ignoring Call from subscriber '%s', because we are busy becoming SpK. \n " , rufnummer ) ;
2016-02-16 17:56:55 +00:00
break ;
}
2019-06-29 05:49:28 +00:00
trans = create_transaction ( cnetz , TRANS_VWG , telegramm - > futln_nationalitaet , telegramm - > futln_heimat_fuvst_nr , telegramm - > futln_rest_nr , - 1 , telegramm - > erweitertes_frequenzbandbit ) ;
2016-02-16 17:56:55 +00:00
if ( ! trans ) {
PDEBUG ( DCNETZ , DEBUG_ERROR , " Failed to create transaction \n " ) ;
break ;
}
2016-08-01 07:27:37 +00:00
trans - > try = 1 ;
2016-02-16 17:56:55 +00:00
valid_frame = 1 ;
break ;
case OPCODE_WUE_M :
2017-08-26 15:48:13 +00:00
trans = search_transaction ( cnetz , TRANS_WAF | TRANS_WBP | TRANS_VAG | TRANS_MO_QUEUE ) ;
2016-02-16 17:56:55 +00:00
if ( ! trans ) {
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Received dialing digits 'Wahluebertragung' message without transaction, ignoring! \n " ) ;
2016-02-16 17:56:55 +00:00
break ;
}
rufnummer = transaction2rufnummer ( trans ) ;
strncpy ( trans - > dialing , telegramm - > wahlziffern , sizeof ( trans - > dialing ) - 1 ) ;
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received dialing digits 'Wahluebertragung' message from Subscriber '%s' to Number '%s' \n " , rufnummer , trans - > dialing ) ;
2016-02-16 17:56:55 +00:00
timer_stop ( & trans - > timer ) ;
trans_new_state ( trans , TRANS_WBP ) ;
2016-08-01 07:27:37 +00:00
trans - > try = 1 ; /* try */
2016-02-16 17:56:55 +00:00
valid_frame = 1 ;
break ;
2017-08-26 15:48:13 +00:00
case OPCODE_ATO_R :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) )
2017-08-26 15:48:13 +00:00
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 */
2019-06-29 05:49:28 +00:00
trans = create_transaction ( cnetz , TRANS_ATQ , telegramm - > futln_nationalitaet , telegramm - > futln_heimat_fuvst_nr , telegramm - > futln_rest_nr , - 1 , - 1 ) ;
2017-08-26 15:48:13 +00:00
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 ;
2016-05-08 13:34:14 +00:00
case OPCODE_MFT_M :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) )
2017-08-26 15:48:13 +00:00
break ;
2016-05-08 13:34:14 +00:00
trans = search_transaction_number ( cnetz , telegramm - > futln_nationalitaet , telegramm - > futln_heimat_fuvst_nr , telegramm - > futln_rest_nr ) ;
if ( ! trans ) {
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Received acknowledge 'Meldung Funktelefonteilnehmer' message without transaction, ignoring! \n " ) ;
2016-05-08 13:34:14 +00:00
break ;
}
2016-05-15 18:35:20 +00:00
rufnummer = transaction2rufnummer ( trans ) ;
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received acknowledge 'Meldung Funktelefonteilnehmer' message from Subscriber '%s' \n " , rufnummer ) ;
2016-05-08 13:34:14 +00:00
destroy_transaction ( trans ) ;
valid_frame = 1 ;
break ;
2016-02-16 17:56:55 +00:00
default :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Received unexpected Telegramm (opcode %d = %s) \n " , opcode , telegramm_name ( opcode ) ) ;
2016-02-16 17:56:55 +00:00
}
if ( cnetz - > sender . loopback ) {
fprintf ( stderr , " we don't know TS here, but we are in loopback mode. in loopback mode call to this function shall never happen. please fix or find a way to know when the time slot was received! \n " ) ;
abort ( ) ;
}
if ( valid_frame )
cnetz_sync_frame ( cnetz , telegramm - > sync_time , block ) ;
}
/*
* SpK handling
*/
/* transmit concentrated messages */
const telegramm_t * cnetz_transmit_telegramm_spk_k ( cnetz_t * cnetz )
{
static telegramm_t telegramm ;
transaction_t * trans = cnetz - > trans_list ;
2016-08-01 07:27:37 +00:00
cnetz_t * ogk ;
2016-02-16 17:56:55 +00:00
if ( ! trans )
2020-12-20 18:21:52 +00:00
return NULL ;
memset ( & telegramm , 0 , sizeof ( telegramm ) ) ;
2016-02-16 17:56:55 +00:00
2020-01-02 08:45:33 +00:00
telegramm . max_sendeleistung = cnetz_power2bits ( cnetz - > ms_power ) ;
telegramm . sendeleistungsanpassung = ( cnetz - > ms_power < 8 ) ? 1 : 0 ;
2019-11-24 17:26:38 +00:00
telegramm . entfernung = si . entfernung ;
telegramm . fuz_nationalitaet = si . fuz_nat ;
telegramm . fuz_fuvst_nr = si . fuz_fuvst ;
telegramm . fuz_rest_nr = si . fuz_rest ;
2016-02-16 17:56:55 +00:00
telegramm . futln_nationalitaet = trans - > futln_nat ;
telegramm . futln_heimat_fuvst_nr = trans - > futln_fuvst ;
telegramm . futln_rest_nr = trans - > futln_rest ;
2019-07-20 16:11:17 +00:00
telegramm . frequenz_nr = atoi ( cnetz - > sender . kanal ) ;
2019-11-24 17:26:38 +00:00
telegramm . bedingte_genauigkeit_der_fufst = si . genauigkeit ;
2019-06-29 05:49:28 +00:00
telegramm . zufallszahl = cnetz - > challenge ;
2016-02-16 17:56:55 +00:00
switch ( trans - > state ) {
case TRANS_BQ :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Belegungsquittung' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_BQ_K ;
2016-08-01 07:27:37 +00:00
if ( + + trans - > repeat > = 8 & & ! timer_running ( & trans - > timer ) ) {
2019-06-29 05:49:28 +00:00
if ( cnetz - > challenge_valid ) {
2019-11-24 17:26:38 +00:00
if ( si . authentifikationsbit = = 0 ) {
2019-06-29 05:49:28 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Cannot authenticate, because base station does not support it. (Authentication disabled in sysinfo.) \n " ) ;
goto no_auth ;
}
if ( trans - > futelg_bit = = 0 ) {
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Cannot authenticate, because mobile station does not support it. (Mobile station has magnetic card.) \n " ) ;
goto no_auth ;
}
2019-10-26 09:38:59 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Perform authentication with subscriber's card, use challenge: 0x%016 " PRIx64 " \n " , telegramm . zufallszahl ) ;
2019-06-29 05:49:28 +00:00
trans_new_state ( trans , TRANS_ZFZ ) ;
timer_start ( & trans - > timer , 0.0375 * F_ZFZ ) ; /* F_ZFZ frames */
} else {
no_auth :
trans_new_state ( trans , TRANS_VHQ_K ) ;
timer_start ( & trans - > timer , 0.0375 * F_VHQK ) ; /* F_VHQK frames */
}
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2016-02-16 17:56:55 +00:00
}
break ;
2019-06-29 05:49:28 +00:00
case TRANS_ZFZ :
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Zufallszahl' on traffic channel (0x%016 " PRIx64 " ). \n " , telegramm . zufallszahl ) ;
telegramm . opcode = OPCODE_ZFZ_K ;
break ;
case TRANS_AP :
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Quittung Verbindung halten' on traffic channel \n " ) ;
telegramm . opcode = OPCODE_VHQ_K ;
break ;
case TRANS_VHQ_K :
2016-04-25 18:20:54 +00:00
if ( ! cnetz - > sender . loopback )
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Quittung Verbindung halten' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_VHQ_K ;
2019-06-29 05:49:28 +00:00
/* continue until next sub frame, so we send DS from first block of next sub frame. */
2016-04-25 18:20:54 +00:00
if ( ! cnetz - > sender . loopback & & ( cnetz - > sched_ts & 7 ) = = 7 & & cnetz - > sched_r_m & & ! timer_running ( & trans - > timer ) ) {
2016-02-16 17:56:55 +00:00
/* next sub frame */
if ( trans - > mo_call ) {
int rc ;
2016-08-01 17:17:13 +00:00
trans - > callref = + + new_callref ;
2017-10-28 05:11:40 +00:00
rc = call_up_setup ( trans - > callref , transaction2rufnummer ( trans ) , trans - > dialing ) ;
2016-02-16 17:56:55 +00:00
if ( rc < 0 ) {
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Call rejected (cause %d), releasing. \n " , - rc ) ;
2016-08-01 17:17:13 +00:00
trans - > callref = 0 ;
2016-02-16 17:56:55 +00:00
cnetz_release ( trans , cnetz_cause_isdn2cnetz ( - rc ) ) ;
goto call_failed ;
}
trans_new_state ( trans , TRANS_DS ) ;
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2016-02-16 17:56:55 +00:00
timer_start ( & trans - > timer , 0.0375 * F_DS ) ; /* F_DS frames */
}
if ( trans - > mt_call ) {
trans_new_state ( trans , TRANS_RTA ) ;
timer_start ( & trans - > timer , 0.0375 * F_RTA ) ; /* F_RTA frames */
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2017-10-28 05:11:40 +00:00
call_up_alerting ( trans - > callref ) ;
2016-02-16 17:56:55 +00:00
}
}
break ;
case TRANS_DS :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Durchschalten' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_DSB_K ;
2019-06-29 05:49:28 +00:00
/* send exactly a sub frame (8 time slots) */
2016-02-16 17:56:55 +00:00
if ( ( cnetz - > sched_ts & 7 ) = = 7 & & cnetz - > sched_r_m & & ! timer_running ( & trans - > timer ) ) {
/* next sub frame */
2019-06-29 05:49:28 +00:00
trans_new_state ( trans , TRANS_VHQ_V ) ;
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2020-06-01 19:07:49 +00:00
cnetz_set_sched_dsp_mode ( cnetz , DSP_MODE_SPK_V , ( cnetz - > sched_ts + 1 ) & 31 ) ;
2016-02-16 17:56:55 +00:00
# ifndef DEBUG_SPK
timer_start ( & trans - > timer , 0.075 + 0.6 * F_VHQ ) ; /* one slot + F_VHQ frames */
# endif
}
break ;
case TRANS_RTA :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Rufton anschalten' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_RTA_K ;
break ;
case TRANS_AHQ :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Abhebe Quittung' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_AHQ_K ;
if ( ( cnetz - > sched_ts & 7 ) = = 7 & & cnetz - > sched_r_m ) {
/* next sub frame */
2019-06-29 05:49:28 +00:00
trans_new_state ( trans , TRANS_VHQ_V ) ;
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2020-06-01 19:07:49 +00:00
cnetz_set_sched_dsp_mode ( cnetz , DSP_MODE_SPK_V , ( cnetz - > sched_ts + 1 ) & 31 ) ;
2016-02-16 17:56:55 +00:00
timer_start ( & trans - > timer , 0.075 + 0.6 * F_VHQ ) ; /* one slot + F_VHQ frames */
}
break ;
case TRANS_AF :
call_failed :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Ausloesen durch FuFSt' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_AF_K ;
2016-08-01 07:27:37 +00:00
if ( + + trans - > repeat < N_AFKT )
break ;
if ( ! trans - > try ) {
/* no retry */
destroy_transaction ( trans ) ;
cnetz_go_idle ( cnetz ) ;
break ;
}
if ( trans - > try = = N ) {
PDEBUG ( DCNETZ , DEBUG_INFO , " Maximum retries, removing transaction \n " ) ;
2016-10-23 09:50:02 +00:00
/* no response to incomming call */
trans - > page_failed = 1 ;
2016-08-01 07:27:37 +00:00
cnetz_release ( trans , CNETZ_CAUSE_FUNKTECHNISCH ) ;
2016-08-21 07:36:55 +00:00
if ( trans - > callref )
2017-10-28 05:11:40 +00:00
call_up_release ( trans - > callref , CAUSE_TEMPFAIL ) ;
2016-08-01 17:17:13 +00:00
/* must destroy transaction after cnetz_release */
destroy_transaction ( trans ) ;
2016-02-16 17:56:55 +00:00
cnetz_go_idle ( cnetz ) ;
2016-08-01 07:27:37 +00:00
break ;
}
2016-08-01 17:17:13 +00:00
/* remove call from SpK (or OgK+SpK) */
2016-08-01 07:27:37 +00:00
unlink_transaction ( trans ) ;
/* idle channel */
cnetz_go_idle ( cnetz ) ;
/* alloc ogk again */
ogk = search_ogk ( ) ;
if ( ! ogk ) {
PDEBUG ( DCNETZ , DEBUG_NOTICE , " Cannot retry, because currently no OgK available (busy) \n " ) ;
cnetz_release ( trans , CNETZ_CAUSE_FUNKTECHNISCH ) ;
2016-08-02 07:02:58 +00:00
if ( trans - > callref )
2017-10-28 05:11:40 +00:00
call_up_release ( trans - > callref , CAUSE_NOCHANNEL ) ;
2016-08-01 17:17:13 +00:00
/* must destroy transaction after cnetz_release */
destroy_transaction ( trans ) ;
2016-08-01 07:27:37 +00:00
break ;
2016-02-16 17:56:55 +00:00
}
2016-08-01 07:27:37 +00:00
PDEBUG ( DCNETZ , DEBUG_INFO , " Retry to assign channel. \n " ) ;
/* attach call to OgK */
link_transaction ( trans , ogk ) ;
/* change state */
if ( trans - > mo_call )
trans_new_state ( trans , TRANS_WBP ) ;
if ( trans - > mt_call )
trans_new_state ( trans , TRANS_VAK ) ;
trans - > try + + ;
2016-02-16 17:56:55 +00:00
break ;
case TRANS_AT :
2016-08-03 10:00:43 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Auslosen durch FuFst' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_AF_K ;
2016-08-01 07:27:37 +00:00
if ( + + trans - > repeat = = 1 ) {
2016-02-16 17:56:55 +00:00
destroy_transaction ( trans ) ;
cnetz_go_idle ( cnetz ) ;
}
break ;
}
return & telegramm ;
}
/* receive concentrated messages */
void cnetz_receive_telegramm_spk_k ( cnetz_t * cnetz , telegramm_t * telegramm )
{
uint8_t opcode = telegramm - > opcode ;
int valid_frame = 0 ;
transaction_t * trans = cnetz - > trans_list ;
if ( ! trans )
return ;
switch ( opcode ) {
case OPCODE_BEL_K :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) ) {
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! match_futln ( telegramm , trans - > futln_nat , trans - > futln_fuvst , trans - > futln_rest ) ) {
break ;
}
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received allocation 'Belegung' message. \n " ) ;
2016-02-16 17:56:55 +00:00
valid_frame = 1 ;
if ( trans - > state ! = TRANS_BQ )
break ;
timer_stop ( & trans - > timer ) ;
2016-08-01 07:27:37 +00:00
trans - > try = 0 ;
2016-02-16 17:56:55 +00:00
break ;
case OPCODE_DSQ_K :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) ) {
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! match_futln ( telegramm , trans - > futln_nat , trans - > futln_fuvst , trans - > futln_rest ) ) {
break ;
}
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received assignment confirm 'Durchschaltung Quittung' message. \n " ) ;
2016-02-16 17:56:55 +00:00
valid_frame = 1 ;
if ( trans - > state ! = TRANS_DS )
break ;
cnetz - > scrambler = telegramm - > betriebs_art ;
2018-07-01 07:18:07 +00:00
cnetz - > scrambler_switch = 0 ;
2016-02-16 17:56:55 +00:00
timer_stop ( & trans - > timer ) ;
break ;
2019-06-29 05:49:28 +00:00
case OPCODE_ZFZQ_K :
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received random number acknowledge 'Zufallszahlquittung' message. \n " ) ;
valid_frame = 1 ;
if ( trans - > state ! = TRANS_ZFZ )
break ;
if ( cnetz - > challenge ! = telegramm - > zufallszahl ) {
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Received random number acknowledge (0x%016 " PRIx64 " ) does not match the transmitted one (0x%016 " PRIx64 " ), ignoring! \n " , telegramm - > zufallszahl , cnetz - > challenge ) ;
break ;
}
timer_stop ( & trans - > timer ) ;
trans_new_state ( trans , TRANS_AP ) ;
timer_start ( & trans - > timer , T_AP ) ; /* 750 milliseconds */
break ;
case OPCODE_AP_K :
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received challenge response 'Autorisierungsparameter' message (0x%016 " PRIx64 " ). \n " , telegramm - > authorisierungsparameter ) ;
valid_frame = 1 ;
if ( trans - > state ! = TRANS_AP )
break ;
/* if authentication response from card does not match */
if ( cnetz - > response_valid & & telegramm - > authorisierungsparameter ! = cnetz - > response ) {
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Received challenge response (0x%016 " PRIx64 " ) does not match the expected one (0x%016 " PRIx64 " ), releasing! \n " , telegramm - > authorisierungsparameter , cnetz - > response ) ;
if ( trans - > callref ) {
call_up_release ( trans - > callref , CAUSE_TEMPFAIL ) ; /* jolly guesses that */
trans - > callref = 0 ;
}
cnetz_release ( trans , CNETZ_CAUSE_GASSENBESETZT ) ; /* when authentication is not valid */
break ;
}
2019-10-26 09:38:59 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Completed authentication with subscriber's card, challenge response: 0x%016 " PRIx64 " \n " , telegramm - > authorisierungsparameter ) ;
2019-06-29 05:49:28 +00:00
timer_stop ( & trans - > timer ) ;
trans_new_state ( trans , TRANS_VHQ_K ) ;
timer_start ( & trans - > timer , 0.0375 * F_VHQK ) ; /* F_VHQK frames */
break ;
2016-02-16 17:56:55 +00:00
case OPCODE_VH_K :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) ) {
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! match_futln ( telegramm , trans - > futln_nat , trans - > futln_fuvst , trans - > futln_rest ) ) {
break ;
}
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received connection hold 'Verbindung halten' message. \n " ) ;
2016-02-16 17:56:55 +00:00
valid_frame = 1 ;
2019-06-29 05:49:28 +00:00
if ( trans - > state ! = TRANS_VHQ_K )
2016-02-16 17:56:55 +00:00
break ;
timer_stop ( & trans - > timer ) ;
break ;
case OPCODE_RTAQ_K :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) ) {
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! match_futln ( telegramm , trans - > futln_nat , trans - > futln_fuvst , trans - > futln_rest ) ) {
break ;
}
valid_frame = 1 ;
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received ringback 'Rufton anschalten Quittung' message. \n " ) ;
2016-02-16 17:56:55 +00:00
if ( trans - > state ! = TRANS_RTA )
break ;
timer_start ( & trans - > timer , 0.0375 * F_RTA ) ; /* F_RTA frames */
break ;
case OPCODE_AH_K :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) ) {
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! match_futln ( telegramm , trans - > futln_nat , trans - > futln_fuvst , trans - > futln_rest ) ) {
break ;
}
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received answer frame 'Abheben' message. \n " ) ;
2016-02-16 17:56:55 +00:00
valid_frame = 1 ;
/* if already received this frame, or if we are already on VHQ or if we are releasing */
2019-10-26 09:38:59 +00:00
if ( trans - > state = = TRANS_AHQ | | trans - > state = = TRANS_VHQ_K | | trans - > state = = TRANS_VHQ_V | | trans - > state = = TRANS_AF )
2016-02-16 17:56:55 +00:00
break ;
cnetz - > scrambler = telegramm - > betriebs_art ;
2018-07-01 07:18:07 +00:00
cnetz - > scrambler_switch = 0 ;
2016-02-16 17:56:55 +00:00
trans_new_state ( trans , TRANS_AHQ ) ;
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2016-02-16 17:56:55 +00:00
timer_stop ( & trans - > timer ) ;
2017-10-28 05:11:40 +00:00
call_up_answer ( trans - > callref , transaction2rufnummer ( trans ) ) ;
2016-02-16 17:56:55 +00:00
break ;
case OPCODE_AT_K :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) ) {
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! match_futln ( telegramm , trans - > futln_nat , trans - > futln_fuvst , trans - > futln_rest ) ) {
break ;
}
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received release frame 'Ausloesen durch FuTln' message. \n " ) ;
2016-02-16 17:56:55 +00:00
valid_frame = 1 ;
/* if already received this frame, if we are releasing */
if ( trans - > state = = TRANS_AT | | trans - > state = = TRANS_AF )
break ;
trans_new_state ( trans , TRANS_AT ) ;
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2016-02-16 17:56:55 +00:00
timer_stop ( & trans - > timer ) ;
2016-08-01 17:17:13 +00:00
if ( trans - > callref ) {
2017-10-28 05:11:40 +00:00
call_up_release ( trans - > callref , CAUSE_NORMAL ) ;
2016-08-01 17:17:13 +00:00
trans - > callref = 0 ;
2016-02-16 17:56:55 +00:00
}
break ;
default :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Received unexpected Telegramm (opcode %d = %s) \n " , opcode , telegramm_name ( opcode ) ) ;
2016-02-16 17:56:55 +00:00
}
if ( valid_frame )
cnetz_sync_frame ( cnetz , telegramm - > sync_time , - 1 ) ;
}
/* transmit distributed messages */
const telegramm_t * cnetz_transmit_telegramm_spk_v ( cnetz_t * cnetz )
{
static telegramm_t telegramm ;
transaction_t * trans = cnetz - > trans_list ;
2017-08-26 15:48:13 +00:00
int meter = 0 ;
2016-02-16 17:56:55 +00:00
if ( ! trans )
2020-12-20 18:21:52 +00:00
return NULL ;
memset ( & telegramm , 0 , sizeof ( telegramm ) ) ;
2016-02-16 17:56:55 +00:00
2017-08-26 15:48:13 +00:00
if ( cnetz - > metering ) {
double now = get_time ( ) ;
if ( ! trans - > call_start )
trans - > call_start = now ;
meter = ( now - trans - > call_start ) / ( double ) cnetz - > metering + 1 ;
}
2020-01-02 08:45:33 +00:00
telegramm . max_sendeleistung = cnetz_power2bits ( cnetz - > ms_power ) ;
telegramm . sendeleistungsanpassung = ( cnetz - > ms_power < 8 ) ? 1 : 0 ;
2016-02-16 17:56:55 +00:00
telegramm . ankuendigung_gespraechsende = 0 ;
2017-08-26 15:48:13 +00:00
telegramm . gebuehren_stand = meter ;
2019-11-24 17:26:38 +00:00
telegramm . fuz_nationalitaet = si . fuz_nat ;
telegramm . fuz_fuvst_nr = si . fuz_fuvst ;
telegramm . fuz_rest_nr = si . fuz_rest ;
2016-02-16 17:56:55 +00:00
telegramm . futln_nationalitaet = trans - > futln_nat ;
telegramm . futln_heimat_fuvst_nr = trans - > futln_fuvst ;
telegramm . futln_rest_nr = trans - > futln_rest ;
2019-07-20 16:11:17 +00:00
telegramm . frequenz_nr = atoi ( cnetz - > sender . kanal ) ;
2019-11-24 17:26:38 +00:00
telegramm . entfernung = si . entfernung ;
telegramm . bedingte_genauigkeit_der_fufst = si . genauigkeit ;
2016-02-16 17:56:55 +00:00
telegramm . gueltigkeit_des_gebuehrenstandes = 0 ;
telegramm . ausloesegrund = trans - > release_cause ;
switch ( trans - > state ) {
2019-06-29 05:49:28 +00:00
case TRANS_VHQ_V :
2016-08-03 10:00:43 +00:00
if ( ( cnetz - > sched_ts & 8 ) = = 0 ) { /* sub frame 1 and 3 */
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Quittung Verbindung halten 1' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_VHQ1_V ;
2016-08-03 10:00:43 +00:00
} else { /* sub frame 2 and 4 */
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Quittung Verbindung halten 2' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_VHQ2_V ;
2016-08-03 10:00:43 +00:00
}
2016-02-16 17:56:55 +00:00
break ;
case TRANS_AF :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending 'Ausloesen durch FuFSt' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_AF_V ;
2016-08-01 07:27:37 +00:00
if ( + + trans - > repeat = = N_AFV ) {
2016-02-16 17:56:55 +00:00
destroy_transaction ( trans ) ;
cnetz_go_idle ( cnetz ) ;
}
break ;
case TRANS_AT :
2019-06-29 05:49:28 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Sending acknowledge to 'Ausloesen durch FuTln' on traffic channel \n " ) ;
2016-02-16 17:56:55 +00:00
telegramm . opcode = OPCODE_AF_V ;
2016-08-01 07:27:37 +00:00
if ( + + trans - > repeat = = 1 ) {
2016-02-16 17:56:55 +00:00
destroy_transaction ( trans ) ;
cnetz_go_idle ( cnetz ) ;
}
break ;
}
return & telegramm ;
}
/* receive distributed messages */
void cnetz_receive_telegramm_spk_v ( cnetz_t * cnetz , telegramm_t * telegramm )
{
uint8_t opcode = telegramm - > opcode ;
int valid_frame = 0 ;
transaction_t * trans = cnetz - > trans_list ;
if ( ! trans )
return ;
switch ( opcode ) {
case OPCODE_VH_V :
2017-08-26 15:48:13 +00:00
case OPCODE_USAI_V :
case OPCODE_USAE_V :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) ) {
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! match_futln ( telegramm , trans - > futln_nat , trans - > futln_fuvst , trans - > futln_rest ) ) {
break ;
}
2019-06-29 05:49:28 +00:00
if ( trans - > state ! = TRANS_VHQ_V )
2016-02-16 17:56:55 +00:00
break ;
timer_start ( & trans - > timer , 0.6 * F_VHQ ) ; /* F_VHQ frames */
2017-08-26 15:48:13 +00:00
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 ;
}
2016-02-16 17:56:55 +00:00
valid_frame = 1 ;
2018-07-01 07:18:07 +00:00
if ( cnetz - > scrambler ! = telegramm - > betriebs_art ) {
/* if the scrambler mode changes, we wait 3 frames */
/* i guess that this was implemented to prevent switching by one corrupt frame. */
if ( + + cnetz - > scrambler_switch > = 3 ) {
cnetz - > scrambler = telegramm - > betriebs_art ;
cnetz - > scrambler_switch = 0 ;
}
} else
cnetz - > scrambler_switch = 0 ;
2016-02-16 17:56:55 +00:00
break ;
case OPCODE_AT_V :
2019-11-24 17:26:38 +00:00
if ( ! match_fuz ( telegramm ) ) {
2016-02-16 17:56:55 +00:00
break ;
}
if ( ! match_futln ( telegramm , trans - > futln_nat , trans - > futln_fuvst , trans - > futln_rest ) ) {
break ;
}
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_INFO , " Received release frame 'Ausloesen durch FuTln' message. \n " ) ;
2016-02-16 17:56:55 +00:00
valid_frame = 1 ;
/* if already received this frame, if we are releasing */
if ( trans - > state = = TRANS_AT | | trans - > state = = TRANS_AF )
break ;
trans_new_state ( trans , TRANS_AT ) ;
2016-08-01 07:27:37 +00:00
trans - > repeat = 0 ;
2016-02-16 17:56:55 +00:00
timer_stop ( & trans - > timer ) ;
2016-08-01 17:17:13 +00:00
if ( trans - > callref ) {
2017-10-28 05:11:40 +00:00
call_up_release ( trans - > callref , CAUSE_NORMAL ) ;
2016-08-01 17:17:13 +00:00
trans - > callref = 0 ;
2016-02-16 17:56:55 +00:00
}
break ;
default :
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DCNETZ , DEBUG_NOTICE , " Received unexpected Telegramm (opcode %d = %s) \n " , opcode , telegramm_name ( opcode ) ) ;
2016-02-16 17:56:55 +00:00
}
if ( valid_frame )
cnetz_sync_frame ( cnetz , telegramm - > sync_time , - 1 ) ;
}
2016-08-02 07:02:58 +00:00
void dump_info ( void )
{
dump_db ( ) ;
}