Add metering information from osmo-cc to B-Netz and C-Netz

Untested!
This commit is contained in:
Andreas Eversberg 2024-01-27 22:53:24 +01:00
parent da9b0a0f8d
commit 2dcf10b1b1
24 changed files with 122 additions and 36 deletions

View File

@ -990,7 +990,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}

View File

@ -21,6 +21,7 @@
#include <stdint.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
#include "../libsample/sample.h"
#include "../liblogging/logging.h"
#include "../libmobile/call.h"

View File

@ -433,7 +433,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}

View File

@ -48,7 +48,7 @@
#define TRENN_COUNT 5 /* min. 720 ms release 'Trennsignal' (according to FTZ 1727 Pfl 32 Clause 3.2.2.2.6) */
#define METERING_DURATION 0,140000 /* duration of metering pulse (according to FTZ 1727 Pfl 32 Clause 3.2.6.6.1) */
#define METERING_DURATION_US 140000 /* duration of metering pulse (according to FTZ 1727 Pfl 32 Clause 3.2.6.6.1) */
#define METERING_START 1,0 /* start metering 1 second after call start */
const char *bnetz_state_name(enum bnetz_state state)
@ -419,9 +419,12 @@ void bnetz_receive_tone(bnetz_t *bnetz, int bit)
osmo_timer_del(&bnetz->timer);
bnetz_new_state(bnetz, BNETZ_GESPRAECH);
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO);
/* start metering pulses if forced */
if (bnetz->metering < 0)
/* start metering pulses, if forced (mobile terminating call) */
if (bnetz->metering < 0) {
bnetz->metering_tv.tv_sec = abs(bnetz->metering);
bnetz->metering_tv.tv_usec = 0;
osmo_timer_schedule(&bnetz->timer, METERING_START);
}
call_up_answer(bnetz->callref, bnetz->station_id);
break;
}
@ -584,9 +587,6 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm)
osmo_timer_del(&bnetz->timer);
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO);
bnetz_new_state(bnetz, BNETZ_GESPRAECH);
/* start metering pulses if enabled and supported by phone or if forced */
if (bnetz->metering < 0 || (bnetz->metering > 0 && (bnetz->dial_type == DIAL_TYPE_METER || bnetz->dial_type == DIAL_TYPE_METER_MUENZ)))
osmo_timer_schedule(&bnetz->timer, METERING_START);
/* setup call */
LOGP(DBNETZ, LOGL_INFO, "Setup call to network.\n");
@ -635,6 +635,7 @@ lets see, if noise will not generate a release signal....
static void bnetz_timeout(void *data)
{
bnetz_t *bnetz = data;
int to_sec, to_usec;
switch (bnetz->state) {
case BNETZ_WAHLABRUF:
@ -673,12 +674,21 @@ static void bnetz_timeout(void *data)
case DSP_MODE_AUDIO:
/* turn on merting pulse */
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO_METER);
osmo_timer_schedule(&bnetz->timer, METERING_DURATION);
osmo_timer_schedule(&bnetz->timer, 0, METERING_DURATION_US);
break;
case DSP_MODE_AUDIO_METER:
/* turn off and wait given seconds for next metering cycle */
bnetz_set_dsp_mode(bnetz, DSP_MODE_AUDIO);
osmo_timer_schedule(&bnetz->timer, (double)abs(bnetz->metering) - METERING_DURATION);
/* if metering has been disabled due to disconnect (must be at least 1s) */
if (!bnetz->metering_tv.tv_sec)
break;
to_sec = bnetz->metering_tv.tv_sec;
to_usec = bnetz->metering_tv.tv_usec - METERING_DURATION_US;
if (to_usec < 0) {
to_usec += 1000000;
to_sec--;
}
osmo_timer_schedule(&bnetz->timer, to_sec, to_usec);
break;
default:
break;
@ -726,8 +736,35 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int callref, struct timeval *tv_meter)
{
sender_t *sender;
bnetz_t *bnetz;
LOGP(DBNETZ, LOGL_INFO, "Call has been answered by network.\n");
for (sender = sender_head; sender; sender = sender->next) {
bnetz = (bnetz_t *) sender;
if (bnetz->callref == callref)
break;
}
if (!sender) {
LOGP(DBNETZ, LOGL_NOTICE, "Incoming answer, but no callref!\n");
return;
}
/* At least tone second! */
if (tv_meter->tv_sec) {
LOGP(DBNETZ, LOGL_INFO, "Network starts metering pulses every %lu.%03lu seconds.\n", tv_meter->tv_sec, tv_meter->tv_usec / 1000);
memcpy(&bnetz->metering_tv, tv_meter, sizeof(bnetz->metering_tv));
osmo_timer_schedule(&bnetz->timer, METERING_START);
} else if (bnetz->metering < 0 || (bnetz->metering > 0 && (bnetz->dial_type == DIAL_TYPE_METER || bnetz->dial_type == DIAL_TYPE_METER_MUENZ))) {
/* start metering pulses if enabled and supported by phone or if forced (mobile origninating call) */
LOGP(DBNETZ, LOGL_INFO, "Command line options starts metering pulses every %d seconds.\n", abs(bnetz->metering));
bnetz->metering_tv.tv_sec = abs(bnetz->metering);
bnetz->metering_tv.tv_usec = 0;
osmo_timer_schedule(&bnetz->timer, METERING_START);
}
}
/* Call control sends disconnect (with tones).
@ -753,8 +790,12 @@ void call_down_disconnect(int callref, int cause)
}
/* Release when not active */
if (bnetz->state == BNETZ_GESPRAECH)
if (bnetz->state == BNETZ_GESPRAECH) {
/* stop metering */
bnetz->metering_tv.tv_sec = 0;
bnetz->metering_tv.tv_usec = 0;
return;
}
switch (bnetz->state) {
case BNETZ_SELEKTIVRUF_EIN:
case BNETZ_SELEKTIVRUF_AUS:

View File

@ -56,6 +56,7 @@ typedef struct bnetz {
/* system info */
int gfs; /* 'Gruppenfreisignal' */
int metering; /* use metering pulses in seconds 0 = off, < 0 = force */
struct timeval metering_tv; /* time to repeat metering pulse (current call) */
/* switch sender to channel 19 */
char paging_file[256]; /* if set, write to given file to switch to channel 19 or back */

View File

@ -58,6 +58,8 @@ void print_help(const char *arg0)
printf(" Pulses will be sent on outgoing calls only and only if mobile station\n");
printf(" requests it. Use negative value to force metering pulses for all calls.\n");
printf(" (default = %d)\n", metering);
printf(" If metering pulses are sent via Osmo-CC interface, pulses are always\n");
printf(" sent, if mobile station requests it. This overrides this option.\n");
printf(" -P --paging tone | notone | positive | negative | <file>=<on>:<off>\n");
printf(" Send a tone, give a signal or write to a file when switching to\n");
printf(" channel 19. (paging the phone).\n");

View File

@ -667,8 +667,35 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int callref, struct timeval *tv_meter)
{
sender_t *sender;
cnetz_t *cnetz;
transaction_t *trans;
LOGP(DCNETZ, LOGL_INFO, "Call has been answered by network.\n");
for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender;
trans = search_transaction_callref(cnetz, callref);
if (trans)
break;
}
if (!sender) {
LOGP(DCNETZ, LOGL_NOTICE, "Incoming answer, but no callref!\n");
return;
}
/* At least tone second! */
if (tv_meter->tv_sec) {
LOGP(DCNETZ, LOGL_INFO, "Network starts metering pulses every %lu.%03lu seconds.\n", tv_meter->tv_sec, tv_meter->tv_usec / 1000);
trans->meter_start = get_time();
trans->metering_time = (double)tv_meter->tv_sec + (double)tv_meter->tv_usec / 1000000.0;
} else if (cnetz->metering) {
LOGP(DCNETZ, LOGL_INFO, "Command line options starts metering pulses every %d seconds.\n", cnetz->metering);
trans->meter_start = get_time();
trans->metering_time = (double)cnetz->metering;
}
}
/* Call control sends disconnect (with tones).
@ -700,6 +727,8 @@ void call_down_disconnect(int callref, int cause)
switch (cnetz->dsp_mode) {
case DSP_MODE_SPK_V:
/* stop metering */
trans->meter_end = get_time();
return;
case DSP_MODE_SPK_K:
LOGP(DCNETZ, LOGL_INFO, "Call control disconnects on speech channel, releasing towards mobile station.\n");
@ -1667,11 +1696,11 @@ const telegramm_t *cnetz_transmit_telegramm_spk_v(cnetz_t *cnetz)
memset(&telegramm, 0, sizeof(telegramm));
if (cnetz->metering) {
double now = get_time();
if (!trans->call_start)
trans->call_start = now;
meter = (now - trans->call_start) / (double)cnetz->metering + 1;
if (trans->metering_time) {
/* get end time. if not set, use current time. (still running) */
double end = (trans->meter_end) ? : get_time();
/* add one unit, because when metering is started, the first unit is counted. */
meter = (end - trans->meter_start) / (double)trans->metering_time + 1.0;
}
telegramm.max_sendeleistung = cnetz_power2bits(cnetz->ms_power);

View File

@ -82,7 +82,7 @@ struct cnetz {
int response_valid; /* expect authorizaton response */
uint64_t response; /* authorization response */
int warteschlange; /* use queue */
int metering; /* use metering pulses in seconds 0 = off */
int metering; /* send metering units in seconds 0 = off */
/* all cnetz states */
enum cnetz_state state; /* main state of sender */

View File

@ -122,8 +122,10 @@ void print_help(const char *arg0)
printf(" Enable queue support. If no channel is available, calls will be kept\n");
printf(" in a queue for maximum of 60 seconds. (default = %d)\n", warteschlange);
printf(" -G --gebuehren <seconds> | 0\n");
printf(" Increment metering counter every given number of seconds.\n");
printf(" Increment metering counter every given number of seconds.\n");
printf(" To turn off, use 0. (default = %d)\n", metering);
printf(" If metering pulses are sent via Osmo-CC interface, pulses are always\n");
printf(" increment metering counter. This overrides this option.\n");
printf(" -V --voice-deviation <2400..4000 Hz>\n");
printf(" It is unclear what the actual voice deviation is. Please increase, if\n");
printf(" mobile's earpiece is too quiet and the microphone is too loud.\n");

View File

@ -54,7 +54,9 @@ typedef struct transaction {
int mo_call; /* flags a moile originating call */
int mt_call; /* flags a moile terminating call */
int page_failed; /* failed to get a response from MS */
double call_start; /* when did the call start? (used for metering) */
double metering_time; /* time between units (0.0 if no metering set) */
double meter_start; /* when did the metering start? (0.0 if not yet started) */
double meter_end; /* when did the metering end? (0.0 if not yet ended) */
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;

View File

@ -684,7 +684,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
euro_call_t *call;

View File

@ -347,7 +347,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}

View File

@ -1360,7 +1360,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int callref)
void call_down_answer(int callref, struct timeval __attribute__((unused)) *tv_meter)
{
transaction_t *trans;
uint8_t opcode, *data;

View File

@ -263,7 +263,7 @@ void call_down_clock(void) {}
int call_down_setup(int __attribute__((unused)) callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char __attribute__((unused)) *dialing) { return 0; }
void call_down_answer(int __attribute__((unused)) callref) { }
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter) { }
void call_down_disconnect(int __attribute__((unused)) callref, int __attribute__((unused)) cause) { }

View File

@ -845,7 +845,7 @@ int call_down_setup(int __attribute__((unused)) callref, const char *caller_id,
return -CAUSE_NORMAL;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}

View File

@ -1203,7 +1203,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}

