From 429ff0f1b11ba7e3eab42040ead7ac6bb9f79479 Mon Sep 17 00:00:00 2001 From: Georgi Gerganov Date: Fri, 4 Dec 2020 22:27:04 +0200 Subject: [PATCH] wip : receive all types of protocols --- CMakeLists.txt | 4 +- examples/ggwave-cli/main.cpp | 36 +---- examples/ggwave-common-sdl2.cpp | 25 +-- examples/ggwave-gui/main.cpp | 38 +---- include/ggwave/ggwave.h | 70 ++++++--- src/ggwave.cpp | 271 +++++++++++++++----------------- 6 files changed, 188 insertions(+), 256 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fdccbda..1473703 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/examples/ggwave-cli/main.cpp b/examples/ggwave-cli/main.cpp index 09c605a..2bd2cb9 100644 --- a/examples/ggwave-cli/main.cpp +++ b/examples/ggwave-cli/main.cpp @@ -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 lock(mutex); - ggWave->init(input.size(), input.data()); + ggWave->init(input.size(), input.data(), ggWave->getTxProtocols()[txProtocol]); } inputOld = input; } diff --git a/examples/ggwave-common-sdl2.cpp b/examples/ggwave-common-sdl2.cpp index 271015d..2cdc39a 100644 --- a/examples/ggwave-common-sdl2.cpp +++ b/examples/ggwave-common-sdl2.cpp @@ -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) { diff --git a/examples/ggwave-gui/main.cpp b/examples/ggwave-gui/main.cpp index 130087c..18cdbef 100644 --- a/examples/ggwave-gui/main.cpp +++ b/examples/ggwave-gui/main.cpp @@ -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; } diff --git a/include/ggwave/ggwave.h b/include/ggwave/ggwave.h index 4a1e27c..24eff1a 100644 --- a/include/ggwave/ggwave.h +++ b/include/ggwave/ggwave.h @@ -4,6 +4,7 @@ #include #include #include +#include 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; using AmplitudeData16 = std::array; using SpectrumData = std::array; using RecordedData = std::array; using TxRxData = std::array; + using TxProtocols = std::vector; using CBQueueAudio = std::function; using CBDequeueAudio = std::function; @@ -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; diff --git a/src/ggwave.cpp b/src/ggwave.cpp index ce0c086..b15721b 100644 --- a/src/ggwave.cpp +++ b/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(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;