diff --git a/include/nxdn96_const.h b/include/nxdn96_const.h deleted file mode 100644 index 8af701e..0000000 --- a/include/nxdn96_const.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2010 DSD Author - * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * NXDN AMBE interleave schedule - */ - -#ifndef _MAIN -extern const int nW[36]; -extern const int nX[36]; -extern const int nY[36]; -extern const int nZ[36]; - -#else - -const int nW[36] = { 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 2, - 0, 2, 0, 2, 0, 2, - 0, 2, 0, 2, 0, 2 -}; - -const int nX[36] = { 23, 10, 22, 9, 21, 8, - 20, 7, 19, 6, 18, 5, - 17, 4, 16, 3, 15, 2, - 14, 1, 13, 0, 12, 10, - 11, 9, 10, 8, 9, 7, - 8, 6, 7, 5, 6, 4 -}; - -const int nY[36] = { 0, 2, 0, 2, 0, 2, - 0, 2, 0, 3, 0, 3, - 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3 -}; - -const int nZ[36] = { 5, 3, 4, 2, 3, 1, - 2, 0, 1, 13, 0, 12, - 22, 11, 21, 10, 20, 9, - 19, 8, 18, 7, 17, 6, - 16, 5, 15, 4, 14, 3, - 13, 2, 12, 1, 11, 0 -}; - -#endif diff --git a/include/nxdn_const.h b/include/nxdn_const.h index 85a5896..d2d4cdc 100644 --- a/include/nxdn_const.h +++ b/include/nxdn_const.h @@ -1,257 +1,82 @@ -/* - * Copyright (C) 2010 DSD Author - * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE - * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ +// Portions Below from Osmocom OP25 +// NXDN Encoder (C) Copyright 2019 Max H. Parke KA1RBI +// thx gr-ysf fr_vch_decoder_bb_impl.cc * Copyright 2015 Mathias Weyland * +// OP25 is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// OP25 is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +// License for more details. +// +// You should have received a copy of the GNU General Public License +// along with OP25; see the file COPYING. If not, write to the Free +// Software Foundation, Inc., 51 Franklin Street, Boston, MA +// 02110-1301, USA. -#ifndef _MAIN -extern const int nW[36]; -extern const int nX[36]; -extern const int nY[36]; -extern const int nZ[36]; -extern const char nxdnpr[145]; -extern const char nxdnpr2[145]; //why is this 145 but referenced later as 182 or 384 -//borrow from LEH -extern const unsigned char nsW[72]; -extern const int DSDNXDN_SACCH_m_Interleave[60]; -extern const int DSDNXDN_SACCH_m_PunctureList[12]; -extern const int DSDNXDN_FACCH1_m_Interleave[144]; -extern const int DSDNXDN_FACCH1_m_PunctureList[48]; -extern const int DSDNXDN_UDCH_m_Interleave[348]; -extern const int DSDNXDN_UDCH_m_PunctureList[58]; -// -//enum -//{ -#define NXDN_VCALL 0b000001 /* VCALL = VCALL_REQ = VCALL_RESP */ -#define NXDN_VCALL_IV 0b000011 -#define NXDN_DCALL_HDR 0b001001 /* Header Format - NXDN_DCALL_HDR = NXDN_DCALL_REQ = NXDN_DCALL_RESP */ -#define NXDN_DCALL_USR 0b001011 /* User Data Format */ -#define NXDN_DCALL_ACK 0b001100 -#define NXDN_REL_EX 0b000111 -#define NXDN_HEAD_DLY 0b001111 -#define NXDN_SDCALL_REQ_HDR 0b111000 /* Header Format */ -#define NXDN_SDCALL_REQ_USR 0b111001 /* User Data Format */ -#define NXDN_SDCALL_RESP 0b111011 -#define NXDN_SDCALL_IV 0b111010 -#define NXDN_STAT_INQ_REQ 0b110000 -#define NXDN_STAT_INQ_RESP 0b110001 -#define NXDN_STAT_REQ 0b110010 -#define NXDN_STAT_RESP 0b110011 -#define NXDN_REM_CON_REQ 0b110100 -#define NXDN_REM_CON_RESP 0b110101 -#define NXDN_REM_CON_E_REQ 0b110110 -#define NXDN_REM_CON_E_RESP 0b110111 -//NXDN_VCALL_REQ = 0b000001, /* VCALL = VCALL_REQ = VCALL_RESP */ -//NXDN_VCALL_RESP = 0b000001, /* VCALL = VCALL_REQ = VCALL_RESP */ -#define NXDN_VCALL_REC_REQ = 0b000010 /* NXDN_VCALL_REC_REQ = NXDN_VCALL_REC_RESP */ -//NXDN_VCALL_REC_RESP = 0b000010, -#define NXDN_VCALL_CONN_REQ = 0b000011 /* NXDN_VCALL_CONN_REQ = NXDN_VCALL_CONN_RESP */ -//NXDN_VCALL_CONN_RESP = 0b000011, /* NXDN_VCALL_CONN_REQ = NXDN_VCALL_CONN_RESP */ -#define NXDN_VCALL_ASSGN_DUP = 0b000101 -//NXDN_DCALL_REQ = 0b001001, /* NXDN_DCALL_HDR = NXDN_DCALL_REQ = NXDN_DCALL_RESP */ -//NXDN_DCALL_RESP = 0b001001, /* NXDN_DCALL_HDR = NXDN_DCALL_REQ = NXDN_DCALL_RESP */ -#define NXDN_DCALL_REC_REQ = 0b001010 /* NXDN_DCALL_REC_REQ = NXDN_DCALL_REC_RESP */ -//NXDN_DCALL_REC_RESP = 0b001010, /* NXDN_DCALL_REC_REQ = NXDN_DCALL_REC_RESP */ -#define NXDN_DCALL_ASSGN = 0b001110 -#define NXDN_DCALL_ASSGN_DUP = 0b001101 -#define NXDN_IDLE 0b010000 -#define NXDN_DISC_REQ = 0b010001 /* NXDN_DISC_REQ = NXDN_DISC */ -#define NXDN_DISC = 0b010001 /* NXDN_DISC_REQ = NXDN_DISC */ - - -#else -/* - * pseudorandom bit sequence - */ -const char nxdnpr[145] = { 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1 }; -//const unsigned char nxdnpr2[384] = -const unsigned char nxdnpr2[182] = //generated from default in manual with the x^9+x^4+1 poly? -{ - 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, - 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, - 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, - 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, - 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, - 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, - 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, - 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, - 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, - 1, 1, 0, 0, 0, 1//, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, -// 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, -// 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, -// 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, -// 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, -// 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, -// 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, -// 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, -// 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, -// 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, -// 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, -// 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, -// 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 -}; -/* - * NXDN AMBE interleave schedule - */ -const int nW[36] = { 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 1, - 0, 1, 0, 1, 0, 2, - 0, 2, 0, 2, 0, 2, - 0, 2, 0, 2, 0, 2 +static const uint8_t PERM_12_5[] = { + 0,12,24,36,48, + 1,13,25,37,49, + 2,14,26,38,50, + 3,15,27,39,51, + 4,16,28,40,52, + 5,17,29,41,53, + 6,18,30,42,54, + 7,19,31,43,55, + 8,20,32,44,56, + 9,21,33,45,57, + 10,22,34,46,58, + 11,23,35,47,59 }; -const int nX[36] = { 23, 10, 22, 9, 21, 8, - 20, 7, 19, 6, 18, 5, - 17, 4, 16, 3, 15, 2, - 14, 1, 13, 0, 12, 10, - 11, 9, 10, 8, 9, 7, - 8, 6, 7, 5, 6, 4 +static const uint8_t PERM_16_9[] = { + 0, 16, 32, 48, 64, 80, 96, 112, 128, + 1, 17, 33, 49, 65, 81, 97, 113, 129, + 2, 18, 34, 50, 66, 82, 98, 114, 130, + 3, 19, 35, 51, 67, 83, 99, 115, 131, + 4, 20, 36, 52, 68, 84, 100, 116, 132, + 5, 21, 37, 53, 69, 85, 101, 117, 133, + 6, 22, 38, 54, 70, 86, 102, 118, 134, + 7, 23, 39, 55, 71, 87, 103, 119, 135, + 8, 24, 40, 56, 72, 88, 104, 120, 136, + 9, 25, 41, 57, 73, 89, 105, 121, 137, + 10, 26, 42, 58, 74, 90, 106, 122, 138, + 11, 27, 43, 59, 75, 91, 107, 123, 139, + 12, 28, 44, 60, 76, 92, 108, 124, 140, + 13, 29, 45, 61, 77, 93, 109, 125, 141, + 14, 30, 46, 62, 78, 94, 110, 126, 142, + 15, 31, 47, 63, 79, 95, 111, 127, 143 }; -const int nY[36] = { 0, 2, 0, 2, 0, 2, - 0, 2, 0, 3, 0, 3, - 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3 +static const uint16_t PERM_12_25[] = { + 0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276,288, + 1,13,25,37,49,61,73,85,97,109,121,133,145,157,169,181,193,205,217,229,241,253,265,277,289, + 2,14,26,38,50,62,74,86,98,110,122,134,146,158,170,182,194,206,218,230,242,254,266,278,290, + 3,15,27,39,51,63,75,87,99,111,123,135,147,159,171,183,195,207,219,231,243,255,267,279,291, + 4,16,28,40,52,64,76,88,100,112,124,136,148,160,172,184,196,208,220,232,244,256,268,280,292, + 5,17,29,41,53,65,77,89,101,113,125,137,149,161,173,185,197,209,221,233,245,257,269,281,293, + 6,18,30,42,54,66,78,90,102,114,126,138,150,162,174,186,198,210,222,234,246,258,270,282,294, + 7,19,31,43,55,67,79,91,103,115,127,139,151,163,175,187,199,211,223,235,247,259,271,283,295, + 8,20,32,44,56,68,80,92,104,116,128,140,152,164,176,188,200,212,224,236,248,260,272,284,296, + 9,21,33,45,57,69,81,93,105,117,129,141,153,165,177,189,201,213,225,237,249,261,273,285,297, + 10,22,34,46,58,70,82,94,106,118,130,142,154,166,178,190,202,214,226,238,250,262,274,286,298, + 11,23,35,47,59,71,83,95,107,119,131,143,155,167,179,191,203,215,227,239,251,263,275,287,299 }; -const int nZ[36] = { 5, 3, 4, 2, 3, 1, - 2, 0, 1, 13, 0, 12, - 22, 11, 21, 10, 20, 9, - 19, 8, 18, 7, 17, 6, - 16, 5, 15, 4, 14, 3, - 13, 2, 12, 1, 11, 0 +static const uint16_t PERM_12_29[] = { + 0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276,288,300,312,324,336, + 1,13,25,37,49,61,73,85,97,109,121,133,145,157,169,181,193,205,217,229,241,253,265,277,289,301,313,325,337, + 2,14,26,38,50,62,74,86,98,110,122,134,146,158,170,182,194,206,218,230,242,254,266,278,290,302,314,326,338, + 3,15,27,39,51,63,75,87,99,111,123,135,147,159,171,183,195,207,219,231,243,255,267,279,291,303,315,327,339, + 4,16,28,40,52,64,76,88,100,112,124,136,148,160,172,184,196,208,220,232,244,256,268,280,292,304,316,328,340, + 5,17,29,41,53,65,77,89,101,113,125,137,149,161,173,185,197,209,221,233,245,257,269,281,293,305,317,329,341, + 6,18,30,42,54,66,78,90,102,114,126,138,150,162,174,186,198,210,222,234,246,258,270,282,294,306,318,330,342, + 7,19,31,43,55,67,79,91,103,115,127,139,151,163,175,187,199,211,223,235,247,259,271,283,295,307,319,331,343, + 8,20,32,44,56,68,80,92,104,116,128,140,152,164,176,188,200,212,224,236,248,260,272,284,296,308,320,332,344, + 9,21,33,45,57,69,81,93,105,117,129,141,153,165,177,189,201,213,225,237,249,261,273,285,297,309,321,333,345, + 10,22,34,46,58,70,82,94,106,118,130,142,154,166,178,190,202,214,226,238,250,262,274,286,298,310,322,334,346, + 11,23,35,47,59,71,83,95,107,119,131,143,155,167,179,191,203,215,227,239,251,263,275,287,299,311,323,335,347 }; -/* - * NXDN SACCH interleave - */ -const unsigned char nsW[72] = { - 0, 12, 24, 36, 48, 60, - 1, 13, 25, 37, 49, 61, - 2, 14, 26, 38, 50, 62, - 3, 15, 27, 39, 51, 63, - 4, 16, 28, 40, 52, 64, - 5, 17, 29, 41, 53, 65, - 6, 18, 30, 42, 54, 66, - 7, 19, 31, 43, 55, 67, - 8, 20, 32, 44, 56, 68, - 9, 21, 33, 45, 57, 69, - 10,22, 34, 46, 58, 70, - 11,23, 35, 47, 59, 71 -}; - -const int DSDNXDN_SACCH_m_Interleave[60] = -{ - 0, 12, 24, 36, 48, - 1, 13, 25, 37, 49, - 2, 14, 26, 38, 50, - 3, 15, 27, 39, 51, - 4, 16, 28, 40, 52, - 5, 17, 29, 41, 53, - 6, 18, 30, 42, 54, - 7, 19, 31, 43, 55, - 8, 20, 32, 44, 56, - 9, 21, 33, 45, 57, - 10, 22, 34, 46, 58, - 11, 23, 35, 47, 59, -}; - -const int DSDNXDN_SACCH_m_PunctureList[12] = { 5, 11, 17, 23, 29, 35, 41, 47, 53, 59, 65, 71 }; - -const unsigned int DSDNXDN_FACCH1_m_Interleave[144] = -{ - 0, 16, 32, 48, 64, 80, 96, 112, 128, - 1, 17, 33, 49, 65, 81, 97, 113, 129, - 2, 18, 34, 50, 66, 82, 98, 114, 130, - 3, 19, 35, 51, 67, 83, 99, 115, 131, - 4, 20, 36, 52, 68, 84, 100, 116, 132, - 5, 21, 37, 53, 69, 85, 101, 117, 133, - 6, 22, 38, 54, 70, 86, 102, 118, 134, - 7, 23, 39, 55, 71, 87, 103, 119, 135, - 8, 24, 40, 56, 72, 88, 104, 120, 136, - 9, 25, 41, 57, 73, 89, 105, 121, 137, - 10, 26, 42, 58, 74, 90, 106, 122, 138, - 11, 27, 43, 59, 75, 91, 107, 123, 139, - 12, 28, 44, 60, 76, 92, 108, 124, 140, - 13, 29, 45, 61, 77, 93, 109, 125, 141, - 14, 30, 46, 62, 78, 94, 110, 126, 142, - 15, 31, 47, 63, 79, 95, 111, 127, 143, -}; - -const unsigned int DSDNXDN_FACCH1_m_PunctureList[48] = -{ - 1U, 5U, 9U, 13U, 17U, 21U, 25U, 29U, 33U, 37U, - 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, 73U, 77U, - 81U, 85U, 89U, 93U, 97U, 101U, 105U, 109U, 113U, 117U, - 121U, 125U, 129U, 133U, 137U, 141U, 145U, 149U, 153U, 157U, - 161U, 165U, 169U, 173U, 177U, 181U, 185U, 189U -}; - -const int DSDNXDN_UDCH_m_Interleave[348] = { - 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 168, 180, 192, 204, 216, 228, 240, 252, 264, 276, 288, 300, 312, 324, 336, - 1, 13, 25, 37, 49, 61, 73, 85, 97, 109, 121, 133, 145, 157, 169, 181, 193, 205, 217, 229, 241, 253, 265, 277, 289, 301, 313, 325, 337, - 2, 14, 26, 38, 50, 62, 74, 86, 98, 110, 122, 134, 146, 158, 170, 182, 194, 206, 218, 230, 242, 254, 266, 278, 290, 302, 314, 326, 338, - 3, 15, 27, 39, 51, 63, 75, 87, 99, 111, 123, 135, 147, 159, 171, 183, 195, 207, 219, 231, 243, 255, 267, 279, 291, 303, 315, 327, 339, - 4, 16, 28, 40, 52, 64, 76, 88, 100, 112, 124, 136, 148, 160, 172, 184, 196, 208, 220, 232, 244, 256, 268, 280, 292, 304, 316, 328, 340, - 5, 17, 29, 41, 53, 65, 77, 89, 101, 113, 125, 137, 149, 161, 173, 185, 197, 209, 221, 233, 245, 257, 269, 281, 293, 305, 317, 329, 341, - 6, 18, 30, 42, 54, 66, 78, 90, 102, 114, 126, 138, 150, 162, 174, 186, 198, 210, 222, 234, 246, 258, 270, 282, 294, 306, 318, 330, 342, - 7, 19, 31, 43, 55, 67, 79, 91, 103, 115, 127, 139, 151, 163, 175, 187, 199, 211, 223, 235, 247, 259, 271, 283, 295, 307, 319, 331, 343, - 8, 20, 32, 44, 56, 68, 80, 92, 104, 116, 128, 140, 152, 164, 176, 188, 200, 212, 224, 236, 248, 260, 272, 284, 296, 308, 320, 332, 344, - 9, 21, 33, 45, 57, 69, 81, 93, 105, 117, 129, 141, 153, 165, 177, 189, 201, 213, 225, 237, 249, 261, 273, 285, 297, 309, 321, 333, 345, - 10, 22, 34, 46, 58, 70, 82, 94, 106, 118, 130, 142, 154, 166, 178, 190, 202, 214, 226, 238, 250, 262, 274, 286, 298, 310, 322, 334, 346, - 11, 23, 35, 47, 59, 71, 83, 95, 107, 119, 131, 143, 155, 167, 179, 191, 203, 215, 227, 239, 251, 263, 275, 287, 299, 311, 323, 335, 347, -}; - -const int DSDNXDN_UDCH_m_PunctureList[58] = { - 3, 11, - 17, 25, - 31, 39, - 45, 53, - 59, 67, - 73, 81, - 87, 95, - 101, 109, - 115, 123, - 129, 137, - 143, 151, - 157, 165, - 171, 179, - 185, 193, - 199, 207, - 213, 221, - 227, 235, - 241, 249, - 255, 263, - 269, 277, - 283, 291, - 297, 305, - 311, 319, - 325, 333, - 339, 347, - 353, 361, - 367, 375, - 381, 389, - 395, 403, -}; - -//#endif /* _MAIN */ - - - -#endif diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c index 8a17f9d..f1b8d69 100644 --- a/src/dsd_ncurses.c +++ b/src/dsd_ncurses.c @@ -109,8 +109,8 @@ char * SyncTypes[44] = { "dPMR", "dPMR", "dPMR", - "NXDN (sync only)", - "NXDN (sync only)", + "NXDN", + "NXDN", "YSF", //30 "YSF", "DMR MS VOICE", @@ -2107,11 +2107,25 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) } //NXDN - if (lls == 8 || lls == 9 || lls == 16 || lls == 17) + //if (lls == 8 || lls == 9 || lls == 16 || lls == 17 || lls == 28 || lls == 29) + if (lls == 28 || lls == 29) { printw ("| RAN: [%2d] ", rn); - printw ("TID: [%4d] ", tgn); - printw ("RID: [%4d] \n| ALG: [0x%02X] KEY: [0x%02X] ", src, state->nxdn_cipher_type, state->nxdn_key); + printw ("TGT: [%4d] ", tgn); + printw ("SRC: [%4d] ", src); + if (state->nxdn_alias_block_segment[0][0] > 0) //could not display if this segment is bad + { + printw ("["); + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + printw ("%s", state->nxdn_alias_block_segment[i][j]); + } + } + printw ("]"); + } + printw ("\n| ALG: [0x%02X] KEY: [0x%02X] ", state->nxdn_cipher_type, state->nxdn_key); if (state->carrier == 1) { printw("%s ", state->nxdn_call_type); @@ -2152,42 +2166,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(3)); } + //printw("%s ", state->nxdn_call_type); printw("\n"); } - - //P25-P1 - // if (lls == 0 || lls == 1) - // { - // // printw("| TID:[%8i] RID:[%8i] ", tg, rd); - // printw("| TID:[%8i] RID:[%8i] ", state->lasttg, state->lastsrc); - // printw(" MFID:[0x%02X] ", state->payload_mfid); - // printw("NAC: [0x%3X] \n", nc); - // printw("| ALG:[0x%02X] ", state->payload_algid); - // printw(" KID:[0x%04X] ", state->payload_keyid); - // printw(" MI:[0x%016llX] ", state->payload_miP); - // - // if (state->payload_algid != 0x80 && state->payload_algid != 0x0 && state->carrier == 1 && state->R == 0) - // { - // attron(COLOR_PAIR(2)); - // printw("**ENC**"); - // attroff(COLOR_PAIR(2)); - // attron(COLOR_PAIR(3)); - // if (state->payload_algid == 0xAA) - // { - // attron(COLOR_PAIR(1)); - // printw(" RC4"); - // attron(COLOR_PAIR(3)); - // } - // if (state->payload_algid == 0x81) - // { - // attron(COLOR_PAIR(1)); - // printw(" DES-OFB"); - // attron(COLOR_PAIR(3)); - // } - // } - // printw("\n"); - // } - + //DMR BS/MS Voice and Data Types if ( lls == 0 || lls == 1 || lls == 12 || lls == 13 || lls == 10 || lls == 11 || lls == 32 || lls == 33 || lls == 34 || lls == 35 || lls == 36) @@ -2676,7 +2658,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) if ( ((time(NULL) - call_matrix[9-j][5]) < 9999) && call_matrix[9-j][0] != 14 && call_matrix[9-j][0] != 15 && call_matrix[9-j][0] != 37 && call_matrix[9-j][0] != 38 ) { printw ("| %s ", SyncTypes[call_matrix[9-j][0]]); - if (lls == 8 || lls == 9 || lls == 16 || lls == 17) + if (lls == 28 || lls == 29) { printw ("RAN [%2lld] ", call_matrix[9-j][1]); printw ("TG [%4lld] ", call_matrix[9-j][4]); @@ -2748,6 +2730,5 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state) void ncursesClose () { endwin(); - //printf("Press CTRL+C again to close. Thanks.\n"); - //printf("Run 'reset' in your terminal to clean up if necessary.\n"); + } diff --git a/src/nxdn96.c b/src/nxdn96.c deleted file mode 100644 index ab532e1..0000000 --- a/src/nxdn96.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "dsd.h" -#include "nxdn96_const.h" - -void -processNXDN96 (dsd_opts * opts, dsd_state * state) -{ - int i, j, k, dibit; - - char ambe_fr[4][24]; - const int *w, *x, *y, *z; - - if (opts->errorbars == 1) - { - fprintf (stderr, "VOICE e:"); - } - -#ifdef NXDN_DUMP - fprintf (stderr, "\n"); -#endif - - for (k = 0; k < 4; k++) - { - for (i = 0; i < 222; i++) - { - dibit = getDibit (opts, state); -#ifdef NXDN_DUMP - fprintf (stderr, "%c", dibit + 48); -#endif - } -#ifdef NXDN_DUMP - fprintf (stderr, " "); -#endif - - if (k < 3) - { - for (j = 0; j < 4; j++) - { - w = nW; - x = nX; - y = nY; - z = nZ; - for (i = 0; i < 36; i++) - { - dibit = getDibit (opts, state); -#ifdef NXDN_DUMP - fprintf (stderr, "%c", dibit + 48); -#endif - ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 - ambe_fr[*y][*z] = (1 & dibit); // bit 0 - w++; - x++; - y++; - z++; - } - processMbeFrame (opts, state, NULL, ambe_fr, NULL); -#ifdef NXDN_DUMP - fprintf (stderr, " "); -#endif - } - } - else - { - for (j = 0; j < 3; j++) // we skip the last voice frame until frame sync can work with < 24 symbols - { - w = nW; - x = nX; - y = nY; - z = nZ; - for (i = 0; i < 36; i++) - { - dibit = getDibit (opts, state); -#ifdef NXDN_DUMP - fprintf (stderr, "%c", dibit + 48); -#endif - ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1 - ambe_fr[*y][*z] = (1 & dibit); // bit 0 - w++; - x++; - y++; - z++; - } - processMbeFrame (opts, state, NULL, ambe_fr, NULL); -#ifdef NXDN_DUMP - fprintf (stderr, " "); -#endif - } - } - - if (k < 3) - { - for (i = 0; i < 18; i++) - { - dibit = getDibit (opts, state); -#ifdef NXDN_DUMP - fprintf (stderr, "%c", dibit + 48); -#endif - } -#ifdef NXDN_DUMP - fprintf (stderr, " "); -#endif - - } - else - { - for (i = 0; i < 30; i++) - { - dibit = getDibit (opts, state); -#ifdef NXDN_DUMP - fprintf (stderr, "%c", dibit + 48); -#endif - } - } - } - -#ifdef NXDN_DUMP - fprintf (stderr, "\n"); -#endif - - if (opts->errorbars == 1) - { - printf ("\n"); - } - -} diff --git a/src/nxdnconvolution.c b/src/nxdn_convolution.c similarity index 98% rename from src/nxdnconvolution.c rename to src/nxdn_convolution.c index 082103b..a3b280e 100644 --- a/src/nxdnconvolution.c +++ b/src/nxdn_convolution.c @@ -24,10 +24,8 @@ /* Include ------------------------------------------------------------------*/ -//#include "nxdnconvolution.h" #include -//#include #include #include #include diff --git a/src/nxdn_data.c b/src/nxdn_data.c deleted file mode 100644 index 2706ad6..0000000 --- a/src/nxdn_data.c +++ /dev/null @@ -1,127 +0,0 @@ -#include "dsd.h" -#include "nxdn_const.h" - -void processNXDNData (dsd_opts * opts, dsd_state * state) -{ - int i, dibit = 0; - unsigned char sacch_raw[72] = {0}; - unsigned char sacch_decoded[32] = {0}; /* 26 bit + 6 bit CRC */ - unsigned char *pr; - uint8_t CrcIsGood = 0; - uint8_t StructureField = 0; - uint8_t RAN = 0; - uint8_t PartOfFrame = 0; - - /* Remove compiler warning */ - //UNUSED_VARIABLE(dibit); - - //if using NXDN Scrambling, run LFSRN (dummy ambe values) to continue seed - if (state->nxdn_cipher_type == 0x1 && state->R != 0) - { - char ambe_temp[49] = {0}; - char ambe_d[49] = {0}; - for (i = 0; i < 4; i++) - { - LFSRN(ambe_temp, ambe_d, state); - } - } - - if (opts->errorbars == 1) - { - fprintf(stderr, "DATA - "); - } - - /* Start pseudo-random NXDN sequence after - * LICH = 16 bit = 8 dibit - * ==> Index 8 */ - pr = (unsigned char *)(&nxdnpr2[8]); - for (i = 0; i < 30; i++) - { - dibit = getDibit (opts, state); - - /* Store and de-interleave directly SACCH bits */ - sacch_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 - sacch_raw[(2*i)+1] = (1 & dibit); // bit 0 - pr++; -#ifdef NXDN_DUMP - fprintf(stderr, "%c", dibit + 48); -#endif - } -#ifdef NXDN_DUMP - fprintf(stderr, " "); -#endif - - - /* Decode the SACCH fields */ - CrcIsGood = NXDN_SACCH_raw_part_decode(sacch_raw, sacch_decoded); - StructureField = (sacch_decoded[0]<<1 | sacch_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */ - RAN = (sacch_decoded[2]<<5 | sacch_decoded[3]<<4 | sacch_decoded[4]<<3 | sacch_decoded[5]<<2 | sacch_decoded[6]<<1 | sacch_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the SACCH) */ - - /* Compute the Part of Frame according to the structure field */ - if (StructureField == 3) PartOfFrame = 0; - else if(StructureField == 2) PartOfFrame = 1; - else if(StructureField == 1) PartOfFrame = 2; - else if(StructureField == 0) PartOfFrame = 3; - else PartOfFrame = 0; /* Normally we should never go here */ - - /* Fill the SACCH structure */ - state->NxdnSacchRawPart[PartOfFrame].CrcIsGood = CrcIsGood; - state->NxdnSacchRawPart[PartOfFrame].StructureField = StructureField; - state->NxdnSacchRawPart[PartOfFrame].RAN = RAN; - - memcpy(state->NxdnSacchRawPart[PartOfFrame].Data, &sacch_decoded[8], 18); /* Copy the 18 bits of SACCH content */ - - //fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); - if(CrcIsGood) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); - fprintf (stderr, "%s", KNRM); - //fprintf (stderr, "(CRC OK) "); - state->nxdn_last_ran = RAN; //disable, try to grab this in voice instead - } - - else - { - fprintf (stderr, "%s", KRED); - fprintf (stderr, "(CRC ERR) "); - fprintf (stderr, "%s", KNRM); - } - - - /* Decode the SACCH only when all 4 voice frame - * SACCH spare parts have been received */ - if(PartOfFrame == 3) - { - /* Decode the entire SACCH content */ - NXDN_SACCH_Full_decode(opts, state); - } - - for (i = 0; i < 144; i++) - { - dibit = getDibit (opts, state); -#ifdef NXDN_DUMP - fprintf(stderr, "%c", dibit + 48); -#endif - } - - if (opts->errorbars == 1) - { - fprintf(stderr, "\n"); - } - - /* Reset the SACCH CRCs when all 4 voice frame - * SACCH spare parts have been received */ - if(PartOfFrame == 3) - { - /* Reset all CRCs of the SACCH */ - for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0; - - //reset Scrambler seed - if (state->nxdn_cipher_type == 0x1) - { - state->payload_miN = 0; - } - - } -} /* End processNXDNData() */ diff --git a/src/nxdn_deperm.c b/src/nxdn_deperm.c new file mode 100644 index 0000000..e932a66 --- /dev/null +++ b/src/nxdn_deperm.c @@ -0,0 +1,516 @@ +//NXDN descramble/deperm/depuncture and utility functions +//Reworked portions from Osmocom OP25 +/* -*- c++ -*- */ +/* + * NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI + * + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "dsd.h" +#include "nxdn_const.h" + +static const uint8_t scramble_t[] = { //values are the position values we need to invert in the descramble + 2, 5, 6, 7, 10, 12, 14, 16, 17, 22, 23, 25, 26, 27, 28, 30, 33, 34, 36, 37, 38, 41, 45, 47, + 52, 54, 56, 57, 59, 62, 63, 64, 65, 66, 67, 69, 70, 73, 76, 79, 81, 82, 84, 85, 86, 87, 88, + 89, 92, 95, 96, 98, 100, 103, 104, 107, 108, 116, 117, 121, 122, 125, 127, 131, 132, 134, + 137, 139, 140, 141, 142, 143, 144, 145, 147, 151, 153, 154, 158, 159, 160, 162, 164, 165, + 168, 170, 171, 174, 175, 176, 177, 181 +}; + +static const int PARITY[] = { + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, + 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, + 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 +}; + +//decoding functions here +void nxdn_descramble(uint8_t dibits[], int len) +{ + for (int i=0; i= len) + break; + dibits[scramble_t[i]] ^= 0x2; // invert sign of scrambled dibits + } +} + +void nxdn_deperm_facch(dsd_opts * opts, dsd_state * state, uint8_t bits[144]) +{ + uint8_t deperm[144]; + uint8_t depunc[192]; + uint8_t trellis_buf[92]; + uint16_t crc = 0; //crc calculated by function + uint16_t check = 0; //crc from payload for comparison + int out; + char buf[128]; + uint8_t answer[12]; + + for (int i=0; i<144; i++) + deperm[PERM_16_9[i]] = bits[i]; + out = 0; + for (int i=0; i<144; i+=3) { + depunc[out++] = deperm[i+0]; + depunc[out++] = 0; //0 + depunc[out++] = deperm[i+1]; + depunc[out++] = deperm[i+2]; + } + + trellis_decode(trellis_buf, depunc, 92); + + //load tail 16 bits into check variable to compare vs computed crc value + for (int i = 0; i < 12; i++) + { + check = check << 1; + check = check + trellis_buf[80+i]; + } + + crc = crc12f (trellis_buf, 80); + cfill(answer, trellis_buf, 12); //<-92 bits in 12 bytes, leaves 4 bits on tail to scrub off + if (opts->payload == 1) + { + fprintf (stderr, "\n"); + fprintf (stderr, " FACCH Payload "); + answer[11] = answer[11] & 0xF0; //scrub the garbage 4 bits from cfill on the end for ppayload print + for (int i = 0; i < 12; i++) + { + fprintf (stderr, "[%02X]", answer[i]); + } + + fprintf (stderr, " - %03X %03X", crc, check); + + } + + if (crc == check) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf); + else NXDN_Elements_Content_decode(opts, state, 0, trellis_buf); +} + +void nxdn_deperm_sacch(dsd_opts * opts, dsd_state * state, uint8_t bits[60]) +{ + uint8_t deperm[60]; + uint8_t depunc[72]; + uint8_t trellis_buf[32]; + uint8_t answer[26]; + int o=0; + uint8_t crc = 0; //value computed by crc6 on payload + uint8_t check = 0; //value pulled from last 6 bits + int sf = 0; + int ran = 0; + int part_of_frame = 0; + + for (int i=0; i<60; i++) + deperm[PERM_12_5[i]] = bits[i]; + for (int p=0; p<60; p+= 10) { + depunc[o++] = deperm[p+0]; + depunc[o++] = deperm[p+1]; + depunc[o++] = deperm[p+2]; + depunc[o++] = deperm[p+3]; + depunc[o++] = deperm[p+4]; + depunc[o++] = 0; //0 + depunc[o++] = deperm[p+5]; + depunc[o++] = deperm[p+6]; + depunc[o++] = deperm[p+7]; + depunc[o++] = deperm[p+8]; + depunc[o++] = deperm[p+9]; + depunc[o++] = 0; //0 + } + + trellis_decode(trellis_buf, depunc, 32); + + crc = crc6(trellis_buf, 32); + for (int i = 0; i < 6; i++) + { + check = check << 1; + check = check + trellis_buf[i+26]; + } + + //sf and ran together are denoted as SR in the manual (more confusing acronyms) + //sf (structure field) and RAN will always exist in first 8 bits of each SACCH, then the next 18 bits are the fragment of the superframe + sf = (trellis_buf[0] << 1) | trellis_buf[1]; + ran = (trellis_buf[2] << 5) | (trellis_buf[3] << 4) | (trellis_buf[4] << 3) | (trellis_buf[5] << 2) | (trellis_buf[6] << 1) | trellis_buf[7]; + if (sf == 3) part_of_frame = 0; + else if (sf == 2) part_of_frame = 1; + else if (sf == 1) part_of_frame = 2; + else if (sf == 0) part_of_frame = 3; + else part_of_frame = 0; + + //gives unusual results when non_superframe SF, not sure why, or if its accurate yet + if (state->nxdn_sacch_non_superframe == FALSE) + { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, " RAN %02d ", state->nxdn_last_ran); + //fprintf (stderr, " RAN %02d - SF %01d - POF %02d", ran, sf, part_of_frame); + fprintf (stderr, "%s", KNRM); + } + else fprintf (stderr, " "); + + //reset scrambler seed to key value on new superframe + if (part_of_frame == 0 && state->nxdn_cipher_type == 0x1) state->payload_miN = 0; + + if (crc == 0 && state->nxdn_sacch_non_superframe == FALSE) //only set these when superframe type, or get odd results (can't verify correct) + { + state->nxdn_ran = state->nxdn_last_ran = ran; + state->nxdn_sf = sf; + state->nxdn_part_of_frame = part_of_frame; + state->nxdn_sacch_frame_segcrc[part_of_frame] = 0; //zero indicates good check + } + else state->nxdn_sacch_frame_segcrc[part_of_frame] = 1; //1 indicates bad check + + int sacch_segment = 0; + + for (int i = 0; i < 18; i++) + { + sacch_segment = sacch_segment << 1; + sacch_segment = sacch_segment + trellis_buf[i+8]; + state->nxdn_sacch_frame_segment[part_of_frame][i] = trellis_buf[i+8]; + } + + //Hand off to LEH NXDN SACCH handling + if (part_of_frame == 3 && state->nxdn_sacch_non_superframe == FALSE) + { + NXDN_SACCH_Full_decode (opts, state); + } + + if (opts->payload == 1) + { + fprintf (stderr, "\n"); + fprintf (stderr, " SACCH Segment #%d - %05X", part_of_frame+1, sacch_segment); + if (crc != 0) fprintf (stderr, " CRC ERR - %02X %02X", crc, check); + } + +} + +void nxdn_deperm_facch2_udch(dsd_opts * opts, dsd_state * state, uint8_t bits[348]) +{ + + uint8_t deperm[348]; + uint8_t depunc[406]; + uint8_t trellis_buf[199]; + int id = 0; + uint16_t crc = 0; + + for (int i=0; i<348; i++) { + deperm[PERM_12_29[i]] = bits[i]; + } + for (int i=0; i<29; i++) { + depunc[id++] = deperm[i*12]; + depunc[id++] = deperm[i*12+1]; + depunc[id++] = deperm[i*12+2]; + depunc[id++] = 0; + depunc[id++] = deperm[i*12+3]; + depunc[id++] = deperm[i*12+4]; + depunc[id++] = deperm[i*12+5]; + depunc[id++] = deperm[i*12+6]; + depunc[id++] = deperm[i*12+7]; + depunc[id++] = deperm[i*12+8]; + depunc[id++] = deperm[i*12+9]; + depunc[id++] = 0; + depunc[id++] = deperm[i*12+10]; + depunc[id++] = deperm[i*12+11]; + } + trellis_decode(trellis_buf, depunc, 199); + crc = crc15(trellis_buf, 199); + + uint8_t MessageType = 0; + for (int i = 0; i < 6; i++) + { + MessageType = MessageType << 1; + MessageType = MessageType + trellis_buf[i+2]; //on +2 on any facch1 + } + + fprintf (stderr, " FACCH2/UDCH "); + if (crc == 0) NXDN_Elements_Content_decode(opts, state, 1, trellis_buf); + else + { + fprintf (stderr, "CRC ERR "); + //NXDN_Elements_Content_decode(opts, state, 0, trellis_buf); + } + +} + +void nxdn_deperm_cac(dsd_opts * opts, dsd_state * state, uint8_t bits[300]) +{ + + uint8_t deperm[300]; + uint8_t depunc[350]; + uint8_t decode[171]; + int id = 0; + uint16_t crc = 0; + + for (int i=0; i<300; i++) { + deperm[PERM_12_25[i]] = bits[i]; + } + for (int i=0; i<25; i++) { + depunc[id++] = deperm[i*12]; + depunc[id++] = deperm[i*12+1]; + depunc[id++] = deperm[i*12+2]; + depunc[id++] = 0; + depunc[id++] = deperm[i*12+3]; + depunc[id++] = deperm[i*12+4]; + depunc[id++] = deperm[i*12+5]; + depunc[id++] = deperm[i*12+6]; + depunc[id++] = deperm[i*12+7]; + depunc[id++] = deperm[i*12+8]; + depunc[id++] = deperm[i*12+9]; + depunc[id++] = 0; + depunc[id++] = deperm[i*12+10]; + depunc[id++] = deperm[i*12+11]; + } + trellis_decode(decode, depunc, 171); + crc = crc16cac(decode, 171); + + fprintf (stderr, " CAC "); + + //these messages can also be double depending on CAC type, so need to check that first, and split the + //decode first, then we can run each message type and element decode if necessary + uint8_t MessageType = 0; + for (int i = 0; i < 6; i++) + { + MessageType = MessageType << 1; + MessageType = MessageType + decode[i+2]; //double check this on CAC + } + + //nxdn_message_type (opts, state, MessageType); + + //not sure if CAC will contain same type of 'elements' as a FACCH or SACCH + //or if its purely for Control Signalling + + //need to check CAC type, CAC can contain two messages, or one long message, + //then we need to break up the messages and process them individually + if (crc == 0) NXDN_Elements_Content_decode(opts, state, 1, decode); + else + { + fprintf (stderr, " CRC ERR "); + //NXDN_Elements_Content_decode(opts, state, 0, decode); + } + +} + +//its own function now to consolidate all the message types to one area to keep track of +//may need to add a 'source' of message so we don't call messages not associated with cac, facch, sacch, etc +void nxdn_message_type (dsd_opts * opts, dsd_state * state, uint8_t MessageType) +{ + + //if (opts->payload == 1) fprintf (stderr, " M%02X ", MessageType); + fprintf (stderr, "%s", KYEL); + if (MessageType == 0x10) fprintf(stderr, " IDLE"); + else if (MessageType == 0x01) fprintf(stderr, " VCALL"); + else if (MessageType == 0x03) fprintf(stderr, " VCALL IV"); + + else if (MessageType == 0x07) fprintf(stderr, " TX_REL_EX"); + else if (MessageType == 0x08) fprintf(stderr, " TX_REL"); + + + //CAC only? valid in all, or just CAC? + else if (MessageType == 0x04) fprintf(stderr, " VCALL ASSGN"); + else if (MessageType == 0x0E) fprintf(stderr, " DCALL ASSGN"); + else if (MessageType == 0x18) fprintf(stderr, " SITE_INFO"); + else if (MessageType == 0x19) fprintf(stderr, " SRV_INFO"); //per Op25 + else if (MessageType == 0x1C) fprintf(stderr, " FAIL_STAT_INFO"); //per the damn manual + else if (MessageType == 0x1A) fprintf(stderr, " CCH_INFO"); + else if (MessageType == 0x1B) fprintf(stderr, " ADJ_SITE_INFO"); + else if (MessageType == 0x20) fprintf(stderr, " REG_RESP"); + else if (MessageType == 0x22) fprintf(stderr, " REG_C_RESP"); + else if (MessageType == 0x24) fprintf(stderr, " GRP_REG_RESP"); + else if (MessageType == 0x32) fprintf(stderr, " STAT_REQ"); + else if (MessageType == 0x33) fprintf(stderr, " STAT_RESP"); + else if (MessageType == 0x38) fprintf(stderr, " SDCALL_REQ_HEADER"); + else if (MessageType == 0x39) fprintf(stderr, " SDCALL_REQ_USERDATA"); + else if (MessageType == 0x3B) fprintf(stderr, " SDCALL_RESP"); + //end CAC only? + + else if (MessageType == 0x3F) fprintf(stderr, " ALIAS"); //observed from DSDPlus and OP25 dumps + else if (MessageType == 0x0C) fprintf(stderr, " DCALL_ACK"); //need to verify these for accuracy vs DSDPlus + else fprintf(stderr, " Unknown M%02X", MessageType); + fprintf (stderr, "%s", KNRM); + + //zero out stale values so they won't persist after a transmit release + if (MessageType == 0x08 || MessageType == 0x10) + { + memset (state->nxdn_alias_block_segment, 0, sizeof(state->nxdn_alias_block_segment)); + state->nxdn_last_rid = 0; + state->nxdn_last_tg = 0; + state->nxdn_cipher_type = 0; + } +} + +//voice descrambler +void LFSRN(char * BufferIn, char * BufferOut, dsd_state * state) +{ + int i; + int lfsr; + int pN[49] = {0}; + int bit = 0; + + lfsr = state->payload_miN & 0x7FFF; + + for (i = 0; i < 49; i++) + { + pN[i] = lfsr & 0x1; + bit = ( (lfsr >> 1) ^ (lfsr >> 0) ) & 1; + lfsr = ( (lfsr >> 1 ) | (bit << 14) ); + BufferOut[i] = BufferIn[i] ^ pN[i]; + } + + state->payload_miN = lfsr & 0x7FFF; +} + +//utility functions here, consider moving to its own file later +static inline void cfill(uint8_t result[], const uint8_t src[], int len) +{ + for (int i=0; i>1]; + result[i] = PARITY[reg & 0x19]; + result[i+1] = PARITY[reg & 0x17]; + } +} + +// simplified trellis 2:1 decode; source and result in bits +// assumes that encoding was done with NTEST trailing zero bits +// result_len should be set to the actual number of data bits +// in the original unencoded message (excl. these trailing bits) +static inline void trellis_decode(uint8_t result[], const uint8_t source[], int result_len) +{ + int reg = 0; + int min_d; + int min_bt; + static const int NTEST = 4; + static const int NTESTC = 1 << NTEST; + uint8_t bt[NTEST]; + uint8_t tt[NTEST*2]; + int dstats[4]; + int sum; + for (int p=0; p < 4; p++) + dstats[p] = 0; + for (int p=0; p < result_len; p++) { + for (int i=0; i>3; + bt[1] = (i&4)>>2; + bt[2] = (i&2)>>1; + bt[3] = (i&1); + trellis_encode(tt, bt, NTEST*2, reg); + sum=0; + for (int j=0; j 3) ? 3 : min_d] += 1; + } + // fprintf (stderr, "stats\t%d %d %d %d\n", dstats[0], dstats[1], dstats[2], dstats[3]); +} + +static uint8_t crc6(const uint8_t buf[], int len) +{ + uint8_t s[6]; + uint8_t a; + for (int i=0;i<6;i++) + s[i] = 1; + for (int i=0;inxdn_sacch_frame_segment[i], 18); + + /* Check CRC */ + if (state->nxdn_sacch_frame_segcrc[i] != 0) CrcCorrect = 0; + } + + /* Decodes the element content */ + //if (CrcCorrect == 1) NXDN_Elements_Content_decode(opts, state, CrcCorrect, SACCH); + //run it, and let each element handler decide what is okay for console, internal, and terminal assignment + if (1 == 1) NXDN_Elements_Content_decode(opts, state, CrcCorrect, SACCH); + +} /* End NXDN_SACCH_Full_decode() */ + + +void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state, + uint8_t CrcCorrect, uint8_t * ElementsContent) +{ + uint32_t i; + uint8_t MessageType; + uint64_t CurrentIV = 0; + unsigned long long int FullMessage = 0; + /* Get the "Message Type" field */ + MessageType = (ElementsContent[2] & 1) << 5; + MessageType |= (ElementsContent[3] & 1) << 4; + MessageType |= (ElementsContent[4] & 1) << 3; + MessageType |= (ElementsContent[5] & 1) << 2; + MessageType |= (ElementsContent[6] & 1) << 1; + MessageType |= (ElementsContent[7] & 1) << 0; + + //only run message type if good CRC? + if (CrcCorrect == 1) nxdn_message_type (opts, state, MessageType); + + /* Save the "F1" and "F2" flags */ + state->NxdnElementsContent.F1 = ElementsContent[0]; + state->NxdnElementsContent.F2 = ElementsContent[1]; + + /* Save the "Message Type" field */ + state->NxdnElementsContent.MessageType = MessageType; + + /* Decode the right "Message Type" */ + switch(MessageType) + { + //Alias 0x3F + case 0x3F: + { + NXDN_decode_Alias(opts, state, ElementsContent); + } + break; + + //Idle + case NXDN_IDLE: + { + //sprintf (state->nxdn_call_type, "NXDN IDLE "); + break; + } + + + /* VCALL */ + case NXDN_VCALL: + { + + /* Set the CRC state */ + state->NxdnElementsContent.VCallCrcIsGood = CrcCorrect; + + /* Decode the "VCALL" message */ + NXDN_decode_VCALL(opts, state, ElementsContent); + + /* Check the "Cipher Type" and the "Key ID" validity */ + if(CrcCorrect) + { + state->NxdnElementsContent.CipherParameterValidity = 1; + } + else state->NxdnElementsContent.CipherParameterValidity = 0; + break; + } /* End case NXDN_VCALL: */ + + /* VCALL_IV */ + case NXDN_VCALL_IV: + { + + /* Set the CRC state */ + state->NxdnElementsContent.VCallIvCrcIsGood = CrcCorrect; + + /* Decode the "VCALL_IV" message */ + NXDN_decode_VCALL_IV(opts, state, ElementsContent); + + if(CrcCorrect) + { + /* CRC is correct, copy the next theorical IV to use directly from the + * received VCALL_IV */ + memcpy(state->NxdnElementsContent.NextIVComputed, state->NxdnElementsContent.IV, 8); + } + else + { + /* CRC is incorrect, compute the next IV to use */ + CurrentIV = 0; + + /* Convert the 8 bytes buffer into a 64 bits integer */ + for(i = 0; i < 8; i++) + { + CurrentIV |= state->NxdnElementsContent.NextIVComputed[i]; + CurrentIV = CurrentIV << 8; + } + + } + break; + } /* End case NXDN_VCALL_IV: */ + + /* Unknown Message Type */ + default: + { + //fprintf(stderr, "Unknown Message type "); + break; + } + } /* End switch(MessageType) */ + +} /* End NXDN_Elements_Content_decode() */ + +void NXDN_decode_Alias(dsd_opts * opts, dsd_state * state, uint8_t * Message) +{ + uint8_t Alias1 = 0x0; //value of an ascii 'NULL' character + uint8_t Alias2 = 0x0; + uint8_t Alias3 = 0x0; + uint8_t Alias4 = 0x0; + uint8_t blocknumber = 0; + uint8_t CrcCorrect = 1; + state->NxdnElementsContent.VCallCrcIsGood = CrcCorrect; + + //FACCH Payload [3F][68][82][04][2 <- block number4] "[69][6F][6E][20]" <- 4 alias octets [00][7F][1C] + blocknumber = (uint8_t)ConvertBitIntoBytes(&Message[32], 4) & 0x7; // & 0x7, might just be three bits, unsure + Alias1 = (uint8_t)ConvertBitIntoBytes(&Message[40], 8); + Alias2 = (uint8_t)ConvertBitIntoBytes(&Message[48], 8); + Alias3 = (uint8_t)ConvertBitIntoBytes(&Message[56], 8); + Alias4 = (uint8_t)ConvertBitIntoBytes(&Message[64], 8); + //sanity check to prevent OOB array assignment + if (blocknumber > 0 && blocknumber < 5) + { + //assign to index -1, since block number conveyed here is 1,2,3,4, and index values are 0,1,2,3 + //only assign if within valid range of ascii characters (not including diacritical extended alphabet) + //else assign "null" ascii character + + //since we are zeroing out the blocks on tx_rel and other conditions, better to just set nothing to bad Alias bytes + //tends to zero out otherwise already good blocks set in a previous repitition. + if (Alias1 > 0x19 && Alias1 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][0], "%c", Alias1); + else ;// sprintf (state->nxdn_alias_block_segment[blocknumber-1][0], "%c", 0); + + if (Alias2 > 0x19 && Alias2 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][1], "%c", Alias2); + else ; //sprintf (state->nxdn_alias_block_segment[blocknumber-1][1], "%c", 0); + + if (Alias3 > 0x19 && Alias3 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][2], "%c", Alias3); + else ; //sprintf (state->nxdn_alias_block_segment[blocknumber-1][2], "%c", 0); + + if (Alias4 > 0x19 && Alias4 < 0x7F) sprintf (state->nxdn_alias_block_segment[blocknumber-1][3], "%c", Alias4); + else ; //sprintf (state->nxdn_alias_block_segment[blocknumber-1][3], "%c", 0); + } + + if (CrcCorrect) //was by blocknumber being 4, but wasn't as frequent as I would like in the console + { + fprintf (stderr, " "); //probably just want a space instead + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + fprintf (stderr, "%s", state->nxdn_alias_block_segment[i][j]); + } + } + fprintf (stderr, " "); + } + else fprintf (stderr, " CRC ERR "); //redundant print? or okay? +} + +void NXDN_decode_cch_info(dsd_opts * opts, dsd_state * state, uint8_t * Message) +{ + uint8_t location_id = 0; + uint8_t channel_ifno = 0; +} + +/* + * @brief : This function decodes the VCALL message + * + * @param opts : Option structure parameters pointer + * + * @param state : State structure parameters pointer + * + * @param Message : A 64 bit buffer containing the VCALL message to decode + * + * @return None + * + */ +void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) +{ + //uint32_t i; + uint8_t CCOption = 0; + uint8_t CallType = 0; + uint8_t VoiceCallOption = 0; + uint16_t SourceUnitID = 0; + uint16_t DestinationID = 0; + uint8_t CipherType = 0; + uint8_t KeyID = 0; + uint8_t DuplexMode[32] = {0}; + uint8_t TransmissionMode[32] = {0}; + unsigned long long int FullMessage = 0; + + /* Message[0..7] contains : + * - The "F1" and "F2" flags + * - The "Message Type" (already decoded before calling this function) + * + * So no need to decode it a second time + */ + + /* Decode "CC Option" */ + CCOption = (uint8_t)ConvertBitIntoBytes(&Message[8], 8); + state->NxdnElementsContent.CCOption = CCOption; + + /* Decode "Call Type" */ + CallType = (uint8_t)ConvertBitIntoBytes(&Message[16], 3); + state->NxdnElementsContent.CallType = CallType; + + /* Decode "Voice Call Option" */ + VoiceCallOption = (uint8_t)ConvertBitIntoBytes(&Message[19], 5); + state->NxdnElementsContent.VoiceCallOption = VoiceCallOption; + + /* Decode "Source Unit ID" */ + SourceUnitID = (uint16_t)ConvertBitIntoBytes(&Message[24], 16); + state->NxdnElementsContent.SourceUnitID = SourceUnitID; + + /* Decode "Destination ID" */ + DestinationID = (uint16_t)ConvertBitIntoBytes(&Message[40], 16); + state->NxdnElementsContent.DestinationID = DestinationID; + + /* Decode the "Cipher Type" */ + CipherType = (uint8_t)ConvertBitIntoBytes(&Message[56], 2); + state->NxdnElementsContent.CipherType = CipherType; + + /* Decode the "Key ID" */ + KeyID = (uint8_t)ConvertBitIntoBytes(&Message[58], 6); + state->NxdnElementsContent.KeyID = KeyID; + + /* Print the "CC Option" */ + if(CCOption & 0x80) fprintf(stderr, "Emergency "); + if(CCOption & 0x40) fprintf(stderr, "Visitor "); + if(CCOption & 0x20) fprintf(stderr, "Priority Paging "); + + if((CipherType == 2) || (CipherType == 3)) + { + state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1; + state->NxdnElementsContent.PartOfNextEncryptedFrame = 2; + } + else + { + state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1; + state->NxdnElementsContent.PartOfNextEncryptedFrame = 1; + } + + /* Print the "Call Type" */ + fprintf (stderr, "%s", KGRN); + fprintf(stderr, "\n %s - ", NXDN_Call_Type_To_Str(CallType)); + sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType)); + + /* Print the "Voice Call Option" */ + NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode); + fprintf(stderr, "%s %s - ", DuplexMode, TransmissionMode); + + /* Print Source ID and Destination ID (Talk Group or Unit ID) */ + //fprintf (stderr, "%s", KGRN); + fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF); + fprintf (stderr, "%s", KNRM); + + /* Print the "Cipher Type" */ + if(CipherType != 0) + { + fprintf (stderr, "\n %s", KYEL); + fprintf(stderr, "%s - ", NXDN_Cipher_Type_To_Str(CipherType)); + //state->nxdn_cipher_type = CipherType; + } + + /* Print the Key ID */ + if(CipherType != 0) + { + + fprintf(stderr, "Key ID %u - ", KeyID & 0xFF); + fprintf (stderr, "%s", KNRM); + //state->nxdn_key = (KeyID & 0xFF); + } + + if (state->nxdn_cipher_type == 0x01 && state->R > 0) //scrambler key value + { + fprintf (stderr, "%s", KYEL); + fprintf(stderr, "Value: %05lld", state->R); + fprintf (stderr, "%s", KNRM); + } + + if(state->NxdnElementsContent.VCallCrcIsGood) + { + if ( (SourceUnitID & 0xFFFF) > 0 ) + { + state->nxdn_last_rid = SourceUnitID & 0xFFFF; //only grab if CRC is okay + state->nxdn_last_tg = (DestinationID & 0xFFFF); + state->nxdn_key = (KeyID & 0xFF); + state->nxdn_cipher_type = CipherType; //will this set to zero if no enc? + } + } + else + { + fprintf (stderr, "%s", KRED); + fprintf(stderr, "(CRC ERR) "); + fprintf (stderr, "%s", KNRM); + } + + //set enc bit here so we can tell playSynthesizedVoice whether or not to play enc traffic + if (state->nxdn_cipher_type != 0) + { + state->dmr_encL = 1; + } + if (state->nxdn_cipher_type == 0 || state->R != 0) + { + state->dmr_encL = 0; + } +} /* End NXDN_decode_VCALL() */ + + +/* + * @brief : This function decodes the VCALL_IV message + * + * @param opts : Option structure parameters pointer + * + * @param state : State structure parameters pointer + * + * @param Message : A 72 bit buffer containing the VCALL_IV message to decode + * + * @return None + * + */ +void NXDN_decode_VCALL_IV(dsd_opts * opts, dsd_state * state, uint8_t * Message) +{ + uint32_t i; + + /* Message[0..7] contains : + * - The "F1" and "F2" flags + * - The "Message Type" (already decoded before calling this function) + * + * So no need to decode it a second time + * + * Message[8..71] contains : The 64 bits IV + */ + state->payload_miN = 0; //zero out + /* Extract the IV from the VCALL_IV message */ + for(i = 0; i < 8; i++) + { + state->NxdnElementsContent.IV[i] = (uint8_t)ConvertBitIntoBytes(&Message[(i + 1) * 8], 8); + + state->payload_miN = state->payload_miN << 8 | state->NxdnElementsContent.IV[i]; + } + + state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 2; + state->NxdnElementsContent.PartOfNextEncryptedFrame = 1; + +} /* End NXDN_decode_VCALL_IV() */ + + +/* + * @brief : This function decodes the "Call Type" and return the + * ASCII string corresponding to it. + * + * @param CallType : The call type parameter to decode + * + * @return An ASCII string of the "Call Type" + * + */ +char * NXDN_Call_Type_To_Str(uint8_t CallType) +{ + char * Ptr = NULL; + + switch(CallType) + { + case 0: Ptr = "Broadcast Call"; break; + case 1: Ptr = "Group Call"; break; + case 2: Ptr = "Unspecified Call"; break; + case 3: Ptr = "Reserved"; break; + case 4: Ptr = "Individual Call"; break; + case 5: Ptr = "Reserved"; break; + case 6: Ptr = "Interconnect Call"; break; + case 7: Ptr = "Speed Dial Call"; break; + default: Ptr = "Unknown Call Type"; break; + } + + return Ptr; +} /* End NXDN_Call_Type_To_Str() */ + + +/* + * @brief : This function decodes the "Voice Call Option" and return the + * ASCII string corresponding to it. + * + * @param VoiceCallOption : The call type parameter to decode + * + * @param Duplex : A 32 bytes ASCII buffer pointer where store + * the Duplex/Half duplex mode + * + * @param TransmissionMode : A 32 bytes ASCII buffer pointer where store + * the transmission mode (bit rate) + * + * @return An ASCII string of the "Voice Call Option" + * + */ +void NXDN_Voice_Call_Option_To_Str(uint8_t VoiceCallOption, uint8_t * Duplex, uint8_t * TransmissionMode) +{ + char * Ptr = NULL; + + Duplex[0] = 0; + TransmissionMode[0] = 0; + + if(VoiceCallOption & 0x10) strcpy((char *)Duplex, "Duplex"); + else strcpy((char *)Duplex, "Half Duplex"); + + switch(VoiceCallOption & 0x17) + { + case 0: Ptr = "4800bps/EHR"; break; + case 2: Ptr = "9600bps/EHR"; break; + case 3: Ptr = "9600bps/EFR"; break; + default: Ptr = "Reserved Voice Call Option"; break; + } + + strcpy((char *)TransmissionMode, Ptr); +} /* End NXDN_Voice_Call_Option_To_Str() */ + +/* + * @brief : This function decodes the "Cipher Type" and return the + * ASCII string corresponding to it. + * + * @param CipherType : The cipher type parameter to decode + * + * @return An ASCII string of the "Cipher Type" + * + */ +char * NXDN_Cipher_Type_To_Str(uint8_t CipherType) +{ + char * Ptr = NULL; + + switch(CipherType) + { + case 0: Ptr = ""; break; /* Non-ciphered mode / clear call */ + case 1: Ptr = "Scrambler"; break; + case 2: Ptr = "DES"; break; + case 3: Ptr = "AES"; break; + default: Ptr = "Unknown Cipher Type"; break; + } + + return Ptr; +} /* End NXDN_Cipher_Type_To_Str() */ \ No newline at end of file diff --git a/src/nxdn_frame.c b/src/nxdn_frame.c new file mode 100644 index 0000000..591eef2 --- /dev/null +++ b/src/nxdn_frame.c @@ -0,0 +1,260 @@ +//NXDN frame handler +//Reworked portions from Osmocom OP25 +//from Osmocom OP25 rx_sync.cc +/* -*- c++ -*- */ +/* + * NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI + * + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "dsd.h" +#include "nxdn_const.h" + +#include + +void nxdn_frame (dsd_opts * opts, dsd_state * state) +{ + // length is implicitly 192, with frame sync in first 10 dibits + uint8_t dbuf[182]; + uint8_t lich; + int answer_len=0; + uint8_t answer[32]; + uint8_t sacch_answer[32]; + int lich_parity_received; + int lich_parity_computed; + int voice=0; + int facch=0; + int facch2=0; + int sacch=0; + int cac=0; + int sr_structure; + int sr_ran; + + uint8_t lich_dibits[8] = {0}; + uint8_t sacch_bits[60] = {0}; + uint8_t facch_bits_a[144] = {0}; + uint8_t facch_bits_b[144] = {0}; + uint8_t cac_bits[300] = {0}; + uint8_t facch2_bits[348] = {0}; //facch2 or udch, same amount of bits + + //nxdn bit buffer, for easy assignment handling + int nxdn_bit_buffer[364] = {0}; + int nxdn_dibit_buffer[182] = {0}; + + memset (dbuf, 0, sizeof(dbuf)); + + //collect lich bits first, if they are good, then we can collect the rest of them + //otherwise we will either exit, or skip and then exit (depends on performance) + for (int i = 0; i < 8; i++) + { + lich_dibits[i] = dbuf[i] = getDibit(opts, state); + } + + nxdn_descramble (lich_dibits, 8); + + lich = 0; + for (int i=0; i<8; i++) + { + lich |= (lich_dibits[i] >> 1) << (7-i); + } + + lich_parity_received = lich & 1; + lich_parity_computed = ((lich >> 7) + (lich >> 6) + (lich >> 5) + (lich >> 4)) & 1; + lich = lich >> 1; + if (lich_parity_received != lich_parity_computed) + { + //fprintf(stderr, "NXDN lich parity error, ignoring frame \n"); + return; + } + + voice = 0; + facch = 0; + facch2 = 0; + sacch = 0; + cac = 0; + switch(lich) { //cases without breaks continue to flow downwards until they hit the break + case 0x01: // CAC types + case 0x05: + cac = 1; + break; + case 0x28: //facch2 types + case 0x29: + case 0x2e: + case 0x2f: + case 0x48: + case 0x49: + case 0x4e: + case 0x4f: + case 0x69: + case 0x6f: + facch2 = 1; + break; + case 0x32: //facch in 1, vch in 2 + case 0x33: + case 0x52: + case 0x53: + case 0x73: + voice = 2; + facch = 1; + sacch = 1; + break; + case 0x34: //vch in 1, facch in 2 + case 0x35: + case 0x54: + case 0x55: + case 0x75: + voice = 1; + facch = 2; + sacch = 1; + break; + case 0x36: //vch in both + case 0x37: + case 0x56: + case 0x57: + case 0x77: + voice = 3; + facch = 0; + sacch = 1; + break; + case 0x20: //facch in both + case 0x21: + case 0x30: + case 0x31: + case 0x40: + case 0x41: + case 0x50: + case 0x51: + case 0x61: + case 0x71: + voice = 0; + facch = 3; + sacch = 1; + break; + case 0x38: //sacch only (NULL?) + case 0x39: + sacch = 1; + break; + default: + if (opts->payload == 1) fprintf(stderr, "unsupported NXDN lich type 0x%02X\n", lich); + //fprintf(stderr, " unsupported NXDN lich 0x%02X\n", lich); + voice = 0; + goto END; + break; + } // end of switch(lich) + + //printframesync after determining we have a good lich and it has something in it + if (voice || facch || sacch || facch2 || cac) + { + // if (state->synctype == 28) fprintf (stderr, " +"); + // else fprintf (stderr, " -"); + if (opts->frame_nxdn48 == 1) + { + printFrameSync (opts, state, "NXDN48 ", 0, "-"); + } + else printFrameSync (opts, state, "NXDN96 ", 0, "-"); + if (opts->payload == 1) fprintf (stderr, "L%02X -", lich); + } + + //now that we have a good LICH, we can collect all of our dibits + //and push them to the proper places for decoding (if LICH calls for that type) + for (int i = 0; i < 174; i++) //192total-10FSW-8lich = 174 + { + dbuf[i+8] = getDibit(opts, state); + } + + nxdn_descramble (dbuf, 182); //sizeof(dbuf) + + //seperate our dbuf (dibit_buffer) into individual bit array + for (int i = 0; i < 182; i++) + { + nxdn_bit_buffer[i*2] = dbuf[i] >> 1; + nxdn_bit_buffer[i*2+1] = dbuf[i] & 1; + } + + //sacch + for (int i = 0; i < 60; i++) + { + sacch_bits[i] = nxdn_bit_buffer[i+16]; + } + + //facch + for (int i = 0; i < 144; i++) + { + facch_bits_a[i] = nxdn_bit_buffer[i+16+60]; + facch_bits_b[i] = nxdn_bit_buffer[i+16+60+144]; + } + + //cac + for (int i = 0; i < 300; i++) + { + cac_bits[i] = nxdn_bit_buffer[i+16]; + } + + //udch or facch2 + for (int i = 0; i < 348; i++) + { + facch2_bits[i] = nxdn_bit_buffer[i+16]; + } + + //vch frames stay inside dbuf, easier to assign that to ambe_fr frames + //sacch needs extra handling depending on superframe or non-superframe variety + + if (voice) + { + fprintf (stderr, "%s", KGRN); + fprintf (stderr, " Voice "); + fprintf (stderr, "%s", KNRM); + } + else + { + fprintf (stderr, "%s", KCYN); + fprintf (stderr, " Data "); + fprintf (stderr, "%s", KNRM); + + //roll the voice scrambler LFSR here if key available to advance seed (usually just needed on NXDN96) + if (state->nxdn_cipher_type == 0x1 && state->R != 0) //!voice, or voice == 0 + { + char ambe_temp[49] = {0}; + char ambe_d[49] = {0}; + for (int i = 0; i < 4; i++) + { + LFSRN(ambe_temp, ambe_d, state); + } + } + + } + + if (sacch) + { + state->nxdn_sacch_non_superframe = (lich == 0x20 || lich == 0x21 || lich == 0x61 || lich == 0x40 || lich == 0x41) ? true : false; + nxdn_deperm_sacch(opts, state, sacch_bits); + } + if (cac) nxdn_deperm_cac(opts, state, cac_bits); + if (facch2) nxdn_deperm_facch2_udch(opts, state, facch2_bits); + if (facch & 1) nxdn_deperm_facch(opts, state, facch_bits_a); + if (facch & 2) + { + //don't run if duplicate of facch in first, may still run both if one has bad CRC + //hopefully can mitigate that later when we having the CRC function working properly for FACCH + if (facch_bits_a != facch_bits_b) nxdn_deperm_facch(opts, state, facch_bits_b); //don't think this check works correctly + } + if (voice) nxdn_voice (opts, state, voice, dbuf); //working great now with new simplified method! + + fprintf (stderr, "\n"); + END: ; //do nothing +} diff --git a/src/nxdn_lib.c b/src/nxdn_lib.c deleted file mode 100644 index 8b48381..0000000 --- a/src/nxdn_lib.c +++ /dev/null @@ -1,1692 +0,0 @@ -/* - ============================================================================ - Name : nxdn_lib - Author : - Version : 1.0 - Date : 2018 December 26 - Copyright : No copyright - Description : NXDN decoding source lib - ============================================================================ - */ - - -/* Include ------------------------------------------------------------------*/ -#include "dsd.h" -#include "nxdn_const.h" - - -/* Global variables ---------------------------------------------------------*/ - - -/* Functions ----------------------------------------------------------------*/ - - -/* - * @brief : This function decodes the LICH - * - * @param InputLich : A 8 ASCII bytes buffer - * - * @param RFChannelType : Output of RF Channel Type - * parameter - * - * @param FunctionnalChannelType : Output of Functional - * Channel Type parameter - * - * @param Option : Output of Option parameter - * - * @param : CompleteLichBinaryFormat : The constitued LICH (7 bits) - * - * @param Direction : Output of Direction parameter - * - * @param Inverted : 1 = Inverted frame ; 0 = Normal frame - * - * @return 1 when LICH parity is good - * 0 when LICH parity is bad - * - */ - //borrowed from LEH my_lib.c file - uint32_t ConvertBitIntoBytes(uint8_t * BufferIn, uint32_t BitLength) - { - uint32_t Output = 0; - uint32_t i; - - for(i = 0; i < BitLength; i++) - { - Output <<= 1; - Output |= (uint32_t)(BufferIn[i] & 1); - } - - return Output; - } /* End ConvertBitIntoBytes() */ - - - uint8_t NXDN_decode_LICH(uint8_t InputLich[8], - uint8_t * RFChannelType, - uint8_t * FunctionnalChannelType, - uint8_t * Option, - uint8_t * Direction, - uint8_t * CompleteLichBinaryFormat, - uint8_t Inverted) -{ - uint8_t GoodParity = 0; - uint32_t i; - uint8_t LichDibits[8] = {0}; - uint8_t LichBits[8] = {0}; - uint8_t EvenParityComputed = 0; - uint8_t *pr; - uint8_t dibit; - uint8_t InvertionDibitValue; - uint8_t CompleteLich = 0; - - if(Inverted) InvertionDibitValue = 0x02; - else InvertionDibitValue = 0x00; - - pr = (uint8_t *)(&nxdnpr[0]); - - /* Recreate a 8 bits field - * 7 bits of LICH + 1 parity bit */ - for(i = 0; i < 8; i++) - { - /* Get the dibit value (convert ASCII to bin value) */ - dibit = ((InputLich[i] - '0') & 0x03) ^ InvertionDibitValue; - - /* Descramble the dibit */ - LichDibits[i] = dibit ^ ((*pr & 0x01) << 1); - - /* Increment pseudo-random pointer */ - pr++; - - /* Decode LICH dibit */ - switch(LichDibits[i]) - { - case 0: - { - LichBits[i] = 0; - break; - } - case 1: - { - LichBits[i] = 0; - break; - } - case 2: - { - LichBits[i] = 1; - break; - } - default: - { - LichBits[i] = 1; - break; - } - } /* End switch(LichDibits[i]) */ - - /* Parity should be even */ - EvenParityComputed += LichBits[i]; - - } /* End for(i = 0; i < 8; i++) */ - - /* Even parity = Good */ - if((EvenParityComputed % 2) == 0) - { - GoodParity = 1; - } - else - { - /* Odd parity = Wrong */ - } - - *RFChannelType = ((LichBits[0] & 0x01) << 1) | (LichBits[1] & 0x01); - *FunctionnalChannelType = ((LichBits[2] & 0x01) << 1) | (LichBits[3] & 0x01); - *Option = ((LichBits[4] & 0x01) << 1) | (LichBits[5] & 0x01); - *Direction = LichBits[6] & 0x01; - - CompleteLich = 0; - for(i = 0; i < 7; i++) - { - CompleteLich = ((CompleteLich << 1) | LichBits[i]) & 0x7F; - } - *CompleteLichBinaryFormat = CompleteLich; - - return GoodParity; -} /* End NXDN_decode_LICH() */ - - -/* - * @brief : This function decodes the RAW part of SACCH received when - * each voice frame starts. - * This is NOT the full SACCH but only 18 bits on 72. - * - * @param Input : A 60 bit (60 bytes) buffer pointer of input data - * - * @param Output : A 32 bit (26 bytes data + 6 bytes CRC) buffer where write output data - * - * @return 1 when CRC is good - * 0 when CRC is bad - * - */ -uint8_t NXDN_SACCH_raw_part_decode(uint8_t * Input, uint8_t * Output) -{ - uint32_t i; - uint8_t sacchRaw[60]; /* SACCH bits retrieved from RF channel */ - uint8_t sacch[72] = {0}; - uint8_t s0; - uint8_t s1; - uint8_t m_data[5] = {0}; /* SACCH bytes after de-convolution (36 bits) */ - uint8_t CRCComputed = 0; - uint8_t CRCExtracted = 0; - uint32_t index = 0; - uint32_t punctureIndex = 0; - uint8_t temp[90] = {0}; /* SACCH working area */ - //uint8_t RAN = 0; - //uint8_t StructureField = 0; - uint8_t GoodCrc = 0; - - //UNUSED_VARIABLE(sacch[0]); - - /* De-interleave */ - for(i = 0; i < 60; i++) - { - sacchRaw[DSDNXDN_SACCH_m_Interleave[i]] = Input[i]; - } - - /* Un-Punture */ - for (index = 0, punctureIndex = 0, i = 0; i < 60; i++) - { - if (index == (uint32_t)DSDNXDN_SACCH_m_PunctureList[punctureIndex]) - { - temp[index++] = 1; - punctureIndex++; - } - - temp[index++] = sacchRaw[i]<<1; // 0->0, 1->2 - } - - for (i = 0; i < 8; i++) - { - temp[index++] = 0; - } - - /* Convolutional decoding */ - CNXDNConvolution_start(); - for (i = 0U; i < 40U; i++) - { - s0 = temp[(2*i)]; - s1 = temp[(2*i)+1]; - - CNXDNConvolution_decode(s0, s1); - } - - CNXDNConvolution_chainback(m_data, 36U); - - - for(i = 0; i < 4; i++) - { - Output[(i*8)+0] = (m_data[i] >> 7) & 1; - Output[(i*8)+1] = (m_data[i] >> 6) & 1; - Output[(i*8)+2] = (m_data[i] >> 5) & 1; - Output[(i*8)+3] = (m_data[i] >> 4) & 1; - Output[(i*8)+4] = (m_data[i] >> 3) & 1; - Output[(i*8)+5] = (m_data[i] >> 2) & 1; - Output[(i*8)+6] = (m_data[i] >> 1) & 1; - Output[(i*8)+7] = (m_data[i] >> 0) & 1; - } - - /* Extract the 6 bit CRC */ - CRCExtracted = m_data[3] & 0x3F; - - /* Compute the 6 bit CRC */ - CRCComputed = CRC6BitNXDN(Output, 26); - - /* Compute the RAN (6 last bits of the SR Information in the SACCH) */ - //RAN = m_data[0] & 0x3F; - - /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */ - //StructureField = (m_data[0] >> 6) & 0x03; - - //fprintf(stderr, "RAN=%u ; StructureField=%u ; ", RAN, StructureField); - - //fprintf(stderr, "SACCH=0x%02X-0x%02X-0x%02X-0x%02X-0x%02X ; ", - // m_data[0], m_data[1], m_data[2], m_data[3], m_data[4]); - - //fprintf(stderr, "CRC Extracted=0x%02X ; CRC computed=0x%02X ; ", CRCExtracted, CRCComputed); - - /* Check CRCs */ - if(CRCExtracted == CRCComputed) - { - //fprintf(stderr, "OK !\n"); - GoodCrc = 1; - } - else - { - //fprintf(stderr, "ERROR !\n"); - GoodCrc = 0; - } - - return GoodCrc; -} /* NXDN_SACCH_raw_part_decode() */ - - -/* - * @brief : This function decodes the full SACCH (when 4 voice frame parts - * have been successfully received) - * - * @param opts : Option structure parameters pointer - * - * @param state : State structure parameters pointer - * - * @return None - * - */ -void NXDN_SACCH_Full_decode(dsd_opts * opts, dsd_state * state) -{ - uint8_t SACCH[72]; - uint32_t i; - uint8_t CrcCorrect = 1; - - /* Consider all SACCH CRC parts as corrects */ - CrcCorrect = 1; - - /* Reconstitute the full 72 bits SACCH */ - for(i = 0; i < 4; i++) - { - memcpy(&SACCH[i * 18], state->NxdnSacchRawPart[i].Data, 18); - - /* Check CRC */ - if(state->NxdnSacchRawPart[i].CrcIsGood == 0) CrcCorrect = 0; - //fprintf(stderr, "\n SAACH P# %1d - %05X", i, state->NxdnSacchRawPart[i].Data); - } - - /* Decodes the element content */ - NXDN_Elements_Content_decode(opts, state, CrcCorrect, SACCH); - -} /* End NXDN_SACCH_Full_decode() */ - - -/* - * @brief : This function decodes the RAW part of FACCH1 received when - * each voice frame starts. - * - * @param Input : A 144 bits (144 bytes) buffer pointer of input data - * - * @param Output : A 96 bits (80 bytes data + 12 bytes CRC + 4 bytes "Tail" all "0") buffer where write output data - * - * @return 1 when CRC is good - * 0 when CRC is bad - * - */ -uint8_t NXDN_FACCH1_decode(uint8_t * Input, uint8_t * Output) -{ - uint32_t i; - uint8_t GoodCrc = 0; - uint16_t CRCComputed = 0; - uint16_t CRCExtracted = 0; - uint8_t facch1Raw[144]; /* FACCH1 bits retrieved from RF channel */ - uint8_t s0; - uint8_t s1; - uint8_t m_data[12] = {0}; /* FACCH1 bytes after de-convolution (96 bits) */ - uint32_t index = 0; - uint32_t punctureIndex = 0; - uint8_t temp[210] = {0}; /* FACCH1 working area */ - - /* De-interleave */ - for(i = 0; i < 144; i++) - { - facch1Raw[DSDNXDN_FACCH1_m_Interleave[i]] = Input[i]; - } - - /* Un-Punture */ - for (index = 0, punctureIndex = 0, i = 0; i < 144; i++) - { - if (index == (uint32_t)DSDNXDN_FACCH1_m_PunctureList[punctureIndex]) - { - temp[index++] = 1; - punctureIndex++; - } - - temp[index++] = facch1Raw[i]<<1; // 0->0, 1->2 - } - - for (i = 0; i < 8; i++) - { - temp[index++] = 0; - } - - /* Convolutional decoding */ - CNXDNConvolution_start(); - for (i = 0U; i < 100U; i++) - { - s0 = temp[(2*i)]; - s1 = temp[(2*i)+1]; - - CNXDNConvolution_decode(s0, s1); - } - /* - fprintf (stderr, "\n"); - for (i = 0U; i < 100U; i++) - { - fprintf (stderr, "temp=%X", temp[i]); - } - fprintf (stderr, "\n"); - */ - CNXDNConvolution_chainback(m_data, 96U); - - /* Reconstitute L3 Data (Data 80 bits + CRC 12 bits + 4 tail bits = Total 96 bits = 12 bytes) */ - for(i = 0; i < 12; i++) - { - Output[(i*8)+0] = (m_data[i] >> 7) & 1; - Output[(i*8)+1] = (m_data[i] >> 6) & 1; - Output[(i*8)+2] = (m_data[i] >> 5) & 1; - Output[(i*8)+3] = (m_data[i] >> 4) & 1; - Output[(i*8)+4] = (m_data[i] >> 3) & 1; - Output[(i*8)+5] = (m_data[i] >> 2) & 1; - Output[(i*8)+6] = (m_data[i] >> 1) & 1; - Output[(i*8)+7] = (m_data[i] >> 0) & 1; - } - - /* Extract the 12 bits CRC */ - CRCExtracted = ((uint16_t)(m_data[10] << 4) | (uint16_t)(m_data[11] >> 4)) & 0x0FFF; - - /* Compute the 12 bits CRC */ - CRCComputed = CRC12BitNXDN(Output, 80); - - //fprintf(stderr, "\n"); - - //fprintf(stderr, "SACCH1 Data = "); - //for(i = 0; i < 12; i++) - //{ - // fprintf(stderr, "0x%02X - ", m_data[i]); - //} - //fprintf(stderr, "\n"); - - //fprintf(stderr, "CRC computed = 0x%03X - CRC extracted = 0x%03X\n", CRCComputed, CRCExtracted); - - /* Check CRCs */ - if(CRCExtracted == CRCComputed) - { - //fprintf(stderr, "OK !\n"); - GoodCrc = 1; - } - else - { - //fprintf(stderr, "ERROR !\n"); - GoodCrc = 0; - } - - return GoodCrc; -} /* End NXDN_FACCH1_decode() */ - - - -/* - * @brief : This function decodes the UDCH/FACCH2 received. - * - * @param Input : A 348 bits (348 bytes) buffer pointer of input data - * - * @param Output : A 203 bits (184 bytes data + 15 bytes CRC + 4 bytes "Tail" all "0") buffer where write output data - * - * @return 1 when CRC is good - * 0 when CRC is bad - * - */ -uint8_t NXDN_UDCH_decode(uint8_t * Input, uint8_t * Output) -{ - uint32_t i; - uint8_t GoodCrc = 0; - uint16_t CRCComputed = 0; - uint16_t CRCExtracted = 0; - uint8_t UdchRaw[348]; /* UDCH bits retrieved from RF channel */ - uint8_t s0; - uint8_t s1; - uint8_t m_data[26] = {0}; /* UDCH bytes after de-convolution (203 bits) */ - uint32_t index = 0; - uint32_t punctureIndex = 0; - uint8_t temp[420] = {0}; /* UDCH working area */ - - /* De-interleave */ - for(i = 0; i < 348; i++) - { - UdchRaw[DSDNXDN_UDCH_m_Interleave[i]] = Input[i]; - } - - /* Un-Punture */ - for (index = 0, punctureIndex = 0, i = 0; i < 348; i++) - { - if (index == (uint32_t)DSDNXDN_UDCH_m_PunctureList[punctureIndex]) - { - temp[index++] = 1; - punctureIndex++; - } - - temp[index++] = UdchRaw[i]<<1; // 0->0, 1->2 - } - - for (i = 0; i < 8; i++) - { - temp[index++] = 0; - } - - /* Convolutional decoding */ - CNXDNConvolution_start(); - for (i = 0U; i < 207U; i++) - { - s0 = temp[(2*i)]; - s1 = temp[(2*i)+1]; - - CNXDNConvolution_decode(s0, s1); - } - - CNXDNConvolution_chainback(m_data, 203U); - - /* Reconstitute L3 Data (Data 184 bits + CRC 15 bits + 4 tail bits = Total 203 bits = 26 bytes) */ - for(i = 0; i < 25; i++) - { - Output[(i*8)+0] = (m_data[i] >> 7) & 1; - Output[(i*8)+1] = (m_data[i] >> 6) & 1; - Output[(i*8)+2] = (m_data[i] >> 5) & 1; - Output[(i*8)+3] = (m_data[i] >> 4) & 1; - Output[(i*8)+4] = (m_data[i] >> 3) & 1; - Output[(i*8)+5] = (m_data[i] >> 2) & 1; - Output[(i*8)+6] = (m_data[i] >> 1) & 1; - Output[(i*8)+7] = (m_data[i] >> 0) & 1; - } - /* Get the 3 last bits */ - Output[200] = (m_data[25] >> 7) & 1; - Output[201] = (m_data[25] >> 6) & 1; - Output[202] = (m_data[25] >> 5) & 1; - - /* Extract the 15 bits CRC */ - CRCExtracted = ((uint16_t)(m_data[23] << 7) | (uint16_t)(m_data[24] >> 1)) & 0x7FFF; - - /* Compute the 15 bits CRC */ - CRCComputed = CRC15BitNXDN(Output, 184); - - //fprintf(stderr, "\n"); - - //fprintf(stderr, "FACCH2 Data = "); - //for(i = 0; i < 26; i++) - //{ - // fprintf(stderr, "0x%02X - ", m_data[i]); - //} - //fprintf(stderr, "\n"); - - //fprintf(stderr, "CRC computed = 0x%04X - CRC extracted = 0x%04X\n", CRCComputed, CRCExtracted); - - /* Check CRCs */ - if(CRCExtracted == CRCComputed) - { - //fprintf(stderr, "OK !\n"); - GoodCrc = 1; - } - else - { - //fprintf(stderr, "ERROR !\n"); - GoodCrc = 0; - } - - return GoodCrc; -} /* End NXDN_UDCH_decode() */ - - - -/* - * @brief : This function decodes the content of elements in : - * - Full SACCH (when 4 voice frame parts have been - * successfully received) - * - * @param opts : Option structure parameters pointer - * - * @param state : State structure parameters pointer - * - * @param CrcCorrect : The CRC status of the last element received - * 0 = CRC incorrect - * Oher = CRC correct - * - * @param ElementsContent : A 64 to 144 bits buffer containing the - * element content - * - * @return None - * - */ -void NXDN_Elements_Content_decode(dsd_opts * opts, dsd_state * state, - uint8_t CrcCorrect, uint8_t * ElementsContent) -{ - uint32_t i; - uint8_t MessageType; - uint64_t CurrentIV = 0; - unsigned long long int FullMessage = 0; - /* Get the "Message Type" field */ - MessageType = (ElementsContent[2] & 1) << 5; - MessageType |= (ElementsContent[3] & 1) << 4; - MessageType |= (ElementsContent[4] & 1) << 3; - MessageType |= (ElementsContent[5] & 1) << 2; - MessageType |= (ElementsContent[6] & 1) << 1; - MessageType |= (ElementsContent[7] & 1) << 0; - - //fprintf(stderr, "\nMessage Type = %X ", MessageType); - - /* Save the "F1" and "F2" flags */ - state->NxdnElementsContent.F1 = ElementsContent[0]; - state->NxdnElementsContent.F2 = ElementsContent[1]; - - /* Save the "Message Type" field */ - state->NxdnElementsContent.MessageType = MessageType; - - //fprintf(stderr, "\n Message Type = 0x%02X ", MessageType & 0xFF); - - //Dump the Message into a HEX value for vieweing - //FullMessage = (unsigned long long int)ConvertBitIntoBytes(&Message[0], 64); - for (short int i = 0; i < 64; i++) - { - FullMessage = FullMessage << 1; - FullMessage |= ElementsContent[i]; - } - //fprintf(stderr, "\nFull Message = %016llX ", FullMessage); - - /* Decode the right "Message Type" */ - switch(MessageType) - { - //Idle - case NXDN_IDLE: - { - //fprintf(stderr, "NXDN IDLE\n"); - sprintf (state->nxdn_call_type, "NXDN IDLE "); - } - break; - - /* VCALL */ - case NXDN_VCALL: - { - /* Set the CRC state */ - state->NxdnElementsContent.VCallCrcIsGood = CrcCorrect; - - /* Decode the "VCALL" message */ - NXDN_decode_VCALL(opts, state, ElementsContent); - - /* Check the "Cipher Type" and the "Key ID" validity */ - if(CrcCorrect) - { - state->NxdnElementsContent.CipherParameterValidity = 1; - } - else state->NxdnElementsContent.CipherParameterValidity = 0; - break; - } /* End case NXDN_VCALL: */ - - /* VCALL_IV */ - case NXDN_VCALL_IV: - { - /* Set the CRC state */ - state->NxdnElementsContent.VCallIvCrcIsGood = CrcCorrect; - - /* Decode the "VCALL_IV" message */ - NXDN_decode_VCALL_IV(opts, state, ElementsContent); - - if(CrcCorrect) - { - /* CRC is correct, copy the next theorical IV to use directly from the - * received VCALL_IV */ - memcpy(state->NxdnElementsContent.NextIVComputed, state->NxdnElementsContent.IV, 8); - } - else - { - /* CRC is incorrect, compute the next IV to use */ - CurrentIV = 0; - - /* Convert the 8 bytes buffer into a 64 bits integer */ - for(i = 0; i < 8; i++) - { - CurrentIV |= state->NxdnElementsContent.NextIVComputed[i]; - CurrentIV = CurrentIV << 8; - } - - } - break; - } /* End case NXDN_VCALL_IV: */ - - /* Unknown Message Type */ - default: - { - //fprintf(stderr, "Unknown Message type "); - break; - } - } /* End switch(MessageType) */ - -} /* End NXDN_Elements_Content_decode() */ - - -/* - * @brief : This function decodes the VCALL message - * - * @param opts : Option structure parameters pointer - * - * @param state : State structure parameters pointer - * - * @param Message : A 64 bit buffer containing the VCALL message to decode - * - * @return None - * - */ -void NXDN_decode_VCALL(dsd_opts * opts, dsd_state * state, uint8_t * Message) -{ - //uint32_t i; - uint8_t CCOption = 0; - uint8_t CallType = 0; - uint8_t VoiceCallOption = 0; - uint16_t SourceUnitID = 0; - uint16_t DestinationID = 0; - uint8_t CipherType = 0; - uint8_t KeyID = 0; - uint8_t DuplexMode[32] = {0}; - uint8_t TransmissionMode[32] = {0}; - unsigned long long int FullMessage = 0; - - //UNUSED_VARIABLE(opts); - //UNUSED_VARIABLE(state); - //UNUSED_VARIABLE(DuplexMode[0]); - //UNUSED_VARIABLE(TransmissionMode[0]); - - /* Message[0..7] contains : - * - The "F1" and "F2" flags - * - The "Message Type" (already decoded before calling this function) - * - * So no need to decode it a second time - */ - - /* Decode "CC Option" */ - CCOption = (uint8_t)ConvertBitIntoBytes(&Message[8], 8); - state->NxdnElementsContent.CCOption = CCOption; - - /* Decode "Call Type" */ - CallType = (uint8_t)ConvertBitIntoBytes(&Message[16], 3); - state->NxdnElementsContent.CallType = CallType; - - /* Decode "Voice Call Option" */ - VoiceCallOption = (uint8_t)ConvertBitIntoBytes(&Message[19], 5); - state->NxdnElementsContent.VoiceCallOption = VoiceCallOption; - - /* Decode "Source Unit ID" */ - SourceUnitID = (uint16_t)ConvertBitIntoBytes(&Message[24], 16); - state->NxdnElementsContent.SourceUnitID = SourceUnitID; - - /* Decode "Destination ID" */ - DestinationID = (uint16_t)ConvertBitIntoBytes(&Message[40], 16); - state->NxdnElementsContent.DestinationID = DestinationID; - - /* Decode the "Cipher Type" */ - CipherType = (uint8_t)ConvertBitIntoBytes(&Message[56], 2); - state->NxdnElementsContent.CipherType = CipherType; - - /* Decode the "Key ID" */ - KeyID = (uint8_t)ConvertBitIntoBytes(&Message[58], 6); - state->NxdnElementsContent.KeyID = KeyID; - - /* Print the "CC Option" */ - if(CCOption & 0x80) fprintf(stderr, "Emergency "); - if(CCOption & 0x40) fprintf(stderr, "Visitor "); - if(CCOption & 0x20) fprintf(stderr, "Priority Paging "); - - //Dump the Message into a HEX value for vieweing - //FullMessage = (unsigned long long int)ConvertBitIntoBytes(&Message[0], 64); - // for (short int i = 0; i < 64; i++) - // { - // FullMessage = FullMessage << 1; - // FullMessage |= Message[i]; - // } - - if((CipherType == 2) || (CipherType == 3)) - { - state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1; - state->NxdnElementsContent.PartOfNextEncryptedFrame = 2; - } - else - { - state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 1; - state->NxdnElementsContent.PartOfNextEncryptedFrame = 1; - } - - /* Print the "Call Type" */ - fprintf (stderr, "%s", KGRN); - fprintf(stderr, "\n %s - ", NXDN_Call_Type_To_Str(CallType)); //line break and 1 space - //sprintf (state->nxdn_call_type, NXDN_Call_Type_To_Str(CallType)); //fix warning below - //warning: format not a string literal and no format arguments [-Wformat-security] - sprintf (state->nxdn_call_type, "%s", NXDN_Call_Type_To_Str(CallType)); //fix warning below - - /* Print the "Voice Call Option" */ - NXDN_Voice_Call_Option_To_Str(VoiceCallOption, DuplexMode, TransmissionMode); - fprintf(stderr, "%s %s - ", DuplexMode, TransmissionMode); - - /* Print Source ID and Destination ID (Talk Group or Unit ID) */ - //fprintf (stderr, "%s", KGRN); - fprintf(stderr, "Src=%u - Dst/TG=%u ", SourceUnitID & 0xFFFF, DestinationID & 0xFFFF); - fprintf (stderr, "%s", KNRM); - - //state->nxdn_key = (KeyID & 0xFF); - //state->nxdn_cipher_type = CipherType; - /* Print the "Cipher Type" */ - if(CipherType != 0) - { - fprintf (stderr, "\n %s", KYEL); - fprintf(stderr, "%s - ", NXDN_Cipher_Type_To_Str(CipherType)); - //state->nxdn_cipher_type = CipherType; - } - - /* Print the Key ID */ - if(CipherType != 0) - { - - fprintf(stderr, "Key ID %u - ", KeyID & 0xFF); - fprintf (stderr, "%s", KNRM); - //state->nxdn_key = (KeyID & 0xFF); - } - - if (state->nxdn_cipher_type == 0x01 && state->R > 0) //scrambler - { - fprintf (stderr, "%s", KYEL); - fprintf(stderr, "Value: %05lld", state->R); - fprintf (stderr, "%s", KNRM); - } - - if(state->NxdnElementsContent.VCallCrcIsGood) - { - if ( (SourceUnitID & 0xFFFF) > 0 ) - { - state->nxdn_last_rid = SourceUnitID & 0xFFFF; //only grab if CRC is okay - state->nxdn_last_tg = (DestinationID & 0xFFFF); - state->nxdn_key = (KeyID & 0xFF); - state->nxdn_cipher_type = CipherType; //will this set to zero if no enc? - } - //fprintf(stderr, "(CRC OK) "); - } - //fprintf(stderr, " (OK) - "); - else - { - fprintf (stderr, "%s", KRED); - fprintf(stderr, "(CRC ERR) "); - fprintf (stderr, "%s", KNRM); - } - //set enc bit here so we can tell playSynthesizedVoice whether or not to play enc traffic - if (state->nxdn_cipher_type != 0) - { - state->dmr_encL = 1; - } - if (state->nxdn_cipher_type == 0 || state->R != 0) - { - state->dmr_encL = 0; - } - //fprintf(stderr, "\nFull Message = %016llX ", FullMessage); -} /* End NXDN_decode_VCALL() */ - - -/* - * @brief : This function decodes the VCALL_IV message - * - * @param opts : Option structure parameters pointer - * - * @param state : State structure parameters pointer - * - * @param Message : A 72 bit buffer containing the VCALL_IV message to decode - * - * @return None - * - */ -void NXDN_decode_VCALL_IV(dsd_opts * opts, dsd_state * state, uint8_t * Message) -{ - uint32_t i; - - //UNUSED_VARIABLE(opts); - //UNUSED_VARIABLE(state); - - /* Message[0..7] contains : - * - The "F1" and "F2" flags - * - The "Message Type" (already decoded before calling this function) - * - * So no need to decode it a second time - * - * Message[8..71] contains : The 64 bits IV - */ - state->payload_miN = 0; //zero out - /* Extract the IV from the VCALL_IV message */ - for(i = 0; i < 8; i++) - { - state->NxdnElementsContent.IV[i] = (uint8_t)ConvertBitIntoBytes(&Message[(i + 1) * 8], 8); - - state->payload_miN = state->payload_miN << 8 | state->NxdnElementsContent.IV[i]; - } - - state->NxdnElementsContent.PartOfCurrentEncryptedFrame = 2; - state->NxdnElementsContent.PartOfNextEncryptedFrame = 1; - -} /* End NXDN_decode_VCALL_IV() */ - - -/* - * @brief : This function decodes the "Call Type" and return the - * ASCII string corresponding to it. - * - * @param CallType : The call type parameter to decode - * - * @return An ASCII string of the "Call Type" - * - */ -char * NXDN_Call_Type_To_Str(uint8_t CallType) -{ - char * Ptr = NULL; - - switch(CallType) - { - case 0: Ptr = "Broadcast Call"; break; - case 1: Ptr = "Group Call"; break; - case 2: Ptr = "Unspecified Call"; break; - case 3: Ptr = "Reserved"; break; - case 4: Ptr = "Individual Call"; break; - case 5: Ptr = "Reserved"; break; - case 6: Ptr = "Interconnect Call"; break; - case 7: Ptr = "Speed Dial Call"; break; - default: Ptr = "Unknown Call Type"; break; - } - - return Ptr; -} /* End NXDN_Call_Type_To_Str() */ - - -/* - * @brief : This function decodes the "Voice Call Option" and return the - * ASCII string corresponding to it. - * - * @param VoiceCallOption : The call type parameter to decode - * - * @param Duplex : A 32 bytes ASCII buffer pointer where store - * the Duplex/Half duplex mode - * - * @param TransmissionMode : A 32 bytes ASCII buffer pointer where store - * the transmission mode (bit rate) - * - * @return An ASCII string of the "Voice Call Option" - * - */ -void NXDN_Voice_Call_Option_To_Str(uint8_t VoiceCallOption, uint8_t * Duplex, uint8_t * TransmissionMode) -{ - char * Ptr = NULL; - - Duplex[0] = 0; - TransmissionMode[0] = 0; - - if(VoiceCallOption & 0x10) strcpy((char *)Duplex, "Duplex"); - else strcpy((char *)Duplex, "Half Duplex"); - - switch(VoiceCallOption & 0x17) - { - case 0: Ptr = "4800bps/EHR"; break; - case 2: Ptr = "9600bps/EHR"; break; - case 3: Ptr = "9600bps/EFR"; break; - default: Ptr = "Reserved Voice Call Option"; break; - } - - strcpy((char *)TransmissionMode, Ptr); -} /* End NXDN_Voice_Call_Option_To_Str() */ - - -/* - * @brief : This function decodes the "Cipher Type" and return the - * ASCII string corresponding to it. - * - * @param CipherType : The cipher type parameter to decode - * - * @return An ASCII string of the "Cipher Type" - * - */ -char * NXDN_Cipher_Type_To_Str(uint8_t CipherType) -{ - char * Ptr = NULL; - - switch(CipherType) - { - case 0: Ptr = ""; break; /* Non-ciphered mode / clear call */ - case 1: Ptr = "Scrambler"; break; - case 2: Ptr = "DES"; break; - case 3: Ptr = "AES"; break; - default: Ptr = "Unknown Cipher Type"; break; - } - - return Ptr; -} /* End NXDN_Cipher_Type_To_Str() */ - - -/* CRC 15 bits computation with the following polynomial : - * X^15 + X^14 + X^11 + X^10 + X^7 + X^6 + X^2 + 1 - * - * X^15 + (1X^14 + 0X^13 + 0X^12 + 1X^11 + 1X^10 + 0X^9 + 0X^8 + 1X^7 + 1X^6 + 0X^5 + 0X^4 + 0X^3 + 1X^2 + 0X^1 + 1X^0) - * => Polynomial = 0b100110011000101 = 0x4CC5 - */ -uint16_t CRC15BitNXDN(uint8_t * BufferIn, uint32_t BitLength) -{ - uint16_t CRC = 0x7FFF; /* Initial value = All bit to '1' (only 15 LSBit are used) */ - uint16_t Polynome = 0x4CC5; /* X^15 + X^14 + X^11 + X^10 + X^7 + X^6 + X^2 + 1 */ - uint32_t i; - - for(i = 0; i < BitLength; i++) - { - if(((CRC >> 14) & 1) ^ (BufferIn[i] & 1)) - { - CRC = ((CRC << 1) ^ Polynome) & 0x7FFF; - } - else - { - CRC = (CRC << 1) & 0x7FFF; - } - } - - return CRC; -} /* End CRC15BitNXDN() */ - - -/* CRC 12 bits computation with the following polynomial : - * X^12 + X^11 + X^3 + X^2 + X + 1 - * - * X^12 + (1X^11 + 0X^10 + 0X^9 + 0X^8 + 0X^7 + 0X^6 + 0X^5 + 0X^4 + 1X^3 + 1X^2 + 1X^1 + 1X^0) - * => Polynomial = 0b100000001111 = 0x80F - */ -uint16_t CRC12BitNXDN(uint8_t * BufferIn, uint32_t BitLength) -{ - uint16_t CRC = 0x0FFF; /* Initial value = All bit to '1' (only 12 LSBit are used) */ - uint16_t Polynome = 0x80F; /* X^12 + X^11 + X^3 + X^2 + X + 1 */ - uint32_t i; - - for(i = 0; i < BitLength; i++) - { - if(((CRC >> 11) & 1) ^ (BufferIn[i] & 1)) - { - CRC = ((CRC << 1) ^ Polynome) & 0x0FFF; - } - else - { - CRC = (CRC << 1) & 0x0FFF; - } - } - - return CRC; -} /* End CRC12BitNXDN() */ - - -/* CRC 6 bit computation with the following - * polynomial : X^6 + X^5 + X^2 + X + 1 - * - * X^6 + (1X^5 + 0X^4 + 0X^3 + 1X^2 + 1X^1 + 1X^0) - * => Polynomial = 0b100111 = 0x27 - */ -uint8_t CRC6BitNXDN(uint8_t * BufferIn, uint32_t BitLength) -{ - uint8_t CRC = 0x3F; /* Initial value = All bit to '1' (only 6 LSBit are used) */ - uint8_t Polynome = 0x27; /* X^6 + X^5 + X^2 + X + 1 */ - uint32_t i; - - for(i = 0; i < BitLength; i++) - { - if(((CRC >> 5) & 1) ^ (BufferIn[i] & 1)) - { - CRC = ((CRC << 1) ^ Polynome) & 0x3F; - } - else - { - CRC = (CRC << 1) & 0x3F; - } - } - - return CRC; -} /* End CRC6BitNXDN() */ - -//NXDN IDLE -void ProcessNXDNIdleData (dsd_opts * opts, dsd_state * state, uint8_t Inverted) -{ - int i, dibit = 0; - unsigned char sacch_raw[72] = {0}; - unsigned char sacch_decoded[32] = {0}; /* 26 bit + 6 bit CRC */ - unsigned char *pr; - uint8_t CrcIsGood = 0; - uint8_t StructureField = 0; - uint8_t RAN = 0; - uint8_t PartOfFrame = 0; - - if (opts->errorbars == 1) - { - fprintf(stderr, "DATA - "); - } - - /* Start pseudo-random NXDN sequence after - * LICH = 16 bit = 8 dibit - * ==> Index 8 */ - pr = (unsigned char *)(&nxdnpr[8]); - for (i = 0; i < 30; i++) - { - dibit = getDibit (opts, state); - - /* Store and de-interleave directly SACCH bits */ - sacch_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 - sacch_raw[(2*i)+1] = (1 & dibit); // bit 0 - pr++; -#ifdef NXDN_DUMP - fprintf(stderr, "%c", dibit + 48); -#endif - } -#ifdef NXDN_DUMP - fprintf(stderr, " "); -#endif - - - /* Decode the SACCH fields */ - CrcIsGood = NXDN_SACCH_raw_part_decode(sacch_raw, sacch_decoded); - StructureField = (sacch_decoded[0]<<1 | sacch_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */ - RAN = (sacch_decoded[2]<<5 | sacch_decoded[3]<<4 | sacch_decoded[4]<<3 | sacch_decoded[5]<<2 | sacch_decoded[6]<<1 | sacch_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the SACCH) */ - - /* Compute the Part of Frame according to the structure field */ - if (StructureField == 3) PartOfFrame = 0; - else if(StructureField == 2) PartOfFrame = 1; - else if(StructureField == 1) PartOfFrame = 2; - else if(StructureField == 0) PartOfFrame = 3; - else PartOfFrame = 0; /* Normally we should never go here */ - - /* Fill the SACCH structure */ - state->NxdnSacchRawPart[PartOfFrame].CrcIsGood = CrcIsGood; - state->NxdnSacchRawPart[PartOfFrame].StructureField = StructureField; - state->NxdnSacchRawPart[PartOfFrame].RAN = RAN; - memcpy(state->NxdnSacchRawPart[PartOfFrame].Data, &sacch_decoded[8], 18); /* Copy the 18 bits of SACCH content */ - - fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); - if(CrcIsGood) fprintf(stderr, " (OK) - "); - else fprintf(stderr, "(CRC ERR) - "); - - - /* This frame is an idle frame */ - fprintf(stderr, "Idle"); - - - /* Decode the SACCH only when all 4 voice frame - * SACCH spare parts have been received */ - if(PartOfFrame == 3) - { - /* Decode the entire SACCH content */ - NXDN_SACCH_Full_decode(opts, state); - } - - for (i = 0; i < 144; i++) - { - dibit = getDibit (opts, state); -#ifdef NXDN_DUMP - fprintf(stderr, "%c", dibit + 48); -#endif - } - - if (opts->errorbars == 1) - { - fprintf(stderr, "\n"); - } - - /* Reset the SACCH CRCs when all 4 voice frame - * SACCH spare parts have been received */ - if(PartOfFrame == 3) - { - /* Reset all CRCs of the SACCH */ - for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0; - } -} /* End ProcessNXDNIdleData() */ - -void ProcessNXDNFacch1Data (dsd_opts * opts, dsd_state * state, uint8_t Inverted) -{ - int i, j, dibit = 0; - unsigned char sacch_raw[72] = {0}; - unsigned char sacch_decoded[32] = {0}; /* 26 bits + 6 bits CRC */ - unsigned char facch1_raw[144] = {0}; - unsigned char facch1_decoded[96] = {0}; /* 80 bits + 12 bits CRC + 4 bits "Tail" (set to "0") */ - unsigned char *pr; - uint8_t CrcIsGood = 0; - uint8_t StructureField = 0; - uint8_t RAN = 0; - uint8_t PartOfFrame = 0; - uint8_t Facch1CrcIsGood = 0; - - if (opts->errorbars == 1) - { - fprintf(stderr, "DATA - "); - } - - /* Start pseudo-random NXDN sequence after - * LITCH = 16 bit = 8 dibit - * ==> Index 8 */ - pr = (unsigned char *)(&nxdnpr[8]); - for (i = 0; i < 30; i++) - { - dibit = getDibit (opts, state); - - /* Store and de-interleave directly SACCH bits */ - sacch_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 - sacch_raw[(2*i)+1] = (1 & dibit); // bit 0 - pr++; -#ifdef NXDN_DUMP - fprintf(stderr, "%c", dibit + 48); -#endif - } -#ifdef NXDN_DUMP - fprintf(stderr, " "); -#endif - - - /* Decode the SACCH fields */ - CrcIsGood = NXDN_SACCH_raw_part_decode(sacch_raw, sacch_decoded); - StructureField = (sacch_decoded[0]<<1 | sacch_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */ - RAN = (sacch_decoded[2]<<5 | sacch_decoded[3]<<4 | sacch_decoded[4]<<3 | sacch_decoded[5]<<2 | sacch_decoded[6]<<1 | sacch_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the SACCH) */ - - /* Compute the Part of Frame according to the structure field */ - if (StructureField == 3) PartOfFrame = 0; - else if(StructureField == 2) PartOfFrame = 1; - else if(StructureField == 1) PartOfFrame = 2; - else if(StructureField == 0) PartOfFrame = 3; - else PartOfFrame = 0; /* Normally we should never go here */ - - /* Fill the SACCH structure */ - state->NxdnSacchRawPart[PartOfFrame].CrcIsGood = CrcIsGood; - state->NxdnSacchRawPart[PartOfFrame].StructureField = StructureField; - state->NxdnSacchRawPart[PartOfFrame].RAN = RAN; - memcpy(state->NxdnSacchRawPart[PartOfFrame].Data, &sacch_decoded[8], 18); /* Copy the 18 bits of SACCH content */ - - fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); - if(CrcIsGood) fprintf(stderr, " (OK) - "); - else fprintf(stderr, "(CRC ERR) - "); - - - /* This frame is an FACCH1 frame */ - fprintf(stderr, "FACCH1 - "); - - - /* Decode the SACCH only when all 4 voice frame - * SACCH spare parts have been received */ - if(PartOfFrame == 3) - { - /* Decode the entire SACCH content */ - //NXDN_SACCH_Full_decode(opts, state); - } - - /* Start pseudo-random NXDN sequence after - * LITCH = 16 bit = 8 dibit + - * SACCH = 60 bit = 30 dibit - * = 76 bit = 38 dibit - * ==> Index 38 */ - pr = (unsigned char *)(&nxdnpr[38]); - - /* The frame contains 2 * 144 bits = 2 * 72 dibit */ - for(j = 0; j < 2; j++) - { - for (i = 0; i < 72; i++) - { - dibit = getDibit (opts, state); - - /* Store and FACCH1 bits */ - facch1_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 - facch1_raw[(2*i)+1] = (1 & dibit); // bit 0 - pr++; - -#ifdef NXDN_DUMP - fprintf(stderr, "%c", dibit + 48); -#endif - } /* End for (i = 0; i < 72; i++) */ - - /* Extract the FACCH1 content */ - Facch1CrcIsGood = NXDN_FACCH1_decode(facch1_raw, facch1_decoded); - - state->NxdnFacch1RawPart[j].CrcIsGood = Facch1CrcIsGood; - memcpy(state->NxdnFacch1RawPart[j].Data, facch1_decoded, 80); - - if(Facch1CrcIsGood) fprintf(stderr, "FACCH1 CRC %d is good - ", j + 1); - else fprintf(stderr, "FACCH1 CRC %d is bad - ", j + 1); - } /* End for(j = 0; j < 2; j++) */ - - if (opts->errorbars == 1) - { - fprintf(stderr, "\n"); - } - - /* Reset the SACCH CRCs when all 4 voice frame - * SACCH spare parts have been received */ - if(PartOfFrame == 3) - { - /* Reset all CRCs of the SACCH */ - for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0; - } -} /* End ProcessNXDNFacch1Data() */ - -void ProcessNXDNUdchData (dsd_opts * opts, dsd_state * state, uint8_t Inverted) -{ - int i, dibit = 0; - unsigned char facch2_raw[348] = {0}; - unsigned char facch2_decoded[203] = {0}; /* 184 bits + 15 bits CRC + 4 bits "Tail" (set to "0") */ - unsigned char *pr; - uint8_t Facch2CrcIsGood = 0; - uint8_t StructureField = 0; - uint8_t RAN = 0; - - if (opts->errorbars == 1) - { - fprintf(stderr, "DATA - "); - } - - /* Start pseudo-random NXDN sequence after - * LITCH = 16 bit = 8 dibit - * ==> Index 8 */ - pr = (unsigned char *)(&nxdnpr[8]); - for (i = 0; i < 174; i++) - { - dibit = getDibit (opts, state); - - /* Store and de-interleave directly SACCH bits */ - facch2_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 - facch2_raw[(2*i)+1] = (1 & dibit); // bit 0 - pr++; -#ifdef NXDN_DUMP - fprintf(stderr, "%c", dibit + 48); -#endif - } -#ifdef NXDN_DUMP - fprintf(stderr, " "); -#endif - - /* Extract the UDCH/FACCH2 content */ - Facch2CrcIsGood = NXDN_UDCH_decode(facch2_raw, facch2_decoded); - - state->NxdnFacch2RawPart.CrcIsGood = Facch2CrcIsGood; - memcpy(state->NxdnFacch2RawPart.Data, facch2_decoded, 184); - - StructureField = (facch2_decoded[0]<<1 | facch2_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the FACCH2) */ - RAN = (facch2_decoded[2]<<5 | facch2_decoded[3]<<4 | facch2_decoded[4]<<3 | facch2_decoded[5]<<2 | facch2_decoded[6]<<1 | facch2_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the FACCH2) */ - - fprintf(stderr, "RAN=%02d ", RAN); - if(Facch2CrcIsGood) fprintf(stderr, " (OK) - "); - else fprintf(stderr, "(CRC ERR) - "); - - /* This frame is an FACCH2 frame */ - fprintf(stderr, "FACCH2 - "); - - if(Facch2CrcIsGood) fprintf(stderr, "UDCH/FACCH2 CRC is good - "); - else fprintf(stderr, "UDCH/FACCH2 CRC is bad - "); - - if (opts->errorbars == 1) - { - fprintf(stderr, "\n"); - } -} /* End ProcessNXDNUdchData() */ - -void ProcessNXDNFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) -{ - /* Switch to the correct type of frame */ - switch(state->NxdnLich.RFChannelType) - { - /* RCCH */ - case 0: - { - ProcessNxdnRCCHFrame(opts, state, Inverted); - break; - } /* End case 0 */ - - /* RTCH */ - case 1: - { - ProcessNxdnRTCHFrame(opts, state, Inverted); - break; - } /* End case 1 */ - - /* RDCH */ - case 2: - { - ProcessNxdnRDCHFrame(opts, state, Inverted); - break; - } /* End case 2 */ - - /* RTCH_C (Composite Control Channel) */ - case 3: - { - ProcessNxdnRTCH_C_Frame(opts, state, Inverted); - break; - } /* End case 3 */ - - default: - { - fprintf(stderr, "- Unknown NXDN Frame type\n"); - - /* Unknown frame type, simply skip the entire frame - * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit - * Preserve 24 bits (12 dibit) => 174 - 12 = 162 dibit */ - skipDibit(opts, state, ((384 - 20 - 16) / 2) - 12); - break; - } /* End default */ - } /* End switch(state->NxdnLich.RFChannelType) */ -} /* End NxdnDecodeFrame() */ - -void ProcessNxdnRCCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) -{ - uint8_t SkipEntireFrameFlag = 0; - - /* Remove compiler warning */ - // UNUSED_VARIABLE(Inverted); - - sprintf(state->fsubtype, " RCCH "); - - switch(state->NxdnLich.CompleteLich) - { - case 0b0011000: - { - fprintf(stderr, "- RCCH - CCCH Transmission using Short CAC\n"); - SkipEntireFrameFlag = 1; - break; - } - case 0b0001000: - { - fprintf(stderr, "- RCCH - UPCH or CCCH Transmission using Long CAC\n"); - SkipEntireFrameFlag = 1; - break; - } - case 0b0000001: - { - fprintf(stderr, "- RCCH - CAC Transmission\n"); - SkipEntireFrameFlag = 1; - break; - } - case 0b0000011: - { - fprintf(stderr, "- RCCH - CAC Transmission which has not to be received\n"); - SkipEntireFrameFlag = 1; - break; - } - case 0b0000101: - { - fprintf(stderr, "- RCCH - CAC Transmission which can be received arbitrary\n"); - SkipEntireFrameFlag = 1; - break; - } - case 0b0011001: - { - fprintf(stderr, "- RCCH - IDAS\n"); - SkipEntireFrameFlag = 1; - break; - } - default: - { - fprintf(stderr, "- RCCH - Unknown RCCH Frame\n"); - SkipEntireFrameFlag = 1; - break; - } /* End default */ - } /* switch(state->NxdnLich.CompleteLich) */ - - if(SkipEntireFrameFlag) - { - /* Unknown frame type or frame not implemented yet, simply skip the entire frame - * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit - * Preserve 24 bits (12 dibit) => 174 - 12 = 162 dibit */ - skipDibit(opts, state, ((384 - 20 - 16) / 2) - 12); - } - -} /* End ProcessNxdnRCCHFrame() */ - -void ProcessNxdnRDCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) -{ - uint8_t SkipEntireFrameFlag = 0; - - /* Remove compiler warning */ - // UNUSED_VARIABLE(Inverted); - - switch(state->NxdnLich.CompleteLich) - { - /* Voice frame */ - case 0b1010110: /* Voice call transmission : Superframe SACCH, VCH Only */ - case 0b1010100: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ - case 0b1010010: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ - case 0b1010111: /* Voice call transmission : Superframe SACCH, VCH Only */ - case 0b1010101: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ - case 0b1010011: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ - { - fprintf(stderr, "- RDCH - "); - processNXDNVoice(opts, state); - break; - } - - case 0b1010000: /* Voice call transmission : Superframe SACCH, two FACCH1s */ - case 0b1010001: /* Voice call transmission : Superframe SACCH, two FACCH1s */ - { - fprintf(stderr, "- RDCH - "); - processNXDNData(opts, state); - break; - } - - case 0b1011000: /* Voice call transmission : Superframe SACCH, Idle State */ - case 0b1011001: /* Voice call transmission : Superframe SACCH, Idle State */ - { - fprintf(stderr, "- RDCH - "); - ProcessNXDNIdleData(opts, state, Inverted); - break; - } - - case 0b1000000: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ - case 0b1000001: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ - { - //fprintf(stderr, "- RDCH - Non-superframe SACCH with two FACCH1s\n"); - fprintf(stderr, "- RDCH - "); - ProcessNXDNFacch1Data(opts, state, Inverted); - break; - } - - case 0b1001110: /* UDCH Transmission */ - case 0b1001111: /* UDCH Transmission */ - { - fprintf(stderr, "- RDCH - UDCH Transmission - "); - ProcessNXDNUdchData(opts, state, Inverted); - break; - } - - case 0b1001000: /* FACCH2 Transmission */ - case 0b1001001: /* FACCH2 Transmission */ - { - fprintf(stderr, "- RDCH - FACCH2 Transmission - "); - ProcessNXDNUdchData(opts, state, Inverted); - break; - } - - default: - { - fprintf(stderr, "- RDCH - Unknown RDCH Frame\n"); - SkipEntireFrameFlag = 1; - break; - } /* End default */ - } /* End switch(state->NxdnLich.CompleteLich) */ - - if(SkipEntireFrameFlag) - { - /* Unknown frame type or frame not implemented yet, simply skip the entire frame - * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit - * Preserve 8 bits (4 dibit) => 174 - 4 = 170 dibit */ - skipDibit(opts, state, ((384 - 20 - 16) / 2) - 4); - } -} /* End ProcessNxdnRDCHFrame() */ - -void ProcessNxdnRTCH_C_Frame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) -{ - uint8_t SkipEntireFrameFlag = 0; - - /* Remove compiler warning */ - // UNUSED_VARIABLE(Inverted); - - switch(state->NxdnLich.CompleteLich) - { - /* Voice frame */ - case 0b1110111: /* Voice call transmission : Superframe SACCH, VCH Only */ - case 0b1110101: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ - case 0b1110011: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ - { - fprintf(stderr, "- RTCH_C - "); - processNXDNVoice(opts, state); - break; - } - - case 0b1110001: /* Voice call transmission : Superframe SACCH, two FACCH1s */ - { - fprintf(stderr, "- RTCH_C - "); - processNXDNData(opts, state); - break; - } - - case 0b1111001: /* Voice call transmission : Superframe SACCH, Idle State */ - { - fprintf(stderr, "- RTCH_C - "); - ProcessNXDNIdleData(opts, state, Inverted); - break; - } - - case 0b1100001: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ - { - //fprintf(stderr, "- RTCH_C - Non-superframe SACCH with two FACCH1s\n"); - fprintf(stderr, "- RTCH_C - "); - ProcessNXDNFacch1Data(opts, state, Inverted); - break; - } - - case 0b1101111: /* UDCH Transmission */ - { - fprintf(stderr, "- RTCH_C - UDCH Transmission - "); - ProcessNXDNUdchData(opts, state, Inverted); - break; - } - - case 0b1101001: /* FACCH2 Transmission */ - { - fprintf(stderr, "- RTCH_C - FACCH2 Transmission - "); - ProcessNXDNUdchData(opts, state, Inverted); - break; - } - - default: - { - fprintf(stderr, "- RTCH_C - Unknown RTCH_C Frame\n"); - SkipEntireFrameFlag = 1; - break; - } /* End default */ - } /* End switch(state->NxdnLich.CompleteLich) */ - - if(SkipEntireFrameFlag) - { - /* Unknown frame type or frame not implemented yet, simply skip the entire frame - * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit - * Preserve 8 bits (4 dibit) => 174 - 4 = 170 dibit */ - skipDibit(opts, state, ((384 - 20 - 16) / 2) - 4); - } -} - - - -/* - * @brief : This function decodes an NXDN RTCH frame - * - * @param opts : Options - * - * @param state : State - * - * @param Inverted : 1 = Inverted frame ; 0 = Normal frame - * - * @return None - * - */ -void ProcessNxdnRTCHFrame(dsd_opts * opts, dsd_state * state, uint8_t Inverted) -{ - uint8_t SkipEntireFrameFlag = 0; - - /* Remove compiler warning */ - // UNUSED_VARIABLE(Inverted); - - switch(state->NxdnLich.CompleteLich) - { - /* Voice frame */ - case 0b0110110: /* Voice call transmission : Superframe SACCH, VCH Only */ - case 0b0110100: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ - case 0b0110010: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ - case 0b0110111: /* Voice call transmission : Superframe SACCH, VCH Only */ - case 0b0110101: /* Voice call transmission : Superframe SACCH, first half VCH & last half FACCH1 */ - case 0b0110011: /* Voice call transmission : Superframe SACCH, first half FACCH1 & last half VCH */ - { - fprintf(stderr, "- RTCH - "); - processNXDNVoice(opts, state); - break; - } - - case 0b0110000: /* Voice call transmission : Superframe SACCH, two FACCH1s */ - case 0b0110001: /* Voice call transmission : Superframe SACCH, two FACCH1s */ - { - fprintf(stderr, "- RTCH - "); - processNXDNData(opts, state); - break; - } - - case 0b0111000: /* Voice call transmission : Superframe SACCH, Idle State */ - case 0b0111001: /* Voice call transmission : Superframe SACCH, Idle State */ - { - fprintf(stderr, "- RTCH - "); - ProcessNXDNIdleData(opts, state, Inverted); - break; - } - - case 0b0100000: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ - case 0b0100001: /* Voice call transmission : Non-superframe SACCH, two FACCH1s */ - { - //fprintf(stderr, "- RTCH - Non-superframe SACCH with two FACCH1s\n"); - fprintf(stderr, "- RDCH - "); - ProcessNXDNFacch1Data(opts, state, Inverted); - break; - } - - case 0b0101110: /* UDCH Transmission */ - case 0b0101111: /* UDCH Transmission */ - { - fprintf(stderr, "- RTCH - UDCH Transmission - "); - ProcessNXDNUdchData(opts, state, Inverted); - break; - } - - case 0b0101000: /* FACCH2 Transmission */ - case 0b0101001: /* FACCH2 Transmission */ - { - fprintf(stderr, "- RTCH - FACCH2 Transmission - "); - ProcessNXDNUdchData(opts, state, Inverted); - break; - } - default: - { - fprintf(stderr, "- RTCH - Unknown RTCH Frame\n"); - SkipEntireFrameFlag = 1; - break; - } /* End default */ - } /* End switch(state->NxdnLich.CompleteLich) */ - - if(SkipEntireFrameFlag) - { - /* Unknown frame type or frame not implemented yet, simply skip the entire frame - * 384 bits - 20 bits Frame Sync Word - 16 bits LICH = 348 bits = 174 dibit - * Preserve 8 bits (4 dibit) => 174 - 4 = 170 dibit */ - skipDibit(opts, state, ((384 - 20 - 16) / 2) - 4); - } -} /* End ProcessNxdnRTCHFrame() */ - -void LFSRN(char * BufferIn, char * BufferOut, dsd_state * state) -{ - int i; - int lfsr; - int pN[49] = {0}; - int bit = 0; - - lfsr = state->payload_miN & 0x7FFF; - - for (i = 0; i < 49; i++) - { - pN[i] = lfsr & 0x1; - bit = ( (lfsr >> 1) ^ (lfsr >> 0) ) & 1; - lfsr = ( (lfsr >> 1 ) | (bit << 14) ); - BufferOut[i] = BufferIn[i] ^ pN[i]; - } - - state->payload_miN = lfsr & 0x7FFF; -} - -/* End of file */ diff --git a/src/nxdn_voice.c b/src/nxdn_voice.c index c212145..d9e8e7e 100644 --- a/src/nxdn_voice.c +++ b/src/nxdn_voice.c @@ -1,169 +1,101 @@ -#include "dsd.h" -#include "nxdn_const.h" +//a new and simplified voice handling routine for NXDN based on lich signalling +/* + * Copyright (C) 2010 DSD Author + * GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ -void processNXDNVoice (dsd_opts * opts, dsd_state * state) + //Originally found at - https://github.com/LouisErigHerve/dsd + //Modified for use in DSD-FME + +#include "dsd.h" + +const int nW[36] = { 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 2, + 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2 +}; + +const int nX[36] = { 23, 10, 22, 9, 21, 8, + 20, 7, 19, 6, 18, 5, + 17, 4, 16, 3, 15, 2, + 14, 1, 13, 0, 12, 10, + 11, 9, 10, 8, 9, 7, + 8, 6, 7, 5, 6, 4 +}; + +const int nY[36] = { 0, 2, 0, 2, 0, 2, + 0, 2, 0, 3, 0, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3 +}; + +const int nZ[36] = { 5, 3, 4, 2, 3, 1, + 2, 0, 1, 13, 0, 12, + 22, 11, 21, 10, 20, 9, + 19, 8, 18, 7, 17, 6, + 16, 5, 15, 4, 14, 3, + 13, 2, 12, 1, 11, 0 +}; + +void nxdn_voice (dsd_opts * opts, dsd_state * state, int voice, uint8_t dbuf[182]) { int i, j, dibit; + int start, stop; char ambe_fr[4][24]; - unsigned char sacch_raw[72] = {0}; - unsigned char sacch_decoded[32] = {0}; /* 26 bit + 6 bit CRC */ - const int *w, *x, *y, *z; + unsigned char *pr; - uint8_t CrcIsGood = 0; - uint8_t StructureField = 0; - uint8_t RAN = 0; - uint8_t PartOfFrame = 0; - char ambe7bytesArray[7] = {0}; - int PartOfEncryptedSuperFrame = 0; + const int *w, *x, *y, *z; - if (opts->errorbars == 1) - { - fprintf(stderr, "VOICE - "); - } + //these conditions will determine our starting and stopping value for voice + //i.e. voice in first, voice in second, or voice in both + if (voice == 1 || voice == 3) start = 0; + if (voice == 1) stop = 2; + if (voice == 2) start = 2; + if (voice == 2 || voice == 3) stop = 4; - /* Start pseudo-random NXDN sequence after - * LICH = 16 bit = 8 dibit - * ==> Index 8 */ - pr = (unsigned char *)(&nxdnpr2[8]); - for (i = 0; i < 30; i++) - { - dibit = getDibit (opts, state); - - /* Store and de-interleave directly SACCH bits */ - sacch_raw[(2*i)] = ((*pr) & 1) ^ (1 & (dibit >> 1)); // bit 1 - sacch_raw[(2*i)+1] = (1 & dibit); // bit 0 - -// TODO : Deinterleave is done in the "NXDN_SACCH_decode" function -// /* Store and de-interleave directly SACCH bits */ -// sacch_raw[nsW[2*i]] = *pr ^ (1 & (dibit >> 1)); // bit 1 -// sacch_raw[nsW[2*i+1]] = (1 & dibit); // bit 0 - pr++; -#ifdef NXDN_DUMP - fprintf(stderr, "%c", dibit + 48); -#endif - } -#ifdef NXDN_DUMP - fprintf(stderr, " "); -#endif - -// TODO : Unpuncture is done in the "NXDN_SACCH_decode" function -// /* For the sake of simplicity, handle the re-insertion of punctured bits here. -// * This makes the actual Viterbi decoder code a LOT simpler. */ -// for (i = 30; i < 36; i++) -// { -// sacch_raw[nsW[2*i]] = 0; -// sacch_raw[nsW[2*i+1]] = 0; -// } - - /* Decode the SACCH fields */ - CrcIsGood = NXDN_SACCH_raw_part_decode(sacch_raw, sacch_decoded); - StructureField = (sacch_decoded[0]<<1 | sacch_decoded[1]<<0) & 0x03; /* Compute the Structure Field (remove 2 first bits of the SR Information in the SACCH) */ - RAN = (sacch_decoded[2]<<5 | sacch_decoded[3]<<4 | sacch_decoded[4]<<3 | sacch_decoded[5]<<2 | sacch_decoded[6]<<1 | sacch_decoded[7]<<0) & 0x3F; /* Compute the RAN (6 last bits of the SR Information in the SACCH) */ - - /* Compute the Part of Frame according to the structure field */ - if (StructureField == 3) PartOfFrame = 0; - else if(StructureField == 2) PartOfFrame = 1; - else if(StructureField == 1) PartOfFrame = 2; - else if(StructureField == 0) PartOfFrame = 3; - else PartOfFrame = 0; /* Normally we should never go here */ - - /* Fill the SACCH structure */ - state->NxdnSacchRawPart[PartOfFrame].CrcIsGood = CrcIsGood; - state->NxdnSacchRawPart[PartOfFrame].StructureField = StructureField; - state->NxdnSacchRawPart[PartOfFrame].RAN = RAN; - memcpy(state->NxdnSacchRawPart[PartOfFrame].Data, &sacch_decoded[8], 18); /* Copy the 18 bits of SACCH content */ - - //fprintf(stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); - //if(CrcIsGood) fprintf(stderr, " (OK) - "); - if(CrcIsGood) - { - fprintf (stderr, "%s", KCYN); - fprintf (stderr, "RAN=%02d - Part %d/4 ", RAN, PartOfFrame + 1); - fprintf (stderr, "%s", KNRM); - //fprintf (stderr, "(CRC OK) "); - state->nxdn_last_ran = RAN; //disable, try to grab this in voice instead - } - else - { - fprintf (stderr, "%s", KRED); - fprintf(stderr, "(CRC ERR) "); - fprintf (stderr, "%s", KNRM); - } - - - /* Determine the current part of superframe - * (in an AES or DES encrypted frame, two superframes - * are used with the same IV, so to decipher the sound - * correctly we must know the current superframe part) */ - if(state->NxdnElementsContent.PartOfNextEncryptedFrame == 1) PartOfEncryptedSuperFrame = 0; - else if(state->NxdnElementsContent.PartOfNextEncryptedFrame == 2) PartOfEncryptedSuperFrame = 1; - else PartOfEncryptedSuperFrame = 0; - - /* Decode the SACCH only when all 4 voice frame - * SACCH spare parts have been received */ - if(PartOfFrame == 3) - { - /* Decode the entire SACCH content */ - NXDN_SACCH_Full_decode(opts, state); - } - - - if (opts->errorbars == 1) - { - //fprintf(stderr, "e:"); - } - - /* Start pseudo-random NXDN sequence after - * LICH = 16 bit = 8 dibit + - * SACCH = 60 bit = 30 dibit - * = 76 bit = 38 dibit - * ==> Index 38 */ - pr = (unsigned char *)(&nxdnpr2[38]); - for (j = 0; j < 4; j++) + for (start; start < stop; start++) { w = nW; x = nX; y = nY; z = nZ; + for (i = 0; i < 36; i++) { - dibit = getDibit (opts, state); -#ifdef NXDN_DUMP - fprintf(stderr, "%c", dibit + 48); -#endif - ambe_fr[*w][*x] = *pr ^ (1 & (dibit >> 1)); // bit 1 - pr++; - ambe_fr[*y][*z] = (1 & dibit); // bit 0 + //skip 8 lich and 30 sacch dibits already in buffer plus 36 times start position + ambe_fr[*w][*x] = dbuf[i+38+start*36] >> 1; + ambe_fr[*y][*z] = dbuf[i+38+start*36] & 1; + w++; x++; y++; z++; - } - if (opts->payload == 1) - { - //fprintf(stderr, "\n"); + } processMbeFrame (opts, state, NULL, ambe_fr, NULL); - state->p25vc++; //increment counter by one here? - - } /* End for (j = 0; j < 4; j++) */ - - if (opts->errorbars == 1) + } + + if (opts->payload == 1) { fprintf(stderr, "\n"); } + - /* Reset the SACCH CRCs when all 4 voice frame - * SACCH spare parts have been received */ - if(PartOfFrame == 3) - { - /* Reset all CRCs of the SACCH */ - if (state->R > 0 && state->nxdn_cipher_type == 0x1) - { - state->payload_miN = state->R; - } - for(i = 0; i < 4; i++) state->NxdnSacchRawPart[i].CrcIsGood = 0; - - } -} /* End processNXDNVoice() */ +} \ No newline at end of file