ggwave : add mono-tone protocols

This commit is contained in:
Georgi Gerganov
2022-05-29 21:25:17 +03:00
parent fb2dcb3a37
commit 6888ca58f2
5 changed files with 89 additions and 39 deletions

View File

@@ -52,11 +52,12 @@ void loop() {
p.sampleRate = frequency;
p.sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I16;
p.samplesPerFrame = 128;
p.payloadLength = 16;
p.payloadLength = 4;
p.operatingMode = GGWAVE_OPERATING_MODE_RX;
GGWave ggwave(p);
ggwave.setRxProtocols({
//{ GGWAVE_TX_PROTOCOL_MT_FASTEST, ggwave.getTxProtocol(GGWAVE_TX_PROTOCOL_MT_FASTEST) },
{ GGWAVE_TX_PROTOCOL_DT_FASTEST, ggwave.getTxProtocol(GGWAVE_TX_PROTOCOL_DT_FASTEST) },
});
Serial.println("Instance initialized");

View File

@@ -41,7 +41,7 @@ int main(int argc, char** argv) {
printf(" -t%d : %s\n", protocol.first, protocol.second.name);
}
if (txProtocolId < 0 || txProtocolId > (int) ggWave->getTxProtocols().size()) {
if (txProtocolId < 0) {
fprintf(stderr, "Unknown Tx protocol %d\n", txProtocolId);
return -3;
}

View File

@@ -44,6 +44,9 @@ extern "C" {
GGWAVE_TX_PROTOCOL_DT_NORMAL,
GGWAVE_TX_PROTOCOL_DT_FAST,
GGWAVE_TX_PROTOCOL_DT_FASTEST,
GGWAVE_TX_PROTOCOL_MT_NORMAL,
GGWAVE_TX_PROTOCOL_MT_FAST,
GGWAVE_TX_PROTOCOL_MT_FASTEST,
GGWAVE_TX_PROTOCOL_CUSTOM_0,
GGWAVE_TX_PROTOCOL_CUSTOM_1,
@@ -331,6 +334,7 @@ public:
int freqStart; // FFT bin index of the lowest frequency
int framesPerTx; // number of frames to transmit a single chunk of data
int bytesPerTx; // number of bytes in a chunk of data
int extra; // 2 if this is a mono-tone protocol, 1 otherwise
int nDataBitsPerTx() const { return 8*bytesPerTx; }
};
@@ -342,15 +346,18 @@ public:
static const TxProtocols & getTxProtocols() {
static const TxProtocols kTxProtocols {
{ GGWAVE_TX_PROTOCOL_AUDIBLE_NORMAL, { "Normal", 40, 9, 3, } },
{ GGWAVE_TX_PROTOCOL_AUDIBLE_FAST, { "Fast", 40, 6, 3, } },
{ GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST, { "Fastest", 40, 3, 3, } },
{ GGWAVE_TX_PROTOCOL_ULTRASOUND_NORMAL, { "[U] Normal", 320, 9, 3, } },
{ GGWAVE_TX_PROTOCOL_ULTRASOUND_FAST, { "[U] Fast", 320, 6, 3, } },
{ GGWAVE_TX_PROTOCOL_ULTRASOUND_FASTEST, { "[U] Fastest", 320, 3, 3, } },
{ GGWAVE_TX_PROTOCOL_DT_NORMAL, { "[DT] Normal", 24, 9, 1, } },
{ GGWAVE_TX_PROTOCOL_DT_FAST, { "[DT] Fast", 24, 6, 1, } },
{ GGWAVE_TX_PROTOCOL_DT_FASTEST, { "[DT] Fastest", 24, 3, 1, } },
{ GGWAVE_TX_PROTOCOL_AUDIBLE_NORMAL, { "Normal", 40, 9, 3, 1, } },
{ GGWAVE_TX_PROTOCOL_AUDIBLE_FAST, { "Fast", 40, 6, 3, 1, } },
{ GGWAVE_TX_PROTOCOL_AUDIBLE_FASTEST, { "Fastest", 40, 3, 3, 1, } },
{ GGWAVE_TX_PROTOCOL_ULTRASOUND_NORMAL, { "[U] Normal", 320, 9, 3, 1, } },
{ GGWAVE_TX_PROTOCOL_ULTRASOUND_FAST, { "[U] Fast", 320, 6, 3, 1, } },
{ GGWAVE_TX_PROTOCOL_ULTRASOUND_FASTEST, { "[U] Fastest", 320, 3, 3, 1, } },
{ GGWAVE_TX_PROTOCOL_DT_NORMAL, { "[DT] Normal", 24, 9, 1, 1, } },
{ GGWAVE_TX_PROTOCOL_DT_FAST, { "[DT] Fast", 24, 6, 1, 1, } },
{ GGWAVE_TX_PROTOCOL_DT_FASTEST, { "[DT] Fastest", 24, 3, 1, 1, } },
{ GGWAVE_TX_PROTOCOL_MT_NORMAL, { "[MT] Normal", 24, 9, 1, 2, } },
{ GGWAVE_TX_PROTOCOL_MT_FAST, { "[MT] Fast", 24, 6, 1, 2, } },
{ GGWAVE_TX_PROTOCOL_MT_FASTEST, { "[MT] Fastest", 24, 3, 1, 2, } },
};
return kTxProtocols;

View File

@@ -520,7 +520,8 @@ GGWave::GGWave(const Parameters & parameters) :
const int totalLength = m_payloadLength + getECCBytesForLength(m_payloadLength);
const int totalTxs = (totalLength + minBytesPerTx() - 1)/minBytesPerTx();
m_rx->spectrumHistoryFixed.resize(totalTxs*maxFramesPerTx());
// TODO: factor of 2 due to Mono-tone protocols
m_rx->spectrumHistoryFixed.resize(2*totalTxs*maxFramesPerTx());
m_rx->detectedBins.resize(2*totalLength);
m_rx->detectedTones.resize(2*16*maxBytesPerTx());
} else {
@@ -618,6 +619,11 @@ bool GGWave::init(int dataSize, const char * dataBuffer, const TxProtocol & txPr
return false;
}
if (txProtocol.extra == 2 && m_isFixedPayloadLength == false) {
ggprintf("Mono-tone protocols with variable length are not supported\n");
return false;
}
m_tx->txProtocol = txProtocol;
m_tx->txDataLength = dataSize;
m_tx->sendVolume = ((double)(volume))/100.0f;
@@ -685,10 +691,10 @@ uint32_t GGWave::encodeSize_samples() const {
// note : +1 extra sample in order to overestimate the buffer size
samplesPerFrameOut = m_resampler->resample(factor, m_samplesPerFrame, m_tx->outputBlock.data(), nullptr) + 1;
}
int nECCBytesPerTx = getECCBytesForLength(m_tx->txDataLength);
int sendDataLength = m_tx->txDataLength + m_encodedDataOffset;
int totalBytes = sendDataLength + nECCBytesPerTx;
int totalDataFrames = ((totalBytes + m_tx->txProtocol.bytesPerTx - 1)/m_tx->txProtocol.bytesPerTx)*m_tx->txProtocol.framesPerTx;
const int nECCBytesPerTx = getECCBytesForLength(m_tx->txDataLength);
const int sendDataLength = m_tx->txDataLength + m_encodedDataOffset;
const int totalBytes = sendDataLength + nECCBytesPerTx;
const int totalDataFrames = m_tx->txProtocol.extra*((totalBytes + m_tx->txProtocol.bytesPerTx - 1)/m_tx->txProtocol.bytesPerTx)*m_tx->txProtocol.framesPerTx;
return (
m_nMarkerFrames + totalDataFrames + m_nMarkerFrames
@@ -703,7 +709,7 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) {
const int nECCBytesPerTx = getECCBytesForLength(m_tx->txDataLength);
const int sendDataLength = m_tx->txDataLength + m_encodedDataOffset;
const int totalBytes = sendDataLength + nECCBytesPerTx;
const int totalDataFrames = ((totalBytes + m_tx->txProtocol.bytesPerTx - 1)/m_tx->txProtocol.bytesPerTx)*m_tx->txProtocol.framesPerTx;
const int totalDataFrames = m_tx->txProtocol.extra*((totalBytes + m_tx->txProtocol.bytesPerTx - 1)/m_tx->txProtocol.bytesPerTx)*m_tx->txProtocol.framesPerTx;
if (m_isFixedPayloadLength == false) {
RS::ReedSolomon rsLength(1, m_encodedDataOffset - 1, m_workRSLength.data());
@@ -741,13 +747,23 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) {
std::fill(m_tx->dataBits.begin(), m_tx->dataBits.end(), 0);
for (int j = 0; j < m_tx->txProtocol.bytesPerTx; ++j) {
{
uint8_t d = m_dataEncoded[dataOffset + j] & 15;
m_tx->dataBits[(2*j + 0)*16 + d] = 1;
}
{
uint8_t d = m_dataEncoded[dataOffset + j] & 240;
m_tx->dataBits[(2*j + 1)*16 + (d >> 4)] = 1;
if (m_tx->txProtocol.extra == 1) {
{
uint8_t d = m_dataEncoded[dataOffset + j] & 15;
m_tx->dataBits[(2*j + 0)*16 + d] = 1;
}
{
uint8_t d = m_dataEncoded[dataOffset + j] & 240;
m_tx->dataBits[(2*j + 1)*16 + (d >> 4)] = 1;
}
} else {
if (dataOffset % m_tx->txProtocol.extra == 0) {
uint8_t d = m_dataEncoded[dataOffset/m_tx->txProtocol.extra + j] & 15;
m_tx->dataBits[(2*j + 0)*16 + d] = 1;
} else {
uint8_t d = m_dataEncoded[dataOffset/m_tx->txProtocol.extra + j] & 240;
m_tx->dataBits[(2*j + 0)*16 + (d >> 4)] = 1;
}
}
}
@@ -843,13 +859,23 @@ bool GGWave::encode(const CBWaveformOut & cbWaveformOut) {
std::fill(m_tx->dataBits.begin(), m_tx->dataBits.end(), 0);
for (int j = 0; j < m_tx->txProtocol.bytesPerTx; ++j) {
{
uint8_t d = m_dataEncoded[dataOffset + j] & 15;
m_tx->dataBits[(2*j + 0)*16 + d] = 1;
}
{
uint8_t d = m_dataEncoded[dataOffset + j] & 240;
m_tx->dataBits[(2*j + 1)*16 + (d >> 4)] = 1;
if (m_tx->txProtocol.extra == 1) {
{
uint8_t d = m_dataEncoded[dataOffset + j] & 15;
m_tx->dataBits[(2*j + 0)*16 + d] = 1;
}
{
uint8_t d = m_dataEncoded[dataOffset + j] & 240;
m_tx->dataBits[(2*j + 1)*16 + (d >> 4)] = 1;
}
} else {
if (dataOffset % m_tx->txProtocol.extra == 0) {
uint8_t d = m_dataEncoded[dataOffset/m_tx->txProtocol.extra + j] & 15;
m_tx->dataBits[(2*j + 0)*16 + d] = 1;
} else {
uint8_t d = m_dataEncoded[dataOffset/m_tx->txProtocol.extra + j] & 240;
m_tx->dataBits[(2*j + 0)*16 + (d >> 4)] = 1;
}
}
}
@@ -1406,6 +1432,11 @@ void GGWave::decode_variable() {
const auto & rxProtocolId = rxProtocolPair.first;
const auto & rxProtocol = rxProtocolPair.second;
// skip Rx protocol if it is mono-tone
if (rxProtocol.extra == 2) {
continue;
}
// skip Rx protocol if start frequency is different from detected one
if (rxProtocol.freqStart != m_rx->markerFreqStart) {
continue;
@@ -1664,13 +1695,14 @@ void GGWave::decode_fixed() {
const int binStart = rxProtocol.freqStart;
const int binDelta = 16;
const int binOffset = rxProtocol.extra == 1 ? binDelta : 0;
if (binStart > m_samplesPerFrame) {
continue;
}
const int totalLength = m_payloadLength + getECCBytesForLength(m_payloadLength);
const int totalTxs = (totalLength + rxProtocol.bytesPerTx - 1)/rxProtocol.bytesPerTx;
const int totalTxs = rxProtocol.extra*((totalLength + rxProtocol.bytesPerTx - 1)/rxProtocol.bytesPerTx);
int historyStartId = m_rx->historyIdFixed - totalTxs*rxProtocol.framesPerTx;
if (historyStartId < 0) {
@@ -1685,7 +1717,9 @@ void GGWave::decode_fixed() {
bool detectedSignal = true;
for (int k = 0; k < totalTxs; ++k) {
std::fill(m_rx->detectedTones.begin(), m_rx->detectedTones.begin() + 16*nTones, 0);
if (k % rxProtocol.extra == 0) {
std::fill(m_rx->detectedTones.begin(), m_rx->detectedTones.begin() + 16*nTones, 0);
}
for (int i = 0; i < rxProtocol.framesPerTx; ++i) {
int historyId = historyStartId + k*rxProtocol.framesPerTx + i;
@@ -1711,7 +1745,7 @@ void GGWave::decode_fixed() {
}
{
const auto & v = m_rx->spectrumHistoryFixed[historyId][binStart + 2*j*binDelta + binDelta + b];
const auto & v = m_rx->spectrumHistoryFixed[historyId][binStart + 2*j*binDelta + binOffset + b];
if (f1max <= v) {
f1max = v;
@@ -1720,23 +1754,25 @@ void GGWave::decode_fixed() {
}
}
m_rx->detectedTones[(2*j + 0)*16 + f0bin]++;
m_rx->detectedTones[(2*j + 1)*16 + f1bin]++;
if ((k + 0)%rxProtocol.extra == 0) m_rx->detectedTones[(2*j + 0)*16 + f0bin]++;
if ((k + 1)%rxProtocol.extra == 0) m_rx->detectedTones[(2*j + 1)*16 + f1bin]++;
}
}
if (rxProtocol.extra > 1 && (k % rxProtocol.extra == 0)) continue;
int txNeeded = 0;
int txDetected = 0;
for (int j = 0; j < rxProtocol.bytesPerTx; ++j) {
if (k*rxProtocol.bytesPerTx + j >= totalLength) break;
if ((k/rxProtocol.extra)*rxProtocol.bytesPerTx + j >= totalLength) break;
txNeeded += 2;
for (int b = 0; b < 16; ++b) {
if (m_rx->detectedTones[(2*j + 0)*16 + b] > rxProtocol.framesPerTx/2) {
m_rx->detectedBins[2*(k*rxProtocol.bytesPerTx + j) + 0] = b;
m_rx->detectedBins[2*((k/rxProtocol.extra)*rxProtocol.bytesPerTx + j) + 0] = b;
txDetected++;
}
if (m_rx->detectedTones[(2*j + 1)*16 + b] > rxProtocol.framesPerTx/2) {
m_rx->detectedBins[2*(k*rxProtocol.bytesPerTx + j) + 1] = b;
m_rx->detectedBins[2*((k/rxProtocol.extra)*rxProtocol.bytesPerTx + j) + 1] = b;
txDetected++;
}
}
@@ -1759,6 +1795,7 @@ void GGWave::decode_fixed() {
if (rsData.Decode(m_dataEncoded.data(), m_rx->rxData.data()) == 0) {
if (m_rx->rxData[0] != 0) {
ggprintf("Decoded length = %d, protocol = '%s' (%d)\n", m_rx->rxData[0], rxProtocol.name, rxProtocolId);
ggprintf("Received sound data successfully: '%s'\n", m_rx->rxData.data());
isValid = true;

View File

@@ -279,6 +279,11 @@ int main(int argc, char ** argv) {
printf("Testing: protocol = %s, in = %d, out = %d\n", txProtocol.second.name, formatInp, formatOut);
for (int length = 1; length <= (int) payload.size(); ++length) {
// mono-tone protocols with variable length are not supported
if (txProtocol.second.extra == 2) {
break;
}
// variable payload length
{
auto parameters = GGWave::getDefaultParameters();