aboutsummaryrefslogtreecommitdiffstats
path: root/src/fsm
diff options
context:
space:
mode:
Diffstat (limited to 'src/fsm')
-rw-r--r--src/fsm/cw.c334
-rw-r--r--src/fsm/cw.h20
-rw-r--r--src/fsm/main.c26
-rw-r--r--src/fsm/psk31.c424
-rw-r--r--src/fsm/psk31.h48
5 files changed, 302 insertions, 550 deletions
diff --git a/src/fsm/cw.c b/src/fsm/cw.c
index 654df22..f3d4335 100644
--- a/src/fsm/cw.c
+++ b/src/fsm/cw.c
@@ -22,15 +22,16 @@
* SOFTWARE.
*/
-/* CW generator
+/* CW and PSK31 generator
*
* Concept:
*
- * +-------------------+ +-----------+
- * | cw_push_message() | -> cw_msg_queue -> | cw_task() | -> cw_audio_queue
- * +-------------------+ +-----------+
+ * +-------------------+ +----------------+
+ * | cw_push_message() | -> cw_msg_queue -> | cw_psk31task() | -> cw_audio_queue
+ * +-------------------+ +----------------+
*
- * The cw_fill_buffer() function can be called to fetch audio from the audio_queue
+ * The cw_psk31_fill_buffer() function can be called to fetch audio from the
+ * audio_queue
*/
#include "cw.h"
@@ -111,12 +112,150 @@ const uint8_t cw_mapping[60] = { // {{{
0b1010111, // SK , ASCII '\'
}; //}}}
+/*
+ * PSK31 Varicode
+ * http://aintel.bi.ehu.es/psk31.html
+ */
+const char *psk31_varicode[] = { // {{{
+ "1010101011",
+ "1011011011",
+ "1011101101",
+ "1101110111",
+ "1011101011",
+ "1101011111",
+ "1011101111",
+ "1011111101",
+ "1011111111",
+ "11101111",
+ "11101",
+ "1101101111",
+ "1011011101",
+ "11111",
+ "1101110101",
+ "1110101011",
+ "1011110111",
+ "1011110101",
+ "1110101101",
+ "1110101111",
+ "1101011011",
+ "1101101011",
+ "1101101101",
+ "1101010111",
+ "1101111011",
+ "1101111101",
+ "1110110111",
+ "1101010101",
+ "1101011101",
+ "1110111011",
+ "1011111011",
+ "1101111111",
+ "1",
+ "111111111",
+ "101011111",
+ "111110101",
+ "111011011",
+ "1011010101",
+ "1010111011",
+ "101111111",
+ "11111011",
+ "11110111",
+ "101101111",
+ "111011111",
+ "1110101",
+ "110101",
+ "1010111",
+ "110101111",
+ "10110111",
+ "10111101",
+ "11101101",
+ "11111111",
+ "101110111",
+ "101011011",
+ "101101011",
+ "110101101",
+ "110101011",
+ "110110111",
+ "11110101",
+ "110111101",
+ "111101101",
+ "1010101",
+ "111010111",
+ "1010101111",
+ "1010111101",
+ "1111101",
+ "11101011",
+ "10101101",
+ "10110101",
+ "1110111",
+ "11011011",
+ "11111101",
+ "101010101",
+ "1111111",
+ "111111101",
+ "101111101",
+ "11010111",
+ "10111011",
+ "11011101",
+ "10101011",
+ "11010101",
+ "111011101",
+ "10101111",
+ "1101111",
+ "1101101",
+ "101010111",
+ "110110101",
+ "101011101",
+ "101110101",
+ "101111011",
+ "1010101101",
+ "111110111",
+ "111101111",
+ "111111011",
+ "1010111111",
+ "101101101",
+ "1011011111",
+ "1011",
+ "1011111",
+ "101111",
+ "101101",
+ "11",
+ "111101",
+ "1011011",
+ "101011",
+ "1101",
+ "111101011",
+ "10111111",
+ "11011",
+ "111011",
+ "1111",
+ "111",
+ "111111",
+ "110111111",
+ "10101",
+ "10111",
+ "101",
+ "110111",
+ "1111011",
+ "1101011",
+ "11011111",
+ "1011101",
+ "111010101",
+ "1010110111",
+ "110111011",
+ "1010110101",
+ "1011010111",
+ "1110110101",
+}; //}}}
+
+
struct cw_message_s {
- char message[MAX_MESSAGE_LEN];
- size_t message_len;
+ char message[MAX_MESSAGE_LEN];
+ size_t message_len;
+
+ int freq;
- int freq;
- int dit_duration;
+ // If dit_duration is 0, the message is sent in PSK31
+ int dit_duration;
};
// The queue contains above structs
@@ -124,15 +263,15 @@ QueueHandle_t cw_msg_queue;
// Queue that contains audio data
QueueHandle_t cw_audio_queue;
-static int cw_samplerate;
+static int cw_psk31_samplerate;
static int cw_transmit_ongoing;
-static void cw_task(void *pvParameters);
+static void cw_psk31_task(void *pvParameters);
-void cw_init(unsigned int samplerate)
+void cw_psk31_init(unsigned int samplerate)
{
- cw_samplerate = samplerate;
+ cw_psk31_samplerate = samplerate;
cw_transmit_ongoing = 0;
cw_msg_queue = xQueueCreate(15, sizeof(struct cw_message_s));
@@ -146,8 +285,8 @@ void cw_init(unsigned int samplerate)
}
xTaskCreate(
- cw_task,
- "TaskCW",
+ cw_psk31_task,
+ "CWPSKTask",
8*configMINIMAL_STACK_SIZE,
(void*) NULL,
tskIDLE_PRIORITY + 2UL,
@@ -199,13 +338,19 @@ size_t cw_symbol(uint8_t sym, uint8_t *on_buffer, size_t on_buffer_size)
return pos;
}
-// Transmit a string in morse code. Supported range:
+// Transmit a string in morse code or PSK31.
+// Supported range for CW:
// All ASCII between '+' and '\', which includes
// numerals and capital letters.
-void cw_push_message(const char* text, int dit_duration, int frequency)
+// Distinction between CW and PSK31 is done on dit_duration==0
+int cw_psk31_push_message(const char* text, int dit_duration, int frequency)
{
const int text_len = strlen(text);
+ if (strlen(text) > MAX_MESSAGE_LEN) {
+ return 0;
+ }
+
struct cw_message_s msg;
for (int i = 0; i < MAX_MESSAGE_LEN; i++) {
if (i < text_len) {
@@ -220,12 +365,14 @@ void cw_push_message(const char* text, int dit_duration, int frequency)
msg.dit_duration = dit_duration;
xQueueSendToBack(cw_msg_queue, &msg, portMAX_DELAY); /* Send Message */
+
+ return 1;
}
/* Parse the message and fill the on_buffer with CW on/CW off information.
* Returns the number of on/off bits written.
*/
-size_t cw_text_to_on_buffer(const char *msg, uint8_t *on_buffer, size_t on_buffer_size)
+static size_t cw_text_to_on_buffer(const char *msg, uint8_t *on_buffer, size_t on_buffer_size)
{
size_t pos = 0;
const char* sym = msg;
@@ -246,7 +393,44 @@ size_t cw_text_to_on_buffer(const char *msg, uint8_t *on_buffer, size_t on_buffe
return pos;
}
-size_t cw_fill_buffer(int16_t *buf, size_t bufsize)
+/*
+ * Turn a null terminated ASCII string into a uint8_t buffer
+ * of 0 and 1 representing the PSK31 varicode for the input.
+ *
+ * outstr must be at least size 20 + strlen(instr)*12 + 20 to accomodate
+ * the header and tail.
+ *
+ * Returns number of bytes written.
+ */
+static size_t psk31_text_to_phase_buffer(const char* instr, uint8_t* outbits)
+{
+ int i=0, j, k;
+
+ /* Header of 0s */
+ for (j=0; j < 20; j++) {
+ outbits[i++] = '0';
+ }
+
+ /* Encode the message, with 00 between letters */
+ for (j=0; j < strlen(instr); j++) {
+ const char* varicode_bits = psk31_varicode[(int)instr[j]];
+ for(k=0; k < strlen(varicode_bits); k++) {
+ outbits[i++] = (varicode_bits[k] == '1') ? 1 : 0;
+ }
+ outbits[i++] = 0;
+ outbits[i++] = 0;
+ }
+
+ /* Tail of 0s */
+ for (j=0; j < 20; j++) {
+ outbits[i++] = 0;
+ }
+
+ return i;
+}
+
+
+size_t cw_psk31_fill_buffer(int16_t *buf, size_t bufsize)
{
if (xQueueReceiveFromISR(cw_audio_queue, buf, NULL)) {
return bufsize;
@@ -257,52 +441,102 @@ size_t cw_fill_buffer(int16_t *buf, size_t bufsize)
}
static int16_t cw_audio_buf[AUDIO_BUF_LEN];
-static uint8_t cw_on_buffer[MAX_ON_BUFFER_LEN];
+static uint8_t cw_psk31_buffer[MAX_ON_BUFFER_LEN];
static struct cw_message_s cw_fill_msg_current;
-static void cw_task(void *pvParameters)
+
+// Routine to generate CW audio
+static float cw_generate_audio_ampl = 0.0f;
+static float cw_generate_audio_nco = 0.0f;
+static int16_t cw_generate_audio(float omega, int i, int t)
{
- float nco_phase = 0.0f;
- float ampl = 0.0f;
+ int16_t s = 0;
+ // Remove clicks from CW
+ if (cw_psk31_buffer[i]) {
+ const float remaining = 32768.0f - cw_generate_audio_ampl;
+ cw_generate_audio_ampl += remaining / 64.0f;
+ }
+ else {
+ cw_generate_audio_ampl -= cw_generate_audio_ampl / 64.0f;
+ }
+
+ cw_generate_audio_nco += omega;
+ if (cw_generate_audio_nco > FLOAT_PI) {
+ cw_generate_audio_nco -= 2.0f * FLOAT_PI;
+ }
+
+ s = cw_generate_audio_ampl * arm_sin_f32(cw_generate_audio_nco);
+ return s;
+}
+
+static float psk31_generate_audio_nco = 0.0f;
+static int psk31_current_psk_phase = 1;
+static int16_t psk31_generate_audio(float omega, int i, int t, int samples_per_symbol)
+{
+ int16_t s = 0;
+ const float base_ampl = 20000.0f;
+ float psk31_generate_audio_ampl = 0.0f;
+
+ if (cw_psk31_buffer[i] == 1) {
+ psk31_generate_audio_ampl = base_ampl;
+ }
+ else {
+ psk31_generate_audio_ampl = base_ampl * arm_cos_f32(
+ FLOAT_PI*(float)t/(float)samples_per_symbol);
+ }
+
+ psk31_generate_audio_nco += omega;
+ if (psk31_generate_audio_nco > FLOAT_PI) {
+ psk31_generate_audio_nco -= 2.0f * FLOAT_PI;
+ }
+ s = psk31_generate_audio_ampl *
+ arm_sin_f32(psk31_generate_audio_nco +
+ (psk31_current_psk_phase == 1 ? 0.0f : FLOAT_PI));
+
+ return s;
+}
+
+static void cw_psk31_task(void *pvParameters)
+{
int buf_pos = 0;
while (1) {
int status = xQueueReceive(cw_msg_queue, &cw_fill_msg_current, portMAX_DELAY);
if (status == pdTRUE) {
- size_t on_buffer_len = cw_text_to_on_buffer(
- cw_fill_msg_current.message,
- cw_on_buffer,
- MAX_ON_BUFFER_LEN);
+ size_t cw_psk31_buffer_len = 0;
cw_transmit_ongoing = 1;
- const int samples_per_dit =
- (cw_samplerate * cw_fill_msg_current.dit_duration) / 1000;
+ if (cw_fill_msg_current.dit_duration) {
+ cw_psk31_buffer_len = cw_text_to_on_buffer(
+ cw_fill_msg_current.message,
+ cw_psk31_buffer,
+ MAX_ON_BUFFER_LEN);
+
+ }
+ else {
+ cw_psk31_buffer_len = psk31_text_to_phase_buffer(
+ cw_fill_msg_current.message,
+ cw_psk31_buffer);
+ }
// Angular frequency of NCO
const float omega = 2.0f * FLOAT_PI * cw_fill_msg_current.freq /
- (float)cw_samplerate;
+ (float)cw_psk31_samplerate;
- for (int i = 0; i < on_buffer_len; i++) {
- for (int t = 0; t < samples_per_dit; t++) {
- int16_t s = 0;
+ const int samples_per_symbol = (cw_fill_msg_current.dit_duration != 0) ?
+ (cw_psk31_samplerate * cw_fill_msg_current.dit_duration) / 1000 :
+ /* BPSK31 is at 31.25 symbols per second. */
+ cw_psk31_samplerate * 100 / 3125;
- // Remove clicks from CW
- if (cw_on_buffer[i]) {
- const float remaining = 32768.0f - ampl;
- ampl += remaining / 64.0f;
- }
- else {
- ampl -= ampl / 64.0f;
- }
-
- nco_phase += omega;
- if (nco_phase > FLOAT_PI) {
- nco_phase -= 2.0f * FLOAT_PI;
- }
+ psk31_current_psk_phase = 1;
- s = ampl * arm_sin_f32(nco_phase);
+ for (int i = 0; i < cw_psk31_buffer_len; i++) {
+ for (int t = 0; t < samples_per_symbol; t++) {
+ int16_t s = (cw_fill_msg_current.dit_duration != 0) ?
+ cw_generate_audio(omega, i, t) :
+ psk31_generate_audio(omega, i, t, samples_per_symbol);
if (buf_pos == AUDIO_BUF_LEN) {
xQueueSendToBack(cw_audio_queue, &cw_audio_buf, portMAX_DELAY);
@@ -317,6 +551,10 @@ static void cw_task(void *pvParameters)
}
cw_audio_buf[buf_pos++] = s;
}
+
+ if (cw_psk31_buffer[i] == 0) {
+ psk31_current_psk_phase *= -1;
+ }
}
// We have completed this message
@@ -326,7 +564,7 @@ static void cw_task(void *pvParameters)
}
}
-int cw_busy(void)
+int cw_psk31_busy(void)
{
return cw_transmit_ongoing;
}
diff --git a/src/fsm/cw.h b/src/fsm/cw.h
index 0cbb29c..384918d 100644
--- a/src/fsm/cw.h
+++ b/src/fsm/cw.h
@@ -30,18 +30,20 @@
// Setup the CW generator to create audio samples at the given
// samplerate.
-void cw_init(unsigned int samplerate);
+void cw_psk31_init(unsigned int samplerate);
-// Append new CW text to transmit
-// dit_duration in ms
-// frequency in Hz
-void cw_push_message(const char* text, int dit_duration, int frequency);
+// Append new CW or PSK31 text to transmit
+// CW/PSK31 audio centre frequency in Hz
+// if dit_duration == 0, message is sent in PSK31
+// otherwise it is sent in CW, with dit_duration in ms
+// returns 0 on failure, 1 on success
+int cw_psk31_push_message(const char* text, int frequency, int dit_duration);
-// Write the waveform into the buffer (stereo)
-size_t cw_fill_buffer(int16_t *buf, size_t bufsize);
+// Write the waveform into the buffer (stereo), both for cw and psk31
+size_t cw_psk31_fill_buffer(int16_t *buf, size_t bufsize);
-// Return 1 if the CW generator is running
-int cw_busy(void);
+// Return 1 if the CW or PSK31 generator is running
+int cw_psk31_busy(void);
#endif // __CW_H_
diff --git a/src/fsm/main.c b/src/fsm/main.c
index 0bd00ef..e901c5d 100644
--- a/src/fsm/main.c
+++ b/src/fsm/main.c
@@ -35,7 +35,6 @@
#include "timers.h"
#include "semphr.h"
#include "cw.h"
-#include "psk31.h"
#include "pio.h"
#include "i2c.h"
#include "gps.h"
@@ -101,8 +100,7 @@ int main(void) {
// already running when calling the init functions.
static void launcher_task(void *pvParameters)
{
- cw_init(16000);
- psk31_init(16000);
+ cw_psk31_init(16000);
pio_init();
i2c_init();
common_init();
@@ -204,11 +202,7 @@ static void audio_callback(void* context, int select_buffer)
select_buffer = 0;
}
- size_t samples_len = psk31_fill_buffer(samples, AUDIO_BUF_LEN);
-
- if (samples_len == 0) {
- samples_len = cw_fill_buffer(samples, AUDIO_BUF_LEN);
- }
+ size_t samples_len = cw_psk31_fill_buffer(samples, AUDIO_BUF_LEN);
if (samples_len == 0) {
for (int i = 0; i < AUDIO_BUF_LEN; i++) {
@@ -265,7 +259,7 @@ static void exercise_fsm(void *pvParameters)
fsm_input.sq = fsm_input.carrier; // TODO clarify
- fsm_input.cw_done = !cw_busy();
+ fsm_input.cw_done = !cw_psk31_busy();
if (fsm_input.cw_done) {
GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_ORANGE);
@@ -274,16 +268,6 @@ static void exercise_fsm(void *pvParameters)
GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_ORANGE);
}
- fsm_input.psk_done = !psk31_busy();
-
- if (fsm_input.psk_done) {
- GPIO_SetBits(GPIOD, GPIOD_BOARD_LED_GREEN);
- }
- else {
- GPIO_ResetBits(GPIOD, GPIOD_BOARD_LED_GREEN);
- }
-
-
fsm_update_inputs(&fsm_input);
fsm_update();
@@ -296,13 +280,13 @@ static void exercise_fsm(void *pvParameters)
// Add message to CW generator only on rising edge of trigger
if (fsm_out.cw_trigger && !cw_last_trigger) {
- cw_push_message(fsm_out.msg, fsm_out.cw_dit_duration, fsm_out.msg_frequency);
+ cw_psk31_push_message(fsm_out.msg, fsm_out.cw_dit_duration, fsm_out.msg_frequency);
}
cw_last_trigger = fsm_out.cw_trigger;
// Same for PSK31
if (fsm_out.psk_trigger && !psk31_last_trigger) {
- psk31_push_message(fsm_out.msg, fsm_out.msg_frequency);
+ cw_psk31_push_message(fsm_out.msg, 0, fsm_out.msg_frequency);
}
psk31_last_trigger = fsm_out.psk_trigger;
}
diff --git a/src/fsm/psk31.c b/src/fsm/psk31.c
deleted file mode 100644
index a4e770a..0000000
--- a/src/fsm/psk31.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Matthias P. Braendli
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
-*/
-
-#include "psk31.h"
-#include "common.h"
-#include "audio.h"
-#include <string.h>
-#include "arm_math.h"
-
-/* Kernel includes. */
-#include "FreeRTOS.h"
-#include "task.h"
-#include "queue.h"
-#include "semphr.h"
-
-/* PSK31 generator
- *
- * Concept:
- *
- * +----------------------+ +--------------+
- * | psk31_push_message() | -> psk31_msg_queue -> | psk31_task() |
- * +----------------------+ +--------------+
- * |
- * _________________________________________________/
- * /
- * |
- * \|/
- * V
- *
- * psk31_audio_queue
- *
- * The psk31_fill_buffer() function can be called to fetch audio from the audio_queue
- */
-
-/*
- * PSK31 Varicode
- * http://aintel.bi.ehu.es/psk31.html
- */
-const char *psk31_varicode[] = { // {{{
- "1010101011",
- "1011011011",
- "1011101101",
- "1101110111",
- "1011101011",
- "1101011111",
- "1011101111",
- "1011111101",
- "1011111111",
- "11101111",
- "11101",
- "1101101111",
- "1011011101",
- "11111",
- "1101110101",
- "1110101011",
- "1011110111",
- "1011110101",
- "1110101101",
- "1110101111",
- "1101011011",
- "1101101011",
- "1101101101",
- "1101010111",
- "1101111011",
- "1101111101",
- "1110110111",
- "1101010101",
- "1101011101",
- "1110111011",
- "1011111011",
- "1101111111",
- "1",
- "111111111",
- "101011111",
- "111110101",
- "111011011",
- "1011010101",
- "1010111011",
- "101111111",
- "11111011",
- "11110111",
- "101101111",
- "111011111",
- "1110101",
- "110101",
- "1010111",
- "110101111",
- "10110111",
- "10111101",
- "11101101",
- "11111111",
- "101110111",
- "101011011",
- "101101011",
- "110101101",
- "110101011",
- "110110111",
- "11110101",
- "110111101",
- "111101101",
- "1010101",
- "111010111",
- "1010101111",
- "1010111101",
- "1111101",
- "11101011",
- "10101101",
- "10110101",
- "1110111",
- "11011011",
- "11111101",
- "101010101",
- "1111111",
- "111111101",
- "101111101",
- "11010111",
- "10111011",
- "11011101",
- "10101011",
- "11010101",
- "111011101",
- "10101111",
- "1101111",
- "1101101",
- "101010111",
- "110110101",
- "101011101",
- "101110101",
- "101111011",
- "1010101101",
- "111110111",
- "111101111",
- "111111011",
- "1010111111",
- "101101101",
- "1011011111",
- "1011",
- "1011111",
- "101111",
- "101101",
- "11",
- "111101",
- "1011011",
- "101011",
- "1101",
- "111101011",
- "10111111",
- "11011",
- "111011",
- "1111",
- "111",
- "111111",
- "110111111",
- "10101",
- "10111",
- "101",
- "110111",
- "1111011",
- "1101011",
- "11011111",
- "1011101",
- "111010101",
- "1010110111",
- "110111011",
- "1010110101",
- "1011010111",
- "1110110101",
-}; //}}}
-
-
-#define PSK31_MAX_MESSAGE_LEN 4096
-#define PHASE_BUFFER_SIZE (20 + PSK31_MAX_MESSAGE_LEN + 20)
-
-struct psk31_out_message_s {
- // Contains a string sequence of '0' and '1' corresponding to
- // the BPSK31 phase. Is terminated with '\0'
- char phase_buffer[PHASE_BUFFER_SIZE];
- size_t phase_buffer_end;
-
- int freq; // Audio frequency for signal center
-};
-
-// The queue contains above structs
-QueueHandle_t psk31_msg_queue;
-
-// Queue that contains audio data
-QueueHandle_t psk31_audio_queue;
-static int psk31_samplerate;
-
-static int psk31_transmit_ongoing;
-
-static void psk31_task(void *pvParameters);
-static int psk31_str_to_bits(const char* instr, char* outbits);
-
-
-void psk31_init(unsigned int samplerate)
-{
- psk31_samplerate = samplerate;
- psk31_transmit_ongoing = 0;
-
- psk31_msg_queue = xQueueCreate(1, sizeof(struct psk31_out_message_s));
- if (psk31_msg_queue == 0) {
- while(1); /* fatal error */
- }
-
- psk31_audio_queue = xQueueCreate(1, AUDIO_BUF_LEN * sizeof(int16_t));
- if (psk31_audio_queue == 0) {
- while(1); /* fatal error */
- }
-
- xTaskCreate(
- psk31_task,
- "TaskPSK",
- 5*configMINIMAL_STACK_SIZE,
- (void*) NULL,
- tskIDLE_PRIORITY + 2UL,
- NULL);
-}
-
-int psk31_push_message(const char* text, int frequency)
-{
- if (strlen(text) > PSK31_MAX_MESSAGE_LEN) {
- return 0;
- }
-
- struct psk31_out_message_s msg;
- msg.phase_buffer_end = 0;
- msg.freq = frequency;
-
- msg.phase_buffer_end = psk31_str_to_bits(text, msg.phase_buffer);
-
- xQueueSendToBack(psk31_msg_queue, &msg, portMAX_DELAY);
-
- return 1;
-}
-
-// Write the waveform into the buffer (stereo)
-size_t psk31_fill_buffer(int16_t *buf, size_t bufsize)
-{
- if (xQueueReceiveFromISR(psk31_audio_queue, buf, NULL)) {
- return bufsize;
- }
- else {
- return 0;
- }
-}
-
-int psk31_busy(void)
-{
- return psk31_transmit_ongoing;
-}
-
-static int16_t psk31_audio_buf[AUDIO_BUF_LEN];
-static struct psk31_out_message_s psk31_fill_msg_current;
-static void psk31_task(void *pvParameters)
-{
- float nco_phase = 0.0f;
- float ampl = 0.0f;
-
- int buf_pos = 0;
-
- while (1) {
- int status = xQueueReceive(psk31_msg_queue, &psk31_fill_msg_current, portMAX_DELAY);
- if (status == pdTRUE) {
-
- psk31_transmit_ongoing = 1;
-
- const float base_ampl = 20000.0f;
-
- /* BPSK31 is at 31.25 symbols per second. */
- const int samples_per_symbol = psk31_samplerate * 100 / 3125;
-
- // Angular frequency of NCO
- const float omega = 2.0f * FLOAT_PI * psk31_fill_msg_current.freq /
- (float)psk31_samplerate;
-
- int current_psk_phase = 1;
-
- for (int i = 0; i < psk31_fill_msg_current.phase_buffer_end; i++) {
- for (int t = 0; t < samples_per_symbol; t++) {
- int16_t s = 0;
-
- if (psk31_fill_msg_current.phase_buffer[i] == '1') {
- ampl = base_ampl;
- }
- else {
- ampl = base_ampl * arm_cos_f32(
- FLOAT_PI*(float)t/(float)samples_per_symbol);
- }
-
- nco_phase += omega;
- if (nco_phase > FLOAT_PI) {
- nco_phase -= 2.0f * FLOAT_PI;
- }
-
- s = ampl * arm_sin_f32(nco_phase +
- (current_psk_phase == 1 ? 0.0f : FLOAT_PI));
-
- if (buf_pos == AUDIO_BUF_LEN) {
- xQueueSendToBack(psk31_audio_queue, &psk31_audio_buf, portMAX_DELAY);
- buf_pos = 0;
- }
- psk31_audio_buf[buf_pos++] = s;
-
- // Stereo
- if (buf_pos == AUDIO_BUF_LEN) {
- xQueueSendToBack(psk31_audio_queue, &psk31_audio_buf, portMAX_DELAY);
- buf_pos = 0;
- }
- psk31_audio_buf[buf_pos++] = s;
- }
-
-
- if (psk31_fill_msg_current.phase_buffer[i] == '0') {
- current_psk_phase *= -1;
- }
- }
-
- // We have completed this message
-
- psk31_transmit_ongoing = 0;
- }
- }
-}
-
-/*
- * Turn a null terminated ASCII string into a null terminated
- * string of '0's and '1's representing the PSK31 varicode for the input.
- *
- * outstr must be at least size 20 + strlen(instr)*12 + 20 to accomodate
- * the header and tail
- */
-static int psk31_str_to_bits(const char* instr, char* outbits)
-{
- int i=0, j, k;
-
- /* Header of 0s */
- for (j=0; j < 20; j++) {
- outbits[i++] = '0';
- }
-
- /* Encode the message, with 00 between letters */
- for (j=0; j < strlen(instr); j++) {
- const char* varicode_bits = psk31_varicode[(int)instr[j]];
- for(k=0; k < strlen(varicode_bits); k++) {
- outbits[i++] = varicode_bits[k];
- }
- outbits[i++] = '0';
- outbits[i++] = '0';
- }
-
- /* Tail of 0s */
- for (j=0; j < 20; j++) {
- outbits[i++] = '0';
- }
-
- /* NULL terminate */
- outbits[i] = 0;
- return i;
-}
-
-#if 0
-/*
- * Turn a null terminated string `bits` containing '0's and '1's
- * into `outlen` IQ samples for BPSK, `outbuf`.
- * Note that `outlen` is set to the number of IQ samples, i.e. half the
- * number of bytes in `outbuf`.
- * Allocates memory (possibly lots of memory) for the IQ samples, which
- * should be freed elsewhere.
- * Modulation:
- * '0': swap phase, smoothed by a cosine
- * '1': maintain phase
- * Output: I carries data, Q constantly 0
- */
-void bits_to_iq(char* bits, uint8_t** outbuf, int* outlen)
-{
- *outlen = strlen(bits) * 256000 * 2;
- *outbuf = malloc(*outlen);
- int8_t *buf = (int8_t*)(*outbuf);
- if(*outbuf == NULL) {
- fprintf(stderr, "Could not allocate memory for IQ buffer\n");
- exit(EXIT_FAILURE);
- }
-
- int i, j, phase = 1;
- for(i=0; i<strlen(bits); i++) {
- if(bits[i] == '1') {
- for(j=0; j<256000; j++) {
- buf[i*256000*2 + 2*j] = phase*50;
- buf[i*256000*2 + 2*j + 1] = 0;
- }
- } else {
- for(j=0; j<256000; j++) {
- buf[i*256000*2 + 2*j] = phase *
- (int8_t)(50.0f * cosf(M_PI*(float)j/256000.0f));
- buf[i*256000*2 + 2*j + 1] = 0;
- }
- phase *= -1;
- }
- }
-}
-#endif
-
diff --git a/src/fsm/psk31.h b/src/fsm/psk31.h
deleted file mode 100644
index 3f08ecf..0000000
--- a/src/fsm/psk31.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Matthias P. Braendli
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
-*/
-
-/* An implementation of a BPSK31 generator.
- */
-
-#ifndef __PSK_31_H_
-#define __PSK_31_H_
-#include <stdint.h>
-#include <stddef.h>
-
-void psk31_init(unsigned int samplerate);
-
-// Append new psk31 text to transmit
-// PSK31 audio centre frequency in Hz
-// returns 0 on failure, 1 on success
-int psk31_push_message(const char* text, int frequency);
-
-
-// Write the waveform into the buffer (stereo)
-size_t psk31_fill_buffer(int16_t *buf, size_t bufsize);
-
-// Return 1 if the psk31 generator has completed transmission
-int psk31_busy(void);
-
-#endif // __PSK_31_H_
-