TinyModem
Header-only software audio modem library
Loading...
Searching...
No Matches
FSKEncoder.h
Go to the documentation of this file.
1#pragma once
2
3#include <math.h>
4
5#include "AudioTools.h"
6#include "DataCodecs.h"
7#include "ModemBase.h"
8#include "ModemConfig.h"
9
10namespace tinymodem {
11
31class FSKEncoder : public ModemEncoder {
32 public:
33 FSKEncoder() = default;
34 FSKEncoder(Print& out) { setOutput(out); }
35 FSKEncoder(audio_tools::SoundGenerator<int16_t>& generator) {
36 setGenerator(generator);
37 }
38 FSKEncoder(Print& out, audio_tools::SoundGenerator<int16_t>& generator) {
39 setOutput(out);
40 setGenerator(generator);
41 }
42
45 ModemConfig result;
46 result.setMode("1200");
47 return result;
48 }
49
51 void setAudioInfo(audio_tools::AudioInfo info) override {
52 cfg.sample_rate = info.sample_rate;
53 cfg.channels = info.channels;
54 cfg.bits_per_sample = info.bits_per_sample;
55 if (is_active) begin();
56 }
57
58 audio_tools::AudioInfo audioInfo() override { return cfg; }
59
60 using audio_tools::AudioEncoder::begin;
61
64 cfg = config;
65 return begin();
66 }
67
68 bool begin() override {
69 is_active = false;
71 if (!active_cfg.resolve()) {
72 LOGE("FSKEncoder: invalid configuration (max 64 bits per frame)");
73 return false;
74 }
75 if (!active_cfg.isTxSupported()) {
76 LOGE("FSKEncoder: transmit is not supported for this mode");
77 return false;
78 }
79 if (active_cfg.bits_per_sample != 16) {
80 LOGE("FSKEncoder: bits_per_sample must be 16, not %d",
81 (int)active_cfg.bits_per_sample);
82 return false;
83 }
84 if (active_cfg.channels < 1) {
85 LOGE("FSKEncoder: invalid number of channels: %d",
86 (int)active_cfg.channels);
87 return false;
88 }
89
90 if (active_cfg.format == DataFormat::BAUDOT) {
91 baudot.setUSOS(active_cfg.baudot_usos);
92 p_codec = &baudot;
93 } else {
94 p_codec = &ascii;
95 }
96
97 bit_nsamples = active_cfg.sample_rate / active_cfg.baud_rate + 0.5f;
98 if (!tones.begin(active_cfg, active_cfg.volume)) return false;
99 transmitting = 0;
100 is_active = true;
101 return true;
102 }
103
104 void end() override {
106 is_active = false;
107 }
108
110 size_t write(const uint8_t* data, size_t len) override {
111 if (!is_active) return 0;
112 for (size_t j = 0; j < len; j++) writeChar(data[j]);
113 return len;
114 }
115
118 bool endTransmission(size_t silence_samples = 0) override {
119 if (!is_active || transmitting == 0) return false;
120 for (int j = 0; j < active_cfg.trailer_bits; j++)
121 tone(active_cfg.mark_freq, bit_nsamples);
122 if (silence_samples) tone(0, silence_samples);
123 transmitting = 0;
124 return true;
125 }
126
128 bool writeIdle(size_t nsamples) override {
129 if (!is_active) return false;
131 tone(idleFreq(), nsamples);
132 return true;
133 }
134
136 bool isTransmitting() override { return transmitting != 0; }
137
139 float symbolRate() override { return active_cfg.baud_rate; }
140
142 size_t bitSamples() { return bit_nsamples; }
143
146 ModemConfig& config() { return cfg; }
147
149 const ModemConfig& activeConfig() const { return active_cfg; }
150
151 operator bool() override { return is_active; }
152
153 protected:
159 size_t bit_nsamples = 0;
160 // 0: idle, 1: leader sent, 2: sync preamble sent
162 bool is_active = false;
163
164 float idleFreq() {
165 return active_cfg.invert_start_stop ? active_cfg.space_freq
166 : active_cfg.mark_freq;
167 }
168
170 transmitting = 1;
171 // the receiver resets its Baudot shift state with each new carrier, so
172 // we start each transmission with a LTRS or FIGS code
173 baudot.resetShift();
174 }
175
176 void writeChar(uint8_t ch) {
177 if (transmitting == 0) {
179 // emit leader tone (mark)
180 for (int j = 0; j < active_cfg.leader_bits; j++)
182 }
183 uint32_t words[2];
184 int nwords = p_codec->encode(words, ch);
185
186 if (transmitting < 2) {
187 transmitting = 2;
188 // emit "preamble" of sync bytes
189 for (int j = 0; j < active_cfg.tx_sync_bytes; j++)
190 transmitFrame(active_cfg.sync_byte, false);
191 }
192 // emit data bits
193 for (int j = 0; j < nwords; j++)
194 transmitFrame(words[j], active_cfg.msb_first);
195 }
196
197 void transmitFrame(uint64_t bits, bool msb_first) {
199 float mark = c.mark_freq;
200 float space = c.space_freq;
201 if (c.start_bits > 0)
202 tone(c.invert_start_stop ? mark : space, bit_nsamples * c.start_bits);
203 for (int i = 0; i < c.data_bits; i++) {
204 unsigned bit = msb_first ? (bits >> (c.data_bits - i - 1)) & 1
205 : (bits >> i) & 1;
206 tone(bit == 1 ? mark : space, bit_nsamples);
207 }
208 if (c.stop_bits > 0)
209 tone(c.invert_start_stop ? space : mark,
210 (size_t)(bit_nsamples * c.stop_bits));
211 }
212
213 void tone(float freq, size_t nsamples) { tones.tone(freq, nsamples); }
214};
215
216} // namespace tinymodem
ASCII 8-bit data (passthrough).
Definition DataCodecs.h:47
Baudot (ITA2) 5-bit data.
Definition DataCodecs.h:65
Converts between characters and the data bits of a frame.
Definition DataCodecs.h:32
ModemConfig & config()
Definition FSKEncoder.h:146
audio_tools::AudioInfo audioInfo() override
Definition FSKEncoder.h:58
bool isTransmitting() override
true between the first character and endTransmission()
Definition FSKEncoder.h:136
void tone(float freq, size_t nsamples)
Definition FSKEncoder.h:213
FSKEncoder(Print &out)
Definition FSKEncoder.h:34
ModemConfig active_cfg
Definition FSKEncoder.h:155
void writeChar(uint8_t ch)
Definition FSKEncoder.h:176
bool endTransmission(size_t silence_samples=0) override
Definition FSKEncoder.h:118
size_t bitSamples()
Number of samples of one bit.
Definition FSKEncoder.h:142
size_t bit_nsamples
Definition FSKEncoder.h:159
float symbolRate() override
Bits per second.
Definition FSKEncoder.h:139
void startTransmission()
Definition FSKEncoder.h:169
FSKEncoder(audio_tools::SoundGenerator< int16_t > &generator)
Definition FSKEncoder.h:35
bool begin() override
Definition FSKEncoder.h:68
bool begin(ModemConfig config)
Starts the processing with the indicated modem configuration.
Definition FSKEncoder.h:63
size_t write(const uint8_t *data, size_t len) override
Modulates the characters.
Definition FSKEncoder.h:110
AsciiCodec ascii
Definition FSKEncoder.h:156
int transmitting
Definition FSKEncoder.h:161
const ModemConfig & activeConfig() const
The active configuration with all derived values (e.g. frequencies).
Definition FSKEncoder.h:149
void setAudioInfo(audio_tools::AudioInfo info) override
Defines the sample rate and number of channels of the generated audio.
Definition FSKEncoder.h:51
bool writeIdle(size_t nsamples) override
Sends the idle (mark) tone for the indicated number of samples.
Definition FSKEncoder.h:128
float idleFreq()
Definition FSKEncoder.h:164
FSKEncoder(Print &out, audio_tools::SoundGenerator< int16_t > &generator)
Definition FSKEncoder.h:38
void transmitFrame(uint64_t bits, bool msb_first)
Definition FSKEncoder.h:197
ModemConfig defaultConfig()
Provides a default configuration for a 1200 baud Bell 202 modem.
Definition FSKEncoder.h:44
DataCodec * p_codec
Definition FSKEncoder.h:158
ModemConfig cfg
Definition FSKEncoder.h:154
BaudotCodec baudot
Definition FSKEncoder.h:157
void end() override
Definition FSKEncoder.h:104
bool is_active
Definition FSKEncoder.h:162
Common API of the modulators (FSKEncoder, MFSKEncoder): the written data is converted to 16 bit PCM a...
Definition ModemBase.h:286
void setOutput(Print &out) override
Definition ModemBase.h:288
void setGenerator(audio_tools::SoundGenerator< int16_t > &generator)
Definition ModemBase.h:293
ToneOutput tones
Definition ModemBase.h:334
TinyModem: software audio modems and packets with error correction.
Definition AX25.h:11
@ BAUDOT
Baudot 5 bit (RTTY, TDD).
Definition ModemConfig.h:15
Configuration of the FSK modem. The fields correspond to the command line options of minimodem....
Definition ModemConfig.h:32
int start_bits
number of start bits (-1 = auto)
Definition ModemConfig.h:50
float stop_bits
number of stop bits (-1 = auto)
Definition ModemConfig.h:52
bool setMode(const char *mode, bool keep_options=false)
Definition ModemConfig.h:109
float space_freq
space frequency in Hz (0 = auto)
Definition ModemConfig.h:44
bool invert_start_stop
invert the start and stop bits
Definition ModemConfig.h:54
int data_bits
number of data bits per frame (0 = auto)
Definition ModemConfig.h:48
float mark_freq
mark frequency in Hz (0 = auto)
Definition ModemConfig.h:42