r2t2 - Transmit data through the PC speaker (#32)

* inital implementation

* remove file

* ggwave-cli : txProtocol -> txProtocolId

* ggwave : add custom protocol enum values

* r2t2 : use cutom protocols

* r2t2 : build only on Unix systems

* r2t2 : remove thread

* r2t2-rx : wip

* r2t2 : wasm build ready + various fixes

* r2t2 : error message

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* r2t2 : length 16

* r2t2 : use slow protocol by default

* r2t2 : add timestamp

* r2t2 : update html

* r2t2 : update github link

* r2t2 : more robust tx

* r2t2 : add option to use beep command

* emscripten : cannot use requestAnimationFrame when capturing audio

This causes the queued audio buffer to grow indefinitely when the page
is not focused, causing the process to run out of memory.

* r2t2 : disable beep option

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* r2t2 : add example to README
This commit is contained in:
Georgi Gerganov
2021-04-18 13:20:45 +03:00
committed by GitHub
parent 464aa2283b
commit 00b23ff54f
28 changed files with 4153 additions and 29 deletions

136
examples/r2t2/main.cpp Normal file
View File

@@ -0,0 +1,136 @@
#include "ggwave/ggwave.h"
#include "ggwave-common.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/kd.h>
#define CONSOLE "/dev/tty0"
#include <cmath>
#include <cstdio>
#include <string>
#include <iostream>
void processTone(int fd, double freq_hz, long duration_ms, bool useBeep, bool printTones) {
if (printTones) {
printf("TONE %8.2f Hz %5ld ms\n", freq_hz, duration_ms);
return;
}
if (useBeep) {
static char cmd[128];
snprintf(cmd, 128, "beep -f %g -l %ld", freq_hz, duration_ms);
system(cmd);
return;
}
long pitch = std::round(1193180.0/freq_hz);
long ms = std::round(duration_ms);
ioctl(fd, KDMKTONE, (ms<<16)|pitch);
usleep(ms*1000);
}
int main(int argc, char** argv) {
printf("Usage: %s [-tN] [-lN]\n", argv[0]);
printf(" -p - print tones, no playback\n");
//printf(" -b - use 'beep' command\n");
printf(" -tN - transmission protocol\n");
printf(" -lN - fixed payload length of size N, N in [1, %d]\n", GGWave::kMaxLengthFixed);
printf("\n");
const GGWave::TxProtocols protocols = {
{ GGWAVE_TX_PROTOCOL_CUSTOM_0, { "[R2T2] Normal", 64, 9, 1, } },
{ GGWAVE_TX_PROTOCOL_CUSTOM_1, { "[R2T2] Fast", 64, 6, 1, } },
{ GGWAVE_TX_PROTOCOL_CUSTOM_2, { "[R2T2] Fastest", 64, 3, 1, } },
};
auto argm = parseCmdArguments(argc, argv);
bool printTones = argm.find("p") != argm.end();
bool useBeep = false; //argm.find("b") != argm.end();
int txProtocolId = argm["t"].empty() ? GGWAVE_TX_PROTOCOL_CUSTOM_0 : std::stoi(argm["t"]);
int payloadLength = argm["l"].empty() ? 16 : std::stoi(argm["l"]);
GGWave ggWave({
payloadLength,
GGWave::kBaseSampleRate,
GGWave::kBaseSampleRate,
GGWave::kDefaultSamplesPerFrame,
GGWave::kDefaultSoundMarkerThreshold,
GGWAVE_SAMPLE_FORMAT_F32,
GGWAVE_SAMPLE_FORMAT_F32});
printf("Available Tx protocols:\n");
for (const auto & protocol : protocols) {
printf(" -t%d : %s\n", protocol.first, protocol.second.name);
}
if (protocols.find(GGWave::TxProtocolId(txProtocolId)) == protocols.end()) {
fprintf(stderr, "Unknown Tx protocol %d\n", txProtocolId);
return -3;
}
printf("Selecting Tx protocol %d\n", txProtocolId);
int fd = 1;
if (useBeep == false && printTones == false) {
if (ioctl(fd, KDMKTONE, 0)) {
fd = open(CONSOLE, O_RDONLY);
}
if (fd < 0) {
perror(CONSOLE);
fprintf(stderr, "This program must be run as root\n");
return 1;
}
}
fprintf(stderr, "Enter a text message:\n");
std::string message;
std::getline(std::cin, message);
printf("\n");
if (message.size() == 0) {
fprintf(stderr, "Invalid message: size = 0\n");
return -2;
}
if ((int) message.size() > payloadLength) {
fprintf(stderr, "Invalid message: size > %d\n", payloadLength);
return -3;
}
ggWave.init(message.size(), message.data(), protocols.at(GGWave::TxProtocolId(txProtocolId)), 10);
GGWave::CBWaveformOut tmp = [](const void * , uint32_t ){};
ggWave.encode(tmp);
int nFrames = 0;
double lastF = -1.0f;
auto tones = ggWave.getWaveformTones();
for (auto & tonesCur : tones) {
if (tonesCur.size() == 0) continue;
const auto & tone = tonesCur.front();
if (tone.freq_hz != lastF) {
if (nFrames > 0) {
processTone(fd, lastF, nFrames*tone.duration_ms, useBeep, printTones);
}
nFrames = 0;
lastF = tone.freq_hz;
}
++nFrames;
}
if (nFrames > 0) {
const auto & tone = tones.front().front();
processTone(fd, lastF, nFrames*tone.duration_ms, useBeep, printTones);
}
return 0;
}