aboutsummaryrefslogtreecommitdiffstats
path: root/src/nmt
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2016-07-20 11:58:12 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2016-07-24 12:31:07 +0200
commit4745b291158fd5b10255f5cb18fed838c2125af0 (patch)
tree5ad44b8852287010b7eb230709b85ae84151b333 /src/nmt
parentba8bf0e9d535f1c9a4848a243ac1d5c700fbb3e6 (diff)
NMT: Caller ID support
Diffstat (limited to 'src/nmt')
-rw-r--r--src/nmt/dsp.c1
-rw-r--r--src/nmt/frame.c78
-rw-r--r--src/nmt/main.c15
-rw-r--r--src/nmt/nmt.c226
-rw-r--r--src/nmt/nmt.h7
5 files changed, 274 insertions, 53 deletions
diff --git a/src/nmt/dsp.c b/src/nmt/dsp.c
index 603d4c4..4badbc9 100644
--- a/src/nmt/dsp.c
+++ b/src/nmt/dsp.c
@@ -25,7 +25,6 @@
#include <math.h>
#include "../common/debug.h"
#include "../common/timer.h"
-#include "../common/call.h"
#include "../common/goertzel.h"
#include "nmt.h"
#include "dsp.h"
diff --git a/src/nmt/frame.c b/src/nmt/frame.c
index d76418f..4e18098 100644
--- a/src/nmt/frame.c
+++ b/src/nmt/frame.c
@@ -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 */
static struct nmt_frame {
enum nmt_mt message_type;
diff --git a/src/nmt/main.c b/src/nmt/main.c
index b29bb2b..8926885 100644
--- a/src/nmt/main.c
+++ b/src/nmt/main.c
@@ -31,7 +31,6 @@
#include "../common/main.h"
#include "../common/debug.h"
#include "../common/timer.h"
-#include "../common/call.h"
#include "../common/mncc_sock.h"
#include "nmt.h"
#include "frame.h"
@@ -53,10 +52,11 @@ char area_no = 0;
int compandor = 1;
int supervisory = 0;
const char *smsc_number = "767";
+int send_callerid = 0;
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(" 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(" If this number is dialed, the mobile is connected to the SMSC (Short\n");
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(" for every start of this program.\n");
}
@@ -98,10 +100,11 @@ static int handle_options(int argc, char **argv)
{"compandor", 1, 0, 'C'},
{"supervisory", 1, 0, '0'},
{"smsc-number", 1, 0, 'S'},
+ {"caller-id", 1, 0, 'I'},
{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) {
int option_index = 0, c, rc;
@@ -193,6 +196,10 @@ error_ta:
smsc_number = strdup(optarg);
skip_args += 2;
break;
+ case 'I':
+ send_callerid = atoi(optarg);
+ skip_args += 2;
+ break;
default:
opt_switch_common(c, argv[0], &skip_args);
}
@@ -337,7 +344,7 @@ int main(int argc, char *argv[])
/* create transceiver instance */
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) {
fprintf(stderr, "Failed to create transceiver instance. Quitting!\n");
goto fail;
diff --git a/src/nmt/nmt.c b/src/nmt/nmt.c
index 15200b0..1f006ee 100644
--- a/src/nmt/nmt.c
+++ b/src/nmt/nmt.c
@@ -25,7 +25,6 @@
#include <time.h>
#include "../common/debug.h"
#include "../common/timer.h"
-#include "../common/call.h"
#include "../common/cause.h"
#include "nmt.h"
#include "dsp.h"
@@ -288,7 +287,7 @@ static void nmt_timeout(struct timer *timer);
static void nmt_go_idle(nmt_t *nmt);
/* 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;
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->compandor = compandor;
nmt->supervisory = supervisory;
+ nmt->send_callerid = send_callerid;
strncpy(nmt->smsc_number, smsc_number, sizeof(nmt->smsc_number) - 1);
/* go into idle state */
@@ -519,6 +519,110 @@ static int match_subscriber(nmt_t *nmt, frame_t *frame)
}
/*
+ * 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
*/
@@ -593,26 +697,6 @@ static void rx_idle(nmt_t *nmt, frame_t *frame)
* 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)
{
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);
if (++nmt->tx_frame_count == 1)
PDEBUG(DNMT, DEBUG_INFO, "Send 'ringing order'.\n");
- if (nmt->tx_frame_count >= 4)
- frame->index = NMT_MESSAGE_6;
- /* repeat ringing after 5 seconds */
- if (nmt->tx_frame_count == 36)
- nmt->tx_frame_count = 0;
+ 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;
+ }
+ 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_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)
@@ -1056,7 +1155,7 @@ static void tx_mt_complete(nmt_t *nmt, frame_t *frame)
}
if (nmt->dms_call) {
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. */
-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;
nmt_t *nmt;
@@ -1501,17 +1600,23 @@ inval:
strncpy(nmt->sms_string, sms, sizeof(nmt->sms_string) - 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);
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).
@@ -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 */
void deliver_sms(const char *sms)
{
- int i, rc;
- char number[8];
+ int rc;
+ char buffer[strlen(sms) + 1], *p = buffer, *caller_id, *number, *message;
+ enum number_type caller_type;
+
+ strcpy(buffer, sms);
+ caller_id = strsep(&p, ",");
+ number = strsep(&p, ",");
+ message = p;
+ if (!caller_id || !number || !message) {
+inval:
+ 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;
+ }
+ if (strlen(number) != 7) {
+ PDEBUG(DNMT, DEBUG_NOTICE, "Given number must be 7 digits\n");
+ goto inval;
+ }
- /* check for number digits */
- for (i = 0; i < 7; i++) {
- if (sms[i] < '0' || sms[i] > '9')
+ 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;
}
- if (i < 7 || sms[7] != ',') {
- PDEBUG(DNMT, DEBUG_NOTICE, "Given SMS MUST start with the 7 digits phone number, followed by a comma (no spaces)\n");
- return;
- }
- strncpy(number, sms, 7);
- number[7] = '\0';
- sms += 8;
+
PDEBUG(DNMT, DEBUG_INFO, "SMS for subscriber '%s'\n", number);
- printf("SMS sending SMSC -> '%s': %s\n", number, sms);
+ printf("SMS sending '%s' -> '%s': %s\n", caller_id, number, sms);
- rc = sms_out_setup(number, sms);
+ rc = sms_out_setup(number, caller_id, caller_type, message);
if (rc < 0) {
PDEBUG(DNMT, DEBUG_INFO, "SMS delivery failed with cause '%d'\n", -rc);
return;
diff --git a/src/nmt/nmt.h b/src/nmt/nmt.h
index cd7ff24..16e2b97 100644
--- a/src/nmt/nmt.h
+++ b/src/nmt/nmt.h
@@ -1,6 +1,7 @@
#include "../common/sender.h"
#include "../common/compandor.h"
#include "../common/dtmf.h"
+#include "../common/call.h"
#include "dms.h"
#include "sms.h"
@@ -86,7 +87,10 @@ typedef struct nmt {
struct timer timer;
int rx_frame_count; /* receive frame counter */
int tx_frame_count; /* transmit frame counter */
+ int tx_callerid_count; /* counter for caller ID repetition */
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 mft_num; /* counter for digit for MFT */
@@ -97,6 +101,7 @@ typedef struct nmt {
/* features */
int compandor; /* if compandor shall be used */
int supervisory; /* if set, use supervisory signal 1..4 */
+ int send_callerid; /* if set, send caller ID while ringing the phone */
/* dsp states */
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);
void nmt_country_list(void);
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_receive_frame(nmt_t *nmt, const char *bits, double quality, double level, double frames_elapsed);
const char *nmt_get_frame(nmt_t *nmt);