NMT-900 System implementation

NMT can now be run as 450 or 900 Network.
This commit is contained in:
Andreas Eversberg
2017-07-22 10:38:18 +02:00
parent 0c9de251be
commit 3274812eab
8 changed files with 498 additions and 194 deletions

View File

@@ -541,22 +541,21 @@ Setup of a base station
<p> <p>
Before running the base station, you need to select a network. Before running the base station, you need to select a network.
The network is defined by the system (NMT-450 or NMT-900) and the Traffic Area (TA).
The NMT-450 is default.
To make the phone access the network, it needs to have the same network selected. To make the phone access the network, it needs to have the same network selected.
Check out what networks are available: Check out what networks are available:
</p> </p>
<pre> <pre>
# nmt -Y list # nmt -N 450 -Y list
TA Short Country (Provider) TA from TA to YY Code Channels Short Country (Provider)
------------------------------------------------------------------------ --------------------------------------------------------------------------------
5 DK Denmark (Tele Danmark Mobile) DK,1 DK,9 51..59 1-399 Denmark (Tele Danmark Mobile)
6 SE Sweden (Telia Mobitel) SE,1 SE,9 61..69 1-399 Sweden (Telia Mobitel)
7 NO Norway (Telenor Mobil) NO,1 NO,9 71..79 1-399 Norway (Telenor Mobil)
8 FI Finland (Telecom Finland) FI,1 FI,9 81..89 1-399 Finland (Telecom Finland)
8 IS Iceland (Post &amp; Telecom)
5 FO Faroe Island (Faroese Telecom)
7 EE Estonia (Eesti Mobiiltelefon)
... ...
</pre> </pre>

View File

