diff options
Diffstat (limited to 'src/fsm')
-rw-r--r-- | src/fsm/cw.c | 334 | ||||
-rw-r--r-- | src/fsm/cw.h | 20 | ||||
-rw-r--r-- | src/fsm/main.c | 26 | ||||
-rw-r--r-- | src/fsm/psk31.c | 424 | ||||
-rw-r--r-- | src/fsm/psk31.h | 48 |
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_ - |