mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-03-06 14:55:52 +08:00
wip : receive all types of protocols
This commit is contained in:
@@ -47,8 +47,8 @@ if (GGWAVE_SANITIZE_THREAD)
|
||||
endif()
|
||||
|
||||
if (GGWAVE_SANITIZE_ADDRESS)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -D_GLIBCXX_DEBUG")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -D_GLIBCXX_DEBUG")
|
||||
endif()
|
||||
|
||||
if (GGWAVE_SANITIZE_UNDEFINED)
|
||||
|
||||
@@ -36,40 +36,6 @@ int main(int argc, char** argv) {
|
||||
ggWave->setTxMode(GGWave::TxMode::VariableLength);
|
||||
|
||||
printf("Selecting Tx protocol %d\n", txProtocol);
|
||||
switch (txProtocol) {
|
||||
case 0:
|
||||
{
|
||||
printf("Using 'Normal' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 40, 9, 3, 50);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
printf("Using 'Fast' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 40, 6, 3, 50);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
printf("Using 'Fastest' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 40, 3, 3, 50);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
printf("Using 'Ultrasonic' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 320, 9, 3, 50);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
printf("Using 'Fast' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 40, 6, 3, 50);
|
||||
}
|
||||
};
|
||||
printf("\n");
|
||||
|
||||
ggWave->init(0, "");
|
||||
|
||||
std::mutex mutex;
|
||||
std::thread inputThread([&]() {
|
||||
@@ -86,7 +52,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
ggWave->init(input.size(), input.data());
|
||||
ggWave->init(input.size(), input.data(), ggWave->getTxProtocols()[txProtocol]);
|
||||
}
|
||||
inputOld = input;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ GGWave *g_ggWave = nullptr;
|
||||
// JS interface
|
||||
extern "C" {
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
int setText(int textLength, const char * text) {
|
||||
g_ggWave->init(textLength, text);
|
||||
int setText(int textLength, const char * text, int protocolId) {
|
||||
g_ggWave->init(textLength, text, g_ggWave->getTxProtocols()[protocolId]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -77,29 +77,8 @@ extern "C" {
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
int setTxMode(int txMode) {
|
||||
g_ggWave->setTxMode((GGWave::TxMode)(txMode));
|
||||
g_ggWave->init(0, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void setParameters(
|
||||
int paramFreqDelta,
|
||||
int paramFreqStart,
|
||||
int paramFramesPerTx,
|
||||
int paramBytesPerTx,
|
||||
int /*paramECCBytesPerTx*/,
|
||||
int paramVolume) {
|
||||
if (g_ggWave == nullptr) return;
|
||||
|
||||
g_ggWave->setParameters(
|
||||
paramFreqDelta,
|
||||
paramFreqStart,
|
||||
paramFramesPerTx,
|
||||
paramBytesPerTx,
|
||||
paramVolume);
|
||||
|
||||
g_ggWave->init(0, "");
|
||||
}
|
||||
}
|
||||
|
||||
void GGWave_setDefaultCaptureDeviceName(std::string name) {
|
||||
|
||||
@@ -71,42 +71,6 @@ int main(int argc, char** argv) {
|
||||
|
||||
ggWave->setTxMode(GGWave::TxMode::VariableLength);
|
||||
|
||||
printf("Selecting Tx protocol %d\n", txProtocol);
|
||||
switch (txProtocol) {
|
||||
case 0:
|
||||
{
|
||||
printf("Using 'Normal' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 40, 9, 3, 50);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
printf("Using 'Fast' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 40, 6, 3, 50);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
printf("Using 'Fastest' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 40, 3, 3, 50);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
printf("Using 'Ultrasonic' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 320, 9, 3, 50);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
printf("Using 'Fast' Tx Protocol\n");
|
||||
ggWave->setParameters(1, 40, 6, 3, 50);
|
||||
}
|
||||
};
|
||||
printf("\n");
|
||||
|
||||
ggWave->init(0, "");
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) {
|
||||
fprintf(stderr, "Error: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
@@ -175,7 +139,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (inputCurrent.update) {
|
||||
ggWave->init(inputCurrent.message.data.size(), inputCurrent.message.data.data());
|
||||
ggWave->init(inputCurrent.message.data.size(), inputCurrent.message.data.data(), ggWave->getTxProtocols()[2]);
|
||||
inputCurrent.update = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <complex>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace RS {
|
||||
class ReedSolomon;
|
||||
@@ -24,11 +25,23 @@ public:
|
||||
static constexpr auto kMaxRecordedFrames = 64*10;
|
||||
static constexpr auto kDefaultFixedLength = 82;
|
||||
|
||||
struct TxProtocol {
|
||||
const char * name;
|
||||
|
||||
int paramFreqDelta;
|
||||
int paramFreqStart;
|
||||
int paramFramesPerTx;
|
||||
int paramBytesPerTx;
|
||||
int paramECCBytesPerTx;
|
||||
int paramVolume;
|
||||
};
|
||||
|
||||
using AmplitudeData = std::array<float, kMaxSamplesPerFrame>;
|
||||
using AmplitudeData16 = std::array<int16_t, kMaxRecordedFrames*kMaxSamplesPerFrame>;
|
||||
using SpectrumData = std::array<float, kMaxSamplesPerFrame>;
|
||||
using RecordedData = std::array<float, kMaxRecordedFrames*kMaxSamplesPerFrame>;
|
||||
using TxRxData = std::array<std::uint8_t, kMaxDataSize>;
|
||||
using TxProtocols = std::vector<TxProtocol>;
|
||||
|
||||
using CBQueueAudio = std::function<void(const void * data, uint32_t nBytes)>;
|
||||
using CBDequeueAudio = std::function<uint32_t(void * data, uint32_t nMaxBytes)>;
|
||||
@@ -41,17 +54,12 @@ public:
|
||||
int aSampleSizeBytesOut);
|
||||
~GGWave();
|
||||
|
||||
void setTxMode(TxMode aTxMode) { txMode = aTxMode; }
|
||||
|
||||
bool setParameters(
|
||||
int aParamFreqDelta,
|
||||
int aParamFreqStart,
|
||||
int aParamFramesPerTx,
|
||||
int aParamBytesPerTx,
|
||||
int aParamVolume);
|
||||
|
||||
bool init(int textLength, const char * stext);
|
||||
void setTxMode(TxMode aTxMode) {
|
||||
txMode = aTxMode;
|
||||
init(0, "", getDefultTxProtocol());
|
||||
}
|
||||
|
||||
bool init(int textLength, const char * stext, const TxProtocol & aProtocol);
|
||||
void send(const CBQueueAudio & cbQueueAudio);
|
||||
void receive(const CBDequeueAudio & CBDequeueAudio);
|
||||
|
||||
@@ -70,6 +78,8 @@ public:
|
||||
const float & getAverageRxTime_ms() const { return averageRxTime_ms; }
|
||||
|
||||
const TxRxData & getRxData() const { return rxData; }
|
||||
const TxProtocol & getDefultTxProtocol() const { return txProtocols[1]; }
|
||||
const TxProtocols & getTxProtocols() const { return txProtocols; }
|
||||
|
||||
int takeRxData(TxRxData & dst) {
|
||||
if (lastRxDataLength == 0) return 0;
|
||||
@@ -82,14 +92,38 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
int nIterations;
|
||||
const TxProtocols txProtocols {
|
||||
{ "Normal", 1, 40, 9, 3, 32, 50 },
|
||||
{ "Fast", 1, 40, 6, 3, 32, 50 },
|
||||
{ "Fastest", 1, 40, 3, 3, 32, 50 },
|
||||
{ "Ultrasonic", 1, 320, 9, 3, 32, 50 },
|
||||
};
|
||||
|
||||
int paramFreqDelta = 6;
|
||||
int paramFreqStart = 40;
|
||||
int paramFramesPerTx = 6;
|
||||
int paramBytesPerTx = 2;
|
||||
int paramECCBytesPerTx = 32; // used for fixed-length Tx
|
||||
int paramVolume = 10;
|
||||
int maxFramesPerTx() const {
|
||||
int res = 0;
|
||||
for (const auto & protocol : txProtocols) {
|
||||
res = std::max(res, protocol.paramFramesPerTx);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int minBytesPerTx() const {
|
||||
int res = txProtocols.front().paramFramesPerTx;
|
||||
for (const auto & protocol : txProtocols) {
|
||||
res = std::min(res, protocol.paramBytesPerTx);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int maxECCBytesPerTx() const {
|
||||
int res = 0;
|
||||
for (const auto & protocol : txProtocols) {
|
||||
res = std::max(res, protocol.paramECCBytesPerTx);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int nIterations;
|
||||
|
||||
// Rx
|
||||
bool receivingData;
|
||||
@@ -135,7 +169,6 @@ private:
|
||||
int frameId;
|
||||
int framesLeftToAnalyze;
|
||||
int framesLeftToRecord;
|
||||
int framesPerTx;
|
||||
int framesToAnalyze;
|
||||
int framesToRecord;
|
||||
int freqDelta_bin = 1;
|
||||
@@ -152,6 +185,7 @@ private:
|
||||
std::string textToSend;
|
||||
|
||||
TxMode txMode = TxMode::FixedLength;
|
||||
TxProtocol txProtocol;
|
||||
|
||||
AmplitudeData outputBlock;
|
||||
AmplitudeData16 outputBlock16;
|
||||
|
||||
271
src/ggwave.cpp
271
src/ggwave.cpp
@@ -121,7 +121,7 @@ GGWave::GGWave(
|
||||
sampleSizeBytesIn = aSampleSizeBytesIn;
|
||||
sampleSizeBytesOut = aSampleSizeBytesOut;
|
||||
|
||||
init(0, "");
|
||||
setTxMode(TxMode::VariableLength);
|
||||
}
|
||||
|
||||
GGWave::~GGWave() {
|
||||
@@ -129,41 +129,26 @@ GGWave::~GGWave() {
|
||||
if (rsLength) delete rsLength;
|
||||
}
|
||||
|
||||
bool GGWave::setParameters(
|
||||
int aParamFreqDelta,
|
||||
int aParamFreqStart,
|
||||
int aParamFramesPerTx,
|
||||
int aParamBytesPerTx,
|
||||
int aParamVolume) {
|
||||
|
||||
paramFreqDelta = aParamFreqDelta;
|
||||
paramFreqStart = aParamFreqStart;
|
||||
paramFramesPerTx = aParamFramesPerTx;
|
||||
paramBytesPerTx = aParamBytesPerTx;
|
||||
paramVolume = aParamVolume;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GGWave::init(int textLength, const char * stext) {
|
||||
bool GGWave::init(int textLength, const char * stext, const TxProtocol & aProtocol) {
|
||||
if (textLength > kMaxLength) {
|
||||
printf("Truncating data from %d to 140 bytes\n", textLength);
|
||||
textLength = kMaxLength;
|
||||
}
|
||||
|
||||
txProtocol = aProtocol;
|
||||
|
||||
const uint8_t * text = reinterpret_cast<const uint8_t *>(stext);
|
||||
frameId = 0;
|
||||
nIterations = 0;
|
||||
hasData = false;
|
||||
|
||||
isamplesPerFrame = 1.0f/samplesPerFrame;
|
||||
sendVolume = ((double)(paramVolume))/100.0f;
|
||||
sendVolume = ((double)(txProtocol.paramVolume))/100.0f;
|
||||
hzPerFrame = sampleRateIn/samplesPerFrame;
|
||||
ihzPerFrame = 1.0/hzPerFrame;
|
||||
framesPerTx = paramFramesPerTx;
|
||||
|
||||
nDataBitsPerTx = paramBytesPerTx*8;
|
||||
nECCBytesPerTx = (txMode == TxMode::FixedLength) ? paramECCBytesPerTx : getECCBytesForLength(textLength);
|
||||
nDataBitsPerTx = txProtocol.paramBytesPerTx*8;
|
||||
nECCBytesPerTx = (txMode == TxMode::FixedLength) ? txProtocol.paramECCBytesPerTx : getECCBytesForLength(textLength);
|
||||
|
||||
framesToAnalyze = 0;
|
||||
framesLeftToAnalyze = 0;
|
||||
@@ -174,10 +159,10 @@ bool GGWave::init(int textLength, const char * stext) {
|
||||
nPostMarkerFrames = 0;
|
||||
sendDataLength = (txMode == TxMode::FixedLength) ? kDefaultFixedLength : textLength + 3;
|
||||
|
||||
freqDelta_bin = paramFreqDelta/2;
|
||||
freqDelta_hz = hzPerFrame*paramFreqDelta;
|
||||
freqStart_hz = hzPerFrame*paramFreqStart;
|
||||
if (paramFreqDelta == 1) {
|
||||
freqDelta_bin = txProtocol.paramFreqDelta/2;
|
||||
freqDelta_hz = hzPerFrame*txProtocol.paramFreqDelta;
|
||||
freqStart_hz = hzPerFrame*txProtocol.paramFreqStart;
|
||||
if (txProtocol.paramFreqDelta == 1) {
|
||||
freqDelta_bin = 1;
|
||||
freqDelta_hz *= 2;
|
||||
}
|
||||
@@ -244,7 +229,6 @@ bool GGWave::init(int textLength, const char * stext) {
|
||||
analyzingData = false;
|
||||
|
||||
sampleAmplitude.fill(0);
|
||||
|
||||
sampleSpectrum.fill(0);
|
||||
for (auto & s : sampleAmplitudeHistory) {
|
||||
s.fill(0);
|
||||
@@ -311,15 +295,15 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
}
|
||||
} else if (frameId <
|
||||
(nMarkerFrames + nPostMarkerFrames) +
|
||||
((sendDataLength + nECCBytesPerTx)/nBytesPerTx + 2)*framesPerTx) {
|
||||
((sendDataLength + nECCBytesPerTx)/nBytesPerTx + 2)*txProtocol.paramFramesPerTx) {
|
||||
int dataOffset = frameId - nMarkerFrames - nPostMarkerFrames;
|
||||
int cycleModMain = dataOffset%framesPerTx;
|
||||
dataOffset /= framesPerTx;
|
||||
int cycleModMain = dataOffset%txProtocol.paramFramesPerTx;
|
||||
dataOffset /= txProtocol.paramFramesPerTx;
|
||||
dataOffset *= nBytesPerTx;
|
||||
|
||||
dataBits.fill(0);
|
||||
|
||||
if (paramFreqDelta > 1) {
|
||||
if (txProtocol.paramFreqDelta > 1) {
|
||||
for (int j = 0; j < nBytesPerTx; ++j) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
dataBits[j*8 + i] = txDataEncoded[dataOffset + j] & (1 << i);
|
||||
@@ -329,10 +313,10 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
for (int k = 0; k < nDataBitsPerTx; ++k) {
|
||||
++nFreq;
|
||||
if (dataBits[k] == false) {
|
||||
::addAmplitudeSmooth(bit0Amplitude[k], outputBlock, sendVolume, 0, samplesPerFrameOut, cycleModMain, framesPerTx);
|
||||
::addAmplitudeSmooth(bit0Amplitude[k], outputBlock, sendVolume, 0, samplesPerFrameOut, cycleModMain, txProtocol.paramFramesPerTx);
|
||||
continue;
|
||||
}
|
||||
::addAmplitudeSmooth(bit1Amplitude[k], outputBlock, sendVolume, 0, samplesPerFrameOut, cycleModMain, framesPerTx);
|
||||
::addAmplitudeSmooth(bit1Amplitude[k], outputBlock, sendVolume, 0, samplesPerFrameOut, cycleModMain, txProtocol.paramFramesPerTx);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < nBytesPerTx; ++j) {
|
||||
@@ -351,19 +335,19 @@ void GGWave::send(const CBQueueAudio & cbQueueAudio) {
|
||||
|
||||
++nFreq;
|
||||
if (k%2) {
|
||||
::addAmplitudeSmooth(bit0Amplitude[k/2], outputBlock, sendVolume, 0, samplesPerFrameOut, cycleModMain, framesPerTx);
|
||||
::addAmplitudeSmooth(bit0Amplitude[k/2], outputBlock, sendVolume, 0, samplesPerFrameOut, cycleModMain, txProtocol.paramFramesPerTx);
|
||||
} else {
|
||||
::addAmplitudeSmooth(bit1Amplitude[k/2], outputBlock, sendVolume, 0, samplesPerFrameOut, cycleModMain, framesPerTx);
|
||||
::addAmplitudeSmooth(bit1Amplitude[k/2], outputBlock, sendVolume, 0, samplesPerFrameOut, cycleModMain, txProtocol.paramFramesPerTx);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (txMode == TxMode::VariableLength && frameId <
|
||||
(nMarkerFrames + nPostMarkerFrames) +
|
||||
((sendDataLength + nECCBytesPerTx)/nBytesPerTx + 2)*framesPerTx +
|
||||
((sendDataLength + nECCBytesPerTx)/nBytesPerTx + 2)*txProtocol.paramFramesPerTx +
|
||||
(nMarkerFrames)) {
|
||||
nFreq = nBitsInMarker;
|
||||
|
||||
int fId = frameId - ((nMarkerFrames + nPostMarkerFrames) + ((sendDataLength + nECCBytesPerTx)/nBytesPerTx + 2)*framesPerTx);
|
||||
int fId = frameId - ((nMarkerFrames + nPostMarkerFrames) + ((sendDataLength + nECCBytesPerTx)/nBytesPerTx + 2)*txProtocol.paramFramesPerTx);
|
||||
for (int i = 0; i < nBitsInMarker; ++i) {
|
||||
if (i%2 == 0) {
|
||||
addAmplitudeSmooth(bit0Amplitude[i], outputBlock, sendVolume, 0, samplesPerFrameOut, fId, nMarkerFrames);
|
||||
@@ -401,6 +385,7 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) {
|
||||
// todo : support for non-float input
|
||||
auto nBytesRecorded = CBDequeueAudio(sampleAmplitude.data(), samplesPerFrame*sampleSizeBytesIn);
|
||||
|
||||
|
||||
if (nBytesRecorded != 0) {
|
||||
{
|
||||
sampleAmplitudeHistory[historyId] = sampleAmplitude;
|
||||
@@ -448,132 +433,136 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) {
|
||||
recordedAmplitude.data() + (framesToRecord - framesLeftToRecord)*samplesPerFrame);
|
||||
|
||||
if (--framesLeftToRecord <= 0) {
|
||||
std::fill(sampleSpectrum.begin(), sampleSpectrum.end(), 0.0f);
|
||||
analyzingData = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (analyzingData) {
|
||||
int nBytesPerTx = nDataBitsPerTx/8;
|
||||
int stepsPerFrame = 16;
|
||||
int step = samplesPerFrame/stepsPerFrame;
|
||||
|
||||
int offsetStart = 0;
|
||||
|
||||
framesToAnalyze = nMarkerFrames*stepsPerFrame;
|
||||
framesLeftToAnalyze = framesToAnalyze;
|
||||
const int stepsPerFrame = 16;
|
||||
const int step = samplesPerFrame/stepsPerFrame;
|
||||
|
||||
bool isValid = false;
|
||||
for (int ii = nMarkerFrames*stepsPerFrame - 1; ii >= nMarkerFrames*stepsPerFrame/2; --ii) {
|
||||
offsetStart = ii;
|
||||
bool knownLength = txMode == TxMode::FixedLength;
|
||||
int encodedOffset = (txMode == TxMode::FixedLength) ? 0 : 3;
|
||||
for (const auto & rxProtocol : txProtocols) {
|
||||
std::fill(sampleSpectrum.begin(), sampleSpectrum.end(), 0.0f);
|
||||
|
||||
for (int itx = 0; itx < 1024; ++itx) {
|
||||
int offsetTx = offsetStart + itx*framesPerTx*stepsPerFrame;
|
||||
if (offsetTx >= recvDuration_frames*stepsPerFrame) {
|
||||
break;
|
||||
}
|
||||
framesToAnalyze = nMarkerFrames*stepsPerFrame;
|
||||
framesLeftToAnalyze = framesToAnalyze;
|
||||
for (int ii = nMarkerFrames*stepsPerFrame - 1; ii >= nMarkerFrames*stepsPerFrame/2; --ii) {
|
||||
bool knownLength = txMode == TxMode::FixedLength;
|
||||
|
||||
std::copy(
|
||||
recordedAmplitude.begin() + offsetTx*step,
|
||||
recordedAmplitude.begin() + offsetTx*step + samplesPerFrame, fftIn.data());
|
||||
const int offsetStart = ii;
|
||||
const int encodedOffset = (knownLength) ? 0 : 3;
|
||||
|
||||
for (int itx = 0; itx < 1024; ++itx) {
|
||||
int offsetTx = offsetStart + itx*rxProtocol.paramFramesPerTx*stepsPerFrame;
|
||||
if (offsetTx >= recvDuration_frames*stepsPerFrame || (itx + 1)*rxProtocol.paramBytesPerTx >= (int) txDataEncoded.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::copy(
|
||||
recordedAmplitude.begin() + offsetTx*step,
|
||||
recordedAmplitude.begin() + offsetTx*step + samplesPerFrame, fftIn.data());
|
||||
|
||||
for (int k = 1; k < rxProtocol.paramFramesPerTx - 1; ++k) {
|
||||
for (int i = 0; i < samplesPerFrame; ++i) {
|
||||
fftIn[i] += recordedAmplitude[(offsetTx + k*stepsPerFrame)*step + i];
|
||||
}
|
||||
}
|
||||
|
||||
FFT(fftIn.data(), fftOut.data(), samplesPerFrame, 1.0);
|
||||
|
||||
for (int k = 1; k < framesPerTx-1; ++k) {
|
||||
for (int i = 0; i < samplesPerFrame; ++i) {
|
||||
fftIn[i] += recordedAmplitude[(offsetTx + k*stepsPerFrame)*step + i];
|
||||
sampleSpectrum[i] = (fftOut[i].real()*fftOut[i].real() + fftOut[i].imag()*fftOut[i].imag());
|
||||
}
|
||||
}
|
||||
|
||||
FFT(fftIn.data(), fftOut.data(), samplesPerFrame, 1.0);
|
||||
|
||||
for (int i = 0; i < samplesPerFrame; ++i) {
|
||||
sampleSpectrum[i] = (fftOut[i].real()*fftOut[i].real() + fftOut[i].imag()*fftOut[i].imag());
|
||||
}
|
||||
for (int i = 1; i < samplesPerFrame/2; ++i) {
|
||||
sampleSpectrum[i] += sampleSpectrum[samplesPerFrame - i];
|
||||
}
|
||||
|
||||
uint8_t curByte = 0;
|
||||
if (paramFreqDelta > 1) {
|
||||
for (int i = 0; i < nDataBitsPerTx; ++i) {
|
||||
int k = i%8;
|
||||
int bin = std::round(dataFreqs_hz[i]*ihzPerFrame);
|
||||
if (sampleSpectrum[bin] > 1*sampleSpectrum[bin + freqDelta_bin]) {
|
||||
curByte += 1 << k;
|
||||
} else if (sampleSpectrum[bin + freqDelta_bin] > 1*sampleSpectrum[bin]) {
|
||||
} else {
|
||||
}
|
||||
if (k == 7) {
|
||||
txDataEncoded[itx*nBytesPerTx + i/8] = curByte;
|
||||
curByte = 0;
|
||||
}
|
||||
for (int i = 1; i < samplesPerFrame/2; ++i) {
|
||||
sampleSpectrum[i] += sampleSpectrum[samplesPerFrame - i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 2*nBytesPerTx; ++i) {
|
||||
int bin = std::round(dataFreqs_hz[0]*ihzPerFrame) + i*16;
|
||||
|
||||
int kmax = 0;
|
||||
double amax = 0.0;
|
||||
for (int k = 0; k < 16; ++k) {
|
||||
if (sampleSpectrum[bin + k] > amax) {
|
||||
kmax = k;
|
||||
amax = sampleSpectrum[bin + k];
|
||||
uint8_t curByte = 0;
|
||||
if (rxProtocol.paramFreqDelta > 1) {
|
||||
for (int i = 0; i < nDataBitsPerTx; ++i) {
|
||||
int k = i%8;
|
||||
int bin = std::round(dataFreqs_hz[i]*ihzPerFrame);
|
||||
if (sampleSpectrum[bin] > 1*sampleSpectrum[bin + freqDelta_bin]) {
|
||||
curByte += 1 << k;
|
||||
} else if (sampleSpectrum[bin + freqDelta_bin] > 1*sampleSpectrum[bin]) {
|
||||
} else {
|
||||
}
|
||||
if (k == 7) {
|
||||
txDataEncoded[itx*rxProtocol.paramBytesPerTx + i/8] = curByte;
|
||||
curByte = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i%2) {
|
||||
curByte += (kmax << 4);
|
||||
txDataEncoded[itx*nBytesPerTx + i/2] = curByte;
|
||||
curByte = 0;
|
||||
} else {
|
||||
curByte = kmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (txMode == TxMode::VariableLength) {
|
||||
if (itx*nBytesPerTx > 3 && knownLength == false) {
|
||||
if ((rsLength->Decode(txDataEncoded.data(), rxData.data()) == 0) && (rxData[0] <= 140)) {
|
||||
knownLength = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (txMode == TxMode::VariableLength && knownLength) {
|
||||
if (rsData) delete rsData;
|
||||
rsData = new RS::ReedSolomon(rxData[0], ::getECCBytesForLength(rxData[0]));
|
||||
}
|
||||
|
||||
if (knownLength) {
|
||||
int decodedLength = rxData[0];
|
||||
if (rsData->Decode(txDataEncoded.data() + encodedOffset, rxData.data()) == 0) {
|
||||
printf("Decoded length = %d\n", decodedLength);
|
||||
if (txMode == TxMode::FixedLength && rxData[0] == 'A') {
|
||||
printf("[ANSWER] Received sound data successfully!\n");
|
||||
} else if (txMode == TxMode::FixedLength && rxData[0] == 'O') {
|
||||
printf("[OFFER] Received sound data successfully!\n");
|
||||
} else {
|
||||
std::string s((char *) rxData.data(), decodedLength);
|
||||
printf("Received sound data successfully: '%s'\n", s.c_str());
|
||||
for (int i = 0; i < 2*rxProtocol.paramBytesPerTx; ++i) {
|
||||
int bin = std::round(dataFreqs_hz[0]*ihzPerFrame) + i*16;
|
||||
|
||||
int kmax = 0;
|
||||
double amax = 0.0;
|
||||
for (int k = 0; k < 16; ++k) {
|
||||
if (sampleSpectrum[bin + k] > amax) {
|
||||
kmax = k;
|
||||
amax = sampleSpectrum[bin + k];
|
||||
}
|
||||
}
|
||||
|
||||
if (i%2) {
|
||||
curByte += (kmax << 4);
|
||||
txDataEncoded[itx*rxProtocol.paramBytesPerTx + i/2] = curByte;
|
||||
curByte = 0;
|
||||
} else {
|
||||
curByte = kmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (txMode == TxMode::VariableLength) {
|
||||
if (itx*rxProtocol.paramBytesPerTx > 3 && knownLength == false) {
|
||||
if ((rsLength->Decode(txDataEncoded.data(), rxData.data()) == 0) && (rxData[0] > 0 && rxData[0] <= 140)) {
|
||||
knownLength = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
hasNewRxData = true;
|
||||
lastRxDataLength = decodedLength;
|
||||
framesToRecord = 0;
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
if (txMode == TxMode::VariableLength && knownLength) {
|
||||
if (rsData) delete rsData;
|
||||
rsData = new RS::ReedSolomon(rxData[0], ::getECCBytesForLength(rxData[0]));
|
||||
}
|
||||
|
||||
if (knownLength) {
|
||||
int decodedLength = rxData[0];
|
||||
if (rsData->Decode(txDataEncoded.data() + encodedOffset, rxData.data()) == 0) {
|
||||
if (txMode == TxMode::FixedLength && rxData[0] == 'A') {
|
||||
printf("[ANSWER] Received sound data successfully!\n");
|
||||
} else if (txMode == TxMode::FixedLength && rxData[0] == 'O') {
|
||||
printf("[OFFER] Received sound data successfully!\n");
|
||||
} else if (rxData[0] != 0) {
|
||||
printf("Decoded length = %d\n", decodedLength);
|
||||
std::string s((char *) rxData.data(), decodedLength);
|
||||
printf("Received sound data successfully: '%s'\n", s.c_str());
|
||||
|
||||
isValid = true;
|
||||
hasNewRxData = true;
|
||||
lastRxDataLength = decodedLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
break;
|
||||
}
|
||||
--framesLeftToAnalyze;
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
break;
|
||||
}
|
||||
--framesLeftToAnalyze;
|
||||
if (isValid) break;
|
||||
}
|
||||
|
||||
framesToRecord = 0;
|
||||
|
||||
if (isValid == false) {
|
||||
printf("Failed to capture sound data. Please try again\n");
|
||||
framesToRecord = -1;
|
||||
@@ -608,9 +597,9 @@ void GGWave::receive(const CBDequeueAudio & CBDequeueAudio) {
|
||||
rxData.fill(0);
|
||||
receivingData = true;
|
||||
if (txMode == TxMode::FixedLength) {
|
||||
recvDuration_frames = nMarkerFrames + nPostMarkerFrames + framesPerTx*((kDefaultFixedLength + paramECCBytesPerTx)/paramBytesPerTx + 1);
|
||||
recvDuration_frames = nMarkerFrames + nPostMarkerFrames + maxFramesPerTx()*((kDefaultFixedLength + maxECCBytesPerTx())/minBytesPerTx() + 1);
|
||||
} else {
|
||||
recvDuration_frames = nMarkerFrames + nPostMarkerFrames + framesPerTx*((kMaxLength + ::getECCBytesForLength(kMaxLength))/paramBytesPerTx + 1);
|
||||
recvDuration_frames = nMarkerFrames + nPostMarkerFrames + maxFramesPerTx()*((kMaxLength + ::getECCBytesForLength(kMaxLength))/minBytesPerTx() + 1);
|
||||
}
|
||||
framesToRecord = recvDuration_frames;
|
||||
framesLeftToRecord = recvDuration_frames;
|
||||
|
||||
Reference in New Issue
Block a user