NMT: Caller ID support
This commit is contained in:
parent
ba8bf0e9d5
commit
4745b29115
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
224
src/nmt/nmt.c
224
src/nmt/nmt.c
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue