/*
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the
Queen in Right of Canada (Communications Research Center Canada)
*/
/*
This file is part of ODR-DabMux.
ODR-DabMux 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 of the
License, or (at your option) any later version.
ODR-DabMux 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 ODR-DabMux. If not, see .
*/
#include
#ifdef _WIN32
# include
#else
# include
#endif // _WIN32
#include
#include "bridge.h"
#include "crc.h"
#include
#include "PcDebug.h"
#ifdef _WIN32
# ifdef _DEBUG
int bridgeVerbosity = 0;
# endif
#else
# ifdef DEBUG
int bridgeVerbosity = 0;
# endif
#endif
void printStats(struct bridgeInfo* info, FILE* out)
{
struct bridgeStats stats = getStats(info);
fprintf(out, "frames : %lu\n", stats.frames);
fprintf(out, " valids : %lu\n", stats.valids);
fprintf(out, " invalids : %lu\n", stats.invalids);
fprintf(out, " bytes : %lu\n", stats.bytes);
fprintf(out, " packets : %lu\n", stats.packets);
fprintf(out, " errors : %lu\n", stats.errors);
fprintf(out, " missings : %lu\n", stats.missings);
fprintf(out, " dropped : %lu\n", stats.dropped);
fprintf(out, " crc : %lu\n", stats.crc);
fprintf(out, " overruns : %lu\n", stats.overruns);
}
void resetStats(struct bridgeInfo* info)
{
memset(&info->stats, 0, sizeof(info->stats));
}
struct bridgeStats getStats(struct bridgeInfo* info)
{
return info->stats;
}
void bridgeInitInfo(struct bridgeInfo* info)
{
memset(info, 0, sizeof(*info));
info->transmitted = -8;
};
int writePacket(void* dataIn, int sizeIn, void* dataOut, int sizeOut,
struct bridgeInfo* info)
{
static struct bridgeHdr header = { 0 };
PDEBUG4_VERBOSE(1, bridgeVerbosity, "writePacket\n sizeIn: %i, sizeOut: %i, "
"offset: %i, transmitted: %i\n",
sizeIn, sizeOut, info->offset, info->transmitted);
assert(info->transmitted < sizeIn);
if ((info->offset == 0) && (sizeIn > 0)) {
((unsigned short*)dataOut)[0] = 0xb486;
info->offset = 2;
}
if (sizeIn == 0) {
memset((unsigned char*)dataOut + info->offset, 0, sizeOut - info->offset);
info->offset = 0;
info->transmitted = -8;
PDEBUG1_VERBOSE(1, bridgeVerbosity, " return %i (sizeIn == 0)\n",
sizeOut);
return 0;
}
while (info->offset < sizeOut) {
switch (info->transmitted) {
case (-8):
((unsigned char*)dataOut)[info->offset++] = 0xcb;
++info->transmitted;
break;
case (-7):
((unsigned char*)dataOut)[info->offset++] = 0x28;
++info->transmitted;
break;
case (-6):
header.size = htons((unsigned short)sizeIn);
header.crc = htons((unsigned short)(crc16(0xffff, &header, 4) ^ 0xffff));
((unsigned char*)dataOut)[info->offset++] = ((char*)&header)[0];
++info->transmitted;
break;
case (-5):
((unsigned char*)dataOut)[info->offset++] = ((char*)&header)[1];
++info->transmitted;
break;
case (-4):
((unsigned char*)dataOut)[info->offset++] = ((char*)&header)[2];
++info->transmitted;
break;
case (-3):
((unsigned char*)dataOut)[info->offset++] = ((char*)&header)[3];
++info->transmitted;
break;
case (-2):
((unsigned char*)dataOut)[info->offset++] = ((char*)&header)[4];
++info->transmitted;
break;
case (-1):
((unsigned char*)dataOut)[info->offset++] = ((char*)&header)[5];
++info->transmitted;
header.seqNb = htons((unsigned short)(ntohs(header.seqNb) + 1));
break;
default:
((unsigned char*)dataOut)[info->offset++] =
((unsigned char*)dataIn)[info->transmitted++];
if (info->transmitted == sizeIn) {
PDEBUG2_VERBOSE(1, bridgeVerbosity,
" Packet done, %i bytes at offset %i\n",
info->transmitted, info->offset);
PDEBUG1_VERBOSE(1, bridgeVerbosity,
" return %i (sizeIn == transmitted)\n", info->offset);
info->transmitted = -8;
return info->offset;
}
}
}
PDEBUG1_VERBOSE(1, bridgeVerbosity, " return %i (offset >= sizeOut)\n",
info->offset);
info->offset = 0;
return 0;
}
int getPacket(void* dataIn, int sizeIn, void* dataOut, int sizeOut,
struct bridgeInfo* info, char async)
{
unsigned char* in = (unsigned char*)dataIn;
unsigned char* out = (unsigned char*)dataOut;
unsigned char ch;
unsigned short crc;
unsigned short diff;
PDEBUG3_VERBOSE(1, bridgeVerbosity,
"getPacket\n pos\t%i\n state\t%i\n received\t%i\n",
info->pos, info->state, info->received);
if (info->pos == 0) {
++info->stats.frames;
if (((unsigned short*)dataIn)[0] != 0xb486) {
if (((unsigned short*)dataIn)[0] != 0) {
++info->stats.invalids;
printf("WARNING: processing frame with invalid magic "
"number!\n");
} else {
PDEBUG0_VERBOSE(1, bridgeVerbosity,
"getPacket: not a valid frame\n");
return 0;
}
} else {
PDEBUG0_VERBOSE(2, bridgeVerbosity, "Valid frame\n");
info->pos += 2;
++info->stats.valids;
}
info->stats.bytes += sizeIn;
}
while (info->pos < sizeIn) {
ch = in[info->pos++];
switch (info->state) {
case 0: // sync search
info->sync <<= 8;
info->sync |= ch;
if (info->sync == 0xcb28) {
PDEBUG0_VERBOSE(2, bridgeVerbosity, "Sync found\n");
++info->stats.packets;
info->received = 0;
info->state = 1;
}
if (info->sync == 0) { // Padding
info->pos = 0;
return 0;
}
break;
case 1: // header search
((char*)&info->header)[info->received++] = ch;
if (info->received == sizeof(struct bridgeHdr)) {
PDEBUG0_VERBOSE(2, bridgeVerbosity, "Header found\n");
out = (unsigned char*)dataOut;
info->received = 0;
info->state = 2;
crc = crc16(0xffff, &info->header, 4);
crc ^= 0xffff;
info->header.size = ntohs(info->header.size);
info->header.seqNb = ntohs(info->header.seqNb);
info->header.crc = ntohs(info->header.crc);
PDEBUG4_VERBOSE(2, bridgeVerbosity,
" size\t%i\n seq\t%i\n crc\t0x%.4x (0x%.4x)\n",
info->header.size, info->header.seqNb,
info->header.crc, crc);
if (crc != info->header.crc) {
PDEBUG0_VERBOSE(2, bridgeVerbosity, "CRC error\n");
++info->stats.errors;
++info->stats.crc;
info->state = 0;
if (info->pos < sizeof(struct bridgeHdr) + 2 + 2) {
info->pos = 2;
}
} else {
if (!info->initSeq) {
info->lastSeq = info->header.seqNb;
info->initSeq = 1;
} else {
if (info->header.seqNb > info->lastSeq) {
diff = (info->header.seqNb - info->lastSeq) - 1;
} else {
diff = ((short)info->lastSeq -
(short)info->header.seqNb) - 1;
}
info->stats.errors += diff;
info->stats.missings += diff;
info->lastSeq = info->header.seqNb;
}
}
}
break;
case 2: // data
out[info->received++] = ch;
if (info->received == info->header.size) {
PDEBUG0_VERBOSE(2, bridgeVerbosity, "data found\n");
info->state = 0;
return info->received;
}
if (info->received == sizeOut) {
PDEBUG1_VERBOSE(1, bridgeVerbosity, "To much data: %i\n",
info->received);
++info->stats.errors;
++info->stats.overruns;
info->sync = 0;
info->state = 0;
return -1;
}
break;
case 3: // Padding or sync
if (ch == 0) { // Padding
info->pos = 0;
return 0;
}
if (ch != 0xcb) { // error
info->sync = ch;
info->state = 0;
} else {
info->state = 4;
}
break;
case 4: // Low byte sync
if (ch != 28) { // error
info->sync <<= 8;
info->sync |= ch;
info->state = 0;
} else {
info->state = 2;
}
break;
}
}
info->pos = 0;
return 0;
}
void dump(void* data, int size, FILE* stream)
{
int i;
fprintf(stream, "%i bytes\n", size);
for (i = 0; i < size; ++i) {
fprintf(stream, " 0x%.2x", ((unsigned char*)data)[i]);
if (i % 8 == 7)
fprintf(stream, "\n");
}
fprintf(stream, "\n");
}
#ifdef BRIDGE_TEST
#include
int test(const unsigned char* data)
{
unsigned char bridgeSize = data[0];
unsigned char nbInput = data[1];
unsigned char nbBridge = 1;
struct bridgeInfo info;
int i, j;
int index = 0;
int max = 0;
int nbBytes;
unsigned char** inputData;
unsigned char** bridgeData;
unsigned char* outputData;
inputData = malloc(nbInput * 4);
bridgeData = malloc(nbBridge * 4);
for (i = 0; i < nbInput; ++i) {
if (data[i + 2] > 0)
inputData[i] = malloc(data[i + 2]);
if (data[i + 2] > max) {
max = data[i + 2];
}
for (j = 0; j < data[i + 2]; ++j) {
inputData[i][j] = index++;
}
}
bridgeData[0] = malloc(bridgeSize);
memset(bridgeData[0], 0, bridgeSize);
outputData = malloc(max);
bridgeInitInfo(&info);
// Write packets
index = 0;
while (1) {
if (data[index + 2] == 0) {
if (++index == nbInput)
break;
}
while ((nbBytes = writePacket(inputData[index], data[index + 2],
bridgeData[nbBridge - 1], bridgeSize, &info))
!= 0) {
if (++index == nbInput) {
break;
}
}
if (index == nbInput)
break;
// TODO check null
bridgeData = realloc(bridgeData, (++nbBridge) * 4);
bridgeData[nbBridge - 1] = malloc(bridgeSize);
memset(bridgeData[nbBridge - 1], 0, bridgeSize);
}
// if (nbBytes != bridgeSize) {
writePacket(NULL, 0, bridgeData[nbBridge - 1], bridgeSize, &info);
// }
// read packets
index = 0;
for (i = 0; i < nbBridge; ++i) {
while ((nbBytes = getPacket(bridgeData[i], bridgeSize, outputData, max,
&info, 0)) != 0) {
while (data[index + 2] == 0) {
++index;
}
if (nbBytes != data[index + 2]) {
printf("FAILED\n");
printf("Invalid size at bridge %i, data %i: %i != %i\n",
i, index, nbBytes, data[index + 2]);
for (i = 0; i < nbInput; ++i) {
printf("Input %i: ", i);
dump(inputData[i], data[i + 2], stdout);
}
for (i = 0; i < nbBridge; ++i) {
printf("Bridge %i: ", i);
dump(bridgeData[i], bridgeSize, stdout);
}
printf("Output %i: ", index);
dump(outputData, nbBytes, stdout);
return -1;
}
if (memcmp(outputData, inputData[index], data[index + 2]) != 0) {
printf("FAILED\n");
printf("output != input\n");
for (i = 0; i < nbInput; ++i) {
printf("Input %i: ", i);
dump(inputData[i], data[i + 2], stdout);
}
for (i = 0; i < nbBridge; ++i) {
printf("Bridge %i: ", i);
dump(bridgeData[i], bridgeSize, stdout);
}
printf("Output %i: ", index);
dump(outputData, nbBytes, stdout);
}
++index;
}
}
printf("SUCCESS\n");
for (i = 0; i < nbInput; ++i) {
if (data[i + 2] > 0)
free(inputData[i]);
}
free(inputData);
free(outputData);
for (i = 0; i < nbBridge; ++i) {
free(bridgeData[i]);
}
free(bridgeData);
return -1;
}
int main(int argc, char* argv[])
{
int i;
// test: bridgesize, nbinput [, input1, input2, ... ]
const unsigned char complete[] = { 32, 1, 16 };
const unsigned char split[] = { 32, 1, 48 };
const unsigned char twice[] = {32, 2, 8, 4 };
const unsigned char secondSplit[] = { 32, 2, 16, 16 };
const unsigned char headerSplit[][4] = {
{ 32, 2, 23, 16 },
{ 32, 2, 22, 16 },
{ 32, 2, 21, 16 },
{ 32, 2, 20, 16 },
{ 32, 2, 19, 16 },
{ 32, 2, 18, 16 },
{ 32, 2, 17, 16 }
};
const unsigned char two[] = { 32, 3, 16, 0, 16 };
const unsigned char doubleSplit[] = { 32, 2, 32, 32 };
const unsigned char full[] = { 32, 2, 24, 12 };
const unsigned char empty[] = { 32, 3, 0, 0, 5 };
#ifdef _WIN32
#ifdef _DEBUG
bridgeVerbosity = argc - 1;
#endif // DEBUG
#else
#ifdef DEBUG
bridgeVerbosity = argc - 1;
#endif // DEBUG
#endif // _WIN32
printf("Complete: ");
test(complete);
// printStats(stdout);
fflush(stdout);
printf("split: ");
test(split);
// printStats(stdout);
fflush(stdout);
printf("twice: ");
test(twice);
// printStats(stdout);
fflush(stdout);
printf("second split: ");
test(secondSplit);
// printStats(stdout);
fflush(stdout);
for (i = 0; i < sizeof(headerSplit) / sizeof(headerSplit[0]); ++i) {
printf("headerSplit%i: ", i);
test(headerSplit[i]);
// printStats(stdout);
fflush(stdout);
}
printf("two: ");
test(two);
// printStats(stdout);
fflush(stdout);
printf("doubleSplit: ");
test(doubleSplit);
// printStats(stdout);
fflush(stdout);
printf("full: ");
test(full);
// printStats(stdout);
fflush(stdout);
printf("empty: ");
test(empty);
// printStats(stdout);
fflush(stdout);
return 0;
}
#endif // BRIDGE_TEST