mISDNuser/tools/E1test.c

2078 lines
48 KiB
C

/*
*
* Copyright 2015 Karsten Keil <keil@b1-systems.de>
* Copyright 2011 Karsten Keil <kkeil@linux-pingi.de>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/udp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include <stdint.h>
#include <getopt.h>
#include <time.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <mISDN/mISDNif.h>
#include <mISDN/af_isdn.h>
/* 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 <number> 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 <level> debuglevel\n");
fprintf(stderr, " --test -t <test #> generate data for test # (default 0)\n");
fprintf(stderr, " --write -w <file> write <file>\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;
}