From 3274812eab64469a118dc66f902eb182d55975e9 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 22 Jul 2017 10:38:18 +0200 Subject: NMT-900 System implementation NMT can now be run as 450 or 900 Network. --- src/nmt/countries.c | 151 ++++++++++++++++++---------- src/nmt/countries.h | 10 +- src/nmt/frame.c | 281 +++++++++++++++++++++++++++++++++++++++++----------- src/nmt/frame.h | 16 ++- src/nmt/main.c | 56 ++++++++--- src/nmt/nmt.c | 141 ++++++++++++++++++-------- src/nmt/nmt.h | 16 +-- 7 files changed, 488 insertions(+), 183 deletions(-) (limited to 'src/nmt') diff --git a/src/nmt/countries.c b/src/nmt/countries.c index c809c91..f2e58fd 100644 --- a/src/nmt/countries.c +++ b/src/nmt/countries.c @@ -32,7 +32,7 @@ struct nmt_frequency { }; /* 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 }, { 181,200, 462.500, 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 } }; +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 */ -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 }, { 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 */ -static struct nmt_frequency frq_mal[] = { +static struct nmt_frequency frq_450_mal[] = { { 1, 180, 462.000, 0.025, 1.0, 10.0, 0 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; /* 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 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; /* 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 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; /* 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 }, { 0, 0, 0.0, 0.0, 0.0, 0.0, 0 } }; /* 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 }, { 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 */ 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 first_ta, last_ta; /* range of used traffic areas */ const char *short_name; @@ -86,47 +110,64 @@ static struct nmt_country { const char *provider_name; struct nmt_frequency *nmt_frequency; /* list of frequency allocations */ } nmt_country[] = { - { 1, 5, 1,9, "DK", "Denmark", "Tele Danmark Mobile", frq_scandinavia }, - { 1, 6, 1,9, "SE", "Sweden", "Telia Mobitel", frq_scandinavia }, - { 1, 7, 1,9, "NO", "Norway", "Telenor Mobil", frq_scandinavia }, - { 1, 8, 1,9, "FI", "Finland", "Telecom Finland", frq_scandinavia }, - { 1, 8, 1,9, "IS", "Iceland", "Post & Telecom", frq_scandinavia }, - { 1, 5, 1,9, "FO", "Faroe Island", "Faroese Telecom", frq_scandinavia }, - { 1, 7, 1,9, "EE", "Estonia", "Eesti Mobiiltelefon", frq_scandinavia }, - { 1, 5, 1,9, "LV", "Latvia", "Latvian Mobile Telephone", frq_scandinavia }, - { 1, 8, 1,9, "LT", "Lithuania", "COMLIET", frq_scandinavia }, - { 1, 6, 1,9, "BY", "Belarus", "Belcel", frq_scandinavia }, - { 1, 5, 1,9, "MO", "OSS/Moscow", "Moscow Cellular Comm.", frq_scandinavia }, - { 1, 6, 1,9, "STP", "OSS/St Petersburg", "Delta Telecom", frq_scandinavia }, - { 1, 6, 1,9, "STP", "OSS/Leningrads Dist.", "Delta Telecom", frq_scandinavia }, - { 1, 7, 1,9, "CAR", "OSS/Carelian Rep.", "Telecom Finland", frq_scandinavia }, - { 1, 5, 1,9, "MUR", "OSS/Murmansk", "Telecom Finland", frq_scandinavia }, - { 1, 5, 1,9, "LED", "OSS/Leningrads Dist.", "Telecom Finland", frq_scandinavia }, - { 1, 5, 1,9, "KAL", "Kaliningrad", "Telecom Finland", frq_scandinavia }, - { 1, 7, 1,9, "PL", "Poland", "CENTERTEL", frq_scandinavia }, - { 1, 6, 1,9, "BG", "Bulgaria", "MOBIFON", frq_scandinavia }, - { 1, 5, 1,9, "RO", "Romania", "Telefonica Romania", frq_scandinavia }, - { 1, 6, 1,9, "UA", "Ukraine", "Ukraine Mobile Comm.", frq_scandinavia }, - { 1, 1, 1,9, "RU1", "", "", frq_scandinavia }, - { 1, 2, 1,9, "RU2", "", "", frq_scandinavia }, - { 1, 3, 1,9, "RU3", "", "", frq_scandinavia }, - { 1, 4, 1,9, "RU4", "", "", frq_scandinavia }, - { 1, 1, 1,9, "NL", "Netherlands", "Royal Dutch Post & Telecom", frq_nl_l_b }, - { 1, 1, 15,15, "L", "Luxemburg", "Enterprise des P&T Luxembourg",frq_nl_l_b }, - { 1, 2, 1,9, "B", "Belgium", "Belgacom Mobile", frq_nl_l_b }, - { 1, 7, 1,9, "CZ", "Czech Republic", "Eurotel Prague", frq_cz_sk }, - { 1, 6, 1,9, "SK", "Slovakia", "Eurotel Bratislava", frq_cz_sk }, + /* 450 */ + { 450, 1, 5, 1,9, "DK", "Denmark", "Tele Danmark Mobile", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "SE", "Sweden", "Telia Mobitel", frq_450_scandinavia }, + { 450, 1, 7, 1,9, "NO", "Norway", "Telenor Mobil", frq_450_scandinavia }, + { 450, 1, 8, 1,9, "FI", "Finland", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 8, 1,9, "IS", "Iceland", "Post & Telecom", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "FO", "Faroe Island", "Faroese Telecom", frq_450_scandinavia }, + { 450, 1, 7, 1,9, "EE", "Estonia", "Eesti Mobiiltelefon", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "LV", "Latvia", "Latvian Mobile Telephone", frq_450_scandinavia }, + { 450, 1, 8, 1,9, "LT", "Lithuania", "COMLIET", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "BY", "Belarus", "Belcel", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "MO", "OSS/Moscow", "Moscow Cellular Comm.", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "STP", "OSS/St Petersburg", "Delta Telecom", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "STP", "OSS/Leningrads Dist.", "Delta Telecom", frq_450_scandinavia }, + { 450, 1, 7, 1,9, "CAR", "OSS/Carelian Rep.", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "MUR", "OSS/Murmansk", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "LED", "OSS/Leningrads Dist.", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "KAL", "Kaliningrad", "Telecom Finland", frq_450_scandinavia }, + { 450, 1, 7, 1,9, "PL", "Poland", "CENTERTEL", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "BG", "Bulgaria", "MOBIFON", frq_450_scandinavia }, + { 450, 1, 5, 1,9, "RO", "Romania", "Telefonica Romania", frq_450_scandinavia }, + { 450, 1, 6, 1,9, "UA", "Ukraine", "Ukraine Mobile Comm.", frq_450_scandinavia }, + { 450, 1, 1, 1,9, "RU1", "", "", frq_450_scandinavia }, + { 450, 1, 2, 1,9, "RU2", "", "", frq_450_scandinavia }, + { 450, 1, 3, 1,9, "RU3", "", "", frq_450_scandinavia }, + { 450, 1, 4, 1,9, "RU4", "", "", frq_450_scandinavia }, + { 450, 1, 1, 1,9, "NL", "Netherlands", "Royal Dutch Post & Telecom", frq_450_nl_l_b }, + { 450, 1, 1, 15,15, "L", "Luxemburg", "Enterprise des P&T Luxembourg",frq_450_nl_l_b }, + { 450, 1, 2, 1,9, "B", "Belgium", "Belgacom Mobile", frq_450_nl_l_b }, + { 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... */ - { 0, 8, 8,8, "MAL", "Malaysia", "Jabatan Telekom Malaysia", frq_mal }, - { 0, 4, 1,9, "T", "Thailand", "Telephone Organization of Thailand",frq_t_ri }, - { 0, 8, 1,9, "E", "Spain", "Telefonica Servicios Moviles", frq_e }, - { 0, 8, 1,1, "RI", "Indonesia", "PT Mobisel", frq_t_ri }, - { 0, 0, 1,3, "A", "Austria", "PTV", frq_a }, - { 0, 9, 1,3, "A2", "Austria 2", "PTV", frq_a }, - { 0, 0, 0,0, NULL, NULL, NULL, NULL } + { 450, 0, 8, 8,8, "MAL", "Malaysia", "Jabatan Telekom Malaysia", frq_450_mal }, + { 450, 0, 4, 1,9, "T", "Thailand", "Telephone Organization of Thailand",frq_450_t_ri }, + { 450, 0, 8, 1,9, "E", "Spain", "Telefonica Servicios Moviles", frq_450_e }, + { 450, 0, 8, 1,1, "RI", "Indonesia", "PT Mobisel", frq_450_t_ri }, + { 450, 0, 0, 1,3, "A", "Austria", "PTV", frq_450_a }, + { 450, 0, 9, 1,3, "A2", "Austria 2", "PTV", frq_450_a }, + { 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 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("--------------------------------------------------------------------------------\n"); 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); if (nmt_country[i].first_ta != 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; 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)) return nmt_country[i].y; } @@ -167,11 +212,13 @@ int nmt_country_by_short_name(const char *short_name) 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; 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)) return nmt_country[i].long_name; } @@ -179,11 +226,13 @@ const char *nmt_long_name_by_short_name(const char *short_name) 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; 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) 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. 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; double freq; 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)) { for (j = 0; nmt_country[i].nmt_frequency[j].first_frequency; j++) { if (channel >= nmt_country[i].nmt_frequency[j].first_channel diff --git a/src/nmt/countries.h b/src/nmt/countries.h index b8a7121..adfbdde 100644 --- a/src/nmt/countries.h +++ b/src/nmt/countries.h @@ -1,7 +1,7 @@ -void nmt_country_list(void); -int nmt_country_by_short_name(const char *short_name); -const char *nmt_long_name_by_short_name(const char *short_name); -int nmt_ta_by_short_name(const char *short_name, int ta); -double nmt_channel2freq(const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested); +void nmt_country_list(int nmt_system); +int nmt_country_by_short_name(int nmt_system, 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(int nmt_system, const char *short_name, int ta); +double nmt_channel2freq(int nmt_system, const char *short_name, int channel, int uplink, double *deviation_factor, int *scandinavia, int *tested); diff --git a/src/nmt/frame.c b/src/nmt/frame.c index 8cad3ca..b64a37c 100644 --- a/src/nmt/frame.c +++ b/src/nmt/frame.c @@ -29,41 +29,116 @@ #include "frame.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; - if (channel >= 200) { - value |= 0x800; - channel -= 200; - } - if (channel >= 100) { - value |= 0x100; - channel -= 100; + 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 { + /* 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; } - value |= channel % 10; - value |= (channel / 10) << 4; - value |= power << 9; 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 ((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; + 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) + return -1; + if ((value & 0x0f0) > 0x090) + return -1; + + *channel = (value & 0x00f) + + ((value & 0x0f0) >> 4) * 10 + + ((value & 0x100) >> 8) * 100 + + ((value & 0x800) >> 11) * 200; + *power = (value & 0x600) >> 9; + } else { + *channel = value & 0x3ff; + } + + 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) { int digit, i; @@ -214,24 +289,30 @@ static struct nmt_frame { } nmt_frame[] = { /* Define Digits Dir. Prefix Nr. Description */ { 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_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_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_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_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_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_4b, "NNNPYYJJJJJJJHHH", MTX_TO_MS, 7, "4b", "Access channel indication" }, { 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_6, "JJJPJJJJJJJJJJJJ", MTX_TO_XX, 0, "6", "Idle frame" }, { 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_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_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_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" }, @@ -288,12 +369,40 @@ static const char *param_hex(uint64_t value, int __attribute__((unused)) ndigits 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]; + int rc, channel, power; + + rc = nmt_decode_channel(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_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_channel(value, &channel, &power); + rc = nmt_decode_tc(450, value, &channel, &power); if (rc < 0) sprintf(result, "invalid(%" PRIu64 ")", value); else @@ -302,6 +411,20 @@ static const char *param_channel_no(uint64_t value, int __attribute__((unused)) 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 char result[32]; @@ -310,7 +433,7 @@ static const char *param_country(uint64_t value, int __attribute__((unused)) ndi case 0: return "no additional info"; case 1: - return "Netherlands / Luxemburg / Malaysia"; + return "Netherlands / Luxemburg / Malaysia / Switzerland"; case 2: return "Belgium"; case 4: @@ -347,7 +470,7 @@ static const char *param_number(uint64_t value, int ndigits, enum nmt_direction 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]; @@ -357,6 +480,18 @@ static const char *param_ta(uint64_t value, int ndigits, enum nmt_direction __at 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) { char *desc = "Spare"; @@ -477,34 +612,38 @@ static const char *param_password(uint64_t value, int ndigits, enum nmt_directio } static struct nmt_parameter { + int system; char digit; const char *description; const char *(*decoder)(uint64_t value, int ndigits, enum nmt_direction direction); } nmt_parameter[] = { - { 'N', "Channel No.", param_channel_no }, - { 'n', "TC No.", param_channel_no }, - { 'Y', "Traffic area", param_ta }, - { 'Z', "Mobile subscriber country", param_country }, - { 'X', "Mobile subscriber No.", param_number }, - { 'Q', "Tariff class", param_integer }, - { 'L', "Line signal", param_line_signal }, - { 'S', "Digit signals", param_digit }, - { 'J', "Idle information", param_hex }, - { 'A', "Channel activation", param_hex }, - { 'V', "Management order", param_hex }, - { 'r', "Measurement results", param_hex }, - { 'P', "Prefix", param_integer }, - { 'f', "Supervisory signal", param_supervisory }, - { 'K', "Mobile subscriber password", param_password }, - { 'T', "Area info", param_hex }, - { 'H', "Additional info", param_hex }, - { 'C', "Random challenge", param_hex }, - { 'R', "Signed response", param_hex }, - { 'l', "Limit strength evaluation", param_hex }, - { 'c', "c", param_hex }, - { 'M', "Sequence Number", param_integer }, - { 'W', "Checksum", param_hex }, - { 0, NULL, NULL } + { 450, 'N', "Channel No.", param_channel_no_450 }, + { 900, 'N', "Channel No.", param_channel_no_900 }, + { 450, 'n', "TC No.", param_tc_no_450 }, + { 900, 'n', "TC No.", param_tc_no_900 }, + { 450, 'Y', "Traffic area", param_ta_450 }, + { 900, 'Y', "Traffic area", param_ta_900 }, + { 0, 'Z', "Mobile subscriber country", param_country }, + { 0, 'X', "Mobile subscriber No.", param_number }, + { 0, 'Q', "Tariff class", param_integer }, + { 0, 'L', "Line signal", param_line_signal }, + { 0, 'S', "Digit signals", param_digit }, + { 0, 'J', "Idle information", param_hex }, + { 0, 'A', "Channel activation", param_hex }, + { 0, 'V', "Management order", param_hex }, + { 0, 'r', "Measurement results", param_hex }, + { 0, 'P', "Prefix", param_integer }, + { 0, 'f', "Supervisory signal", param_supervisory }, + { 0, 'K', "Mobile subscriber password", param_password }, + { 0, 'T', "Area info", param_hex }, + { 0, 'H', "Additional info", param_hex }, + { 0, 'C', "Random challenge", param_hex }, + { 0, 'R', "Signed response", param_hex }, + { 0, 'l', "Limit strength evaluation", param_hex }, + { 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 @@ -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_4; case 4: - return NMT_MESSAGE_1b; + 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; + } case 5: if (digits[6] == 15) 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_5a; 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: return NMT_MESSAGE_7; case 9: @@ -609,7 +766,7 @@ enum nmt_mt decode_frame_mt(const uint8_t *digits, enum nmt_direction direction, case 10: return NMT_MESSAGE_30; case 11: - break; + return NMT_MESSAGE_1a_a; case 12: /* no subscriber */ 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; } case 13: - break; + return NMT_MESSAGE_1a_b; case 14: if (digits[13] != 15) break; @@ -697,7 +854,7 @@ int init_frame(void) } /* 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; 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) { 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) { 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 */ -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; int i, j; @@ -956,6 +1115,8 @@ static void assemble_frame(frame_t *frame, uint8_t *digits, int debug) i++; } 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) { 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 * 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]; static char bits[166]; int i; - assemble_frame(frame, digits, debug); + assemble_frame(nmt_system, frame, digits, debug); /* hagelbarger code */ message[8] = 0x00; @@ -994,7 +1155,7 @@ const char *encode_frame(frame_t *frame, int debug) } /* 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]; 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; } - disassemble_frame(frame, digits, direction, callack); + disassemble_frame(nmt_system, frame, digits, direction, callack); return 0; } diff --git a/src/nmt/frame.h b/src/nmt/frame.h index 3eb7abc..85b2aa1 100644 --- a/src/nmt/frame.h +++ b/src/nmt/frame.h @@ -1,16 +1,21 @@ enum nmt_mt { NMT_MESSAGE_1a = 0, + NMT_MESSAGE_1a_a, + NMT_MESSAGE_1a_b, NMT_MESSAGE_1b, NMT_MESSAGE_2a, NMT_MESSAGE_2b, NMT_MESSAGE_2c, NMT_MESSAGE_2d, + NMT_MESSAGE_2e, NMT_MESSAGE_2f, NMT_MESSAGE_3a, NMT_MESSAGE_3b, NMT_MESSAGE_3c, + NMT_MESSAGE_3d, NMT_MESSAGE_4, + NMT_MESSAGE_4b, NMT_MESSAGE_5a, NMT_MESSAGE_5b, NMT_MESSAGE_6, @@ -19,6 +24,7 @@ enum nmt_mt { NMT_MESSAGE_10a, NMT_MESSAGE_10b, NMT_MESSAGE_10c, + NMT_MESSAGE_10d, NMT_MESSAGE_11a, NMT_MESSAGE_11b, NMT_MESSAGE_12, @@ -77,8 +83,10 @@ typedef struct frame { int init_frame(void); -uint64_t nmt_encode_channel(int channel, int power); -int nmt_decode_channel(uint64_t value, int *channel, int *power); +uint64_t nmt_encode_channel(int nmt_system, 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); uint64_t nmt_digits2value(const char *digits, int num); 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 *encode_frame(frame_t *frame, int debug); -int decode_frame(frame_t *frame, const char *bits, enum nmt_direction direction, int callack); +const char *encode_frame(int nmt_system, frame_t *frame, int debug); +int decode_frame(int nmt_system, frame_t *frame, const char *bits, enum nmt_direction direction, int callack); diff --git a/src/nmt/main.c b/src/nmt/main.c index cec5266..396f7d0 100644 --- a/src/nmt/main.c +++ b/src/nmt/main.c @@ -44,9 +44,10 @@ static int sms_deliver_fd = -1; /* settings */ +int nmt_system = 450; int num_chan_type = 0; 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 traffic_area[3] = ""; char area_no = 0; @@ -58,13 +59,19 @@ int send_callerid = 0; void print_help(const char *arg0) { - print_help_common(arg0, "-Y | list [-I 1] [-0 1] "); + print_help_common(arg0, "[-N 900] -Y | 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 | 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 \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"); + printf(" Give power level of the mobile station 0..3. (default = '%d')\n", ms_power); + 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 | list\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"); @@ -97,6 +104,7 @@ static int handle_options(int argc, char **argv) int skip_args = 0; static struct option long_options_special[] = { + {"nmt-system", 1, 0, 'N'}, {"channel-type", 1, 0, 'T'}, {"ms-power", 1, 0, 'P'}, {"traffic-area", 1, 0, 'Y'}, @@ -108,10 +116,11 @@ static int handle_options(int argc, char **argv) {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) { int option_index = 0, c, rc; + static int first_option = 1; c = getopt_long(argc, argv, optstring, long_options, &option_index); @@ -119,12 +128,26 @@ static int handle_options(int argc, char **argv) break; switch (c) { + case 'N': + nmt_system = atoi(optarg); + 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); + } + 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_channel_list(nmt_system); exit(0); } - rc = nmt_channel_by_short_name(optarg); + rc = nmt_channel_by_short_name(nmt_system, optarg); 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); exit(0); @@ -136,14 +159,14 @@ static int handle_options(int argc, char **argv) ms_power = atoi(optarg); if (ms_power > 3) ms_power = 3; - if (ms_power < 1) - ms_power = 1; + if (ms_power < 0) + ms_power = 0; skip_args += 2; break; case 'Y': if (!strcmp(optarg, "list")) { - nmt_country_list(); + nmt_country_list(nmt_system); exit(0); } /* digits */ @@ -155,7 +178,7 @@ static int handle_options(int argc, char **argv) exit(0); } *p++ = '\0'; - rc = nmt_country_by_short_name(country); + rc = nmt_country_by_short_name(nmt_system, country); if (rc < 0) { error_ta: 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'; 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) goto error_ta; } @@ -203,6 +226,7 @@ error_ta: default: opt_switch_common(c, argv[0], &skip_args); } + first_option = 0; } free(long_options); @@ -378,15 +402,15 @@ int main(int argc, char *argv[]) /* create transceiver instance */ 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) { fprintf(stderr, "Failed to create transceiver instance. Quitting!\n"); 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); diff --git a/src/nmt/nmt.c b/src/nmt/nmt.c index 809a168..01a7b3c 100644 --- a/src/nmt/nmt.c +++ b/src/nmt/nmt.c @@ -119,7 +119,7 @@ void nmt_display_status(void) display_status_start(); for (sender = sender_head; sender; sender = sender->next) { 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) 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 { + int system; enum nmt_chan_type chan_type; const char *short_name; const char *long_name; } nmt_channels[] = { - { CHAN_TYPE_CC, "CC", "calling channel (incomming calls)" }, - { CHAN_TYPE_TC, "TC", "traffic channel (outgoing calls)" }, - { CHAN_TYPE_CC_TC, "CC/TC","combined calling & traffic channel (both way calls)" }, - { CHAN_TYPE_TEST, "TEST", "test channel" }, - { 0, NULL, NULL } + { 0, CHAN_TYPE_CC, "CC", "calling channel (incomming calls)" }, + { 900, CHAN_TYPE_CCA, "CCA", "calling channel for group A mobiles with odd secret key (incomming calls)" }, + { 900, CHAN_TYPE_CCB, "CCB", "calling channel for group B mobiles with even secret key (incomming calls)" }, + { 0, CHAN_TYPE_TC, "TC", "traffic channel (outgoing calls)" }, + { 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; printf("Type\tDescription\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); + } } -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; 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)) return nmt_channels[i].chan_type; } @@ -169,11 +178,13 @@ int nmt_channel_by_short_name(const char *short_name) 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; 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) return nmt_channels[i].short_name; } @@ -181,11 +192,13 @@ const char *chan_type_short_name(enum nmt_chan_type chan_type) 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; 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) 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); /* 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; int rc; @@ -240,7 +253,7 @@ int nmt_create(const char *country, int channel, enum nmt_chan_type chan_type, c int tested; /* 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); 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); /* 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) { PDEBUG(DNMT, DEBUG_ERROR, "Failed to init transceiver process!\n"); goto error; } timer_init(&nmt->timer, nmt_timeout, nmt); + nmt->sysinfo.system = nmt_system; nmt->sysinfo.chan_type = chan_type; nmt->sysinfo.ms_power = ms_power; 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 */ 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)); - if (nmt_long_name_by_short_name(country)) - PDEBUG(DNMT, DEBUG_NOTICE, " -> Using country '%s'\n", nmt_long_name_by_short_name(country)); + 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(nmt_system, 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); if (nmt->supervisory) PDEBUG(DNMT, DEBUG_NOTICE, " -> Using supervisory signal %d\n", supervisory); @@ -327,32 +341,64 @@ error: return rc; } -void nmt_check_channels(void) +void nmt_check_channels(int __attribute__((unused)) nmt_system) { sender_t *sender; 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) { nmt = (nmt_t *) sender; - if (nmt->sysinfo.chan_type == CHAN_TYPE_CC) - cc = 1; + if (nmt->sysinfo.chan_type == CHAN_TYPE_CC) { + 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) tc = 1; + if (nmt->sysinfo.chan_type == CHAN_TYPE_AC_TC) + tc = 1; if (nmt->sysinfo.chan_type == CHAN_TYPE_CC_TC) { - cc = 1; + cca = 1; + ccb = 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, "*** No call from the mobile phone is possible on this channel.\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, "*** No call to the mobile phone is possible on this channel.\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); 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_new_state(nmt, STATE_IDLE); 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; /* check channel match */ - nmt_decode_channel(frame->channel_no, &channel, &power); - if (channel != nmt->sender.kanal) { + nmt_decode_channel(nmt->sysinfo.system, frame->channel_no, &channel, &power); + if ((channel & 0x3ff) != (nmt->sender.kanal & 0x3ff)) { PDEBUG_CHAN(DNMT, DEBUG_NOTICE, "Frame for different channel %d received, ignoring.\n", channel); return 0; } @@ -505,8 +551,8 @@ static void tx_ident(nmt_t *nmt, frame_t *frame) transaction_t *trans = nmt->trans; frame->mt = NMT_MESSAGE_3b; - frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); - frame->traffic_area = nmt->sysinfo.traffic_area; + frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power); + 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_number = nmt_digits2value(trans->subscriber.number, 6); 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; frame->mt = NMT_MESSAGE_5a; - frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); - frame->traffic_area = nmt->sysinfo.traffic_area; + frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power); + 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_number = nmt_digits2value(trans->subscriber.number, 6); 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 */ frame->mt = NMT_MESSAGE_8; - frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); - frame->traffic_area = nmt->sysinfo.traffic_area; + frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power); + frame->traffic_area = nmt_encode_traffic_area(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.traffic_area); frame->seq_number = index; if (index == 0) { /* number type */ @@ -614,9 +660,18 @@ static void tx_idle(nmt_t *nmt, frame_t *frame) case CHAN_TYPE_CC: frame->mt = NMT_MESSAGE_1a; 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: frame->mt = NMT_MESSAGE_4; break; + case CHAN_TYPE_AC_TC: + frame->mt = NMT_MESSAGE_4b; + break; case CHAN_TYPE_CC_TC: frame->mt = NMT_MESSAGE_1b; break; @@ -624,8 +679,8 @@ static void tx_idle(nmt_t *nmt, frame_t *frame) frame->mt = NMT_MESSAGE_30; break; } - frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); - frame->traffic_area = nmt->sysinfo.traffic_area; + frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power); + 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); } @@ -663,6 +718,7 @@ static void rx_idle(nmt_t *nmt, frame_t *frame) break; case NMT_MESSAGE_10b: /* seizure from ordinary MS */ case NMT_MESSAGE_12: /* seizure from coinbox MS */ + case NMT_MESSAGE_10a: /* access signal */ if (!match_channel(nmt, frame)) break; 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; frame->mt = NMT_MESSAGE_2a; - frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); - frame->traffic_area = nmt->sysinfo.traffic_area; + frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power); + 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_number = nmt_digits2value(trans->subscriber.number, 6); 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) { case NMT_MESSAGE_10a: /* call acknowledgment */ + case NMT_MESSAGE_10d: /* call ack on alternate type */ if (!match_channel(nmt, frame)) break; 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; frame->mt = NMT_MESSAGE_2b; - frame->channel_no = nmt_encode_channel(nmt->sender.kanal, nmt->sysinfo.ms_power); - frame->traffic_area = nmt->sysinfo.traffic_area; + frame->channel_no = nmt_encode_channel(nmt->sysinfo.system, nmt->sender.kanal, nmt->sysinfo.ms_power); + 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_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"); 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); - 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) { PDEBUG_CHAN(DNMT, (nmt->sender.loopback) ? DEBUG_NOTICE : DEBUG_DEBUG, "Received invalid frame.\n"); return; @@ -1661,7 +1718,7 @@ const char *nmt_get_frame(nmt_t *nmt) if (nmt->dsp_mode != DSP_MODE_FRAME) 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)); return bits; diff --git a/src/nmt/nmt.h b/src/nmt/nmt.h index 075c3e9..1ed438e 100644 --- a/src/nmt/nmt.h +++ b/src/nmt/nmt.h @@ -17,7 +17,10 @@ enum dsp_mode { enum nmt_chan_type { 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_AC_TC, /* combined AC + TC */ CHAN_TYPE_CC_TC, /* combined CC + TC */ CHAN_TYPE_TEST, /* test channel */ }; @@ -59,6 +62,7 @@ enum nmt_direction { }; typedef struct nmt_sysinfo { + int system; /* 450 or 900 */ enum nmt_chan_type chan_type; /* channel type */ int ms_power; /* ms power level 3 = full */ uint8_t traffic_area; /* two digits traffic area, encoded as YY */ @@ -137,12 +141,12 @@ typedef struct nmt { struct timer sms_timer; } nmt_t; -void nmt_channel_list(void); -int nmt_channel_by_short_name(const char *short_name); -const char *chan_type_short_name(enum nmt_chan_type chan_type); -const char *chan_type_long_name(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); -void nmt_check_channels(void); +void nmt_channel_list(int nmt_system); +int nmt_channel_by_short_name(int nmt_system, const char *short_name); +const char *chan_type_short_name(int nmt_system, enum nmt_chan_type chan_type); +const char *chan_type_long_name(int nmt_system, enum nmt_chan_type chan_type); +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(int nmt_system); void nmt_destroy(sender_t *sender); void nmt_go_idle(nmt_t *nmt); void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double level, double frames_elapsed); -- cgit v1.2.3