Multi transceiver support

This can be multiple transceivers on multiple sound cards.

Two transceivers can be bundled on one sound device as well, using both channels.
This commit is contained in:
Andreas Eversberg
2016-04-25 20:20:54 +02:00
parent de0ce7ba98
commit 7434e21dc2
20 changed files with 709 additions and 161 deletions

View File

@@ -37,7 +37,8 @@
#include "announcement.h"
/* settings */
enum nmt_chan_type chan_type = CHAN_TYPE_CC_TC;
int num_chan_type = 0;
enum nmt_chan_type chan_type[MAX_SENDER] = { CHAN_TYPE_CC_TC };
int ms_power = 1; /* 1..3 */
char traffic_area[3] = "";
char area_no = 0;
@@ -49,7 +50,7 @@ void print_help(const char *arg0)
print_help_common(arg0, "-y <traffic area> | list ");
/* - - */
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));
printf(" Give channel type, use 'list' to get a list. (default = '%s')\n", chan_type_short_name(chan_type[0]));
printf(" -P --ms-power <power level>\n");
printf(" Give power level of the mobile station 1..3. (default = '%d')\n", ms_power);
printf(" 3 = 15 W / 7 W (handheld), 2 = 1.5 W, 1 = 150 mW\n");
@@ -99,7 +100,6 @@ static int handle_options(int argc, char **argv)
switch (c) {
case 't':
if (!strcmp(optarg, "list")) {
nmt_channel_list();
exit(0);
@@ -109,7 +109,7 @@ static int handle_options(int argc, char **argv)
fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg);
exit(0);
}
chan_type = rc;
OPT_ARRAY(num_chan_type, chan_type, rc)
skip_args += 2;
break;
case 'P':
@@ -192,6 +192,7 @@ int main(int argc, char *argv[])
int skip_args;
const char *station_id = "";
int mandatory = 0;
int i;
/* init common tones */
init_nmt_tones();
@@ -204,10 +205,22 @@ int main(int argc, char *argv[])
if (argc > 1)
station_id = argv[1];
if (!kanal) {
if (!num_kanal) {
printf("No channel (\"Kanal\") is specified, I suggest channel 1 (-k 1).\n\n");
mandatory = 1;
}
if (num_kanal == 1 && num_sounddev == 0)
num_sounddev = 1; /* use defualt */
if (num_kanal != num_sounddev) {
fprintf(stdout, "You need to specify as many sound devices as you have channels.\n");
exit(0);
}
if (num_kanal == 1 && num_chan_type == 0)
num_chan_type = 1; /* use defualt */
if (num_kanal != num_chan_type) {
fprintf(stdout, "You need to specify as many channel types as you have channels.\n");
exit(0);
}
if (!traffic_area[0]) {
printf("No traffic area is specified, I suggest to use Sweden (-y SE,1) and set the phone's roaming to 'SE' also.\n\n");
@@ -239,19 +252,17 @@ int main(int argc, char *argv[])
}
/* create transceiver instance */
rc = nmt_create(sounddev, samplerate, do_pre_emphasis, do_de_emphasis, write_wave, read_wave, kanal, (loopback) ? CHAN_TYPE_TEST : chan_type, ms_power, nmt_digits2value(traffic_area, 2), area_no, compander, supervisory, loopback);
if (rc < 0) {
fprintf(stderr, "Failed to create transceiver instance. Quitting!\n");
goto fail;
}
if (kanal > 200) {
printf("Base station ready, please tune transmitter to %.4f MHz and receiver "
"to %.4f MHz.\n", nmt_channel2freq(kanal, 0),
nmt_channel2freq(kanal, 1));
} else {
printf("Base station ready, please tune transmitter to %.3f MHz and receiver "
"to %.3f MHz.\n", nmt_channel2freq(kanal, 0),
nmt_channel2freq(kanal, 1));
for (i = 0; i < num_kanal; i++) {
rc = nmt_create(kanal[i], (loopback) ? CHAN_TYPE_TEST : chan_type[i], sounddev[i], samplerate, cross_channels, do_pre_emphasis, do_de_emphasis, write_wave, read_wave, ms_power, nmt_digits2value(traffic_area, 2), area_no, compander, supervisory, loopback);
if (rc < 0) {
fprintf(stderr, "Failed to create transceiver instance. Quitting!\n");
goto fail;
}
if (kanal[i] > 200) {
printf("Base station on channel %d ready, please tune transmitter to %.4f MHz and receiver to %.4f MHz.\n", kanal[i], nmt_channel2freq(kanal[i], 0), nmt_channel2freq(kanal[i], 1));
} else {
printf("Base station on channel %d ready, please tune transmitter to %.3f MHz and receiver to %.3f MHz.\n", kanal[i], nmt_channel2freq(kanal[i], 0), nmt_channel2freq(kanal[i], 1));
}
}
signal(SIGINT,sighandler);

View File

@@ -283,7 +283,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(const char *sounddev, int samplerate, int pre_emphasis, int de_emphasis, const char *write_wave, const char *read_wave, int channel, enum nmt_chan_type chan_type, uint8_t ms_power, uint8_t traffic_area, uint8_t area_no, int compander, int supervisory, int loopback)
int nmt_create(int channel, enum nmt_chan_type chan_type, const char *sounddev, int samplerate, int cross_channels, 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 compander, int supervisory, int loopback)
{
nmt_t *nmt;
int rc;
@@ -303,12 +303,12 @@ int nmt_create(const char *sounddev, int samplerate, int pre_emphasis, int de_em
if (chan_type == CHAN_TYPE_CC) {
PDEBUG(DNMT, DEBUG_NOTICE, "*** Selected channel can be used for calling only.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** No call from the mobile phone is possible.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** No call from the mobile phone is possible on this channel.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** Use combined 'CC/TC' instead!\n");
}
if (chan_type == CHAN_TYPE_TC) {
PDEBUG(DNMT, DEBUG_NOTICE, "*** Selected channel can be used for traffic only.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** No call to the mobile phone is possible.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** No call to the mobile phone is possible on this channel.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** Use combined 'CC/TC' instead!\n");
}
if (chan_type == CHAN_TYPE_TEST && !loopback) {
@@ -324,7 +324,7 @@ int nmt_create(const char *sounddev, int samplerate, int pre_emphasis, int de_em
PDEBUG(DNMT, DEBUG_DEBUG, "Creating 'NMT' instance for channel = %d (sample rate %d).\n", channel, samplerate);
/* init general part of transceiver */
rc = sender_create(&nmt->sender, sounddev, samplerate, pre_emphasis, de_emphasis, write_wave, read_wave, channel, loopback, 0, -1);
rc = sender_create(&nmt->sender, channel, sounddev, samplerate, cross_channels, pre_emphasis, de_emphasis, write_wave, read_wave, loopback, 0, -1);
if (rc < 0) {
PDEBUG(DNMT, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error;
@@ -372,6 +372,7 @@ void nmt_destroy(sender_t *sender)
static void nmt_go_idle(nmt_t *nmt)
{
timer_stop(&nmt->timer);
nmt->page_for_nmt = NULL;
PDEBUG(DNMT, DEBUG_INFO, "Entering IDLE state, sending idle frames on %s.\n", chan_type_long_name(nmt->sysinfo.chan_type));
nmt_new_state(nmt, STATE_IDLE);
@@ -395,13 +396,34 @@ static void nmt_release(nmt_t *nmt)
/* Enter paging state and transmit phone's number on calling channel */
static void nmt_page(nmt_t *nmt, char ms_country, const char *ms_number, int try)
{
sender_t *sender;
nmt_t *other;
PDEBUG(DNMT, DEBUG_INFO, "Entering paging state (try %d), sending call to '%c,%s'.\n", try, ms_country, ms_number);
nmt->subscriber.country = ms_country;
strcpy(nmt->subscriber.number, ms_number);
nmt->page_try = try;
nmt_new_state(nmt, STATE_MT_PAGING);
nmt_set_dsp_mode(nmt, DSP_MODE_FRAME);
nmt->tx_frame_count = 0;
/* page on all CC (CC/TC) */
for (sender = sender_head; sender; sender = sender->next) {
other = (nmt_t *)sender;
if (nmt->sysinfo.chan_type != CHAN_TYPE_CC
&& nmt->sysinfo.chan_type != CHAN_TYPE_CC_TC)
continue;
if (nmt->state != STATE_IDLE)
continue;
if (other == nmt) {
/* this is us */
PDEBUG(DNMT, DEBUG_INFO, "Paging on our channel %d.\n", other->sender.kanal);
} else {
/* this is not us */
PDEBUG(DNMT, DEBUG_INFO, "Paging on other channel %d.\n", other->sender.kanal);
other->page_for_nmt = nmt;
}
nmt_new_state(other, STATE_MT_PAGING);
nmt_set_dsp_mode(other, DSP_MODE_FRAME);
other->tx_frame_count = 0;
other->mt_channel = nmt->sender.kanal; /* ! channel from us (nmt->...) */
}
}
/*
@@ -801,6 +823,11 @@ static void tx_mt_paging(nmt_t *nmt, frame_t *frame)
tx_idle(nmt, frame);
/* wait some time to get answer. use more than one frame due to delay of audio processing */
if (nmt->tx_frame_count == 5) {
/* if we page for different channel, we go idle on timeout */
if (nmt->page_for_nmt) {
nmt_go_idle(nmt);
return;
}
PDEBUG(DNMT, DEBUG_NOTICE, "No answer from mobile phone (try %d).\n", nmt->page_try);
if (nmt->page_try == PAGE_TRIES) {
PDEBUG(DNMT, DEBUG_INFO, "Release call towards network.\n");
@@ -821,9 +848,16 @@ static void rx_mt_paging(nmt_t *nmt, frame_t *frame)
break;
if (!match_subscriber(nmt, frame))
break;
PDEBUG(DNMT, DEBUG_INFO, "Received call acknowledgement.\n");
PDEBUG(DNMT, DEBUG_INFO, "Received call acknowledgement on channel %d.\n", nmt->sender.kanal);
nmt_new_state(nmt, STATE_MT_CHANNEL);
nmt->tx_frame_count = 0;
if (nmt->page_for_nmt) {
PDEBUG(DNMT, DEBUG_INFO, " -> Notify initiating channel %d about this ack.\n", nmt->mt_channel);
/* we just send frame 2b on initiating channel, but this is ignored by the phone anyway.
* it would be correct to send frame 6 on initiating channel. */
nmt_new_state(nmt->page_for_nmt, STATE_MT_CHANNEL);
nmt->page_for_nmt->tx_frame_count = 0;
}
break;
default:
PDEBUG(DNMT, DEBUG_DEBUG, "Dropping message %s in state %s\n", nmt_frame_name(frame->index), nmt_state_name(nmt->state));
@@ -837,8 +871,13 @@ static void tx_mt_channel(nmt_t *nmt, frame_t *frame)
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->tc_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->tc_no = nmt_encode_channel(nmt->mt_channel, nmt->sysinfo.ms_power);
PDEBUG(DNMT, DEBUG_INFO, "Send channel activation to mobile.\n");
/* after assigning for differnet channel, we go idle. */
if (nmt->page_for_nmt) {
nmt_go_idle(nmt);
return;
}
nmt_new_state(nmt, STATE_MT_IDENT);
}

View File

@@ -85,6 +85,10 @@ typedef struct nmt {
char dialing[33]; /* dialed digits */
int page_try; /* number of paging try */
/* special state for paging on different CC */
struct nmt *page_for_nmt; /* only page and assign channel for nmt instance as set */
int mt_channel; /* channel to use */
/* features */
int compander; /* if compander shall be used */
int supervisory; /* if set, use supervisory signal 1..4 */
@@ -134,7 +138,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(const char *sounddev, int samplerate, int pre_emphasis, int de_emphasis, const char *write_wave, const char *read_wave, int channel, enum nmt_chan_type chan_type, uint8_t ms_power, uint8_t traffic_area, uint8_t area_no, int compander, int supervisory, int loopback);
int nmt_create(int channel, enum nmt_chan_type chan_type, const char *sounddev, int samplerate, int cross_channels, 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 compander, int supervisory, 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);