View File

@ -513,7 +513,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}

View File

@ -660,9 +660,10 @@ void ll_msg_cb(osmo_cc_endpoint_t __attribute__((unused)) *ep, uint32_t callref,
{
process_t *process;
uint8_t coding, location, progress, isdn_cause, socket_cause;
uint16_t sip_cause;
uint16_t sip_cause, metering_connect_units, metering_unit_period_decisecs;
uint8_t type, plan, present, screen, caller_type;
char caller_id[33], number[33];
struct timeval tv_meter = {};
const char *suffix, *invalid;
int rc;
@ -704,6 +705,13 @@ void ll_msg_cb(osmo_cc_endpoint_t __attribute__((unused)) *ep, uint32_t callref,
return;
}
/* get metering information */
rc = osmo_cc_get_ie_metering(msg, 0, &metering_connect_units, &metering_unit_period_decisecs);
if (rc >= 0) {
tv_meter.tv_sec = metering_unit_period_decisecs / 10;
tv_meter.tv_usec = (metering_unit_period_decisecs % 10) / 10;
}
switch(msg->type) {
case OSMO_CC_MSG_SETUP_REQ:
{
@ -852,7 +860,7 @@ void ll_msg_cb(osmo_cc_endpoint_t __attribute__((unused)) *ep, uint32_t callref,
goto nego_failed;
new_state_process(callref, PROCESS_CONNECT);
LOGP(DCALL, LOGL_INFO, "Call answered\n");
call_down_answer(callref);
call_down_answer(callref, &tv_meter);
indicate_answer_ack(callref);
break;
case OSMO_CC_MSG_DISC_REQ:

View File

@ -31,7 +31,7 @@ void call_tone_recall(int callref, int on);
/* send messages */
int call_down_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing);
void call_down_answer(int callref);
void call_down_answer(int callref, struct timeval *tv_meter);
void call_down_disconnect(int callref, int cause);
void call_down_release(int callref, int cause);

View File

@ -1598,7 +1598,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}

View File

@ -1869,7 +1869,7 @@ int sms_out_setup(char *dialing, const char *caller_id, enum number_type caller_
return _out_setup(0, caller_id, caller_type, dialing, sms);
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}

View File

@ -541,7 +541,7 @@ void pocsag_msg_done(pocsag_t *pocsag)
pocsag_scan_or_loopback(pocsag);
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}

View File

@ -1434,7 +1434,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
}
/* Call control answers call toward station mobile. */
void call_down_answer(int callref)
void call_down_answer(int callref, struct timeval __attribute__((unused)) *tv_meter)
{
sender_t *sender;
r2000_t *r2000;

View File

@ -358,7 +358,7 @@ int call_down_setup(int callref, const char __attribute__((unused)) *caller_id,
return 0;
}
void call_down_answer(int __attribute__((unused)) callref)
void call_down_answer(int __attribute__((unused)) callref, struct timeval __attribute__((unused)) *tv_meter)
{
}