/*
Copyright (C) 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 "prbs.h"
#include
#include
#include
/*
* Generate a parity check for a 32-bit word.
*/
unsigned long parity_check(unsigned long prbs_accum)
{
unsigned long mask=1UL, parity=0UL;
int i;
for (i = 0; i < 32; ++i) {
parity ^= ((prbs_accum & mask) != 0UL);
mask <<= 1;
}
return parity;
}
/*
* Generate a table of matrix products to update a 32-bit PRBS generator.
*/
void gen_prbs_table(void* args)
{
prbs_data* data = (prbs_data*)args;
int i;
for (i = 0; i < 4; ++i) {
int j;
for (j = 0; j < 256; ++j) {
unsigned long prbs_accum = ((unsigned long)j << (i * 8));
int k;
for (k = 0; k < 8; ++k) {
prbs_accum = (prbs_accum << 1)
^ parity_check(prbs_accum & data->polynomial);
}
data->prbs_table[i][j] = (prbs_accum & 0xff);
}
}
}
/*
* Update a 32-bit PRBS generator eight bits at a time.
*/
unsigned long update_prbs(void* args)
{
prbs_data* data = (prbs_data*)args;
unsigned char acc_lsb = 0;
int i;
for (i = 0; i < 4; ++i ) {
acc_lsb ^= data->prbs_table [i] [ (data->accum >> (i * 8) ) & 0xff ];
}
return (data->accum << 8) ^ ((unsigned long)acc_lsb);
}
/*
* Generate the weight table.
*/
void gen_weight_table(void* args)
{
prbs_data* data = (prbs_data*)args;
int i;
for (i = 0; i < 256; ++i) {
unsigned char mask=1U, ones_count = 0U;
int j;
for (j = 0; j < 8; ++j) {
ones_count += ((i & mask) != 0U);
mask = mask << 1;
}
data->weight[i] = ones_count;
}
}
/*
* Count the number of errors in a block of received data.
*/
unsigned long error_count(void* args, unsigned char *rx_data,
int rx_data_length)
{
prbs_data* data = (prbs_data*)args;
unsigned long error_count = 0U;
unsigned long prbs_accum = 0U;
int i;
/* seed the PRBS accumulator */
for (i = 0; i < 4; ++i) {
prbs_accum = (prbs_accum << 8) ^ (rx_data[i] ^ data->polarity_mask);
}
/* check the received data */
for (i = 0; i < rx_data_length; ++i) {
unsigned char error_pattern = (unsigned char)
((prbs_accum >> 24)
^ (rx_data[i] ^ data->polarity_mask));
if (error_pattern != 0U) {
error_count += data->weight[error_pattern];
}
prbs_accum = update_prbs(data);
}
return error_count;
}
void gen_sequence(void* args, unsigned char *tx_data, int tx_data_length,
unsigned long polynomial)
{
prbs_data* data = (prbs_data*)args;
unsigned long prbs_accum = 0U;
while (prbs_accum < polynomial) {
prbs_accum <<= 1;
prbs_accum |= 1;
}
while (tx_data_length-- > 0) {
prbs_accum = update_prbs(data);
*(tx_data++) = (unsigned char)(prbs_accum & 0xff);
}
}