NMT: Caller ID support

This commit is contained in:
Andreas Eversberg 2016-07-20 11:58:12 +02:00
parent ba8bf0e9d5
commit 4745b29115
11 changed files with 333 additions and 73 deletions

View File

@ -698,7 +698,7 @@ reject:
*/ */
/* Call control starts call towards mobile station. */ /* Call control starts call towards mobile station. */
int call_out_setup(int callref, char *dialing) int call_out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing)
{ {
sender_t *sender; sender_t *sender;
amps_t *amps; amps_t *amps;

View File

@ -274,7 +274,7 @@ void anetz_receive_tone(anetz_t *anetz, int tone)
int rc; int rc;
PDEBUG(DANETZ, DEBUG_INFO, "1750 Hz signal from mobile station is gone, setup call.\n"); PDEBUG(DANETZ, DEBUG_INFO, "1750 Hz signal from mobile station is gone, setup call.\n");
rc = call_in_setup(callref, anetz->station_id, "0"); rc = call_in_setup(callref, "", "0");
if (rc < 0) { if (rc < 0) {
PDEBUG(DANETZ, DEBUG_NOTICE, "Call rejected (cause %d), sending release tone.\n", -rc); PDEBUG(DANETZ, DEBUG_NOTICE, "Call rejected (cause %d), sending release tone.\n", -rc);
anetz_release(anetz); anetz_release(anetz);
@ -331,7 +331,7 @@ static void anetz_timeout(struct timer *timer)
} }
/* Call control starts call towards mobile station. */ /* Call control starts call towards mobile station. */
int call_out_setup(int callref, char *dialing) int call_out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing)
{ {
sender_t *sender; sender_t *sender;
anetz_t *anetz; anetz_t *anetz;

View File

@ -769,7 +769,7 @@ static void bnetz_timeout(struct timer *timer)
} }
/* Call control starts call towards mobile station. */ /* Call control starts call towards mobile station. */
int call_out_setup(int callref, char *dialing) int call_out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing)
{ {
sender_t *sender; sender_t *sender;
bnetz_t *bnetz; bnetz_t *bnetz;

View File

@ -350,7 +350,7 @@ cnetz_t *search_ogk(void)
return NULL; return NULL;
} }
int call_out_setup(int callref, char *dialing) int call_out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing)
{ {
sender_t *sender; sender_t *sender;
cnetz_t *cnetz; cnetz_t *cnetz;

View File

@ -491,7 +491,7 @@ dial_after_hangup:
call.dialing[0] = '\0'; call.dialing[0] = '\0';
call_new_state(CALL_SETUP_MT); call_new_state(CALL_SETUP_MT);
call.callref = callref; call.callref = callref;
rc = call_out_setup(callref, call.station_id); rc = call_out_setup(callref, "", TYPE_NOTAVAIL, call.station_id);
if (rc < 0) { if (rc < 0) {
PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc); PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc);
call_new_state(CALL_DISCONNECTED); call_new_state(CALL_DISCONNECTED);
@ -712,7 +712,7 @@ void call_in_alerting(int callref)
} }
/* Transceiver indicates answer. */ /* Transceiver indicates answer. */
static void _indicate_answer(int callref, const char *connectid) static void _indicate_answer(int callref, const char *connect_id)
{ {
uint8_t buf[sizeof(struct gsm_mncc)]; uint8_t buf[sizeof(struct gsm_mncc)];
struct gsm_mncc *mncc = (struct gsm_mncc *)buf; struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
@ -721,23 +721,28 @@ static void _indicate_answer(int callref, const char *connectid)
mncc->msg_type = MNCC_SETUP_CNF; mncc->msg_type = MNCC_SETUP_CNF;
mncc->callref = callref; mncc->callref = callref;
mncc->fields |= MNCC_F_CONNECTED; mncc->fields |= MNCC_F_CONNECTED;
strncpy(mncc->connected.number, connectid, sizeof(mncc->connected.number) - 1); /* copy connected number as subscriber number */
mncc->connected.type = 0; strncpy(mncc->connected.number, connect_id, sizeof(mncc->connected.number));
mncc->connected.type = 4;
mncc->connected.plan = 1;
mncc->connected.present = 0;
mncc->connected.screen = 3;
PDEBUG(DMNCC, DEBUG_INFO, "Indicate MNCC answer towards Network\n"); PDEBUG(DMNCC, DEBUG_INFO, "Indicate MNCC answer towards Network\n");
mncc_write(buf, sizeof(struct gsm_mncc)); mncc_write(buf, sizeof(struct gsm_mncc));
} }
void call_in_answer(int callref, const char *connectid) void call_in_answer(int callref, const char *connect_id)
{ {
if (!callref) { if (!callref) {
PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring answer, because callref not set. (not for us)\n"); PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring answer, because callref not set. (not for us)\n");
return; return;
} }
PDEBUG(DCALL, DEBUG_INFO, "Call has been answered by '%s'\n", connectid); PDEBUG(DCALL, DEBUG_INFO, "Call has been answered by '%s'\n", connect_id);
if (use_mncc_sock) { if (use_mncc_sock) {
_indicate_answer(callref, connectid); _indicate_answer(callref, connect_id);
set_pattern_process(callref, PATTERN_NONE); set_pattern_process(callref, PATTERN_NONE);
set_state_process(callref, CALL_CONNECT); set_state_process(callref, CALL_CONNECT);
return; return;
@ -749,7 +754,7 @@ void call_in_answer(int callref, const char *connectid)
return; return;
} }
call_new_state(CALL_CONNECT); call_new_state(CALL_CONNECT);
strncpy(call.station_id, connectid, call.dial_digits); strncpy(call.station_id, connect_id, call.dial_digits);
call.station_id[call.dial_digits] = '\0'; call.station_id[call.dial_digits] = '\0';
} }
@ -856,6 +861,8 @@ void call_mncc_recv(uint8_t *buf, int length)
{ {
struct gsm_mncc *mncc = (struct gsm_mncc *)buf; struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
char number[sizeof(mncc->called.number)]; char number[sizeof(mncc->called.number)];
char caller_id[sizeof(mncc->calling.number)];
enum number_type caller_type;
int callref; int callref;
int rc; int rc;
@ -870,7 +877,6 @@ void call_mncc_recv(uint8_t *buf, int length)
} }
callref = mncc->callref; callref = mncc->callref;
strcpy(number, mncc->called.number);
if (is_process_disconnected(callref)) { if (is_process_disconnected(callref)) {
switch(mncc->msg_type) { switch(mncc->msg_type) {
@ -898,7 +904,30 @@ void call_mncc_recv(uint8_t *buf, int length)
switch(mncc->msg_type) { switch(mncc->msg_type) {
case MNCC_SETUP_REQ: case MNCC_SETUP_REQ:
PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC call from Network to '%s'\n", mncc->called.number); strcpy(number, mncc->called.number);
/* caller ID conversion */
strcpy(caller_id, mncc->calling.number);
switch(mncc->calling.type) {
case 1:
caller_type = TYPE_INTERNATIONAL;
break;
case 2:
caller_type = TYPE_NATIONAL;
break;
case 4:
caller_type = TYPE_SUBSCRIBER;
break;
default: /* or 0 */
caller_type = TYPE_UNKNOWN;
break;
}
if (!caller_id[0])
caller_type = TYPE_NOTAVAIL;
if (mncc->calling.present == 1)
caller_type = TYPE_ANONYMOUS;
PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC call from Network to '%s'\n", caller_id);
if (mncc->callref >= 0x4000000) { if (mncc->callref >= 0x4000000) {
fprintf(stderr, "Invalid callref from network, please fix!\n"); fprintf(stderr, "Invalid callref from network, please fix!\n");
@ -916,11 +945,11 @@ void call_mncc_recv(uint8_t *buf, int length)
mncc_write(buf, sizeof(struct gsm_mncc)); mncc_write(buf, sizeof(struct gsm_mncc));
PDEBUG(DCALL, DEBUG_INFO, "Outgoing call from to '%s'\n", number); PDEBUG(DCALL, DEBUG_INFO, "Outgoing call from '%s' to '%s'\n", caller_id, number);
create_process(callref, CALL_SETUP_MT); create_process(callref, CALL_SETUP_MT);
rc = call_out_setup(callref, number); rc = call_out_setup(callref, caller_id, caller_type, number);
if (rc < 0) { if (rc < 0) {
PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc); PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc);
if (send_patterns) { if (send_patterns) {

View File

@ -1,4 +1,14 @@
/* number type, includes presentation info */
enum number_type {
TYPE_NOTAVAIL,
TYPE_ANONYMOUS,
TYPE_UNKNOWN,
TYPE_SUBSCRIBER,
TYPE_NATIONAL,
TYPE_INTERNATIONAL,
};
int call_init(const char *station_id, const char *sounddev, int samplerate, int latency, int dial_digits, int loopback); int call_init(const char *station_id, const char *sounddev, int samplerate, int latency, int dial_digits, int loopback);
void call_cleanup(void); void call_cleanup(void);
void process_call(int c); void process_call(int c);
@ -6,11 +16,11 @@ void process_call(int c);
/* received messages */ /* received messages */
int call_in_setup(int callref, const char *callerid, const char *dialing); int call_in_setup(int callref, const char *callerid, const char *dialing);
void call_in_alerting(int callref); void call_in_alerting(int callref);
void call_in_answer(int callref, const char *connecid); void call_in_answer(int callref, const char *connect_id);
void call_in_release(int callref, int cause); void call_in_release(int callref, int cause);
/* send messages */ /* send messages */
int call_out_setup(int callref, char *dialing); int call_out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing);
void call_out_disconnect(int callref, int cause); void call_out_disconnect(int callref, int cause);
void call_out_release(int callref, int cause); void call_out_release(int callref, int cause);

View File

@ -25,7 +25,6 @@
#include <math.h> #include <math.h>
#include "../common/debug.h" #include "../common/debug.h"
#include "../common/timer.h" #include "../common/timer.h"
#include "../common/call.h"
#include "../common/goertzel.h" #include "../common/goertzel.h"
#include "nmt.h" #include "nmt.h"
#include "dsp.h" #include "dsp.h"

View File

@ -111,6 +111,84 @@ uint16_t nmt_encode_area_no(uint8_t area_no)
} }
} }
/* convert given number to caller ID frame with given index
* return next index */
int nmt_encode_a_number(frame_t *frame, int index, enum number_type type, const char *number)
{
int number_offset = 0;
int number_len = strlen(number);
int nframes;
uint8_t sum, ntype = 0, digit;
int i, shift;
/* number of frames
* 0..5 digits need one frame, 6..12 digits need two frames, ... */
nframes = (number_len + 8) / 7;
/* cycle index */
index %= nframes;
/* number offset for second frame is 5, and then additional 7 for the following frames */
if (index)
number_offset = index * 7 - 2;
/* encode */
frame->index = NMT_MESSAGE_8;
frame->seq_number = index;
if (index == 0) {
/* number type */
switch (type) {
case TYPE_NOTAVAIL:
ntype = 3;
break;
case TYPE_ANONYMOUS:
ntype = 4;
break;
case TYPE_UNKNOWN:
ntype = 0;
break;
case TYPE_SUBSCRIBER:
ntype = 0;
break;
case TYPE_NATIONAL:
ntype = 1;
break;
case TYPE_INTERNATIONAL:
ntype = 2;
break;
}
/* first 5 digits */
frame->additional_info = ((nframes - 1) << 24) | (ntype << 20);
shift = 16;
} else {
/* next digits */
frame->additional_info = 0;
shift = 24;
}
for (i = number_offset; number[i] && shift >= 0; i++, shift -= 4) {
digit = number[i];
if (digit >= '1' && digit <= '9')
digit -= '0';
else if (digit == '0')
digit = 10;
else
digit = 13; /* '+' and illegal digits */
frame->additional_info |= (digit << shift);
}
/* checksum */
sum = (frame->seq_number << 4) | frame->additional_info >> 24;
sum += (frame->additional_info >> 16);
sum += (frame->additional_info >> 8);
sum += frame->additional_info;
frame->checksum = sum;
/* return next frame index or cycle to first frame */
if (++index == nframes)
index = 0;
return index;
}
/* NMT Doc 450-1 4.3.2 */ /* NMT Doc 450-1 4.3.2 */
static struct nmt_frame { static struct nmt_frame {
enum nmt_mt message_type; enum nmt_mt message_type;

View File

@ -31,7 +31,6 @@
#include "../common/main.h" #include "../common/main.h"
#include "../common/debug.h" #include "../common/debug.h"
#include "../common/timer.h" #include "../common/timer.h"
#include "../common/call.h"
#include "../common/mncc_sock.h" #include "../common/mncc_sock.h"
#include "nmt.h" #include "nmt.h"
#include "frame.h" #include "frame.h"
@ -53,10 +52,11 @@ char area_no = 0;
int compandor = 1; int compandor = 1;
int supervisory = 0; int supervisory = 0;
const char *smsc_number = "767"; const char *smsc_number = "767";
int send_callerid = 0;
void print_help(const char *arg0) void print_help(const char *arg0)
{ {
print_help_common(arg0, "-y <traffic area> | list "); print_help_common(arg0, "-y <traffic area> | list [-I]");
/* - - */ /* - - */
printf(" -t --channel-type <channel type> | list\n"); printf(" -t --channel-type <channel type> | list\n");
printf(" Give channel type, use 'list' to get a list. (default = '%s')\n", chan_type_short_name(chan_type[0])); printf(" Give channel type, use 'list' to get a list. (default = '%s')\n", chan_type_short_name(chan_type[0]));
@ -81,6 +81,8 @@ void print_help(const char *arg0)
printf(" -S --smsc-number <digits>\n"); printf(" -S --smsc-number <digits>\n");
printf(" If this number is dialed, the mobile is connected to the SMSC (Short\n"); printf(" If this number is dialed, the mobile is connected to the SMSC (Short\n");
printf(" Message Service Center). (default = '%s')\n", smsc_number); printf(" Message Service Center). (default = '%s')\n", smsc_number);
printf(" -I --caller-id 1 | 0\n");
printf(" If set, the caller ID is sent while ringing the phone. (default = '%d')\n", send_callerid);
printf("\nstation-id: Give 7 digits of station-id, you don't need to enter it\n"); printf("\nstation-id: Give 7 digits of station-id, you don't need to enter it\n");
printf(" for every start of this program.\n"); printf(" for every start of this program.\n");
} }
@ -98,10 +100,11 @@ static int handle_options(int argc, char **argv)
{"compandor", 1, 0, 'C'}, {"compandor", 1, 0, 'C'},
{"supervisory", 1, 0, '0'}, {"supervisory", 1, 0, '0'},
{"smsc-number", 1, 0, 'S'}, {"smsc-number", 1, 0, 'S'},
{"caller-id", 1, 0, 'I'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
set_options_common("t:P:a:y:C:0:S:", long_options_special); set_options_common("t:P:a:y:C:0:S:I:", long_options_special);
while (1) { while (1) {
int option_index = 0, c, rc; int option_index = 0, c, rc;
@ -193,6 +196,10 @@ error_ta:
smsc_number = strdup(optarg); smsc_number = strdup(optarg);
skip_args += 2; skip_args += 2;
break; break;
case 'I':
send_callerid = atoi(optarg);
skip_args += 2;
break;
default: default:
opt_switch_common(c, argv[0], &skip_args); opt_switch_common(c, argv[0], &skip_args);
} }
@ -337,7 +344,7 @@ int main(int argc, char *argv[])
/* create transceiver instance */ /* create transceiver instance */
for (i = 0; i < num_kanal; i++) { for (i = 0; i < num_kanal; i++) {
rc = nmt_create(kanal[i], (loopback) ? CHAN_TYPE_TEST : chan_type[i], sounddev[i], samplerate, cross_channels, rx_gain, do_pre_emphasis, do_de_emphasis, write_wave, read_wave, ms_power, nmt_digits2value(traffic_area, 2), area_no, compandor, supervisory, smsc_number, loopback); rc = nmt_create(kanal[i], (loopback) ? CHAN_TYPE_TEST : chan_type[i], sounddev[i], samplerate, cross_channels, rx_gain, do_pre_emphasis, do_de_emphasis, write_wave, read_wave, ms_power, nmt_digits2value(traffic_area, 2), area_no, compandor, supervisory, smsc_number, send_callerid, loopback);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "Failed to create transceiver instance. Quitting!\n"); fprintf(stderr, "Failed to create transceiver instance. Quitting!\n");
goto fail; goto fail;

View File

@ -25,7 +25,6 @@
#include <time.h> #include <time.h>
#include "../common/debug.h" #include "../common/debug.h"
#include "../common/timer.h" #include "../common/timer.h"
#include "../common/call.h"
#include "../common/cause.h" #include "../common/cause.h"
#include "nmt.h" #include "nmt.h"
#include "dsp.h" #include "dsp.h"
@ -288,7 +287,7 @@ static void nmt_timeout(struct timer *timer);
static void nmt_go_idle(nmt_t *nmt); static void nmt_go_idle(nmt_t *nmt);
/* Create transceiver instance and link to a list. */ /* Create transceiver instance and link to a list. */
int nmt_create(int channel, enum nmt_chan_type chan_type, const char *sounddev, int samplerate, int cross_channels, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_wave, const char *read_wave, uint8_t ms_power, uint8_t traffic_area, uint8_t area_no, int compandor, int supervisory, const char *smsc_number, int loopback) int nmt_create(int channel, enum nmt_chan_type chan_type, const char *sounddev, int samplerate, int cross_channels, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_wave, const char *read_wave, uint8_t ms_power, uint8_t traffic_area, uint8_t area_no, int compandor, int supervisory, const char *smsc_number, int send_callerid, int loopback)
{ {
nmt_t *nmt; nmt_t *nmt;
int rc; int rc;
@ -363,6 +362,7 @@ int nmt_create(int channel, enum nmt_chan_type chan_type, const char *sounddev,
nmt->sysinfo.area_no = area_no; nmt->sysinfo.area_no = area_no;
nmt->compandor = compandor; nmt->compandor = compandor;
nmt->supervisory = supervisory; nmt->supervisory = supervisory;
nmt->send_callerid = send_callerid;
strncpy(nmt->smsc_number, smsc_number, sizeof(nmt->smsc_number) - 1); strncpy(nmt->smsc_number, smsc_number, sizeof(nmt->smsc_number) - 1);
/* go into idle state */ /* go into idle state */
@ -518,6 +518,110 @@ static int match_subscriber(nmt_t *nmt, frame_t *frame)
return 1; return 1;
} }
/*
* helper functions to generate frames
*/
static void tx_ident(nmt_t *nmt, frame_t *frame)
{
frame->index = NMT_MESSAGE_3b;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area;
frame->ms_country = nmt_digits2value(&nmt->subscriber.country, 1);
frame->ms_number = nmt_digits2value(nmt->subscriber.number, 6);
frame->additional_info = nmt_encode_area_no(nmt->sysinfo.area_no);
}
static void set_line_signal(nmt_t *nmt, frame_t *frame, uint8_t signal)
{
frame->index = NMT_MESSAGE_5a;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area;
frame->ms_country = nmt_digits2value(&nmt->subscriber.country, 1);
frame->ms_number = nmt_digits2value(nmt->subscriber.number, 6);
frame->line_signal = (signal << 8) | (signal << 4) | signal;
}
/* convert given number to caller ID frame with given index
* return next index */
static int encode_a_number(nmt_t *nmt, frame_t *frame, int index, enum number_type type, const char *number)
{
int number_offset = 0;
int number_len = strlen(number);
int nframes;
uint8_t sum, ntype = 0, digit;
int i, shift;
/* number of frames
* 0..5 digits need one frame, 6..12 digits need two frames, ... */
nframes = (number_len + 8) / 7;
/* cycle index */
index %= nframes;
/* number offset for second frame is 5, and then additional 7 for the following frames */
if (index)
number_offset = index * 7 - 2;
/* encode */
frame->index = NMT_MESSAGE_8;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area;
frame->seq_number = index;
if (index == 0) {
/* number type */
switch (type) {
case TYPE_NOTAVAIL:
ntype = 3;
break;
case TYPE_ANONYMOUS:
ntype = 4;
break;
case TYPE_UNKNOWN:
ntype = 0;
break;
case TYPE_SUBSCRIBER:
ntype = 0;
break;
case TYPE_NATIONAL:
ntype = 1;
break;
case TYPE_INTERNATIONAL:
ntype = 2;
break;
}
/* first 5 digits */
frame->additional_info = ((nframes - 1) << 24) | (ntype << 20);
shift = 16;
} else {
/* next digits */
frame->additional_info = 0;
shift = 24;
}
for (i = number_offset; number[i] && shift >= 0; i++, shift -= 4) {
digit = number[i];
if (digit >= '1' && digit <= '9')
digit -= '0';
else if (digit == '0')
digit = 10;
else
digit = 13; /* '+' and illegal digits */
frame->additional_info |= (digit << shift);
}
/* checksum */
sum = (frame->seq_number << 4) | frame->additional_info >> 24;
sum += (frame->additional_info >> 16);
sum += (frame->additional_info >> 8);
sum += frame->additional_info;
frame->checksum = sum;
/* return next frame index or cycle to first frame */
if (++index == nframes)
index = 0;
return index;
}
/* /*
* handle idle channel * handle idle channel
*/ */
@ -593,26 +697,6 @@ static void rx_idle(nmt_t *nmt, frame_t *frame)
* handle roaming * handle roaming
*/ */
static void tx_ident(nmt_t *nmt, frame_t *frame)
{
frame->index = NMT_MESSAGE_3b;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area;
frame->ms_country = nmt_digits2value(&nmt->subscriber.country, 1);
frame->ms_number = nmt_digits2value(nmt->subscriber.number, 6);
frame->additional_info = nmt_encode_area_no(nmt->sysinfo.area_no);
}
static void set_line_signal(nmt_t *nmt, frame_t *frame, uint8_t signal)
{
frame->index = NMT_MESSAGE_5a;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area;
frame->ms_country = nmt_digits2value(&nmt->subscriber.country, 1);
frame->ms_number = nmt_digits2value(nmt->subscriber.number, 6);
frame->line_signal = (signal << 8) | (signal << 4) | signal;
}
static void tx_roaming_ident(nmt_t *nmt, frame_t *frame) static void tx_roaming_ident(nmt_t *nmt, frame_t *frame)
{ {
if (++nmt->tx_frame_count == 1) if (++nmt->tx_frame_count == 1)
@ -1009,11 +1093,26 @@ static void tx_mt_ringing(nmt_t *nmt, frame_t *frame)
set_line_signal(nmt, frame, 9); set_line_signal(nmt, frame, 9);
if (++nmt->tx_frame_count == 1) if (++nmt->tx_frame_count == 1)
PDEBUG(DNMT, DEBUG_INFO, "Send 'ringing order'.\n"); PDEBUG(DNMT, DEBUG_INFO, "Send 'ringing order'.\n");
if (nmt->tx_frame_count >= 4) if (nmt->tx_frame_count >= 4) {
if (nmt->tx_callerid_count) {
if (nmt->tx_frame_count == 5)
PDEBUG(DNMT, DEBUG_INFO, "Send 'A-number'.\n");
encode_a_number(nmt, frame, nmt->tx_frame_count - 4, nmt->caller_type, nmt->caller_id);
} else
frame->index = NMT_MESSAGE_6; frame->index = NMT_MESSAGE_6;
/* repeat ringing after 5 seconds */ }
if (nmt->tx_frame_count == 36) if (nmt->tx_callerid_count == 1) {
/* start ringing after first caller ID of 6 frames */
if (nmt->tx_frame_count == 10) {
nmt->tx_frame_count = 0; nmt->tx_frame_count = 0;
nmt->tx_callerid_count++;
}
} else {
/* repeat ringing after 5 seconds */
if (nmt->tx_frame_count == 36) {
nmt->tx_frame_count = 0;
}
}
} }
static void rx_mt_ringing(nmt_t *nmt, frame_t *frame) static void rx_mt_ringing(nmt_t *nmt, frame_t *frame)
@ -1056,7 +1155,7 @@ static void tx_mt_complete(nmt_t *nmt, frame_t *frame)
} }
if (nmt->dms_call) { if (nmt->dms_call) {
time_t ti = time(NULL); time_t ti = time(NULL);
sms_deliver(nmt, sms_ref, "", SMS_TYPE_UKNOWN, SMS_PLAN_ISDN_TEL, ti, nmt->sms_string); sms_deliver(nmt, sms_ref, nmt->caller_id, nmt->caller_type, SMS_PLAN_ISDN_TEL, ti, nmt->sms_string);
} }
} }
} }
@ -1449,7 +1548,7 @@ const char *nmt_get_frame(nmt_t *nmt)
*/ */
/* Call control starts call towards mobile station. */ /* Call control starts call towards mobile station. */
int _out_setup(int callref, char *dialing, const char *sms) int _out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing, const char *sms)
{ {
sender_t *sender; sender_t *sender;
nmt_t *nmt; nmt_t *nmt;
@ -1501,17 +1600,23 @@ inval:
strncpy(nmt->sms_string, sms, sizeof(nmt->sms_string) - 1); strncpy(nmt->sms_string, sms, sizeof(nmt->sms_string) - 1);
nmt->dms_call = 1; nmt->dms_call = 1;
} }
if (caller_type == TYPE_INTERNATIONAL) {
nmt->caller_id[0] = '+'; /* not done by phone */
strncpy(nmt->caller_id + 1, caller_id, sizeof(nmt->caller_id) - 2);
} else
strncpy(nmt->caller_id, caller_id, sizeof(nmt->caller_id) - 1);
nmt->caller_type = caller_type;
nmt_page(nmt, ms_country, ms_number, 1); nmt_page(nmt, ms_country, ms_number, 1);
return 0; return 0;
} }
int call_out_setup(int callref, char *dialing) int call_out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing)
{ {
return _out_setup(callref, dialing, NULL); return _out_setup(callref, caller_id, caller_type, dialing, NULL);
} }
int sms_out_setup(char *dialing, const char *sms) int sms_out_setup(char *dialing, const char *caller_id, enum number_type caller_type, const char *sms)
{ {
return _out_setup(0, dialing, sms); return _out_setup(0, caller_id, caller_type, dialing, sms);
} }
/* Call control sends disconnect (with tones). /* Call control sends disconnect (with tones).
@ -1655,25 +1760,52 @@ void sms_deliver_report(nmt_t *nmt, uint8_t ref, int error, uint8_t cause)
/* application sends ud a message, we need to deliver */ /* application sends ud a message, we need to deliver */
void deliver_sms(const char *sms) void deliver_sms(const char *sms)
{ {
int i, rc; int rc;
char number[8]; char buffer[strlen(sms) + 1], *p = buffer, *caller_id, *number, *message;
enum number_type caller_type;
/* check for number digits */ strcpy(buffer, sms);
for (i = 0; i < 7; i++) { caller_id = strsep(&p, ",");
if (sms[i] < '0' || sms[i] > '9') number = strsep(&p, ",");
break; message = p;
} if (!caller_id || !number || !message) {
if (i < 7 || sms[7] != ',') { inval:
PDEBUG(DNMT, DEBUG_NOTICE, "Given SMS MUST start with the 7 digits phone number, followed by a comma (no spaces)\n"); PDEBUG(DNMT, DEBUG_NOTICE, "Given SMS MUST be in the following format: [i|n|s|u]<caller ID>,<7 digits number>,<message with comma and spaces> (i, n, s, u indicate the type of number)\n");
return; return;
} }
strncpy(number, sms, 7); if (strlen(number) != 7) {
number[7] = '\0'; PDEBUG(DNMT, DEBUG_NOTICE, "Given number must be 7 digits\n");
sms += 8; goto inval;
PDEBUG(DNMT, DEBUG_INFO, "SMS for subscriber '%s'\n", number); }
printf("SMS sending SMSC -> '%s': %s\n", number, sms);
rc = sms_out_setup(number, sms); switch(caller_id[0]) {
case '\0':
caller_type = TYPE_NOTAVAIL;
break;
case 'i':
caller_type = TYPE_INTERNATIONAL;
caller_id++;
break;
case 'n':
caller_type = TYPE_NATIONAL;
caller_id++;
break;
case 's':
caller_type = TYPE_SUBSCRIBER;
caller_id++;
break;
case 'u':
caller_type = TYPE_UNKNOWN;
caller_id++;
break;
default:
caller_type = TYPE_UNKNOWN;
}
PDEBUG(DNMT, DEBUG_INFO, "SMS for subscriber '%s'\n", number);
printf("SMS sending '%s' -> '%s': %s\n", caller_id, number, sms);
rc = sms_out_setup(number, caller_id, caller_type, message);
if (rc < 0) { if (rc < 0) {
PDEBUG(DNMT, DEBUG_INFO, "SMS delivery failed with cause '%d'\n", -rc); PDEBUG(DNMT, DEBUG_INFO, "SMS delivery failed with cause '%d'\n", -rc);
return; return;

View File

@ -1,6 +1,7 @@
#include "../common/sender.h" #include "../common/sender.h"
#include "../common/compandor.h" #include "../common/compandor.h"
#include "../common/dtmf.h" #include "../common/dtmf.h"
#include "../common/call.h"
#include "dms.h" #include "dms.h"
#include "sms.h" #include "sms.h"
@ -86,7 +87,10 @@ typedef struct nmt {
struct timer timer; struct timer timer;
int rx_frame_count; /* receive frame counter */ int rx_frame_count; /* receive frame counter */
int tx_frame_count; /* transmit frame counter */ int tx_frame_count; /* transmit frame counter */
int tx_callerid_count; /* counter for caller ID repetition */
char dialing[33]; /* dialed digits */ char dialing[33]; /* dialed digits */
char caller_id[33]; /* caller id digits */
enum number_type caller_type; /* caller id type */
int page_try; /* number of paging try */ int page_try; /* number of paging try */
int mft_num; /* counter for digit for MFT */ int mft_num; /* counter for digit for MFT */
@ -97,6 +101,7 @@ typedef struct nmt {
/* features */ /* features */
int compandor; /* if compandor shall be used */ int compandor; /* if compandor shall be used */
int supervisory; /* if set, use supervisory signal 1..4 */ int supervisory; /* if set, use supervisory signal 1..4 */
int send_callerid; /* if set, send caller ID while ringing the phone */
/* dsp states */ /* dsp states */
enum dsp_mode dsp_mode; /* current mode: audio, durable tone 0 or 1, paging */ enum dsp_mode dsp_mode; /* current mode: audio, durable tone 0 or 1, paging */
@ -152,7 +157,7 @@ const char *chan_type_long_name(enum nmt_chan_type chan_type);
double nmt_channel2freq(int channel, int uplink); double nmt_channel2freq(int channel, int uplink);
void nmt_country_list(void); void nmt_country_list(void);
uint8_t nmt_country_by_short_name(const char *short_name); uint8_t nmt_country_by_short_name(const char *short_name);
int nmt_create(int channel, enum nmt_chan_type chan_type, const char *sounddev, int samplerate, int cross_channels, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_wave, const char *read_wave, uint8_t ms_power, uint8_t traffic_area, uint8_t area_no, int compandor, int supervisory, const char *smsc_number, int loopback); int nmt_create(int channel, enum nmt_chan_type chan_type, const char *sounddev, int samplerate, int cross_channels, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_wave, const char *read_wave, uint8_t ms_power, uint8_t traffic_area, uint8_t area_no, int compandor, int supervisory, const char *smsc_number, int send_callerid, int loopback);
void nmt_destroy(sender_t *sender); void nmt_destroy(sender_t *sender);
void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double level, double frames_elapsed); void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double level, double frames_elapsed);
const char *nmt_get_frame(nmt_t *nmt); const char *nmt_get_frame(nmt_t *nmt);