/* * * Copyright 2015 Karsten Keil * Copyright 2011 Karsten Keil * * This program 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 2 of the License, or (at your option) * any later version. * * This program 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 program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* We do not have the all the ioctl controls mainstream yet so define it here. * It should still work then with the old standalone driver */ #ifndef MISDN_CTRL_L1_TESTS #define MISDN_CTRL_L1_TESTS 0x00010000 #define MISDN_CTRL_L1_STATE_TEST 0x00010001 #define MISDN_CTRL_L1_AIS_TEST 0x00010002 #define MISDN_CTRL_L1_TS0_MODE 0x00010003 #define MISDN_CTRL_L1_GET_SYNC_INFO 0x00010004 #endif #define FRAME_SIZE 32 #define SMFR_SIZE (8 * FRAME_SIZE) #define MFR_SIZE (2 * SMFR_SIZE) #define DATA_SIZE_125US 32 #define DATA_SIZE_1MS (8 * 32) #define DATA_SIZE_1S (8000 * 32) #define MFR_SYNC_VALUE 0x2c #define MFR_SYNC_MASK 0xfc #define MFR_SYNC_BIT 0x01 #define MFR_SYNC_BITS 8 #define MFR_SYNC_OFFSET 15 #define FR_FAS_VAL 0xd8 #define FR_FAS_VAL_FAIL 0xc0 #define FR_FAS_MASK 0xfe #define FR_NFAS_B2 0xfa #define FR_NFAS_B2_FAIL 0xf8 enum FrameTypes { ftNone, /* send out AIS (all TS 0xff) */ ftAIS, /* Basic Frames */ ftFAS, ftBIT2, /* Sub multi frames */ ftSMFA, ftSMFB, /* Multi frames */ ftMFA, ftMFB, /* Frames */ ftFRAME_A, ftFRAME_B, ftFRAME_C, /* Control items */ ftCtrl_Start, ftCtrl_Repeat, ftCtrl_End, ftCtrl_Stop }; struct fr_cdesc { enum FrameTypes type; uint8_t prop; uint8_t subcnt; uint16_t count; }; struct fr_flatdesc { enum FrameTypes type; /* only basic frame types */ uint8_t prop; enum FrameTypes otype; /* original type from generation */ uint8_t mf_pos; /* 0 - 15 */ uint32_t pos; uint8_t *data; }; #define ftPROP_NONE 0x00 #define ftPROP_FAIL 0x01 /* frame type failure (/FAS or /BIT2) */ #define ftPROP_CRC4 0x02 /* CRC4 failure in submultiframe */ #define ftPROP_MFAS 0x04 /* MFAS failure in multiframe */ #define ftPROP_TS31 0x08 /* simulate BIT2 (FAS in TS 0) and FAS (BIT2 in TS0) in TS 31 */ #define ftPROP_START 0x10 /* Start test */ #define ftPROP_AIS 0x80 /* AIS */ struct fr_data { int count; struct fr_flatdesc *desc; size_t data_size; uint8_t *data; }; static struct fr_data *TestData; struct fr_cdesc preamble[] = { {ftAIS, ftPROP_AIS, 1, 16000}, {ftSMFA, ftPROP_NONE, 8, 1100}, {ftCtrl_Stop, ftPROP_NONE, 0, 0} }; struct fr_cdesc test0[] = { {ftSMFA, ftPROP_NONE, 8, 10000}, {ftCtrl_Stop, ftPROP_NONE, 0, 0} }; struct fr_cdesc test1[] = { {ftSMFA, ftPROP_NONE, 8, 1500}, {ftCtrl_Start, ftPROP_START, 0, 0}, {ftSMFA, ftPROP_NONE, 8, 500}, {ftSMFB, ftPROP_CRC4, 8, 1}, {ftSMFA, ftPROP_NONE, 8, 1000}, {ftSMFB, ftPROP_CRC4, 8, 2}, {ftSMFA, ftPROP_NONE, 8, 1500}, {ftSMFB, ftPROP_CRC4, 8, 914}, {ftSMFA, ftPROP_NONE, 8, 86}, {ftSMFB, ftPROP_CRC4, 8, 914}, {ftSMFA, ftPROP_NONE, 8, 2000}, {ftSMFB, ftPROP_CRC4, 8, 915}, {ftSMFA, ftPROP_NONE, 8, 85}, {ftSMFB, ftPROP_CRC4, 8, 915}, {ftSMFA, ftPROP_NONE, 8, 1500}, {ftCtrl_Repeat, ftPROP_NONE, 0, 4000}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftCtrl_Stop, ftPROP_NONE, 0, 0} }; struct fr_cdesc test2[] = { {ftCtrl_Repeat, ftPROP_NONE, 0, 9000}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftCtrl_Start, ftPROP_START, 0, 0}, {ftCtrl_Repeat, ftPROP_NONE, 0, 1000}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftCtrl_Repeat, ftPROP_NONE, 0, 20}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftCtrl_Repeat, ftPROP_NONE, 0, 20}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftCtrl_Repeat, ftPROP_NONE, 0, 20}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftCtrl_Repeat, ftPROP_NONE, 0, 20}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_Repeat, ftPROP_NONE, 0, 20}, {ftBIT2, ftPROP_FAIL, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftCtrl_Repeat, ftPROP_NONE, 0, 20}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftCtrl_Repeat, ftPROP_NONE, 0, 20}, {ftBIT2, ftPROP_FAIL, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftCtrl_Repeat, ftPROP_NONE, 0, 20}, {ftBIT2, ftPROP_FAIL, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftBIT2, ftPROP_FAIL, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftCtrl_Repeat, ftPROP_NONE, 0, 20}, {ftBIT2, ftPROP_FAIL, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftBIT2, ftPROP_FAIL, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftBIT2, ftPROP_FAIL, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftCtrl_Repeat, ftPROP_NONE, 0, 200}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_NONE, 1, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFRAME_B, ftPROP_TS31, 2, 16000}, {ftFRAME_C, ftPROP_TS31, 2, 6}, {ftFRAME_B, ftPROP_TS31, 2, 16000}, {ftCtrl_Stop, ftPROP_NONE, 0, 0} }; struct fr_cdesc test3[] = { {ftFRAME_B, ftPROP_TS31, 2, 15000}, {ftCtrl_Start, ftPROP_START, 0, 0}, {ftFRAME_B, ftPROP_TS31, 2, 1000}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 4}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 37}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 251}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftMFB, ftPROP_NONE, 16, 250}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 4}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 2}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 2}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 2}, {ftMFA, ftPROP_NONE, 16, 2}, {ftCtrl_Repeat, ftPROP_NONE, 0, 500}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftCtrl_Stop, ftPROP_NONE, 0, 0} }; struct fr_cdesc test4[] = { {ftFRAME_B, ftPROP_TS31, 2, 16000}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 4}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 37}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 251}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftFAS, ftPROP_FAIL, 1, 1}, {ftBIT2, ftPROP_NONE, 1, 1}, {ftMFB, ftPROP_NONE, 16, 250}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 4}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 2}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 2}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftMFB, ftPROP_NONE, 16, 2}, {ftMFA, ftPROP_NONE, 16, 2}, {ftCtrl_Repeat, ftPROP_NONE, 0, 500}, {ftMFB, ftPROP_NONE, 16, 1}, {ftMFA, ftPROP_NONE, 16, 1}, {ftCtrl_End, ftPROP_NONE, 0, 0}, {ftCtrl_Stop, ftPROP_NONE, 0, 0} }; static uint8_t mfr_sync; static uint8_t startcnt = MFR_SYNC_BITS; static uint8_t *inbuf, *ib_p, *ib_end; static int ib_size, ib_pos; static uint8_t *outbuf, *ob_p, *ob_end; static int ob_size, ob_pos; enum FSyncState { FSync_None, FSync_FAS, FSync_NFAS, FSync_AIS, FSync_LOS }; enum MFRSyncState { MFR_State_NotSync, MFR_State_Sync }; static enum FSyncState fsync_state = FSync_None; static enum MFRSyncState mfr_state = MFR_State_NotSync; static uint8_t *last_mfrs; static int good_mfr, bad_mfr; static int debuglevel = 0; static int RawReadMode = 0; static int cardnr = 0; static char *WriteFileName = NULL; static int ListMode = 0; struct fr_cdesc *Test = test0; static void usage(char *pname) { fprintf(stderr, "Call with %s [options]\n", pname); fprintf(stderr, "\n"); fprintf(stderr, "\n Valid options are:\n"); fprintf(stderr, "\n"); fprintf(stderr, " --help -? Usage ; printout this information\n"); fprintf(stderr, " --card -c use card number # (default 0)\n"); fprintf(stderr, " --flat -f list flat test frame description\n"); fprintf(stderr, " --list -l list test frame description\n"); fprintf(stderr, " --raw -r rawread only mode\n"); fprintf(stderr, " --debug -d debuglevel\n"); fprintf(stderr, " --test -t generate data for test # (default 0)\n"); fprintf(stderr, " --write -w write \n"); fprintf(stderr, "\n"); fprintf(stderr, "Tests:\n"); fprintf(stderr, " 0 - 10 seconds normal CRC4 framing\n"); fprintf(stderr, " 1 - TBR4 B.4.2 (table B.1)\n"); fprintf(stderr, " 2 - TBR4 B.5.2 (table B.2)\n"); fprintf(stderr, " 3 - TBR4 B.5.3 (table B.3)\n"); fprintf(stderr, "\n"); } static int opt_parse(int ac, char *av[]) { int c; for (;;) { int option_index = 0; static struct option long_options[] = { {"help", 0, 0, '?'}, {"card", 1, 0, 'c'}, {"debug", 1, 0, 'd'}, {"flat", 0, 0, 'f'}, {"list", 0, 0, 'l'}, {"raw", 0, 0, 'r'}, {"test", 1, 0, 't'}, {"write", 1, 0, 'w'}, {0, 0, 0, 0} }; c = getopt_long(ac, av, "?c:d:flrt:w:", long_options, &option_index); if (c == -1) break; switch (c) { case 0: fprintf(stderr, "option %s", long_options[option_index].name); if (optarg) fprintf(stderr, " with arg %s", optarg); fprintf(stderr, "\n"); break; case 'c': if (optarg) cardnr = atoi(optarg); else { fprintf(stderr, "option -c but no card number\n"); return -2; } break; case 'w': if (optarg) WriteFileName = strdup(optarg); else { fprintf(stderr, "option -w but no filename\n"); return -2; } break; case 'd': if (optarg) { debuglevel = atoi(optarg); } else { fprintf(stderr, "option -d but no value for debug level\n"); return -3; } break; case 'l': ListMode = 1; break; case 'f': ListMode = 2; break; case 'r': RawReadMode = 1; break; case 't': if (optarg) { switch (*optarg) { case '0': Test = test0; break; case '1': Test = test1; break; case '2': Test = test2; break; case '3': Test = test3; break; default: fprintf(stderr, "Unknown test %s\n", optarg); return -4; } } else { fprintf(stderr, "option -t but no value for test\n"); return -3; } break; case '?': usage(av[0]); return -1; } } c = ac - optind; if (c != 0) { fprintf(stderr, "unknown options: %s\n", av[optind]); return -2; } return 0; } static void printbinary(const char *name, uint32_t val, uint8_t bits) { uint32_t m; if (bits > 32) bits = 32; printf("%s: ", name); m = 1 << (bits - 1); while (m) { printf("%c", val & m ? '1' : '0'); m >>= 1; } } static void printhex(unsigned char *p, uint16_t idx, int len, int head) { int i, j; for (i = 1; i <= len; i++) { printf(" %02x", p[idx++]); if ((i != len) && !(i % 4) && (i % 16)) printf(" "); if ((i != len) && !(i % 16)) { printf("\n"); for (j = 0; j < head; j++) printf(" "); } } printf("\n"); } /* table for bit swap */ uint8_t bitswap_tbl[256]; /* table for CRC4 (x^4 + x + 1, Generator poly 0x13) */ uint8_t crc4_tbl[16] = { 0x0, 0x3, 0x6, 0x5, 0xc, 0xf, 0xa, 0x9, 0xb, 0x8, 0xd, 0xe, 0x7, 0x4, 0x1, 0x2 }; void calc_bitswap_table(void) { uint8_t v = 0; do { bitswap_tbl[v] = (((v & 0x01) << 7) | ((v & 0x02) << 5) | ((v & 0x04) << 3) | ((v & 0x08) << 1) | ((v & 0x10) >> 1) | ((v & 0x20) >> 3) | ((v & 0x40) >> 5) | ((v & 0x80) >> 7)); v++; } while (v != 0); } static uint8_t calc_crc4(uint8_t * data, uint16_t start, int len) { uint16_t i, idx = start; uint8_t b, crc4 = 0; for (i = 0; i < len; i++) { b = bitswap_tbl[data[idx]]; crc4 ^= ((b >> 4) & 0xf); crc4 = crc4_tbl[crc4]; crc4 ^= (b & 0xf); crc4 = crc4_tbl[crc4]; idx++; } return crc4; }; static uint8_t calc_and_set_crc4_smf(uint8_t * smf, uint8_t crc) { uint16_t i; uint8_t d, b, crc4 = 0; for (i = 0; i < SMFR_SIZE; i++) { d = smf[i]; if (!(i % 64)) { /* Cx bit */ d &= 0xfe; b = bitswap_tbl[d]; if (crc != 0xff) { /* no set if ff */ if (crc & 8) d |= 1; crc <<= 1; smf[i] = d; } } else b = bitswap_tbl[d]; crc4 ^= ((b >> 4) & 0xf); crc4 = crc4_tbl[crc4]; crc4 ^= (b & 0xf); crc4 = crc4_tbl[crc4]; } return crc4 & 0xf; } #ifdef NOT_USED_YET static uint8_t get_crc4_smf(uint8_t * smf) { uint16_t i; uint8_t crc4 = 0; for (i = 0; i < 4; i++) { crc4 <<= 1; crc4 |= (smf[64 * i] & 1); } return crc4; } #endif static int cur_Err = 0; // cur_RAI = 0; static int analyse_mfr(uint8_t * p) { uint16_t i, t0idx; uint8_t d, crcfr[16]; uint8_t A = 0; uint8_t E = 0; uint8_t C = 0; uint8_t cr0, cr1; const char *stim; struct fr_flatdesc *dsc; size_t ipos; ob_pos = ob_p - outbuf; ipos = p - inbuf; if (ipos < ((MFR_SYNC_OFFSET + 12) * FRAME_SIZE)) { stim = "VOID"; } else { ipos -= ((MFR_SYNC_OFFSET + 12) * FRAME_SIZE); ipos /= FRAME_SIZE; dsc = &TestData->desc[ipos]; switch (dsc->otype) { case ftAIS: stim = "AIS"; break; /* Basic Frames */ case ftFAS: if (dsc->prop & ftPROP_FAIL) stim = "/FAS"; else stim = "FAS"; break; case ftBIT2: if (dsc->prop & ftPROP_FAIL) stim = "/BIT 2"; else stim = "BIT 2"; break; /* Sub multi frames */ case ftSMFA: stim = "SMF A"; break; case ftSMFB: stim = "SMF B"; break; /* Multi frames */ case ftMFA: stim = "MF A"; break; case ftMFB: stim = "MF B"; break; /* Frames */ case ftFRAME_A: stim = "FRAME A"; break; case ftFRAME_B: stim = "FRAME B"; break; case ftFRAME_C: stim = "FRAME C"; break; default: stim = "VOID"; break; } } printf("Time:%6d ms {TX: %-7s} MFR %5d Error %3d ", ob_pos / DATA_SIZE_1MS, stim, good_mfr, bad_mfr); last_mfrs = p; p -= MFR_SYNC_OFFSET * FRAME_SIZE; for (i = 0; i < 16; i++) { t0idx = i * 32; d = p[t0idx]; crcfr[i] = d; if (i & 1) { A <<= 1; if (d & 0x04) A |= 1; if (i >= 13) { E <<= 1; if (d & 0x01) E |= 1; } } else { C <<= 1; C |= (0x1 & d); } } cr0 = calc_and_set_crc4_smf(p, 0xff); cr1 = calc_and_set_crc4_smf(p + 256, 0xff); switch (E) { case 0: cur_Err += 2; break; case 1: cur_Err++; break; case 2: cur_Err = 1; break; case 3: cur_Err = 0; break; } printbinary("A", A, 8); printbinary(" C", C, 8); printbinary(" CR0", cr0, 4); printbinary(" CR1", cr1, 4); printbinary(" E", E, 2); printf(" Cerr %4d", cur_Err); printf(" "); printhex(crcfr, 0, 16, 0); if (E == 1) cur_Err = 0; return 0; } /* * Write one multiframe 16 * 2048 bit ; 512 bytes * returns the CRC4 for the next sub multiframe */ uint8_t fill_outframe(uint8_t * of, uint8_t A, uint8_t E, uint8_t S, uint8_t F, uint8_t cr0, uint8_t MFRSW, uint8_t * dch, uint8_t def) { uint16_t i, tidx; static unsigned char p; uint8_t c0, c1, j; tidx = 0; for (i = 0; i < 16; i++) { if (i & 1) { /* NFAS */ p = 0xf8 & S; if (A & 0x80) p |= 4; A <<= 1; p |= 2; if (i >= 13) { if (E & 0x2) p |= 1; E <<= 1; } else { if (MFRSW & 0x80) p |= 1; MFRSW <<= 1; } } else { p = F & 0xfe; } of[tidx] = p; tidx++; for (j = 1; j < 32; j++) { if (j == 16) { /* D channel */ of[tidx] = *dch; dch++; } else of[tidx] = def; tidx++; } } c0 = calc_crc4(of, 0, 256); c1 = calc_crc4(of, 256, 256); for (i = 0; i < 16; i += 2) { tidx = 32 * i; p = of[tidx]; if (i < 8) { if (cr0 & 0x8) p |= 1; cr0 <<= 1; } else { if (c0 & 0x8) p |= 1; c0 <<= 1; } of[tidx] = p; } return c1; } static uint8_t *ib_cp; static int process_data(int cnt) { uint16_t dist, nidx; uint8_t i; static uint8_t fr[5]; static enum FSyncState frT[5]; if (debuglevel == 2) printf("Start %d %p/%p ", cnt, ib_cp, ib_p); while (1) { dist = ib_p - ib_cp; if (dist <= 400) break; switch (fsync_state) { case FSync_None: case FSync_AIS: case FSync_LOS: /* hunt for basic sync */ fr[0] = ib_cp[0]; if ((fr[0] & FR_FAS_MASK) != FR_FAS_VAL) { ib_cp++; continue; } else { frT[0] = FSync_FAS; if (debuglevel == 2) printf("F"); nidx = 32; fr[1] = ib_cp[nidx]; if (!(fr[1] & 0x2)) { ib_cp++; continue; } else frT[1] = FSync_NFAS; if (debuglevel == 2) printf("N"); nidx = 64; fr[2] = ib_cp[nidx]; if ((fr[2] & FR_FAS_MASK) != FR_FAS_VAL) { ib_cp++; continue; } else frT[2] = FSync_FAS; if (debuglevel == 2) printf("f %p/%d", ib_cp, dist); for (i = 3; i < 5; i++) { nidx = i * 32; fr[i] = ib_cp[nidx]; if ((fr[i] & FR_FAS_MASK) == FR_FAS_VAL) { frT[i] = FSync_FAS; } else if (fr[i] & 0x2) { frT[i] = FSync_NFAS; } else frT[i] = FSync_None; } } break; default: for (i = 0; i < 4; i++) { fr[i] = fr[i + 1]; frT[i] = frT[i + 1]; } /* i = 4 */ nidx = i * 32; fr[i] = ib_cp[nidx]; if ((fr[i] & FR_FAS_MASK) == FR_FAS_VAL) { frT[i] = FSync_FAS; } else if (fr[i] & 0x2) { frT[i] = FSync_NFAS; } else frT[i] = FSync_None; break; } switch (frT[0]) { case FSync_FAS: switch (fsync_state) { case FSync_None: case FSync_AIS: case FSync_LOS: fsync_state = FSync_FAS; startcnt = MFR_SYNC_BITS; mfr_sync = 0; break; case FSync_NFAS: fsync_state = FSync_FAS; break; case FSync_FAS: if ((frT[2] != FSync_NFAS) && (frT[4] != FSync_NFAS)) { /* 3 wrong NFAS received - sync lost */ fsync_state = FSync_LOS; } else { /* assume we did receive a NFAS, with wrong Bit 2 */ fsync_state = FSync_NFAS; } break; } break; case FSync_NFAS: switch (fsync_state) { case FSync_None: case FSync_AIS: case FSync_LOS: /* cannot happen, since sa new sync always starts with FAS */ fprintf(stderr, "Line %d: Wrong state %d while processing NFAS\n", __LINE__, fsync_state); exit(1); break; case FSync_FAS: fsync_state = FSync_NFAS; break; case FSync_NFAS: if ((frT[2] != FSync_FAS) && (frT[4] != FSync_FAS)) { /* 3 wrong FAS received - sync lost */ fsync_state = FSync_LOS; } else { /* assume we did receive a wrong coded FAS */ fsync_state = FSync_FAS; } break; } break; case FSync_None: switch (fsync_state) { case FSync_None: case FSync_AIS: case FSync_LOS: /* cannot happen, since a new sync always starts with FAS */ fprintf(stderr, "Line %d: Wrong state %d\n", __LINE__, fsync_state); exit(1); break; case FSync_FAS: if ((frT[2] != FSync_NFAS) && (frT[4] != FSync_NFAS)) { /* 3 wrong NFAS received - sync lost */ fsync_state = FSync_LOS; } else { /* assume we did receive a NFAS, with wrong Bit 2 */ fsync_state = FSync_NFAS; } break; case FSync_NFAS: if ((frT[2] != FSync_FAS) && (frT[4] != FSync_FAS)) { /* 3 wrong FAS received - sync lost */ fsync_state = FSync_LOS; } else { /* assume we did receive a wrong coded FAS */ fsync_state = FSync_FAS; } break; } break; default: /* not possible here */ fprintf(stderr, "Line %d: Wrong state %d\n", __LINE__, frT[0]); exit(1); break; } /* check for multi frame sync now */ switch (fsync_state) { case FSync_LOS: /* start new sync hunting */ continue; case FSync_NFAS: mfr_sync <<= 1; mfr_sync |= (fr[0] & MFR_SYNC_BIT); if (startcnt == 0) { dist = ib_cp - last_mfrs; if ((mfr_sync & MFR_SYNC_MASK) == MFR_SYNC_VALUE) { /* sync found */ if (mfr_state == MFR_State_NotSync) { mfr_state = MFR_State_Sync; good_mfr = 1; analyse_mfr(ib_cp); } else if (dist == 16 * 32) { good_mfr++; analyse_mfr(ib_cp); } } else { if (mfr_state == MFR_State_Sync) { if (dist == 16 * 32) { bad_mfr++; } else if (dist == 32 * 32) { mfr_state = MFR_State_NotSync; } } } } else startcnt--; break; case FSync_FAS: break; default: fprintf(stderr, "Wrong state %d\n", fsync_state); exit(1); break; } ib_cp += 32; } if (debuglevel == 2) printf("\n"); return 0; } static int fill_buffer(unsigned char *p, int len) { ib_pos = ib_p - inbuf; if ((ib_pos + len) >= ib_size) len = ib_size - ib_pos; memcpy(ib_p, p, len); ib_p += len; return len; } /* returns next start frame */ static uint8_t *fill_timeslot(uint8_t * p0, int ts, uint8_t * data, int datalen, int repeat) { uint8_t *p = p0; int i, cnt = repeat; while (cnt) { for (i = 0; i < datalen; i++) { p[ts] = data[i]; p += FRAME_SIZE; } cnt--; } return p; } uint8_t *fill_timeslot_ts0_smf(uint8_t * p0, int ts, int smf, uint8_t fas_err, uint8_t nfas_err, uint8_t mfsw, uint8_t S, uint8_t A, uint8_t C, uint8_t E, int repeat) { uint8_t *p = p0; uint8_t i, d[8], a, c, e, n, f, m; while (repeat) { e = E; if (smf & 1) { a = A & 0xf; c = C & 0xf; n = nfas_err & 0xf; f = fas_err & 0xf; m = mfsw & 0xf; } else { a = A >> 4; c = C >> 4; n = nfas_err >> 4; f = fas_err >> 4; m = mfsw >> 4; } for (i = 0; i < 8; i++) { if (i & 1) { /* NFAS */ if (n & 8) /* nfas error */ d[i] = 0; else d[i] = 2; n <<= 1; if (i > 4 && (smf & 1)) { if (e & 2) d[i] |= 1; e <<= 1; } else { if (m & 8) d[i] |= 1; m <<= 1; } d[i] |= (S & 0xF8); if (a & 8) d[i] |= 4; a <<= 1; } else { /* FAS */ if (f & 8) /* FAS error */ d[i] = 0xc8; else d[i] = FR_FAS_VAL; f <<= 1; if (c & 8) d[i] |= 1; c <<= 1; } } p = fill_timeslot(p, ts, d, 8, 1); smf++; repeat--; } return p; } static uint8_t *calc_and_set_crc4_ts(uint8_t * start, uint8_t ts, uint8_t * first_last_crc, int smf_count) { uint8_t crc = *first_last_crc & 0xf; uint8_t wrong_crc = *first_last_crc & 0xf0; uint8_t *p = start; while (smf_count) { if (wrong_crc) crc = crc + 2; crc = calc_and_set_crc4_smf(&p[ts], crc & 0xf); p += SMFR_SIZE; smf_count--; } *first_last_crc = crc; return p; } static int transmit(int sock, uint8_t * ob, uint16_t len) { struct msghdr mh; struct iovec iov[2]; int ret; struct mISDNhead hh = { PH_DATA_REQ, 1 }; mh.msg_name = NULL; mh.msg_namelen = 0; mh.msg_iov = iov; mh.msg_iovlen = 2; mh.msg_control = NULL; mh.msg_controllen = 0; mh.msg_flags = 0; iov[0].iov_base = &hh; iov[0].iov_len = MISDN_HEADER_LEN; iov[1].iov_base = ob; iov[1].iov_len = len; ret = sendmsg(sock, &mh, 0); if (ret != (len + MISDN_HEADER_LEN)) { fprintf(stderr, "Send error %d (%d + %d) - %s\n", ret, (int)MISDN_HEADER_LEN, len, strerror(errno)); ret = 0; } else ret = len; return ret; } #define MAX_RECV_BUFFER_SIZE 4200 static int start_transmit = 1; static int last_dlen = 64; static int receive_ts0dch(int socket) { int ret, cnt, head; uint8_t buffer[MAX_RECV_BUFFER_SIZE]; struct mISDNhead *hh = (struct mISDNhead *)buffer; ret = recv(socket, buffer, MAX_RECV_BUFFER_SIZE, 0); if (ret < 0) { fprintf(stderr, "read error %s\n", strerror(errno)); return ret; } #if 0 if (cts.cmsg_type == MISDN_TIME_STAMP) { mt = localtime((time_t *) & cts.tv.tv_sec); head = printf("%02d.%02d.%04d %02d:%02d:%02d.%06ld", mt->tm_mday, mt->tm_mon + 1, mt->tm_year + 1900, mt->tm_hour, mt->tm_min, mt->tm_sec, cts.tv.tv_usec); } else { cts.tv.tv_sec = 0; cts.tv.tv_usec = 0; } #endif head = 0; switch (hh->prim) { case PH_DATA_IND: last_dlen = ret - MISDN_HEADER_LEN; if (!RawReadMode) { if (start_transmit && RawReadMode == 0) { ob_p += transmit(socket, ob_p, last_dlen); start_transmit = 0; } cnt = fill_buffer(&buffer[MISDN_HEADER_LEN], last_dlen); process_data(cnt); if ((mfr_state == MFR_State_NotSync && debuglevel == 3) || debuglevel == 4) { head = printf("Got %3d bytes ", last_dlen); printhex(buffer, MISDN_HEADER_LEN, cnt, head); } } else { head = printf("Got %3d bytes ", last_dlen); printhex(buffer, MISDN_HEADER_LEN, last_dlen, head); } break; case PH_DATA_CNF: if (!RawReadMode) { ob_pos = ob_p - outbuf; if ((ob_pos + last_dlen) >= ob_size) { ret = -1; /* stop */ last_dlen = ob_size - ob_pos; } if (debuglevel == 5) { head = printf("Send %3d bytes ", last_dlen); printhex(ob_p, 0, last_dlen, head); } ob_p += transmit(socket, ob_p, last_dlen); } break; } return ret; } /* test description sub routines */ static const char *printhead[] = { "", " ", " ", " ", " ", " ", " ", " ", " " }; static void print_testdescription(struct fr_cdesc *arg) { struct fr_cdesc *dsc = arg; int head = 0; while (dsc) { if (dsc->type == ftNone) { fprintf(stdout, "unexpected end of description\n"); break; } else if (dsc->type == ftCtrl_Start) { fprintf(stdout, "Start of test sequence\n"); } else if (dsc->type == ftCtrl_Stop) { fprintf(stdout, "End of test\n"); break; } else if (dsc->type == ftCtrl_Repeat) { fprintf(stdout, "%sdo %d times {\n", printhead[head], dsc->count); head++; } else if (dsc->type == ftCtrl_End) { head--; fprintf(stdout, "%s}\n", printhead[head]); } else { fprintf(stdout, "%s%4d ", printhead[head], dsc->count); switch (dsc->type) { case ftAIS: fprintf(stdout, "%-8s", "AIS"); break; /* Basic Frames */ case ftFAS: if (dsc->prop & ftPROP_FAIL) fprintf(stdout, "%-8s", "/FAS"); else fprintf(stdout, "%-8s", "FAS"); break; case ftBIT2: if (dsc->prop & ftPROP_FAIL) fprintf(stdout, "%-8s", "/BIT 2"); else fprintf(stdout, "%-8s", "BIT 2"); break; /* Sub multi frames */ case ftSMFA: fprintf(stdout, "%-8s", "SMF A"); break; case ftSMFB: fprintf(stdout, "%-8s", "SMF B"); break; /* Multi frames */ case ftMFA: fprintf(stdout, "%-8s", "MF A"); break; case ftMFB: fprintf(stdout, "%-8s", "MF B"); break; /* Frames */ case ftFRAME_A: fprintf(stdout, "%-8s", "FRAME A"); break; case ftFRAME_B: fprintf(stdout, "%-8s", "FRAME B"); break; case ftFRAME_C: fprintf(stdout, "%-8s", "FRAME C"); break; default: fprintf(stdout, "%-8s", "UNKNOWN"); break; } if (dsc->prop & ftPROP_CRC4) fprintf(stdout, " (CRC4 Error)"); if (dsc->prop & ftPROP_MFAS) fprintf(stdout, " (MFAS Error)"); if (dsc->prop & ftPROP_TS31) fprintf(stdout, " (TS 31)"); if (dsc->prop & ftPROP_START) fprintf(stdout, " (Start Test)"); fprintf(stdout, "\n"); } dsc++; } } static void print_flatdescription(struct fr_flatdesc *dsc) { fprintf(stdout, "Start test\n"); while (dsc) { if (dsc->type == ftNone) { fprintf(stdout, "unexpected end of description\n"); break; } else if (dsc->type == ftCtrl_Stop) { fprintf(stdout, "End of test\n"); break; } else if (dsc->type == ftAIS) { fprintf(stdout, "%7d %2d %-6s", dsc->pos, dsc->mf_pos, "AIS"); } else if (dsc->type == ftFAS) { if (dsc->prop & ftPROP_FAIL) fprintf(stdout, "%7d %2d %-6s", dsc->pos, dsc->mf_pos, "/FAS"); else fprintf(stdout, "%7d %2d %-6s", dsc->pos, dsc->mf_pos, "FAS"); } else if (dsc->type == ftBIT2) { if (dsc->prop & ftPROP_FAIL) fprintf(stdout, "%7d %2d %-6s", dsc->pos, dsc->mf_pos, "/BIT 2"); else fprintf(stdout, "%7d %2d %-6s", dsc->pos, dsc->mf_pos, "BIT 2"); } switch (dsc->otype) { case ftAIS: fprintf(stdout, "[%-7s]", "AIS"); break; /* Basic Frames */ case ftFAS: if (dsc->prop & ftPROP_FAIL) fprintf(stdout, "[%-7s]", "/FAS"); else fprintf(stdout, "[%-7s]", "FAS"); break; case ftBIT2: if (dsc->prop & ftPROP_FAIL) fprintf(stdout, "[%-7s]", "/BIT 2"); else fprintf(stdout, "[%-7s]", "BIT 2"); break; /* Sub multi frames */ case ftSMFA: fprintf(stdout, "[%-7s]", "SMF A"); break; case ftSMFB: fprintf(stdout, "[%-7s]", "SMF B"); break; /* Multi frames */ case ftMFA: fprintf(stdout, "[%-7s]", "MF A"); break; case ftMFB: fprintf(stdout, "[%-7s]", "MF B"); break; /* Frames */ case ftFRAME_A: fprintf(stdout, "[%-7s]", "FRAME A"); break; case ftFRAME_B: fprintf(stdout, "[%-7s]", "FRAME B"); break; case ftFRAME_C: fprintf(stdout, "[%-7s]", "FRAME C"); break; default: fprintf(stdout, "[%-7s]", "VOID"); break; } if (dsc->prop & ftPROP_CRC4) fprintf(stdout, " (CRC4 Error)"); if (dsc->prop & ftPROP_MFAS) fprintf(stdout, " (MFAS Error)"); if (dsc->prop & ftPROP_TS31) fprintf(stdout, " (TS 31)"); if (dsc->prop & ftPROP_START) fprintf(stdout, " (Start Test)"); fprintf(stdout, "\n"); dsc++; } } static int calc_flatcount(struct fr_cdesc *arg) { struct fr_cdesc *dsc = arg; int count[8], repeat[8]; int cnt, csp = 0; count[0] = 0; while (dsc) { if (dsc->type == ftNone) { fprintf(stderr, "unexpected end of description\n"); csp = 0; count[0] = -1; break; } if (dsc->type == ftCtrl_Stop) break; if (dsc->type == ftCtrl_Start) { /* nothing to do */ } else if (dsc->type == ftCtrl_Repeat) { csp++; if (csp >= 8) { fprintf(stderr, "To deep nesting of loops\n"); csp = 0; count[0] = -1; break; } repeat[csp] = dsc->count; count[csp] = 0; } else if (dsc->type == ftCtrl_End) { if (csp < 1) { fprintf(stderr, "End of description, but no Repeatblock\n"); csp = 0; count[0] = -1; break; } cnt = repeat[csp] * count[csp]; csp--; count[csp] += cnt; } else { count[csp] += (dsc->subcnt * dsc->count); } dsc++; } if (csp != 0) { fprintf(stderr, "End of description, but repeat level %d (not 0)\n", csp); csp = 0; count[0] = -1; } return count[0]; } static struct fr_flatdesc *make_flat_description(struct fr_cdesc *test, struct fr_flatdesc *begin) { struct fr_cdesc *dsc = test; struct fr_flatdesc *flat = begin; int repeat[8]; struct fr_flatdesc *seq, *end, *start[8]; int cnt, i, csp = 0, pos, mfpos; pos = flat->pos; mfpos = flat->mf_pos; while (dsc) { if (dsc->type == ftNone) { fprintf(stderr, "unexpected end of description\n"); flat = NULL; break; } if (dsc->type == ftCtrl_Stop) { flat->pos = pos; flat->type = dsc->type; break; } if (dsc->type == ftCtrl_Start) { /* nothing to do */ flat->prop = ftPROP_START; } else if (dsc->type == ftCtrl_Repeat) { csp++; if (csp >= 8) { fprintf(stderr, "To deep nesting of loops\n"); csp = 0; flat = NULL; break; } repeat[csp] = dsc->count; start[csp] = flat; } else if (dsc->type == ftCtrl_End) { if (csp < 1) { fprintf(stderr, "End of description, but no Repeatblock\n"); flat = NULL; break; } end = flat; repeat[csp]--; /* one already done */ while (repeat[csp]) { seq = start[csp]; while (seq != end) { *flat = *seq; flat->pos = pos; flat->prop &= ~ftPROP_START; seq++; flat++; pos++; } --repeat[csp]; } csp--; } else { for (cnt = 0; cnt < dsc->count; cnt++) { switch (dsc->type) { case ftAIS: /* Basic Frames */ case ftFAS: case ftBIT2: flat->pos = pos; flat->type = dsc->type; flat->otype = dsc->type; flat->prop |= dsc->prop; flat++; pos++; break; /* Sub multi frames */ case ftSMFA: for (i = 0; i < 8; i++) { flat->pos = pos; flat->otype = dsc->type; if (i & 1) { flat->type = ftBIT2; } else { flat->type = ftFAS; } flat++; pos++; } break; case ftSMFB: for (i = 0; i < 8; i++) { flat->pos = pos; flat->otype = dsc->type; if (i & 1) { flat->type = ftBIT2; } else { flat->type = ftFAS; } flat->prop |= dsc->prop; flat++; pos++; } break; /* Multi frames */ case ftMFA: for (i = 0; i < 16; i++) { flat->pos = pos; flat->otype = dsc->type; if (i & 1) { flat->type = ftBIT2; } else { flat->type = ftFAS; } flat++; pos++; } break; case ftMFB: for (i = 0; i < 16; i++) { flat->pos = pos; flat->otype = dsc->type; if (i & 1) { flat->type = ftBIT2; } else { flat->type = ftFAS; } flat->prop |= ftPROP_MFAS; flat++; pos++; } break; /* Frames */ case ftFRAME_A: flat->pos = pos; flat->otype = dsc->type; flat->type = ftFAS; flat++; pos++; flat->pos = pos; flat->otype = dsc->type; flat->type = ftBIT2; flat++; pos++; break; case ftFRAME_B: flat->pos = pos; flat->otype = dsc->type; flat->type = ftFAS; flat->prop |= ftPROP_TS31; flat++; pos++; flat->pos = pos; flat->otype = dsc->type; flat->type = ftBIT2; flat->prop |= ftPROP_TS31; flat++; pos++; break; case ftFRAME_C: flat->pos = pos; flat->otype = dsc->type; flat->type = ftFAS; flat->prop |= ftPROP_FAIL | ftPROP_TS31; flat++; pos++; flat->pos = pos; flat->otype = dsc->type; flat->type = ftBIT2; flat->prop |= ftPROP_TS31; flat++; pos++; break; default: /* never */ fprintf(stderr, "Got wrong type %x\n", dsc->type); exit(1); } } } dsc++; } if (!flat) return flat; flat = begin; mfpos = flat->mf_pos; while (flat) { if (flat->type == ftNone) { fprintf(stdout, "unexpected end of description\n"); flat = NULL; break; } else if (flat->type == ftCtrl_Stop) { flat->mf_pos = mfpos; break; } else if (flat->type == ftAIS) { flat->mf_pos = 0xff; flat->mf_pos = 14; } else if (flat->type == ftFAS) { if (mfpos & 1) /* reset */ mfpos = 0; } else if (flat->type == ftBIT2) { if (!(mfpos & 1)) mfpos = 1; } flat->mf_pos = mfpos; mfpos++; if (mfpos > 15) mfpos = 0; flat++; } return flat; } static struct fr_data *gen_flat_frame_desc(struct fr_cdesc *dsc) { struct fr_data loc_frd, *frd; struct fr_flatdesc *flat_dsc; int cnt, sum, pre; pre = calc_flatcount(preamble); cnt = calc_flatcount(dsc); sum = pre + cnt; loc_frd.count = sum; flat_dsc = calloc(sum + 2, sizeof(*flat_dsc)); /* reserve for stop */ if (!flat_dsc) { fprintf(stderr, "No memory to allocate %d * %zd bytes for flat description\n", loc_frd.count, sizeof(*flat_dsc)); return NULL; } loc_frd.desc = flat_dsc; flat_dsc = make_flat_description(preamble, flat_dsc); if (!flat_dsc) { fprintf(stderr, "Error while generating flat description of preamble\n"); free(flat_dsc); return NULL; } flat_dsc = make_flat_description(dsc, flat_dsc); if (!flat_dsc) { fprintf(stderr, "Error while generating flat description\n"); free(flat_dsc); return NULL; } frd = malloc(sizeof(*frd)); if (!frd) { fprintf(stderr, "No memory to allocate %zd bytes\n", sizeof(*frd)); free(flat_dsc); return NULL; } *frd = loc_frd; return frd; } static int gen_flat_frame_data(struct fr_data *frd) { struct fr_flatdesc *flat; size_t size; int ret = 0; uint8_t crc, *p, dch_flags = 0x7e; flat = frd->desc; size = frd->count; size *= FRAME_SIZE; frd->data_size = size; frd->data = malloc(size + 100 * FRAME_SIZE); /* Reserve to avoid crash when manipulate frames on the end */ if (!frd->data) { fprintf(stderr, "No memory to allocate %zd + %d bytes\n", size, 100 * FRAME_SIZE); flat = NULL; ret = -ENOMEM; } memset(frd->data, 0xff, size + 100 * FRAME_SIZE); p = frd->data; fill_timeslot(p, 16, &dch_flags, 1, frd->count); while (flat) { flat->data = p; if (flat->type == ftNone) { fprintf(stdout, "unexpected end of description\n"); free(frd->data); frd->data = NULL; ret = -EINVAL; break; } else if (flat->type == ftCtrl_Stop) { fprintf(stdout, "End of test\n"); break; } else if (flat->type == ftAIS) { memset(p, 0xff, FRAME_SIZE); } else if (flat->type == ftFAS) { if (flat->prop & ftPROP_FAIL) *p = FR_FAS_VAL_FAIL; else *p = FR_FAS_VAL; if (flat->prop & ftPROP_TS31) p[31] = FR_NFAS_B2; } else if (flat->type == ftBIT2) { if (flat->prop & ftPROP_FAIL) *p = FR_NFAS_B2_FAIL; else *p = FR_NFAS_B2; if ((flat->mf_pos & 0xf) == 5) { if (!(flat->prop & ftPROP_MFAS)) *p |= 1; } else if ((flat->mf_pos & 0xf) > 7) { *p |= 1; } if (flat->prop & ftPROP_TS31) p[31] = FR_FAS_VAL; } p += FRAME_SIZE; flat++; } p = frd->data; crc = 0; /* start value */ flat = frd->desc; while (flat) { if (flat->type == ftNone) { fprintf(stdout, "unexpected end of description\n"); free(frd->data); frd->data = NULL; ret = -EINVAL; break; } else if (flat->type == ftCtrl_Stop) { fprintf(stdout, "End of test\n"); break; } else if (flat->type == ftAIS) { crc = 0; } else { if ((flat->mf_pos & 0x7) == 0) { calc_and_set_crc4_ts(flat->data, 0, &crc, 1); } if ((flat->mf_pos & 0x7) == 2) { if (flat->prop & ftPROP_CRC4) { /* insert a bit failure in TS 3 (0xFF -> 0xEF) */ flat->data[3] = 0xef; } } } flat++; } return ret; } int main(int argc, char *argv[]) { int i, channel; int log_socket; struct sockaddr_mISDN log_addr; int buflen = 4104; u_char buffer[buflen]; int result; int cnt, dlen; struct mISDN_devinfo di; struct mISDNhead *hh; struct mISDNversion ver; struct pollfd pfd[8]; int pfd_nr; struct mISDN_ctrl_req creq; result = opt_parse(argc, argv); if (result) { exit(1); } calc_bitswap_table(); cnt = calc_flatcount(preamble); fprintf(stdout, "preamble: %d test: %d\n", cnt, calc_flatcount(Test)); if (ListMode == 1) { print_testdescription(Test); return 0; } TestData = gen_flat_frame_desc(Test); if (!TestData) { fprintf(stdout, "Did not generate flat description\n"); exit(1); } if (ListMode == 2) { print_flatdescription(TestData->desc); return 0; } result = gen_flat_frame_data(TestData); if (result) { fprintf(stderr, "Error generating test data\n"); exit(1); } if (cardnr < 0) { fprintf(stderr, "card nr may not be negative\n"); exit(1); } if ((log_socket = socket(PF_ISDN, SOCK_RAW, 0)) < 0) { printf("could not open socket %s\n", strerror(errno)); exit(1); } result = ioctl(log_socket, IMGETVERSION, &ver); if (result < 0) { printf("ioctl error %s\n", strerror(errno)); exit(1); } if (ver.release & MISDN_GIT_RELEASE) printf("mISDN kernel version %d.%02d.%d (git.misdn.eu) found\n", ver.major, ver.minor, ver.release & ~MISDN_GIT_RELEASE); else printf("mISDN kernel version %d.%02d.%d found\n", ver.major, ver.minor, ver.release); printf("mISDN user version %d.%02d.%d found\n", MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); if (ver.major != MISDN_MAJOR_VERSION) { printf("VERSION incompatible please update\n"); exit(1); } result = ioctl(log_socket, IMGETCOUNT, &cnt); if (result < 0) { printf("ioctl error %s\n", strerror(errno)); exit(1); } else printf("%d controller%s found\n", cnt, (cnt == 1) ? "" : "s"); di.id = cardnr; result = ioctl(log_socket, IMGETDEVINFO, &di); if (result < 0) { printf("ioctl error %s\n", strerror(errno)); } else { printf(" id: %d\n", di.id); printf(" Dprotocols: %08x\n", di.Dprotocols); printf(" Bprotocols: %08x\n", di.Bprotocols); printf(" protocol: %d\n", di.protocol); printf(" channelmap: "); for (i = MISDN_CHMAP_SIZE - 1; i >= 0; i--) printf("%02x", di.channelmap[i]); printf("\n"); printf(" nrbchan: %d\n", di.nrbchan); printf(" name: %s\n", di.name); } close(log_socket); outbuf = TestData->data; ob_size = TestData->data_size; ob_end = outbuf + ob_size; ib_size = ob_size; ib_size += (5 * MFR_SIZE); inbuf = malloc(ib_size + (5 * MFR_SIZE)); if (!inbuf) { fprintf(stderr, "Could not allocate in buffer (%d bytes)\n", ib_size + (5 * MFR_SIZE)); exit(1); } else if (debuglevel) printf("Allocated in buffer %d bytes (Reserve:%d)\n", ib_size, 10 * MFR_SIZE); ib_p = inbuf; ib_cp = inbuf; ib_end = outbuf + ib_size; /* Ready for transmit */ ob_p = outbuf; if ((log_socket = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW)) < 0) { printf("could not open log socket %s\n", strerror(errno)); exit(1); } log_addr.family = AF_ISDN; log_addr.dev = cardnr; result = -1; channel = 0; log_addr.channel = (unsigned char)channel; result = bind(log_socket, (struct sockaddr *)&log_addr, sizeof(log_addr)); printf("log bind ch(%i) return %d\n", log_addr.channel, result); if (result < 0) { printf("log bind error %s\n", strerror(errno)); close(log_socket); exit(1); } result = fcntl(log_socket, F_SETFL, O_NONBLOCK); if (result < 0) { printf("log F_SETFL O_NONBLOCK error %s\n", strerror(errno)); close(log_socket); exit(1); } pfd[0].fd = log_socket; pfd[0].events = POLLIN; pfd[0].revents = 0; pfd_nr = 1; hh = (struct mISDNhead *)buffer; creq.op = MISDN_CTRL_GETOP; creq.channel = 0; creq.p1 = 0; creq.p2 = 0; creq.unused = 0; result = ioctl(log_socket, IMCTRLREQ, &creq); if (result < 0) { fprintf(stdout, "Error on MISDN_CTRL_L1_TS0_MODE ioctl - %s\n", strerror(errno)); close(log_socket); exit(1); } if (!(creq.op & MISDN_CTRL_L1_TESTS)) { fprintf(stdout, "MISDN_CTRL_L1_TESTS controls are not supported on this card/driver\n"); close(log_socket); exit(1); } if (debuglevel) fprintf(stdout, "MISDN_CTRL_GETOP ioctl supported operations %x\n", creq.op); /* This set the register values in the card so, that the TS0 is not in full transparent mode, * so the receiver can syncronize - this allows to get the TS0 data on byte boundaries, so bit shifting all * incoming data is not needed. After we did detect syncron state for 3 times, will will switch off * autosync and put TS0 into full transparent mode */ creq.op = MISDN_CTRL_L1_TS0_MODE; creq.channel = 0; creq.p1 = 0x06; /* R_RX_SL0_CFG0 = (V_AUTOSYNC | V_AUTO_RECO) */ creq.p2 = 0x31; /* R_TX_SL0_CFG1 = (V_TX_MF | V_TX_E | V_INV_E) */ creq.unused = 0; if (debuglevel) fprintf(stdout, "L1 TS0 ioctl R_RX_SL0_CFG0=%02x R_TX_SL0_CFG1=%02x\n", creq.p1, creq.p2); result = ioctl(log_socket, IMCTRLREQ, &creq); if (debuglevel) fprintf(stdout, "L1 TS0 ioctl old register values R_RX_SL0_CFG0=%02x R_TX_SL0_CFG1=%02x\n", creq.p1, creq.p2); if (result < 0) { fprintf(stdout, "Error on MISDN_CTRL_L1_TS0_MODE ioctl - %s\n", strerror(errno)); close(log_socket); exit(1); } hh->prim = PH_ACTIVATE_REQ; hh->id = MISDN_ID_ANY; result = sendto(log_socket, buffer, MISDN_HEADER_LEN, 0, NULL, 0); if (result < 0) { fprintf(stdout, "could not send ACTIVATE_REQ %s\n", strerror(errno)); close(log_socket); exit(1); } /* Disable RX for the sync search time */ creq.op = MISDN_CTRL_RX_OFF; creq.channel = 0; creq.p1 = 1; creq.p2 = 0; creq.unused = 0; result = ioctl(log_socket, IMCTRLREQ, &creq); if (result < 0) { fprintf(stdout, "Error on MISDN_CTRL_RX_OFF ioctl - %s\n", strerror(errno)); close(log_socket); exit(1); } if (debuglevel) fprintf(stdout, "RX_OFF result %d ioctl p1=%02x p2=%02x p3=%02x\n", result, creq.p1, creq.p2, creq.unused); creq.op = MISDN_CTRL_L1_GET_SYNC_INFO; creq.channel = 0; cnt = 0; /* Wait for sync - this will make sure that we do not need bit shifting incomming data */ for (i = 0; i < 5000; i++) { result = ioctl(log_socket, IMCTRLREQ, &creq); if (result < 0) { fprintf(stdout, "Error on MISDN_CTRL_L1_GET_SYNC_INFO ioctl - %s\n", strerror(errno)); close(log_socket); exit(1); } if (debuglevel) fprintf(stdout, "L1 GET_SYNC_INFO ioctl p1=%02x p2=%02x p3=%02x\n", creq.p1, creq.p2, creq.unused); if ((creq.p1 & 0xff07) == 0x2701) { cnt++; if (cnt == 3) break; i--; } else cnt = 0; usleep(100000); }; if (cnt != 3) { fprintf(stdout, "L1 ts0 sync state not reached\n"); close(log_socket); exit(1); } else fprintf(stdout, "L1 ts0 sync state reached (need %d iterations)\n", i); /* reenable receive */ creq.op = MISDN_CTRL_RX_OFF; creq.channel = 0; creq.p1 = 0; creq.p2 = 0; creq.unused = 0; result = ioctl(log_socket, IMCTRLREQ, &creq); if (result < 0) { fprintf(stdout, "Error on MISDN_CTRL_RX_OFF ioctl - %s\n", strerror(errno)); close(log_socket); exit(1); } if (debuglevel) fprintf(stdout, "RX_OFF ioctl p1=%02x p2=%02x p3=%02x\n", creq.p1, creq.p2, creq.unused); creq.op = MISDN_CTRL_L1_TS0_MODE; creq.channel = 0; creq.p1 = 0x01; /* R_RX_SL0_CFG0 = (V_NO_INSYNC) */ creq.p2 = 0x03; /* R_TX_SL0_CFG1 = (V_TX_MF | V_TRP_SL0) */ creq.unused = 0; if (debuglevel) fprintf(stdout, "L1 TS0 ioctl R_RX_SL0_CFG0=%02x R_TX_SL0_CFG1=%02x\n", creq.p1, creq.p2); result = ioctl(log_socket, IMCTRLREQ, &creq); if (debuglevel) fprintf(stdout, "L1 TS0 ioctl old register values R_RX_SL0_CFG0=%02x R_TX_SL0_CFG1=%02x\n", creq.p1, creq.p2); if (result < 0) { fprintf(stdout, "Error on MISDN_CTRL_L1_TS0_MODE ioctl - %s\n", strerror(errno)); close(log_socket); exit(1); } dlen = 64; while (1) { result = poll(pfd, pfd_nr, 1000); if (result < 0) { fprintf(stderr, "Poll error %s\n", strerror(errno)); continue; } else if (result == 0) { fprintf(stderr, "Poll timeout restart\n"); continue; } if (pfd[0].revents) { dlen = receive_ts0dch(log_socket); if (dlen < 1) /* end of data */ break; } } close(log_socket); return 0; }