@@ -32,7 +32,7 @@ struct nmt_frequency {
}; };
/* channel allocation used in scandinavian countries */ /* channel allocation used in scandinavian countries */
static struct nmt_frequency frq_scandinavia[] = { static struct nmt_frequency frq_450_scandinavia[] = {
{ 1, 180, 463.000, 0.025, 1.0, 10.0, 1 }, { 1, 180, 463.000, 0.025, 1.0, 10.0, 1 },
{ 181,200, 462.500, 0.025, 1.0, 10.0, 1 }, { 181,200, 462.500, 0.025, 1.0, 10.0, 1 },
{ 201,380, 463.0125, 0.025, 1.0, 10.0, 1 }, { 201,380, 463.0125, 0.025, 1.0, 10.0, 1 },
@@ -40,45 +40,69 @@ static struct nmt_frequency frq_scandinavia[] = {
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
}; };
static struct nmt_frequency frq_900_scandinavia[] = {
{ 1, 1000, 935.0125, 0.025, 1.0, 45.0, 0 },
{ 1025,2023, 935.025, 0.025, 1.0, 45.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
};
/* channel allocation used in Netherlands, Luxemburg, Belgium */ /* channel allocation used in Netherlands, Luxemburg, Belgium */
static struct nmt_frequency frq_nl_l_b[] = { static struct nmt_frequency frq_450_nl_l_b[] = {
{ 1, 222, 461.310, 0.020, 0.8, 10.0, 0 }, { 1, 222, 461.310, 0.020, 0.8, 10.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
}; };
static struct nmt_frequency frq_900_nl[] = {
{ 1, 1000, 935.0125, 0.025, 1.0, 45.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
};
/* channel allocation used in Malaysia */ /* channel allocation used in Malaysia */
static struct nmt_frequency frq_mal[] = { static struct nmt_frequency frq_450_mal[] = {
{ 1, 180, 462.000, 0.025, 1.0, 10.0, 0 }, { 1, 180, 462.000, 0.025, 1.0, 10.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
}; };
/* channel allocation used in Thailand, Indonesia */ /* channel allocation used in Thailand, Indonesia */
static struct nmt_frequency frq_t_ri[] = { static struct nmt_frequency frq_450_t_ri[] = {
{ 1, 224, 489.000, 0.020, 0.8, 10.0, 0 }, { 1, 224, 489.000, 0.020, 0.8, 10.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
}; };
/* channel allocation used in Spain */ /* channel allocation used in Spain */
static struct nmt_frequency frq_e[] = { static struct nmt_frequency frq_450_e[] = {
{ 1, 180, 464.325, 0.025, 1.0, 10.0, 0 }, { 1, 180, 464.325, 0.025, 1.0, 10.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
}; };
/* channel allocation used in Austria */ /* channel allocation used in Austria */
static struct nmt_frequency frq_a[] = { static struct nmt_frequency frq_450_a[] = {
{ 1, 180, 465.730, -0.020, 0.8, 10.0, 0 }, { 1, 180, 465.730, -0.020, 0.8, 10.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
}; };
/* channel allocation used in Czech Republic and Slovakia */ /* channel allocation used in Czech Republic and Slovakia */
static struct nmt_frequency frq_cz_sk[] = { static struct nmt_frequency frq_450_cz_sk[] = {
{ 1, 222, 465.730, -0.020, 0.8, 10.0, 0 }, { 1, 222, 465.730, -0.020, 0.8, 10.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
}; };
/* channel allocation used in Turkey */
static struct nmt_frequency frq_900_tr[] = {
{ 1, 180, 461.500, 0.025, 1.0, 10.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
};
/* channel allocation used in France */
static struct nmt_frequency frq_900_f[] = {
{ 1, 540, 430.050, 0.025, 1.0, -10.0, 0 },
{ 0, 0, 0.0, 0.0, 0.0, 0.0, 0 }
};
/* country selector */ /* country selector */
static struct nmt_country { static struct nmt_country {
int tested; int system; /* 450 or 900 */
int tested; /* tested with a real phone */
int y; /* country code of traffic area */ int y; /* country code of traffic area */
int first_ta, last_ta; /* range of used traffic areas */ int first_ta, last_ta; /* range of used traffic areas */
const char *short_name; const char *short_name;
@@ -86,47 +110,64 @@ static struct nmt_country {
const char *provider_name; const char *provider_name;
struct nmt_frequency *nmt_frequency; /* list of frequency allocations */ struct nmt_frequency *nmt_frequency; /* list of frequency allocations */
} nmt_country[] = { } nmt_country[] = {
{ 1, 5, 1,9, "DK", "Denmark", "Tele Danmark Mobile", frq_scandinavia }, /* 450 */
{ 1, 6, 1,9, "SE", "Sweden", "Telia Mobitel", frq_scandinavia }, { 450, 1, 5, 1,9, "DK", "Denmark", "Tele Danmark Mobile", frq_450_scandinavia },
{ 1, 7, 1,9, "NO", "Norway", "Telenor Mobil", frq_scandinavia }, { 450, 1, 6, 1,9, "SE", "Sweden", "Telia Mobitel", frq_450_scandinavia },
{ 1, 8, 1,9, "FI", "Finland", "Telecom Finland", frq_scandinavia }, { 450, 1, 7, 1,9, "NO", "Norway", "Telenor Mobil", frq_450_scandinavia },
{ 1, 8, 1,9, "IS", "Iceland", "Post & Telecom", frq_scandinavia }, { 450, 1, 8, 1,9, "FI", "Finland", "Telecom Finland", frq_450_scandinavia },
{ 1, 5, 1,9, "FO", "Faroe Island", "Faroese Telecom", frq_scandinavia }, { 450, 1, 8, 1,9, "IS", "Iceland", "Post & Telecom", frq_450_scandinavia },
{ 1, 7, 1,9, "EE", "Estonia", "Eesti Mobiiltelefon", frq_scandinavia }, { 450, 1, 5, 1,9, "FO", "Faroe Island", "Faroese Telecom", frq_450_scandinavia },
{ 1, 5, 1,9, "LV", "Latvia", "Latvian Mobile Telephone", frq_scandinavia }, { 450, 1, 7, 1,9, "EE", "Estonia", "Eesti Mobiiltelefon", frq_450_scandinavia },
{ 1, 8, 1,9, "LT", "Lithuania", "COMLIET", frq_scandinavia }, { 450, 1, 5, 1,9, "LV", "Latvia", "Latvian Mobile Telephone", frq_450_scandinavia },
{ 1, 6, 1,9, "BY", "Belarus", "Belcel", frq_scandinavia }, { 450, 1, 8, 1,9, "LT", "Lithuania", "COMLIET", frq_450_scandinavia },
{ 1, 5, 1,9, "MO", "OSS/Moscow", "Moscow Cellular Comm.", frq_scandinavia }, { 450, 1, 6, 1,9, "BY", "Belarus", "Belcel", frq_450_scandinavia },
{ 1, 6, 1,9, "STP", "OSS/St Petersburg", "Delta Telecom", frq_scandinavia }, { 450, 1, 5, 1,9, "MO", "OSS/Moscow", "Moscow Cellular Comm.", frq_450_scandinavia },
{ 1, 6, 1,9, "STP", "OSS/Leningrads Dist.", "Delta Telecom", frq_scandinavia }, { 450, 1, 6, 1,9, "STP", "OSS/St Petersburg", "Delta Telecom", frq_450_scandinavia },
{ 1, 7, 1,9, "CAR", "OSS/Carelian Rep.", "Telecom Finland", frq_scandinavia }, { 450, 1, 6, 1,9, "STP", "OSS/Leningrads Dist.", "Delta Telecom", frq_450_scandinavia },
{ 1, 5, 1,9, "MUR", "OSS/Murmansk", "Telecom Finland", frq_scandinavia }, { 450, 1, 7, 1,9, "CAR", "OSS/Carelian Rep.", "Telecom Finland", frq_450_scandinavia },
{ 1, 5, 1,9, "LED", "OSS/Leningrads Dist.", "Telecom Finland", frq_scandinavia }, { 450, 1, 5, 1,9, "MUR", "OSS/Murmansk", "Telecom Finland", frq_450_scandinavia },
{ 1, 5, 1,9, "KAL", "Kaliningrad", "Telecom Finland", frq_scandinavia }, { 450, 1, 5, 1,9, "LED", "OSS/Leningrads Dist.", "Telecom Finland", frq_450_scandinavia },
{ 1, 7, 1,9, "PL", "Poland", "CENTERTEL", frq_scandinavia }, { 450, 1, 5, 1,9, "KAL", "Kaliningrad", "Telecom Finland", frq_450_scandinavia },
{ 1, 6, 1,9, "BG", "Bulgaria", "MOBIFON", frq_scandinavia }, { 450, 1, 7, 1,9, "PL", "Poland", "CENTERTEL", frq_450_scandinavia },
{ 1, 5, 1,9, "RO", "Romania", "Telefonica Romania", frq_scandinavia }, { 450, 1, 6, 1,9, "BG", "Bulgaria", "MOBIFON", frq_450_scandinavia },
{ 1, 6, 1,9, "UA", "Ukraine", "Ukraine Mobile Comm.", frq_scandinavia }, { 450, 1, 5, 1,9, "RO", "Romania", "Telefonica Romania", frq_450_scandinavia },
{ 1, 1, 1,9, "RU1", "", "", frq_scandinavia }, { 450, 1, 6, 1,9, "UA", "Ukraine", "Ukraine Mobile Comm.", frq_450_scandinavia },
{ 1, 2, 1,9, "RU2", "", "", frq_scandinavia }, { 450, 1, 1, 1,9, "RU1", "", "", frq_450_scandinavia },
{ 1, 3, 1,9, "RU3", "", "", frq_scandinavia }, { 450, 1, 2, 1,9, "RU2", "", "", frq_450_scandinavia },
{ 1, 4, 1,9, "RU4", "", "", frq_scandinavia }, { 450, 1, 3, 1,9, "RU3", "", "", frq_450_scandinavia },
{ 1, 1, 1,9, "NL", "Netherlands", "Royal Dutch Post & Telecom", frq_nl_l_b }, { 450, 1, 4, 1,9, "RU4", "", "", frq_450_scandinavia },
{ 1, 1, 15,15, "L", "Luxemburg", "Enterprise des P&T Luxembourg",frq_nl_l_b }, { 450, 1, 1, 1,9, "NL", "Netherlands", "Royal Dutch Post & Telecom", frq_450_nl_l_b },
{ 1, 2, 1,9, "B", "Belgium", "Belgacom Mobile", frq_nl_l_b }, { 450, 1, 1, 15,15, "L", "Luxemburg", "Enterprise des P&T Luxembourg",frq_450_nl_l_b },
{ 1, 7, 1,9, "CZ", "Czech Republic", "Eurotel Prague", frq_cz_sk }, { 450, 1, 2, 1,9, "B", "Belgium", "Belgacom Mobile", frq_450_nl_l_b },
{ 1, 6, 1,9, "SK", "Slovakia", "Eurotel Bratislava", frq_cz_sk }, { 450, 1, 7, 1,9, "CZ", "Czech Republic", "Eurotel Prague", frq_450_cz_sk },
{ 450, 1, 6, 1,9, "SK", "Slovakia", "Eurotel Bratislava", frq_450_cz_sk },
/* 900 */
{ 900, 1, 1, 1,9, "DK", "Denmark", "Tele Danmark Mobile", frq_900_scandinavia },
{ 900, 1, 2, 1,9, "SE", "Sweden", "Telia Mobitel", frq_900_scandinavia },
{ 900, 1, 3, 1,9, "NO", "Norway", "Telenor Mobil", frq_900_scandinavia },
{ 900, 1, 4, 1,9, "FI", "Finland", "Telecom Finland", frq_900_scandinavia },
/* untested... */ /* untested... */
{ 0, 8, 8,8, "MAL", "Malaysia", "Jabatan Telekom Malaysia", frq_mal }, { 450, 0, 8, 8,8, "MAL", "Malaysia", "Jabatan Telekom Malaysia", frq_450_mal },
{ 0, 4, 1,9, "T", "Thailand", "Telephone Organization of Thailand",frq_t_ri }, { 450, 0, 4, 1,9, "T", "Thailand", "Telephone Organization of Thailand",frq_450_t_ri },
{ 0, 8, 1,9, "E", "Spain", "Telefonica Servicios Moviles", frq_e }, { 450, 0, 8, 1,9, "E", "Spain", "Telefonica Servicios Moviles", frq_450_e },
{ 0, 8, 1,1, "RI", "Indonesia", "PT Mobisel", frq_t_ri }, { 450, 0, 8, 1,1, "RI", "Indonesia", "PT Mobisel", frq_450_t_ri },
{ 0, 0, 1,3, "A", "Austria", "PTV", frq_a }, { 450, 0, 0, 1,3, "A", "Austria", "PTV", frq_450_a },
{ 0, 9, 1,3, "A2", "Austria 2", "PTV", frq_a }, { 450, 0, 9, 1,3, "A2", "Austria 2", "PTV", frq_450_a },
{ 0, 0, 0,0, NULL, NULL, NULL, NULL } { 900, 0, 5, 1,9, "CH", "Switzerland", "PTT", frq_900_scandinavia },
{ 900, 0, 6, 1,15, "NL", "Netherlands", "Royal Dutch Post & Telecom", frq_900_nl },
{ 900, 0, 1, 1,9, "TR", "Turkey", "Turkcell", frq_900_tr },
{ 900, 0, 0, 1,9, "F0", "France (Group 0)", "France Telecom", frq_900_f },
{ 900, 0, 1, 1,9, "F1", "France (Group 1)", "France Telecom", frq_900_f },
{ 900, 0, 2, 1,9, "F2", "France (Group 2)", "France Telecom", frq_900_f },
{ 900, 0, 3, 1,9, "F3", "France (Group 3)", "France Telecom", frq_900_f },
{ 900, 0, 4, 1,9, "F4", "France (Group 4)", "France Telecom", frq_900_f },
{ 900, 0, 5, 1,9, "F5", "France (Group 5)", "France Telecom", frq_900_f },
{ 900, 0, 6, 1,9, "F6", "France (Group 6)", "France Telecom", frq_900_f },
{ 900, 0, 7, 1,9, "F7", "France (Group 7)", "France Telecom", frq_900_f },
{ 0,0, 0, 0,0, NULL, NULL, NULL, NULL }
}; };
void nmt_country_list(void) void nmt_country_list(int nmt_system)
{ {
int i, j; int i, j;
int ch_from = 0, ch_to = 0; int ch_from = 0, ch_to = 0;
@@ -135,6 +176,8 @@ void nmt_country_list(void)
printf("TA from\tTA to\tYY Code\tChannels\tShort\tCountry (Provider)\n"); printf("TA from\tTA to\tYY Code\tChannels\tShort\tCountry (Provider)\n");
printf("--------------------------------------------------------------------------------\n"); printf("--------------------------------------------------------------------------------\n");
for (i = 0; nmt_country[i].short_name; i++) { for (i = 0; nmt_country[i].short_name; i++) {
if (nmt_system != nmt_country[i].system)
continue;
printf("%s,%d\t", nmt_country[i].short_name, nmt_country[i].first_ta); printf("%s,%d\t", nmt_country[i].short_name, nmt_country[i].first_ta);
if (nmt_country[i].first_ta != nmt_country[i].last_ta) if (nmt_country[i].first_ta != nmt_country[i].last_ta)
printf("%s,%d", nmt_country[i].short_name, nmt_country[i].last_ta); printf("%s,%d", nmt_country[i].short_name, nmt_country[i].last_ta);
@@ -155,11 +198,13 @@ void nmt_country_list(void)
} }
} }
int nmt_country_by_short_name(const char *short_name) int nmt_country_by_short_name(int nmt_system, const char *short_name)
{ {
int i; int i;
for (i = 0; nmt_country[i].short_name; i++) { for (i = 0; nmt_country[i].short_name; i++) {
if (nmt_system != nmt_country[i].system)
continue;
if (!strcasecmp(nmt_country[i].short_name, short_name)) if (!strcasecmp(nmt_country[i].short_name, short_name))
return nmt_country[i].y; return nmt_country[i].y;
} }
@@ -167,11 +212,13 @@ int nmt_country_by_short_name(const char *short_name)
return -1; return -1;
} }
const char *nmt_long_name_by_short_name(const char *short_name) const char *nmt_long_name_by_short_name(int nmt_system, const char *short_name)
{ {
int i; int i;
for (i = 0; nmt_country[i].short_name; i++) { for (i = 0; nmt_country[i].short_name; i++) {
if (nmt_system != nmt_country[i].system)
continue;
if (!strcasecmp(nmt_country[i].short_name, short_name)) if (!strcasecmp(nmt_country[i].short_name, short_name))
return nmt_country[i].long_name; return nmt_country[i].long_name;
} }
@@ -179,11 +226,13 @@ const char *nmt_long_name_by_short_name(const char *short_name)
return NULL; return NULL;
} }
int nmt_ta_by_short_name(const char *short_name, int ta) int nmt_ta_by_short_name(int nmt_system, const char *short_name, int ta)
{ {
int i; int i;
for (i = 0; nmt_country[i].short_name; i++) { for (i = 0; nmt_country[i].short_name; i++) {
if (nmt_system != nmt_country[i].system)
continue;
if (!strcasecmp(nmt_country[i].short_name, short_name) && ta >= nmt_country[i].first_ta && ta <= nmt_country[i].last_ta) if (!strcasecmp(nmt_country[i].short_name, short_name) && ta >= nmt_country[i].first_ta && ta <= nmt_country[i].last_ta)
return ta; return ta;
} }
@@ -193,12 +242,14 @@ int nmt_ta_by_short_name(const char *short_name, int ta)
/* Convert channel number to frequency number of base station. /* Convert channel number to frequency number of base station.
Set 'uplink' to 1 to get frequency of mobile station. */ Set 'uplink' to 1 to get frequency of mobile station. */
double nmt_channel2freq(const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested) double nmt_channel2freq(int nmt_system, const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested)
{ {
int i, j; int i, j;
double freq; double freq;
for (i = 0; nmt_country[i].short_name; i++) { for (i = 0; nmt_country[i].short_name; i++) {
if (nmt_system != nmt_country[i].system)
continue;
if (!strcasecmp(nmt_country[i].short_name, short_name)) { if (!strcasecmp(nmt_country[i].short_name, short_name)) {
for (j = 0; nmt_country[i].nmt_frequency[j].first_frequency; j++) { for (j = 0; nmt_country[i].nmt_frequency[j].first_frequency; j++) {
if (channel >= nmt_country[i].nmt_frequency[j].first_channel if (channel >= nmt_country[i].nmt_frequency[j].first_channel

View File

@@ -1,7 +1,7 @@
void nmt_country_list(void); void nmt_country_list(int nmt_system);
int nmt_country_by_short_name(const char *short_name); int nmt_country_by_short_name(int nmt_system, const char *short_name);
const char *nmt_long_name_by_short_name(const char *short_name); const char *nmt_long_name_by_short_name(int nmt_system, const char *short_name);
int nmt_ta_by_short_name(const char *short_name, int ta); int nmt_ta_by_short_name(int nmt_system, const char *short_name, int ta);
double nmt_channel2freq(const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested); double nmt_channel2freq(int nmt_system, const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested);

View File

@@ -29,10 +29,11 @@
#include "frame.h" #include "frame.h"
#include "hagelbarger.h" #include "hagelbarger.h"
uint64_t nmt_encode_channel(int channel, int power) uint64_t nmt_encode_channel(int nmt_system, int channel, int power)
{ {
uint64_t value = 0; uint64_t value = 0;
if (nmt_system == 450) {
if (channel >= 200) { if (channel >= 200) {
value |= 0x800; value |= 0x800;
channel -= 200; channel -= 200;
@@ -44,12 +45,67 @@ uint64_t nmt_encode_channel(int channel, int power)
value |= channel % 10; value |= channel % 10;
value |= (channel / 10) << 4; value |= (channel / 10) << 4;
value |= power << 9; value |= power << 9;
} else {
/* interleaved channels are indicated in traffic area */
if (value > 1000)
value -= 1000;
value |= channel;
/* if channel >= 512, set upper bit */
if (value & 0x200)
value = value - 0x200 + 0x800;
value |= power << 9;
}
return value; return value;
} }
int nmt_decode_channel(uint64_t value, int *channel, int *power) int nmt_decode_channel(int nmt_system, uint64_t value, int *channel, int *power)
{ {
if (nmt_system == 450) {
if ((value & 0x00f) > 0x009)
return -1;
if ((value & 0x0f0) > 0x090)
return -1;
*channel = (value & 0x00f) +
((value & 0x0f0) >> 4) * 10 +
((value & 0x100) >> 8) * 100 +
((value & 0x800) >> 11) * 200;
} else {
*channel = (value & 0x1ff) +
((value & 0x800) >> 2);
}
*power = (value & 0x600) >> 9;
return 0;
}
uint64_t nmt_encode_tc(int nmt_system, int channel, int power)
{
uint64_t value = 0;
if (nmt_system == 450) {
if (channel >= 200) {
value |= 0x800;
channel -= 200;
}
if (channel >= 100) {
value |= 0x100;
channel -= 100;
}
value |= channel % 10;
value |= (channel / 10) << 4;
value |= power << 9;
} else {
value = channel;
}
return value;
}
static int nmt_decode_tc(int nmt_system, uint64_t value, int *channel, int *power)
{
if (nmt_system == 450) {
if ((value & 0x00f) > 0x009) if ((value & 0x00f) > 0x009)
return -1; return -1;
if ((value & 0x0f0) > 0x090) if ((value & 0x0f0) > 0x090)
@@ -60,10 +116,29 @@ int nmt_decode_channel(uint64_t value, int *channel, int *power)
((value & 0x100) >> 8) * 100 + ((value & 0x100) >> 8) * 100 +
((value & 0x800) >> 11) * 200; ((value & 0x800) >> 11) * 200;
*power = (value & 0x600) >> 9; *power = (value & 0x600) >> 9;
} else {
*channel = value & 0x3ff;
}
return 0; return 0;
} }
uint64_t nmt_encode_traffic_area(int nmt_system, int channel, uint8_t traffic_area)
{
uint64_t value = 0;
if (nmt_system == 450) {
value = traffic_area;
} else {
/* upper bit is used for indication of interleaved channel */
value = traffic_area & 0x7f;
if (channel > 1000)
value |= 0x80;
}
return value;
}
void nmt_value2digits(uint64_t value, char *digits, int num) void nmt_value2digits(uint64_t value, char *digits, int num)
{ {
int digit, i; int digit, i;
@@ -214,24 +289,30 @@ static struct nmt_frame {
} nmt_frame[] = { } nmt_frame[] = {
/* Define Digits Dir. Prefix Nr. Description */ /* Define Digits Dir. Prefix Nr. Description */
{ NMT_MESSAGE_1a, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 12, "1a", "Calling channel indication" }, { NMT_MESSAGE_1a, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 12, "1a", "Calling channel indication" },
{ NMT_MESSAGE_1a_a, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 11, "1a'", "Calling channel indication (for MS group A)" },
{ NMT_MESSAGE_1a_b, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 13, "1a''", "Calling channel indication (for MS group B)" },
{ NMT_MESSAGE_1b, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 4, "1b", "Combined calling and traffic channel indication" }, { NMT_MESSAGE_1b, "NNNPYYHHHHHHHHHH", MTX_TO_MS, 4, "1b", "Combined calling and traffic channel indication" },
{ NMT_MESSAGE_2a, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2a", "Call to mobile subscriber on calling channel" }, { NMT_MESSAGE_2a, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2a", "Call to mobile subscriber on calling channel" },
{ NMT_MESSAGE_2b, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 12, "2b", "Traffic channel allocation on calling channel" }, { NMT_MESSAGE_2b, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 12, "2b", "Traffic channel allocation on calling channel" },
{ NMT_MESSAGE_2c, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2c", "Queueing information to MS with priority on calling channel" }, { NMT_MESSAGE_2c, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2c", "Queueing information to MS with priority on calling channel" },
{ NMT_MESSAGE_2d, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2d", "Traffic channel scanning order on calling channel" }, { NMT_MESSAGE_2d, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2d", "Traffic channel scanning order on calling channel" },
{ NMT_MESSAGE_2e, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 4, "2e", "Alternative type of call to MS on combinded CC/TC" },
{ NMT_MESSAGE_2f, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2f", "Queuing information to ordinary MS" }, { NMT_MESSAGE_2f, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 12, "2f", "Queuing information to ordinary MS" },
{ NMT_MESSAGE_3a, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 5, "3a", "Traffic channel allocation on traffic channel" }, { NMT_MESSAGE_3a, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 5, "3a", "Traffic channel allocation on traffic channel" },
{ NMT_MESSAGE_3b, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 5, "3b", "Identity request on traffic channel" }, { NMT_MESSAGE_3b, "NNNPYYZXXXXXXHHH", MTX_TO_MS, 5, "3b", "Identity request on traffic channel" },
{ NMT_MESSAGE_3c, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 9, "3c", "Traffic channel allocation on traffic channel, short procedure" }, { NMT_MESSAGE_3c, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 9, "3c", "Traffic channel allocation on traffic channel, short procedure" },
{ NMT_MESSAGE_3d, "NNNPYYZXXXXXXnnn", MTX_TO_MS, 7, "3d", "Traffic channel allocation on access channel" },
{ NMT_MESSAGE_4, "NNNPYYJJJJJJJHHH", MTX_TO_MS, 3, "4", "Free traffic channel indication" }, { NMT_MESSAGE_4, "NNNPYYJJJJJJJHHH", MTX_TO_MS, 3, "4", "Free traffic channel indication" },
{ NMT_MESSAGE_4b, "NNNPYYJJJJJJJHHH", MTX_TO_MS, 7, "4b", "Access channel indication" },
{ NMT_MESSAGE_5a, "NNNPYYZXXXXXXLLL", MTX_TO_MS, 6, "5a", "Line signal" }, { NMT_MESSAGE_5a, "NNNPYYZXXXXXXLLL", MTX_TO_MS, 6, "5a", "Line signal" },
{ NMT_MESSAGE_5b, "NNNPYYZXXXXXXLQQ", MTX_TO_MS, 6, "5b", "Line signal: Answer to coin-box" }, { NMT_MESSAGE_5b, "NNNPYYZXXXXXXLQQ", MTX_TO_MS, 6, "5b", "Line signal: Answer to coin-box" },
{ NMT_MESSAGE_6, "JJJPJJJJJJJJJJJJ", MTX_TO_XX, 0, "6", "Idle frame" }, { NMT_MESSAGE_6, "JJJPJJJJJJJJJJJJ", MTX_TO_XX, 0, "6", "Idle frame" },
{ NMT_MESSAGE_7, "NNNPYYCCCCCCCJJJ", MTX_TO_MS, 8, "7", "Authentication request" }, { NMT_MESSAGE_7, "NNNPYYCCCCCCCJJJ", MTX_TO_MS, 8, "7", "Authentication request" },
{ NMT_MESSAGE_8, "NNNPYYMHHHHHHHWW", MTX_TO_MS, 1, "8", "A-subscriber number" }, { NMT_MESSAGE_8, "NNNPYYMHHHHHHHWW", MTX_TO_MS, 1, "8", "A-subscriber number" },
{ NMT_MESSAGE_10a, "NNNPZXXXXXXTJJJJ", MS_TO_MTX, 1, "10a", "Call acknowledgment from MS on calling channel (shortened frame)" }, { NMT_MESSAGE_10a, "NNNPZXXXXXXTJJJJ", MS_TO_MTX, 1, "10a", "Call acknowledgment from MS on calling channel and access on access channel (shortened frame)" },
{ NMT_MESSAGE_10b, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 1, "10b", "Seizure from ordinary MS and identity on traffic channel" }, { NMT_MESSAGE_10b, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 1, "10b", "Seizure from ordinary MS and identity on traffic channel" },
{ NMT_MESSAGE_10c, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 6, "10c", "Seizure and identity from called MS on traffic channel" }, { NMT_MESSAGE_10c, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 6, "10c", "Seizure and identity from called MS on traffic channel" },
{ NMT_MESSAGE_10d, "NNNPZXXXXXXTJJJJ", MS_TO_MTX, 6, "10c", "Call acknowledgement from MS on the alternative type of call on combined CC/TC (shortened frame)" },
{ NMT_MESSAGE_11a, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 14, "11a", "Roaming updating seizure and identity on traffic channel" }, { NMT_MESSAGE_11a, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 14, "11a", "Roaming updating seizure and identity on traffic channel" },
{ NMT_MESSAGE_11b, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 15, "11b", "Seizure and call achnowledgment on calling channel from MS with priority (shortened frame)" }, { NMT_MESSAGE_11b, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 15, "11b", "Seizure and call achnowledgment on calling channel from MS with priority (shortened frame)" },
{ NMT_MESSAGE_12, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 11, "12", "Seizure from coin-box on traffic channel" }, { NMT_MESSAGE_12, "NNNPZXXXXXXTYKKK", MS_TO_MTX, 11, "12", "Seizure from coin-box on traffic channel" },
@@ -288,12 +369,12 @@ static const char *param_hex(uint64_t value, int __attribute__((unused)) ndigits
return result; return result;
} }
static const char *param_channel_no(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction) static const char *param_channel_no_450(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction)
{ {
static char result[32]; static char result[32];
int rc, channel, power; int rc, channel, power;
rc = nmt_decode_channel(value, &channel, &power); rc = nmt_decode_channel(450, value, &channel, &power);
if (rc < 0) if (rc < 0)
sprintf(result, "invalid(%" PRIu64 ")", value); sprintf(result, "invalid(%" PRIu64 ")", value);
else else
@@ -302,6 +383,48 @@ static const char *param_channel_no(uint64_t value, int __attribute__((unused))
return result; return result;
} }
static const char *param_channel_no_900(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction)
{
static char result[32];
int rc, channel, power;
rc = nmt_decode_channel(900, value, &channel, &power);
if (rc < 0)
sprintf(result, "invalid(%" PRIu64 ")", value);
else
sprintf(result, "channel=%d power=%d", channel, power);
return result;
}
static const char *param_tc_no_450(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction)
{
static char result[32];
int rc, channel, power;
rc = nmt_decode_tc(450, value, &channel, &power);
if (rc < 0)
sprintf(result, "invalid(%" PRIu64 ")", value);
else
sprintf(result, "channel=%d power=%d", channel, power);
return result;
}
static const char *param_tc_no_900(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction)
{
static char result[32];
int rc, channel;
rc = nmt_decode_tc(900, value, &channel, NULL);
if (rc < 0)
sprintf(result, "invalid(%" PRIu64 ")", value);
else
sprintf(result, "channel=%d", channel);
return result;
}
static const char *param_country(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction) static const char *param_country(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction)
{ {
static char result[32]; static char result[32];
@@ -310,7 +433,7 @@ static const char *param_country(uint64_t value, int __attribute__((unused)) ndi
case 0: case 0:
return "no additional info"; return "no additional info";
case 1: case 1:
return "Netherlands / Luxemburg / Malaysia"; return "Netherlands / Luxemburg / Malaysia / Switzerland";
case 2: case 2:
return "Belgium"; return "Belgium";
case 4: case 4:
@@ -347,7 +470,7 @@ static const char *param_number(uint64_t value, int ndigits, enum nmt_direction
return result; return result;
} }
static const char *param_ta(uint64_t value, int ndigits, enum nmt_direction __attribute__((unused)) direction) static const char *param_ta_450(uint64_t value, int ndigits, enum nmt_direction __attribute__((unused)) direction)
{ {
static char result[32]; static char result[32];
@@ -357,6 +480,18 @@ static const char *param_ta(uint64_t value, int ndigits, enum nmt_direction __at
return result; return result;
} }
static const char *param_ta_900(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction __attribute__((unused)) direction)
{
static char result[32];
if ((value & 0x80))
sprintf(result, "%" PRIu64 " (Channel No. + 1000)", value & 0x7f);
else
sprintf(result, "%" PRIu64, value);
return result;
}
static const char *param_line_signal(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction direction) static const char *param_line_signal(uint64_t value, int __attribute__((unused)) ndigits, enum nmt_direction direction)
{ {
char *desc = "Spare"; char *desc = "Spare";
@@ -477,34 +612,38 @@ static const char *param_password(uint64_t value, int ndigits, enum nmt_directio
} }
static struct nmt_parameter { static struct nmt_parameter {
int system;
char digit; char digit;
const char *description; const char *description;
const char *(*decoder)(uint64_t value, int ndigits, enum nmt_direction direction); const char *(*decoder)(uint64_t value, int ndigits, enum nmt_direction direction);
} nmt_parameter[] = { } nmt_parameter[] = {
{ 'N', "Channel No.", param_channel_no }, { 450, 'N', "Channel No.", param_channel_no_450 },
{ 'n', "TC No.", param_channel_no }, { 900, 'N', "Channel No.", param_channel_no_900 },
{ 'Y', "Traffic area", param_ta }, { 450, 'n', "TC No.", param_tc_no_450 },
{ 'Z', "Mobile subscriber country", param_country }, { 900, 'n', "TC No.", param_tc_no_900 },
{ 'X', "Mobile subscriber No.", param_number }, { 450, 'Y', "Traffic area", param_ta_450 },
{ 'Q', "Tariff class", param_integer }, { 900, 'Y', "Traffic area", param_ta_900 },
{ 'L', "Line signal", param_line_signal }, { 0, 'Z', "Mobile subscriber country", param_country },
{ 'S', "Digit signals", param_digit }, { 0, 'X', "Mobile subscriber No.", param_number },
{ 'J', "Idle information", param_hex }, { 0, 'Q', "Tariff class", param_integer },
{ 'A', "Channel activation", param_hex }, { 0, 'L', "Line signal", param_line_signal },
{ 'V', "Management order", param_hex }, { 0, 'S', "Digit signals", param_digit },
{ 'r', "Measurement results", param_hex }, { 0, 'J', "Idle information", param_hex },
{ 'P', "Prefix", param_integer }, { 0, 'A', "Channel activation", param_hex },
{ 'f', "Supervisory signal", param_supervisory }, { 0, 'V', "Management order", param_hex },
{ 'K', "Mobile subscriber password", param_password }, { 0, 'r', "Measurement results", param_hex },
{ 'T', "Area info", param_hex }, { 0, 'P', "Prefix", param_integer },
{ 'H', "Additional info", param_hex }, { 0, 'f', "Supervisory signal", param_supervisory },
{ 'C', "Random challenge", param_hex }, { 0, 'K', "Mobile subscriber password", param_password },
{ 'R', "Signed response", param_hex }, { 0, 'T', "Area info", param_hex },
{ 'l', "Limit strength evaluation", param_hex }, { 0, 'H', "Additional info", param_hex },
{ 'c', "c", param_hex }, { 0, 'C', "Random challenge", param_hex },
{ 'M', "Sequence Number", param_integer }, { 0, 'R', "Signed response", param_hex },
{ 'W', "Checksum", param_hex }, { 0, 'l', "Limit strength evaluation", param_hex },
{ 0, NULL, NULL } { 0, 'c', "c", param_hex },
{ 0, 'M', "Sequence Number", param_integer },
{ 0, 'W', "Checksum", param_hex },
{ 0, 0, NULL, NULL }
}; };
/* Depending on P-value, direction and additional info, frame index (used for /* Depending on P-value, direction and additional info, frame index (used for
@@ -582,7 +721,16 @@ enum nmt_mt decode_frame_mt(const uint8_t *digits, enum nmt_direction direction,
return NMT_MESSAGE_21b; return NMT_MESSAGE_21b;
return NMT_MESSAGE_4; return NMT_MESSAGE_4;
case 4: case 4:
switch((digits[13] << 8) + (digits[14] << 4) + digits[15]) {
case 0x3f3:
case 0x3f4:
case 0x3f5:
case 0x3f6:
case 0x000:
return NMT_MESSAGE_2e;
default:
return NMT_MESSAGE_1b; return NMT_MESSAGE_1b;
}
case 5: case 5:
if (digits[6] == 15) if (digits[6] == 15)
return NMT_MESSAGE_21c; return NMT_MESSAGE_21c;
@@ -601,7 +749,16 @@ enum nmt_mt decode_frame_mt(const uint8_t *digits, enum nmt_direction direction,
return NMT_MESSAGE_5b; return NMT_MESSAGE_5b;
return NMT_MESSAGE_5a; return NMT_MESSAGE_5a;
case 7: case 7:
break; switch((digits[13] << 8) + (digits[14] << 4) + digits[15]) {
case 0x3f3:
case 0x3f4:
case 0x3f5:
case 0x3f6:
case 0x000:
return NMT_MESSAGE_4b;
default:
return NMT_MESSAGE_3d;
}
case 8: case 8:
return NMT_MESSAGE_7; return NMT_MESSAGE_7;
case 9: case 9:
@@ -609,7 +766,7 @@ enum nmt_mt decode_frame_mt(const uint8_t *digits, enum nmt_direction direction,
case 10: case 10:
return NMT_MESSAGE_30; return NMT_MESSAGE_30;
case 11: case 11:
break; return NMT_MESSAGE_1a_a;
case 12: case 12:
/* no subscriber */ /* no subscriber */
if (digits[6] == 0) if (digits[6] == 0)
@@ -637,7 +794,7 @@ enum nmt_mt decode_frame_mt(const uint8_t *digits, enum nmt_direction direction,
return NMT_MESSAGE_2b; return NMT_MESSAGE_2b;
} }
case 13: case 13:
break; return NMT_MESSAGE_1a_b;
case 14: case 14:
if (digits[13] != 15) if (digits[13] != 15)
break; break;
@@ -697,7 +854,7 @@ int init_frame(void)
} }
/* decode 16 digits frame */ /* decode 16 digits frame */
static void disassemble_frame(frame_t *frame, const uint8_t *digits, enum nmt_direction direction, int callack) static void disassemble_frame(int nmt_system, frame_t *frame, const uint8_t *digits, enum nmt_direction direction, int callack)
{ {
enum nmt_mt mt; enum nmt_mt mt;
int i, j, ndigits; int i, j, ndigits;
@@ -804,6 +961,8 @@ static void disassemble_frame(frame_t *frame, const uint8_t *digits, enum nmt_di
} }
if (debuglevel <= DEBUG_DEBUG) { if (debuglevel <= DEBUG_DEBUG) {
for (j = 0; nmt_parameter[j].digit; j++) { for (j = 0; nmt_parameter[j].digit; j++) {
if (nmt_parameter[j].system != 0 && nmt_parameter[j].system != nmt_system)
continue;
if (nmt_parameter[j].digit == digit) { if (nmt_parameter[j].digit == digit) {
PDEBUG(DFRAME, DEBUG_DEBUG, " %c: %s\n", digit, nmt_parameter[j].decoder(value, ndigits, direction)); PDEBUG(DFRAME, DEBUG_DEBUG, " %c: %s\n", digit, nmt_parameter[j].decoder(value, ndigits, direction));
} }
@@ -823,7 +982,7 @@ static void disassemble_frame(frame_t *frame, const uint8_t *digits, enum nmt_di
} }
/* encode 16 digits frame */ /* encode 16 digits frame */
static void assemble_frame(frame_t *frame, uint8_t *digits, int debug) static void assemble_frame(int nmt_system, frame_t *frame, uint8_t *digits, int debug)
{ {
enum nmt_mt mt; enum nmt_mt mt;
int i, j; int i, j;
@@ -956,6 +1115,8 @@ static void assemble_frame(frame_t *frame, uint8_t *digits, int debug)
i++; i++;
} }
for (j = 0; nmt_parameter[j].digit; j++) { for (j = 0; nmt_parameter[j].digit; j++) {
if (nmt_parameter[j].system != 0 && nmt_parameter[j].system != nmt_system)
continue;
if (nmt_parameter[j].digit == digit) { if (nmt_parameter[j].digit == digit) {
PDEBUG(DFRAME, DEBUG_DEBUG, " %c: %s\n", digit, nmt_parameter[j].decoder(value, ndigits, direction)); PDEBUG(DFRAME, DEBUG_DEBUG, " %c: %s\n", digit, nmt_parameter[j].decoder(value, ndigits, direction));
} }
@@ -973,13 +1134,13 @@ static void assemble_frame(frame_t *frame, uint8_t *digits, int debug)
/* encode frame to bits /* encode frame to bits
* debug can be turned on or off * debug can be turned on or off
*/ */
const char *encode_frame(frame_t *frame, int debug) const char *encode_frame(int nmt_system, frame_t *frame, int debug)
{ {
uint8_t digits[16], message[9], code[18]; uint8_t digits[16], message[9], code[18];
static char bits[166]; static char bits[166];
int i; int i;
assemble_frame(frame, digits, debug); assemble_frame(nmt_system, frame, digits, debug);
/* hagelbarger code */ /* hagelbarger code */
message[8] = 0x00; message[8] = 0x00;
@@ -994,7 +1155,7 @@ const char *encode_frame(frame_t *frame, int debug)
} }
/* decode bits to frame */ /* decode bits to frame */
int decode_frame(frame_t *frame, const char *bits, enum nmt_direction direction, int callack) int decode_frame(int nmt_system, frame_t *frame, const char *bits, enum nmt_direction direction, int callack)
{ {
uint8_t digits[16], message[8], code[19]; uint8_t digits[16], message[8], code[19];
int i; int i;
@@ -1009,7 +1170,7 @@ int decode_frame(frame_t *frame, const char *bits, enum nmt_direction direction,
digits[i * 2 + 1] = message[i] & 0x0f; digits[i * 2 + 1] = message[i] & 0x0f;
} }
disassemble_frame(frame, digits, direction, callack); disassemble_frame(nmt_system, frame, digits, direction, callack);
return 0; return 0;
} }

View File

@@ -1,16 +1,21 @@
enum nmt_mt { enum nmt_mt {
NMT_MESSAGE_1a = 0, NMT_MESSAGE_1a = 0,
NMT_MESSAGE_1a_a,
NMT_MESSAGE_1a_b,
NMT_MESSAGE_1b, NMT_MESSAGE_1b,
NMT_MESSAGE_2a, NMT_MESSAGE_2a,
NMT_MESSAGE_2b, NMT_MESSAGE_2b,
NMT_MESSAGE_2c, NMT_MESSAGE_2c,
NMT_MESSAGE_2d, NMT_MESSAGE_2d,
NMT_MESSAGE_2e,
NMT_MESSAGE_2f, NMT_MESSAGE_2f,
NMT_MESSAGE_3a, NMT_MESSAGE_3a,
NMT_MESSAGE_3b, NMT_MESSAGE_3b,
NMT_MESSAGE_3c, NMT_MESSAGE_3c,
NMT_MESSAGE_3d,
NMT_MESSAGE_4, NMT_MESSAGE_4,
NMT_MESSAGE_4b,
NMT_MESSAGE_5a, NMT_MESSAGE_5a,
NMT_MESSAGE_5b, NMT_MESSAGE_5b,
NMT_MESSAGE_6, NMT_MESSAGE_6,
@@ -19,6 +24,7 @@ enum nmt_mt {
NMT_MESSAGE_10a, NMT_MESSAGE_10a,
NMT_MESSAGE_10b, NMT_MESSAGE_10b,
NMT_MESSAGE_10c, NMT_MESSAGE_10c,
NMT_MESSAGE_10d,
NMT_MESSAGE_11a, NMT_MESSAGE_11a,
NMT_MESSAGE_11b, NMT_MESSAGE_11b,
NMT_MESSAGE_12, NMT_MESSAGE_12,
@@ -77,8 +83,10 @@ typedef struct frame {
int init_frame(void); int init_frame(void);
uint64_t nmt_encode_channel(int channel, int power); uint64_t nmt_encode_channel(int nmt_system, int channel, int power);
int nmt_decode_channel(uint64_t value, int *channel, int *power); int nmt_decode_channel(int nmt_system, uint64_t value, int *channel, int *power);
uint64_t nmt_encode_tc(int nmt_system, int channel, int power);
uint64_t nmt_encode_traffic_area(int nmt_system, int channel, uint8_t traffic_area);
void nmt_value2digits(uint64_t value, char *digits, int num); void nmt_value2digits(uint64_t value, char *digits, int num);
uint64_t nmt_digits2value(const char *digits, int num); uint64_t nmt_digits2value(const char *digits, int num);
char nmt_value2digit(uint64_t value); char nmt_value2digit(uint64_t value);
@@ -86,6 +94,6 @@ uint16_t nmt_encode_area_no(uint8_t area_no);
const char *nmt_frame_name(enum nmt_mt mt); const char *nmt_frame_name(enum nmt_mt mt);
const char *encode_frame(frame_t *frame, int debug); const char *encode_frame(int nmt_system, frame_t *frame, int debug);
int decode_frame(frame_t *frame, const char *bits, enum nmt_direction direction, int callack); int decode_frame(int nmt_system, frame_t *frame, const char *bits, enum nmt_direction direction, int callack);

View File

@@ -44,9 +44,10 @@
static int sms_deliver_fd = -1; static int sms_deliver_fd = -1;
/* settings */ /* settings */
int nmt_system = 450;
int num_chan_type = 0; int num_chan_type = 0;
enum nmt_chan_type chan_type[MAX_SENDER] = { CHAN_TYPE_CC_TC }; enum nmt_chan_type chan_type[MAX_SENDER] = { CHAN_TYPE_CC_TC };
int ms_power = 1; /* 1..3 */ int ms_power = 1; /* 0..3 */
char country[16] = ""; char country[16] = "";
char traffic_area[3] = ""; char traffic_area[3] = "";
char area_no = 0; char area_no = 0;
@@ -58,13 +59,19 @@ int send_callerid = 0;
void print_help(const char *arg0) void print_help(const char *arg0)
{ {
print_help_common(arg0, "-Y <traffic area> | list [-I 1] [-0 1] "); print_help_common(arg0, "[-N 900] -Y <traffic area> | list [-I 1] [-0 1] ");
/* - - */ /* - - */
printf(" -N --nmt-system 450/900\n");
printf(" Give NMT type as first paramer. (default = '%d')\n", nmt_system);
printf(" Note: This option must be given at first!\n");
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(nmt_system, chan_type[0]));
printf(" -P --ms-power <power level>\n"); printf(" -P --ms-power <power level>\n");
printf(" Give power level of the mobile station 1..3. (default = '%d')\n", ms_power); printf(" Give power level of the mobile station 0..3. (default = '%d')\n", ms_power);
printf(" 3 = 15 W / 7 W (handheld), 2 = 1.5 W, 1 = 150 mW\n"); if (nmt_system == 450)
printf(" NMT-450: 3 = 15 W / 7 W (handheld), 2 = 1.5 W, 1/0 = 150 mW\n");
else
printf(" NMT-900: 3/2 = 6 W, 1 = 1.5 W, 0 = 150 mW\n");
printf(" -Y --traffic-area <traffic area> | list\n"); printf(" -Y --traffic-area <traffic area> | list\n");
printf(" NOTE: MUST MATCH WITH YOUR ROAMING SETTINGS IN THE PHONE!\n"); printf(" NOTE: MUST MATCH WITH YOUR ROAMING SETTINGS IN THE PHONE!\n");
printf(" Your phone will not connect, if country code is different!\n"); printf(" Your phone will not connect, if country code is different!\n");
@@ -97,6 +104,7 @@ static int handle_options(int argc, char **argv)
int skip_args = 0; int skip_args = 0;
static struct option long_options_special[] = { static struct option long_options_special[] = {
{"nmt-system", 1, 0, 'N'},
{"channel-type", 1, 0, 'T'}, {"channel-type", 1, 0, 'T'},
{"ms-power", 1, 0, 'P'}, {"ms-power", 1, 0, 'P'},
{"traffic-area", 1, 0, 'Y'}, {"traffic-area", 1, 0, 'Y'},
@@ -108,10 +116,11 @@ static int handle_options(int argc, char **argv)
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
set_options_common("T:P:Y:A:C:0:S:I:", long_options_special); set_options_common("N:T:P:Y:A:C:0:S:I:", long_options_special);
while (1) { while (1) {
int option_index = 0, c, rc; int option_index = 0, c, rc;
static int first_option = 1;
c = getopt_long(argc, argv, optstring, long_options, &option_index); c = getopt_long(argc, argv, optstring, long_options, &option_index);
@@ -119,12 +128,26 @@ static int handle_options(int argc, char **argv)
break; break;
switch (c) { switch (c) {
case 'T': case 'N':
if (!strcmp(optarg, "list")) { nmt_system = atoi(optarg);
nmt_channel_list(); if (nmt_system != 450 && nmt_system != 900) {
fprintf(stderr, "Error, NMT system type '%s' unknown. Please use '-N 450' for NMT-450 or '-N 900' for NMT-900.\n", optarg);
exit(0); exit(0);
} }
rc = nmt_channel_by_short_name(optarg); if (nmt_system == 900)
ms_power = 0;
if (!first_option) {
fprintf(stderr, "Please specify the NMT system (-N) as first command line option!\n");
exit(0);
}
skip_args += 2;
break;
case 'T':
if (!strcmp(optarg, "list")) {
nmt_channel_list(nmt_system);
exit(0);
}
rc = nmt_channel_by_short_name(nmt_system, optarg);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "Error, channel type '%s' unknown. Please use '-t list' to get a list. I suggest to use the default.\n", optarg); 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); exit(0);
@@ -136,14 +159,14 @@ static int handle_options(int argc, char **argv)
ms_power = atoi(optarg); ms_power = atoi(optarg);
if (ms_power > 3) if (ms_power > 3)
ms_power = 3; ms_power = 3;
if (ms_power < 1) if (ms_power < 0)
ms_power = 1; ms_power = 0;
skip_args += 2; skip_args += 2;
break; break;
case 'Y': case 'Y':
if (!strcmp(optarg, "list")) { if (!strcmp(optarg, "list")) {
nmt_country_list(); nmt_country_list(nmt_system);
exit(0); exit(0);
} }
/* digits */ /* digits */
@@ -155,7 +178,7 @@ static int handle_options(int argc, char **argv)
exit(0); exit(0);
} }
*p++ = '\0'; *p++ = '\0';
rc = nmt_country_by_short_name(country); rc = nmt_country_by_short_name(nmt_system, country);
if (rc < 0) { if (rc < 0) {
error_ta: error_ta:
fprintf(stderr, "Invalid traffic area '%s', use '-Y list' for a list of valid areas\n", optarg); fprintf(stderr, "Invalid traffic area '%s', use '-Y list' for a list of valid areas\n", optarg);
@@ -163,7 +186,7 @@ error_ta:
} }
traffic_area[0] = rc + '0'; traffic_area[0] = rc + '0';
if (p[strlen(p) - 1] != '!') { if (p[strlen(p) - 1] != '!') {
rc = nmt_ta_by_short_name(country, atoi(p)); rc = nmt_ta_by_short_name(nmt_system, country, atoi(p));
if (rc < 0) if (rc < 0)
goto error_ta; goto error_ta;
} }
@@ -203,6 +226,7 @@ error_ta:
default: default:
opt_switch_common(c, argv[0], &skip_args); opt_switch_common(c, argv[0], &skip_args);
} }
first_option = 0;
} }
free(long_options); free(long_options);
@@ -378,15 +402,15 @@ 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(country, kanal[i], (loopback) ? CHAN_TYPE_TEST : chan_type[i], audiodev[i], use_sdr, samplerate, rx_gain, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, ms_power, nmt_digits2value(traffic_area, 2), area_no, compandor, supervisory[i], smsc_number, send_callerid, loopback); rc = nmt_create(nmt_system, country, kanal[i], (loopback) ? CHAN_TYPE_TEST : chan_type[i], audiodev[i], use_sdr, samplerate, rx_gain, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, ms_power, nmt_digits2value(traffic_area, 2), area_no, compandor, supervisory[i], 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;
} }
printf("base station on channel %d ready, please tune transmitter to %.4f MHz and receiver to %.4f MHz.\n", kanal[i], nmt_channel2freq(country, kanal[i], 0, NULL, NULL, NULL) / 1e6, nmt_channel2freq(country, kanal[i], 1, NULL, NULL, NULL) / 1e6); printf("base station on channel %d ready, please tune transmitter to %.4f MHz and receiver to %.4f MHz.\n", kanal[i], nmt_channel2freq(nmt_system, country, kanal[i], 0, NULL, NULL, NULL) / 1e6, nmt_channel2freq(nmt_system, country, kanal[i], 1, NULL, NULL, NULL) / 1e6);
} }
nmt_check_channels(); nmt_check_channels(nmt_system);
main_common(&quit, latency, interval, myhandler, station_id, 7); main_common(&quit, latency, interval, myhandler, station_id, 7);

View File

@@ -119,7 +119,7 @@ void nmt_display_status(void)
display_status_start(); display_status_start();
for (sender = sender_head; sender; sender = sender->next) { for (sender = sender_head; sender; sender = sender->next) {
nmt = (nmt_t *) sender; nmt = (nmt_t *) sender;
display_status_channel(nmt->sender.kanal, chan_type_short_name(nmt->sysinfo.chan_type), nmt_state_name(nmt->state)); display_status_channel(nmt->sender.kanal, chan_type_short_name(nmt->sysinfo.system, nmt->sysinfo.chan_type), nmt_state_name(nmt->state));
if (nmt->trans) if (nmt->trans)
display_status_subscriber(nmt->trans->subscriber.number, NULL); display_status_subscriber(nmt->trans->subscriber.number, NULL);
} }
@@ -136,32 +136,41 @@ static void nmt_new_state(nmt_t *nmt, enum nmt_state new_state)
} }
static struct nmt_channels { static struct nmt_channels {
int system;
enum nmt_chan_type chan_type; enum nmt_chan_type chan_type;
const char *short_name; const char *short_name;
const char *long_name; const char *long_name;
} nmt_channels[] = { } nmt_channels[] = {
{ CHAN_TYPE_CC, "CC", "calling channel (incomming calls)" }, { 0, CHAN_TYPE_CC, "CC", "calling channel (incomming calls)" },
{ CHAN_TYPE_TC, "TC", "traffic channel (outgoing calls)" }, { 900, CHAN_TYPE_CCA, "CCA", "calling channel for group A mobiles with odd secret key (incomming calls)" },
{ CHAN_TYPE_CC_TC, "CC/TC","combined calling & traffic channel (both way calls)" }, { 900, CHAN_TYPE_CCB, "CCB", "calling channel for group B mobiles with even secret key (incomming calls)" },
{ CHAN_TYPE_TEST, "TEST", "test channel" }, { 0, CHAN_TYPE_TC, "TC", "traffic channel (outgoing calls)" },
{ 0, NULL, NULL } { 900, CHAN_TYPE_AC_TC, "AC/TC","combined access & traffic channel (outgoing calls)" },
{ 0, CHAN_TYPE_CC_TC, "CC/TC","combined calling & traffic channel (both way calls)" },
{ 0, CHAN_TYPE_TEST, "TEST", "test channel" },
{ 0, 0, NULL, NULL }
}; };
void nmt_channel_list(void) void nmt_channel_list(int nmt_system)
{ {
int i; int i;
printf("Type\tDescription\n"); printf("Type\tDescription\n");
printf("------------------------------------------------------------------------\n"); printf("------------------------------------------------------------------------\n");
for (i = 0; nmt_channels[i].long_name; i++) for (i = 0; nmt_channels[i].long_name; i++) {
if (nmt_channels[i].system != 0 && nmt_channels[i].system != nmt_system)
continue;
printf("%s\t%s\n", nmt_channels[i].short_name, nmt_channels[i].long_name); printf("%s\t%s\n", nmt_channels[i].short_name, nmt_channels[i].long_name);
} }
}
int nmt_channel_by_short_name(const char *short_name) int nmt_channel_by_short_name(int nmt_system, const char *short_name)
{ {
int i; int i;
for (i = 0; nmt_channels[i].short_name; i++) { for (i = 0; nmt_channels[i].short_name; i++) {
if (nmt_channels[i].system != 0 && nmt_channels[i].system != nmt_system)
continue;
if (!strcasecmp(nmt_channels[i].short_name, short_name)) if (!strcasecmp(nmt_channels[i].short_name, short_name))
return nmt_channels[i].chan_type; return nmt_channels[i].chan_type;
} }
@@ -169,11 +178,13 @@ int nmt_channel_by_short_name(const char *short_name)
return -1; return -1;
} }
const char *chan_type_short_name(enum nmt_chan_type chan_type) const char *chan_type_short_name(int nmt_system, enum nmt_chan_type chan_type)
{ {
int i; int i;
for (i = 0; nmt_channels[i].short_name; i++) { for (i = 0; nmt_channels[i].short_name; i++) {
if (nmt_channels[i].system != 0 && nmt_channels[i].system != nmt_system)
continue;
if (nmt_channels[i].chan_type == chan_type) if (nmt_channels[i].chan_type == chan_type)
return nmt_channels[i].short_name; return nmt_channels[i].short_name;
} }
@@ -181,11 +192,13 @@ const char *chan_type_short_name(enum nmt_chan_type chan_type)
return "invalid"; return "invalid";
} }
const char *chan_type_long_name(enum nmt_chan_type chan_type) const char *chan_type_long_name(int nmt_system, enum nmt_chan_type chan_type)
{ {
int i; int i;
for (i = 0; nmt_channels[i].long_name; i++) { for (i = 0; nmt_channels[i].long_name; i++) {
if (nmt_channels[i].system != 0 && nmt_channels[i].system != nmt_system)
continue;
if (nmt_channels[i].chan_type == chan_type) if (nmt_channels[i].chan_type == chan_type)
return nmt_channels[i].long_name; return nmt_channels[i].long_name;
} }
@@ -231,7 +244,7 @@ static int dialstring2number(const char *dialstring, char *ms_country, char *ms_
static void nmt_timeout(struct timer *timer); static void nmt_timeout(struct timer *timer);
/* Create transceiver instance and link to a list. */ /* Create transceiver instance and link to a list. */
int nmt_create(const char *country, int channel, enum nmt_chan_type chan_type, const char *audiodev, int use_sdr, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_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) int nmt_create(int nmt_system, const char *country, int channel, enum nmt_chan_type chan_type, const char *audiodev, int use_sdr, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_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;
@@ -240,7 +253,7 @@ int nmt_create(const char *country, int channel, enum nmt_chan_type chan_type, c
int tested; int tested;
/* check channel matching and set deviation factor */ /* check channel matching and set deviation factor */
if (nmt_channel2freq(country, channel, 0, &deviation_factor, &scandinavia, &tested) == 0.0) { if (nmt_channel2freq(nmt_system, country, channel, 0, &deviation_factor, &scandinavia, &tested) == 0.0) {
PDEBUG(DNMT, DEBUG_NOTICE, "Channel number %d invalid, use '-Y list' to get a list of available channels.\n", channel); PDEBUG(DNMT, DEBUG_NOTICE, "Channel number %d invalid, use '-Y list' to get a list of available channels.\n", channel);
return -EINVAL; return -EINVAL;
} }
@@ -270,13 +283,14 @@ int nmt_create(const char *country, int channel, enum nmt_chan_type chan_type, c
PDEBUG(DNMT, DEBUG_DEBUG, "Creating 'NMT' instance for channel = %d (sample rate %d).\n", channel, samplerate); PDEBUG(DNMT, DEBUG_DEBUG, "Creating 'NMT' instance for channel = %d (sample rate %d).\n", channel, samplerate);
/* init general part of transceiver */ /* init general part of transceiver */
rc = sender_create(&nmt->sender, channel, nmt_channel2freq(country, channel, 0, NULL, NULL, NULL), nmt_channel2freq(country, channel, 1, NULL, NULL, NULL), audiodev, use_sdr, samplerate, rx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, 0, PAGING_SIGNAL_NONE); rc = sender_create(&nmt->sender, channel, nmt_channel2freq(nmt_system, country, channel, 0, NULL, NULL, NULL), nmt_channel2freq(nmt_system, country, channel, 1, NULL, NULL, NULL), audiodev, use_sdr, samplerate, rx_gain, pre_emphasis, de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, 0, PAGING_SIGNAL_NONE);
if (rc < 0) { if (rc < 0) {
PDEBUG(DNMT, DEBUG_ERROR, "Failed to init transceiver process!\n"); PDEBUG(DNMT, DEBUG_ERROR, "Failed to init transceiver process!\n");
goto error; goto error;
} }
timer_init(&nmt->timer, nmt_timeout, nmt); timer_init(&nmt->timer, nmt_timeout, nmt);
nmt->sysinfo.system = nmt_system;
nmt->sysinfo.chan_type = chan_type; nmt->sysinfo.chan_type = chan_type;
nmt->sysinfo.ms_power = ms_power; nmt->sysinfo.ms_power = ms_power;
nmt->sysinfo.traffic_area = traffic_area; nmt->sysinfo.traffic_area = traffic_area;
@@ -310,9 +324,9 @@ int nmt_create(const char *country, int channel, enum nmt_chan_type chan_type, c
/* go into idle state */ /* go into idle state */
nmt_go_idle(nmt); nmt_go_idle(nmt);
PDEBUG(DNMT, DEBUG_NOTICE, "Created channel #%d of type '%s' = %s\n", channel, chan_type_short_name(chan_type), chan_type_long_name(chan_type)); PDEBUG(DNMT, DEBUG_NOTICE, "Created channel #%d of type '%s' = %s\n", channel, chan_type_short_name(nmt_system, chan_type), chan_type_long_name(nmt_system, chan_type));
if (nmt_long_name_by_short_name(country)) if (nmt_long_name_by_short_name(nmt_system, country))
PDEBUG(DNMT, DEBUG_NOTICE, " -> Using country '%s'\n", nmt_long_name_by_short_name(country)); PDEBUG(DNMT, DEBUG_NOTICE, " -> Using country '%s'\n", nmt_long_name_by_short_name(nmt_system, country));
PDEBUG(DNMT, DEBUG_NOTICE, " -> Using traffic area %d,%d and area no %d\n", traffic_area >> 4, traffic_area & 0xf, area_no); PDEBUG(DNMT, DEBUG_NOTICE, " -> Using traffic area %d,%d and area no %d\n", traffic_area >> 4, traffic_area & 0xf, area_no);
if (nmt->supervisory) if (nmt->supervisory)
PDEBUG(DNMT, DEBUG_NOTICE, " -> Using supervisory signal %d\n", supervisory); PDEBUG(DNMT, DEBUG_NOTICE, " -> Using supervisory signal %d\n", supervisory);
@@ -327,32 +341,64 @@ error:
return rc; return rc;
} }
void nmt_check_channels(void) void nmt_check_channels(int __attribute__((unused)) nmt_system)
{ {
sender_t *sender; sender_t *sender;
nmt_t *nmt; nmt_t *nmt;
int cc = 0, tc = 0; int cca = 0, ccb = 0, tc = 0;
int note = 0;
for (sender = sender_head; sender; sender = sender->next) { for (sender = sender_head; sender; sender = sender->next) {
nmt = (nmt_t *) sender; nmt = (nmt_t *) sender;
if (nmt->sysinfo.chan_type == CHAN_TYPE_CC) if (nmt->sysinfo.chan_type == CHAN_TYPE_CC) {
cc = 1; cca = 1;
ccb = 1;
}
if (nmt->sysinfo.chan_type == CHAN_TYPE_CCA)
cca = 1;
if (nmt->sysinfo.chan_type == CHAN_TYPE_CCB)
ccb = 1;
if (nmt->sysinfo.chan_type == CHAN_TYPE_TC) if (nmt->sysinfo.chan_type == CHAN_TYPE_TC)
tc = 1; tc = 1;
if (nmt->sysinfo.chan_type == CHAN_TYPE_AC_TC)
tc = 1;
if (nmt->sysinfo.chan_type == CHAN_TYPE_CC_TC) { if (nmt->sysinfo.chan_type == CHAN_TYPE_CC_TC) {
cc = 1; cca = 1;
ccb = 1;
tc = 1; tc = 1;
} }
} }
if (cc && !tc) { if ((cca || ccb) && !tc) {
if (note)
PDEBUG(DNMT, DEBUG_NOTICE, "\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** Selected channel(s) can be used for calling only.\n"); PDEBUG(DNMT, DEBUG_NOTICE, "*** Selected channel(s) can be used for calling only.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** No call from the mobile phone is possible on this channel.\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"); PDEBUG(DNMT, DEBUG_NOTICE, "*** Use combined 'CC/TC' instead!\n");
note = 1;
} }
if (tc && !cc) { if (tc && !(cca || ccb)) {
if (note)
PDEBUG(DNMT, DEBUG_NOTICE, "\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** Selected channel(s) can be used for traffic only.\n"); PDEBUG(DNMT, DEBUG_NOTICE, "*** Selected channel(s) can be used for traffic only.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** No call to the mobile phone is possible on this channel.\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"); PDEBUG(DNMT, DEBUG_NOTICE, "*** Use combined 'CC/TC' instead!\n");
note = 1;
}
if (cca && !ccb) {
if (note)
PDEBUG(DNMT, DEBUG_NOTICE, "\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** Selected channel(s) can be used for calling of MS type A only.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** No call from the MS type B phone is possible on this channel.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** Use combined 'CC' or 'CC/TC' instead!\n");
note = 1;
}
if (!cca && ccb) {
if (note)
PDEBUG(DNMT, DEBUG_NOTICE, "\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** Selected channel(s) can be used for calling of MS type B only.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** No call from the MS type A phone is possible on this channel.\n");
PDEBUG(DNMT, DEBUG_NOTICE, "*** Use combined 'CC' or 'CC/TC' instead!\n");
note = 1;
} }
} }
@@ -378,7 +424,7 @@ void nmt_go_idle(nmt_t *nmt)
dms_reset(nmt); dms_reset(nmt);
sms_reset(nmt); sms_reset(nmt);
PDEBUG_CHAN(DNMT, DEBUG_INFO, "Entering IDLE state, sending idle frames on %s.\n", chan_type_long_name(nmt->sysinfo.chan_type)); PDEBUG_CHAN(DNMT, DEBUG_INFO, "Entering IDLE state, sending idle frames on %s.\n", chan_type_long_name(nmt->sysinfo.system, nmt->sysinfo.chan_type));
nmt->trans = NULL; /* remove transaction before state change, so status is shown correctly */ nmt->trans = NULL; /* remove transaction before state change, so status is shown correctly */
nmt_new_state(nmt, STATE_IDLE); nmt_new_state(nmt, STATE_IDLE);
nmt_set_dsp_mode(nmt, DSP_MODE_FRAME); nmt_set_dsp_mode(nmt, DSP_MODE_FRAME);
@@ -446,8 +492,8 @@ static int match_channel(nmt_t *nmt, frame_t *frame)
int channel, power; int channel, power;
/* check channel match */ /* check channel match */
nmt_decode_channel(frame->channel_no, &channel, &power); nmt_decode_channel(nmt->sysinfo.system, frame->channel_no, &channel, &power);
if (channel != nmt->sender.kanal) { if ((channel & 0x3ff) != (nmt->sender.kanal & 0x3ff)) {
PDEBUG_CHAN(DNMT, DEBUG_NOTICE, "Frame for different channel %d received, ignoring.\n", channel); PDEBUG_CHAN(DNMT, DEBUG_NOTICE, "Frame for different channel %d received, ignoring.\n", channel);
return 0; return 0;
} }
@@ -505,8 +551,8 @@ static void tx_ident(nmt_t *nmt, frame_t *frame)
transaction_t *trans = nmt->trans; transaction_t *trans = nmt->trans;
frame->mt = NMT_MESSAGE_3b; frame->mt = NMT_MESSAGE_3b;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area; frame->traffic_area = nmt_encode_traffic_area(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.traffic_area);
frame->ms_country = nmt_digits2value(&trans->subscriber.country, 1); frame->ms_country = nmt_digits2value(&trans->subscriber.country, 1);
frame->ms_number = nmt_digits2value(trans->subscriber.number, 6); frame->ms_number = nmt_digits2value(trans->subscriber.number, 6);
frame->additional_info = nmt_encode_area_no(nmt->sysinfo.area_no); frame->additional_info = nmt_encode_area_no(nmt->sysinfo.area_no);
@@ -517,8 +563,8 @@ static void set_line_signal(nmt_t *nmt, frame_t *frame, uint8_t signal)
transaction_t *trans = nmt->trans; transaction_t *trans = nmt->trans;
frame->mt = NMT_MESSAGE_5a; frame->mt = NMT_MESSAGE_5a;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area; frame->traffic_area = nmt_encode_traffic_area(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.traffic_area);
frame->ms_country = nmt_digits2value(&trans->subscriber.country, 1); frame->ms_country = nmt_digits2value(&trans->subscriber.country, 1);
frame->ms_number = nmt_digits2value(trans->subscriber.number, 6); frame->ms_number = nmt_digits2value(trans->subscriber.number, 6);
frame->line_signal = (signal << 8) | (signal << 4) | signal; frame->line_signal = (signal << 8) | (signal << 4) | signal;
@@ -547,8 +593,8 @@ static int encode_a_number(nmt_t *nmt, frame_t *frame, int index, enum number_ty
/* encode */ /* encode */
frame->mt = NMT_MESSAGE_8; frame->mt = NMT_MESSAGE_8;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area; frame->traffic_area = nmt_encode_traffic_area(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.traffic_area);
frame->seq_number = index; frame->seq_number = index;
if (index == 0) { if (index == 0) {
/* number type */ /* number type */
@@ -614,9 +660,18 @@ static void tx_idle(nmt_t *nmt, frame_t *frame)
case CHAN_TYPE_CC: case CHAN_TYPE_CC:
frame->mt = NMT_MESSAGE_1a; frame->mt = NMT_MESSAGE_1a;
break; break;
case CHAN_TYPE_CCA:
frame->mt = NMT_MESSAGE_1a_a;
break;
case CHAN_TYPE_CCB:
frame->mt = NMT_MESSAGE_1a_b;
break;
case CHAN_TYPE_TC: case CHAN_TYPE_TC:
frame->mt = NMT_MESSAGE_4; frame->mt = NMT_MESSAGE_4;
break; break;
case CHAN_TYPE_AC_TC:
frame->mt = NMT_MESSAGE_4b;
break;
case CHAN_TYPE_CC_TC: case CHAN_TYPE_CC_TC:
frame->mt = NMT_MESSAGE_1b; frame->mt = NMT_MESSAGE_1b;
break; break;
@@ -624,8 +679,8 @@ static void tx_idle(nmt_t *nmt, frame_t *frame)
frame->mt = NMT_MESSAGE_30; frame->mt = NMT_MESSAGE_30;
break; break;
} }
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area; frame->traffic_area = nmt_encode_traffic_area(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.traffic_area);
frame->additional_info = nmt_encode_area_no(nmt->sysinfo.area_no); frame->additional_info = nmt_encode_area_no(nmt->sysinfo.area_no);
} }
@@ -663,6 +718,7 @@ static void rx_idle(nmt_t *nmt, frame_t *frame)
break; break;
case NMT_MESSAGE_10b: /* seizure from ordinary MS */ case NMT_MESSAGE_10b: /* seizure from ordinary MS */
case NMT_MESSAGE_12: /* seizure from coinbox MS */ case NMT_MESSAGE_12: /* seizure from coinbox MS */
case NMT_MESSAGE_10a: /* access signal */
if (!match_channel(nmt, frame)) if (!match_channel(nmt, frame))
break; break;
if (!match_area(nmt, frame)) if (!match_area(nmt, frame))
@@ -973,8 +1029,8 @@ static void tx_mt_paging(nmt_t *nmt, frame_t *frame)
transaction_t *trans = nmt->trans; transaction_t *trans = nmt->trans;
frame->mt = NMT_MESSAGE_2a; frame->mt = NMT_MESSAGE_2a;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area; frame->traffic_area = nmt_encode_traffic_area(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.traffic_area);
frame->ms_country = nmt_digits2value(&trans->subscriber.country, 1); frame->ms_country = nmt_digits2value(&trans->subscriber.country, 1);
frame->ms_number = nmt_digits2value(trans->subscriber.number, 6); frame->ms_number = nmt_digits2value(trans->subscriber.number, 6);
frame->additional_info = nmt_encode_area_no(nmt->sysinfo.area_no); frame->additional_info = nmt_encode_area_no(nmt->sysinfo.area_no);
@@ -1004,6 +1060,7 @@ static void rx_mt_paging(nmt_t *nmt, frame_t *frame)
switch (frame->mt) { switch (frame->mt) {
case NMT_MESSAGE_10a: /* call acknowledgment */ case NMT_MESSAGE_10a: /* call acknowledgment */
case NMT_MESSAGE_10d: /* call ack on alternate type */
if (!match_channel(nmt, frame)) if (!match_channel(nmt, frame))
break; break;
if (!match_subscriber(trans, frame)) if (!match_subscriber(trans, frame))
@@ -1034,11 +1091,11 @@ static void tx_mt_channel(nmt_t *nmt, frame_t *frame)
transaction_t *trans = nmt->trans; transaction_t *trans = nmt->trans;
frame->mt = NMT_MESSAGE_2b; frame->mt = NMT_MESSAGE_2b;
frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power);
frame->traffic_area = nmt->sysinfo.traffic_area; frame->traffic_area = nmt_encode_traffic_area(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.traffic_area);
frame->ms_country = nmt_digits2value(&trans->subscriber.country, 1); frame->ms_country = nmt_digits2value(&trans->subscriber.country, 1);
frame->ms_number = nmt_digits2value(trans->subscriber.number, 6); frame->ms_number = nmt_digits2value(trans->subscriber.number, 6);
frame->tc_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); frame->tc_no = nmt_encode_tc(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power);
PDEBUG_CHAN(DNMT, DEBUG_INFO, "Send channel activation to mobile.\n"); PDEBUG_CHAN(DNMT, DEBUG_INFO, "Send channel activation to mobile.\n");
nmt_new_state(nmt, STATE_MT_IDENT); nmt_new_state(nmt, STATE_MT_IDENT);
} }
@@ -1477,7 +1534,7 @@ void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double leve
PDEBUG_CHAN(DDSP, DEBUG_INFO, "RX Level: %.0f%% Quality=%.0f\n", level * 100.0, quality * 100.0); PDEBUG_CHAN(DDSP, DEBUG_INFO, "RX Level: %.0f%% Quality=%.0f\n", level * 100.0, quality * 100.0);
rc = decode_frame(&frame, bits, (nmt->sender.loopback) ? MTX_TO_XX : XX_TO_MTX, (nmt->state == STATE_MT_PAGING)); rc = decode_frame(nmt->sysinfo.system, &frame, bits, (nmt->sender.loopback) ? MTX_TO_XX : XX_TO_MTX, (nmt->state == STATE_MT_PAGING));
if (rc < 0) { if (rc < 0) {
PDEBUG_CHAN(DNMT, (nmt->sender.loopback) ? DEBUG_NOTICE : DEBUG_DEBUG, "Received invalid frame.\n"); PDEBUG_CHAN(DNMT, (nmt->sender.loopback) ? DEBUG_NOTICE : DEBUG_DEBUG, "Received invalid frame.\n");
return; return;
@@ -1661,7 +1718,7 @@ const char *nmt_get_frame(nmt_t *nmt)
if (nmt->dsp_mode != DSP_MODE_FRAME) if (nmt->dsp_mode != DSP_MODE_FRAME)
return NULL; return NULL;
bits = encode_frame(&frame, debug); bits = encode_frame(nmt->sysinfo.system, &frame, debug);
PDEBUG_CHAN(DNMT, DEBUG_DEBUG, "Sending frame %s.\n", nmt_frame_name(frame.mt)); PDEBUG_CHAN(DNMT, DEBUG_DEBUG, "Sending frame %s.\n", nmt_frame_name(frame.mt));
return bits; return bits;

View File

@@ -17,7 +17,10 @@ enum dsp_mode {
enum nmt_chan_type { enum nmt_chan_type {
CHAN_TYPE_CC, /* calling channel */ CHAN_TYPE_CC, /* calling channel */
CHAN_TYPE_CCA, /* calling channel type A mobiles */
CHAN_TYPE_CCB, /* calling channel type B mobiles */
CHAN_TYPE_TC, /* traffic channel */ CHAN_TYPE_TC, /* traffic channel */
CHAN_TYPE_AC_TC, /* combined AC + TC */
CHAN_TYPE_CC_TC, /* combined CC + TC */ CHAN_TYPE_CC_TC, /* combined CC + TC */
CHAN_TYPE_TEST, /* test channel */ CHAN_TYPE_TEST, /* test channel */
}; };
@@ -59,6 +62,7 @@ enum nmt_direction {
}; };
typedef struct nmt_sysinfo { typedef struct nmt_sysinfo {
int system; /* 450 or 900 */
enum nmt_chan_type chan_type; /* channel type */ enum nmt_chan_type chan_type; /* channel type */
int ms_power; /* ms power level 3 = full */ int ms_power; /* ms power level 3 = full */
uint8_t traffic_area; /* two digits traffic area, encoded as YY */ uint8_t traffic_area; /* two digits traffic area, encoded as YY */
@@ -137,12 +141,12 @@ typedef struct nmt {
struct timer sms_timer; struct timer sms_timer;
} nmt_t; } nmt_t;
void nmt_channel_list(void); void nmt_channel_list(int nmt_system);
int nmt_channel_by_short_name(const char *short_name); int nmt_channel_by_short_name(int nmt_system, const char *short_name);
const char *chan_type_short_name(enum nmt_chan_type chan_type); const char *chan_type_short_name(int nmt_system, enum nmt_chan_type chan_type);
const char *chan_type_long_name(enum nmt_chan_type chan_type); const char *chan_type_long_name(int nmt_system, enum nmt_chan_type chan_type);
int nmt_create(const char *country, int channel, enum nmt_chan_type chan_type, const char *audiodev, int use_sdr, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_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); int nmt_create(int nmt_system, const char *country, int channel, enum nmt_chan_type chan_type, const char *audiodev, int use_sdr, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_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_check_channels(void); void nmt_check_channels(int nmt_system);
void nmt_destroy(sender_t *sender); void nmt_destroy(sender_t *sender);
void nmt_go_idle(nmt_t *nmt); void nmt_go_idle(nmt_t *nmt);
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);