package de.tu.darmstadt.seemoo.ansian.tools;
import de.tu.darmstadt.seemoo.ansian.model.SamplePacket;
/**
* <h1>AnSiAn - unsigned 8-bit IQ Converter</h1>
*
* Module: Unsigned8BitIQConverter.java Description: This class implements
* methods to convert the raw input data of IQ sources (8 bit unsigned) to
* SamplePackets. It has also methods to do converting and down-mixing at the
* same time.
*
* @author Dennis Mantz
*
* Copyright (C) 2014 Dennis Mantz License:
* http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
public class Unsigned8BitIQConverter extends IQConverter {
public Unsigned8BitIQConverter() {
super();
}
@Override
protected void generateLookupTable() {
/**
* The rtl_sdr delivers samples in the following format: The bytes are
* interleaved, 8-bit, unsigned IQ samples (in-phase component first,
* followed by the quadrature component):
*
* [--------- first sample ----------] [-------- second sample --------]
* I Q I Q ... receivedBytes[0] receivedBytes[1] receivedBytes[2] ...
*/
lookupTable = new float[256];
for (int i = 0; i < 256; i++)
lookupTable[i] = (i - 127.4f) / 128.0f;
}
@Override
protected void generateMixerLookupTable(int mixFrequency) {
// If mix frequency is too low, just add the sample rate (sampled
// spectrum is periodic):
if (mixFrequency == 0 || (sampleRate / Math.abs(mixFrequency) > MAX_COSINE_LENGTH))
mixFrequency += sampleRate;
// Only generate lookupTable if null or invalid:
if (cosineRealLookupTable == null || mixFrequency != cosineFrequency) {
cosineFrequency = mixFrequency;
int bestLength = calcOptimalCosineLength();
cosineRealLookupTable = new float[bestLength][256];
cosineImagLookupTable = new float[bestLength][256];
float cosineAtT;
float sineAtT;
for (int t = 0; t < bestLength; t++) {
cosineAtT = (float) Math.cos(2 * Math.PI * cosineFrequency * t / (float) sampleRate);
sineAtT = (float) Math.sin(2 * Math.PI * cosineFrequency * t / (float) sampleRate);
for (int i = 0; i < 256; i++) {
cosineRealLookupTable[t][i] = (i - 127.4f) / 128.0f * cosineAtT;
cosineImagLookupTable[t][i] = (i - 127.4f) / 128.0f * sineAtT;
}
}
cosineIndex = 0;
}
}
@Override
public int fillPacketIntoSamplePacket(byte[] packet, SamplePacket samplePacket) {
int capacity = samplePacket.capacity();
int count = 0;
int startIndex = samplePacket.size();
float[] re = samplePacket.getRe();
float[] im = samplePacket.getIm();
for (int i = 0; i < packet.length; i += 2) {
re[startIndex + count] = lookupTable[packet[i] & 0xff];
im[startIndex + count] = lookupTable[packet[i + 1] & 0xff];
count++;
if (startIndex + count >= capacity)
break;
}
samplePacket.setSize(samplePacket.size() + count); // update the size of
// the sample packet
samplePacket.setSampleRate(sampleRate); // update the sample rate
samplePacket.setFrequency(frequency); // update the frequency
return count;
}
@Override
public int mixPacketIntoSamplePacket(byte[] packet, SamplePacket samplePacket, long channelFrequency) {
int mixFrequency = (int) (frequency - channelFrequency);
generateMixerLookupTable(mixFrequency); // will only generate table if
// really necessary
// Mix the samples from packet and store the results in the samplePacket
int capacity = samplePacket.capacity();
int count = 0;
int startIndex = samplePacket.size();
float[] re = samplePacket.getRe();
float[] im = samplePacket.getIm();
for (int i = 0; i < packet.length; i += 2) {
re[startIndex + count] = cosineRealLookupTable[cosineIndex][packet[i] & 0xff]
- cosineImagLookupTable[cosineIndex][packet[i + 1] & 0xff];
im[startIndex + count] = cosineRealLookupTable[cosineIndex][packet[i + 1] & 0xff]
+ cosineImagLookupTable[cosineIndex][packet[i] & 0xff];
cosineIndex = (cosineIndex + 1) % cosineRealLookupTable.length;
count++;
if (startIndex + count >= capacity)
break;
}
samplePacket.setSize(samplePacket.size() + count); // update the size of
// the sample packet
samplePacket.setSampleRate(sampleRate); // update the sample rate
samplePacket.setFrequency(channelFrequency); // update the frequency
return count;
}
}