aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@member.fsf.org>2015-12-16 00:14:05 +0100
committerMattias Andrée <maandree@member.fsf.org>2015-12-16 00:14:05 +0100
commitc89285ecb638a6efb1f0d5c42a34d6d2237eff01 (patch)
treeaea9133fb44f04b503cd36deaf4d1abcfacb6e9a
parentfirst commit (diff)
downloadfodtmf-c89285ecb638a6efb1f0d5c42a34d6d2237eff01.tar.gz
fodtmf-c89285ecb638a6efb1f0d5c42a34d6d2237eff01.tar.bz2
fodtmf-c89285ecb638a6efb1f0d5c42a34d6d2237eff01.tar.xz
draft
Signed-off-by: Mattias Andrée <maandree@member.fsf.org>
Diffstat (limited to '')
-rw-r--r--README2
-rw-r--r--src/send.c138
2 files changed, 139 insertions, 1 deletions
diff --git a/README b/README
index 51bc22b..f5138cc 100644
--- a/README
+++ b/README
@@ -1,2 +1,2 @@
-File over fual-tone multi-frequency signaling
+File over dual-tone multi-frequency signaling
diff --git a/src/send.c b/src/send.c
new file mode 100644
index 0000000..d457bbb
--- /dev/null
+++ b/src/send.c
@@ -0,0 +1,138 @@
+/**
+ * Copyright © 2015 Mattias Andrée (maandree@member.fsf.org)
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdio.h>
+#include <math.h> /* -lm */
+#include <stdint.h>
+#include <alsa/asoundlib.h> /* dep: alsa-lib (pkg-config alsa) */
+
+
+#define UTYPE uint32_t
+#define SMIN INT32_MIN
+#define SMAX INT32_MAX
+#define FORMAT SND_PCM_FORMAT_U32
+
+#define SAMPLE_RATE 52000 /* Hz */
+#define DURATION 100 /* ms */ /* 100 ms → 10 Bd → 5 B/s */
+#define LATENCY 100000 /* µs */
+
+
+#define N(buf) (sizeof(buf) / sizeof(*buf))
+
+
+static const char* argv0;
+static snd_pcm_t* sound_handle = NULL;
+
+
+void get_freq(int nibble, int* low, int* high)
+{
+ static const int LOW[] = { 697, 770, 852, 941 };
+ static const int HIGH[] = { 1209, 1336, 1477, 1663 };
+
+ *low = LOW[(nibble >> 0) & 0x03];
+ *high = HIGH[(nibble >> 2) & 0x03];
+}
+
+int send_tones(int low, int high)
+{
+#define GENERATE_TONE(tone) \
+ sin(2 * M_PI * ((double)i / (SAMPLE_RATE / tone)))
+
+ static UTYPE buffer[SAMPLE_RATE / 1000 * DURATION];
+ snd_pcm_sframes_t frames;
+ int r;
+ size_t i;
+
+ for (i = 0; i < N(buffer); i++)
+ buffer[i] = (GENERATE_TONE(low) + GENERATE_TONE(high)) * (SMAX / 2) - SMIN;
+
+ r = frames = snd_pcm_writei(sound_handle, buffer, N(buffer));
+ if (frames < 0)
+ r = frames = snd_pcm_recover(sound_handle, r, 0 /* do not print error reason? */);
+ if (r < 0)
+ {
+ fprintf(stderr, "%s: snd_pcm_writei: %s\n", argv0, snd_strerror(r));
+ return -1;
+ }
+ if ((r > 0) && ((size_t)r < N(buffer)))
+ printf("%s: short write: expected %zu, wrote %zu\n", argv0, N(buffer), (size_t)frames);
+
+ return 0;
+}
+
+int send_byte(int c)
+{
+ int low1, high1, low2, high2;
+ get_freq((c >> 0) & 0x0F, &low1, &high1);
+ get_freq((c >> 4) & 0x0F, &low2, &high2);
+ if (send_tones(low1, high1))
+ return -1;
+ if (send_tones(low2, high2))
+ return -1;
+ return 0;
+}
+
+
+int main(int argc, char* argv[])
+{
+ int r;
+ char buf[1024];
+ ssize_t n, i;
+
+ (void) argc;
+ argv0 = argv[0];
+
+ r = snd_pcm_open(&sound_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
+ if (r < 0)
+ return
+ fprintf(stderr, "%s: snd_pcm_open: %s\n", *argv, snd_strerror(r)),
+ 1;
+
+ r = snd_pcm_set_params(sound_handle,
+ FORMAT,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ 1, /* channels */
+ SAMPLE_RATE,
+ 1, /* allow resampling? */
+ LATENCY);
+ if (r < 0)
+ {
+ fprintf(stderr, "%s: snd_pcm_set_params: %s\n", *argv, snd_strerror(r));
+ goto snd_fail;
+ }
+
+ for (;;)
+ {
+ n = read(STDIN_FILENO, buf, sizeof(buf));
+ if (n < 0)
+ goto fail;
+ if (n == 0)
+ break;
+ for (i = 0; i < n; i++)
+ if (send_byte(buf[i]))
+ goto snd_fail;
+ }
+
+ snd_pcm_close(sound_handle);
+ return 0;
+ fail:
+ perror(argv0);
+ return 1;
+ snd_fail:
+ snd_pcm_close(sound_handle);
+ return 1;
+}
+