http://rowetel.com/codec2.html
Also included is a FDMDV modem (README_fdmdv.txt), and an API for
-embeddeding FreeDV in other programs (see example below). For more
+embedding FreeDV in other programs (see example below). For more
information on building Codec 2 see READE.cmake
Quickstart
----------
+NOTE: Use the "codec2" or "codec2-dev" depending on which repository
+ you are working with
+
1/ Listen to Codec 2:
$ cd codec2
$ mkdir build_linux
See freedv_api.h and freedv_api.c, and the demo programs freedv_tx &
freedv_rx. Quickstart:
- $ ./freedv_tx ../../raw/hts1.raw - | ./freedv_rx - - | play -t raw -r 8000 -s -2 -
+ $ ./freedv_tx ../../raw/hts1.raw - | ./freedv_rx - - | play -t raw -r 8000 -s -2 -q -
Or with a simulated 2 dB SNR channel:
- $ ./freedv_tx ../../raw/hts1.raw - | ./fdmdv_channel - - 2 | ./freedv_rx - - | play -t raw -r 8000 -s -2
+ $ ./freedv_tx ../../raw/hts1.raw - | ./fdmdv_channel - - 2 | ./freedv_rx - - | play -t raw -r 8000 -s -2 -q -
+
+To log the demod state information and received text msg characters to a text file:
+
+ $ ./freedv_tx ../../raw/hts1.raw - | ./fdmdv_channel - - 2 | ./freedv_rx - - log.txt | play -t raw -r 8000 -s -2 -q -
+ $ cat log.txt
Programs
--------
Debugging
---------
-1/ For dump file support:
+1/ To compile with debug symbols for using gdb:
- $ cd codec2
- $ CFLAGS=-DDUMP ./configure
- $ make clean && make
+ $ cd ~/codec2
+ $ rm -Rf build_linux && mkdir build_linux
+ $ cd build_linux
+ $ CFLAGS=-g cmake ..
+ $ make
-2/ To use gdb:
+2/ For dump file support:
- $ libtool --mode=execute gdb c2sim
+ $ cd ~/codec2
+ $ rm -Rf build_linux && mkdir build_linux
+ $ CFLAGS=-DDUMP cmake ..
+ $ cd build_linux
+ $ make
Directories
-----------
- octave - Octave scripts used for visualising internal signals
- during development
- script - shell scripts for playing and converting raw files
- src - C source code
- raw - speech files in raw format (16 bits signed linear 8 kHz)
- unittest - unit test source code
- wav - speech files in wave file format
- stm32 - Support for the STM32F4 microcntroller
+ asterisk & - unmaintained Asterisk support
+ asterisk-11
+ cmake - cmake support files
+ octave - Octave scripts used for visualising internal signals
+ during development
+ script - shell scripts for playing and converting raw files
+ src - C source code for Codec 2, FDMDV modem, FreeDV API
+ raw - speech files in raw format (16 bits signed linear 8 kHz)
+ stm32 - Support for the STM32F4 microcontroller and SM1000 FreeDV speaker-mic
+ unittest - unit test source code
+ wav - speech files in wave file format
TODO:
[X] speex tx/rx works
- [ ] txt messages
+ [X] txt messages
[ ] optional test tx framemode
\*---------------------------------------------------------------------------*/
f->freedv_put_next_rx_char = NULL;
golay23_init();
+ f->total_bit_errors = 0;
return f;
}
// bit/frame to send txt messages
data_flag_index = codec2_get_spare_bit_index(f->codec2);
- assert(data_flag_index != -1); // not supported for all rates
if (f->nvaricode_bits) {
f->codec_bits[data_flag_index] = f->tx_varicode_bits[f->varicode_bit_index++];
COMP rx_fdm[FDMDV_MAX_SAMPLES_PER_FRAME];
int bits_per_codec_frame, bytes_per_codec_frame, bits_per_fdmdv_frame;
int reliable_sync_bit, i, j, bit, byte, nin_prev, nout;
- int recd_codeword, codeword1, data_flag_index, n_ascii, valid;
- struct FDMDV_STATS fdmdv_stats;
+ int recd_codeword, codeword1, data_flag_index, n_ascii;
short abit[1];
char ascii_out;
nin_prev = f->nin;
fdmdv_demod(f->fdmdv, f->fdmdv_bits, &reliable_sync_bit, rx_fdm, &f->nin);
- fdmdv_get_demod_stats(f->fdmdv, &fdmdv_stats);
+ fdmdv_get_demod_stats(f->fdmdv, &f->fdmdv_stats);
- if (fdmdv_stats.sync) {
+ if (f->fdmdv_stats.sync) {
if (reliable_sync_bit == 0) {
memcpy(f->rx_bits, f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int));
nout = 0;
recd_codeword |= f->rx_bits[i];
}
codeword1 = golay23_decode(recd_codeword);
+ f->total_bit_errors += golay23_count_errors(recd_codeword, codeword1);
+
//codeword1 = recd_codeword;
//fprintf(stderr, "received codeword1: 0x%x decoded codeword1: 0x%x\n", recd_codeword, codeword1);
// extract txt msg data bit ------------------------------------------------------------
data_flag_index = codec2_get_spare_bit_index(f->codec2);
- assert(data_flag_index != -1); // not supported for all rates
-
abit[0] = f->codec_bits[data_flag_index];
n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, abit, 1, 1);
- assert((n_ascii == 0) || (n_asacii == 1));
if (n_ascii && (f->freedv_put_next_rx_char != NULL)) {
(*f->freedv_put_next_rx_char)(f->callback_state, ascii_out);
}
// reconstruct missing bit we steal for data bit and decode speech
- valid = codec2_rebuild_spare_bit(f->codec2, f->codec_bits);
- assert(valid != -1);
+ codec2_rebuild_spare_bit(f->codec2, f->codec_bits);
// pack bits, MSB received first
/* squelch if beneath SNR threshold */
- if (fdmdv_stats.snr_est < f->snr_thresh) {
+ if (f->fdmdv_stats.snr_est < f->snr_thresh) {
for(i=0; i<FREEDV_NSAMPLES; i++)
speech_out[i] = 0;
}
#ifndef __FREEDV__
-
-#define FREEDV_MODE_1600 0
-#define FREEDV_NSAMPLES 320
+#define FREEDV_MODE_1600 0
+#define FREEDV_NSAMPLES 320
#include "varicode.h"
+#include "codec2_fdmdv.h"
struct freedv {
int mode;
+
void *codec2;
struct FDMDV *fdmdv;
+ struct FDMDV_STATS fdmdv_stats;
+
unsigned char *packed_codec_bits;
int *codec_bits;
int *tx_bits;
int *fdmdv_bits;
int *rx_bits;
int tx_sync_bit;
+ int total_bit_errors;
+
float snr_thresh;
int nin;
+
struct VARICODE_DEC varicode_dec_states;
short tx_varicode_bits[VARICODE_MAX_BITS];
int nvaricode_bits;
#include "freedv_api.h"
+struct my_callback_state {
+ FILE *ftxt;
+};
+
void my_put_next_rx_char(void *callback_state, char c) {
- fprintf(stderr, "%c", c);
+ struct my_callback_state* pstate = (struct my_callback_state*)callback_state;
+ if (pstate->ftxt != NULL) {
+ fprintf(pstate->ftxt, "text char received callback: %c\n", c);
+ }
}
int main(int argc, char *argv[]) {
- FILE *fin, *fout;
- short speech_out[FREEDV_NSAMPLES];
- short demod_in[FREEDV_NSAMPLES];
- struct freedv *freedv;
- int nin, nout;
+ FILE *fin, *fout, *ftxt;
+ short speech_out[FREEDV_NSAMPLES];
+ short demod_in[FREEDV_NSAMPLES];
+ struct freedv *freedv;
+ int nin, nout, frame;
+ struct my_callback_state my_cb_state;
if (argc < 3) {
- printf("usage: %s InputModemSpeechFile OutputSpeechawFile\n", argv[0]);
- printf("e.g %s hts1a_fdmdv.raw hts1a_out.raw\n", argv[0]);
+ printf("usage: %s InputModemSpeechFile OutputSpeechawFile txtLogFile\n", argv[0]);
+ printf("e.g %s hts1a_fdmdv.raw hts1a_out.raw txtLogFile\n", argv[0]);
exit(1);
}
exit(1);
}
+ ftxt = NULL;
+ if ( (argc > 3) && (strcmp(argv[3],"|") != 0) ) {
+ if ((ftxt = fopen(argv[3],"wt")) == NULL ) {
+ fprintf(stderr, "Error opening txt Log File: %s: %s.\n",
+ argv[3], strerror(errno));
+ exit(1);
+ }
+ }
+
freedv = freedv_open(FREEDV_MODE_1600);
assert(freedv != NULL);
+ my_cb_state.ftxt = ftxt;
+ freedv->callback_state = (void*)&my_cb_state;
freedv->freedv_put_next_rx_char = &my_put_next_rx_char;
/* Note we need to work out how many samples demod needs on each
fwrite(speech_out, sizeof(short), nout, fout);
nin = freedv_nin(freedv);
+ /* log some side info to the txt file */
+
+ frame++;
+ if (ftxt != NULL) {
+ fprintf(ftxt, "frame: %d demod sync: %d demod snr: %3.2f dB bit errors: %d\n", frame,
+ freedv->fdmdv_stats.sync, freedv->fdmdv_stats.snr_est, freedv->total_bit_errors);
+ }
+
/* if this is in a pipeline, we probably don't want the usual
buffering to occur */
$(CODEC2_SRC)/codebookjvm.c \
$(CODEC2_SRC)/codebookge.c \
$(CODEC2_SRC)/dump.c \
-$(CODEC2_SRC)/fdmdv.c
+$(CODEC2_SRC)/fdmdv.c \
+$(CODEC2_SRC)/freedv_api.c \
+$(CODEC2_SRC)/varicode.c \
+$(CODEC2_SRC)/golay23.c
-CFLAGS += -D__EMBEDDED__ -DTIMER
+CFLAGS += -D__EMBEDDED__
#enable this for dump files to help verify optimisation
#CFLAGS += -DDUMP
###################################################
-all: libstm32f4.a codec2_profile.elf fft_test.elf dac_ut.elf dac_play.elf adc_rec.elf pwm_ut.elf power_ut.elf fdmdv_profile.elf
+all: libstm32f4.a codec2_profile.elf fft_test.elf dac_ut.elf dac_play.elf adc_rec.elf pwm_ut.elf power_ut.elf fdmdv_profile.elf sm1000_leds_switches_ut.elf sm1000.elf
dl/$(PERIPHLIBZIP):
mkdir -p dl
CODEC2_PROFILE_SRCS += $(CODEC2_SRCS)
codec2_profile.elf: $(CODEC2_PROFILE_SRCS)
- $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS)
+ $(CC) $(CFLAGS) -DTIMER $^ -o $@ $(LIBPATHS) $(LIBS)
fft_test.elf: $(FFT_TEST_SRCS)
$(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS)
FDMDV_PROFILE_SRCS += $(CODEC2_SRCS)
fdmdv_profile.elf: $(FDMDV_PROFILE_SRCS)
+ $(CC) $(CFLAGS) -DTIMER $^ -o $@ $(LIBPATHS) $(LIBS)
+
+SM1000_LEDS_SWITCHES_UT_SRCS=\
+src/sm1000_leds_switches_ut.c \
+src/sm1000_leds_switches.c \
+src/system_stm32f4xx.c \
+src/startup_stm32f4xx.s \
+src/init.c
+
+sm1000_leds_switches_ut.elf: $(SM1000_LEDS_SWITCHES_UT_SRCS)
+ $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS)
+
+SM1000_SRCS=\
+src/sm1000_main.c \
+src/sm1000_leds_switches.c \
+../src/fifo.c \
+src/stm32f4_adc.c \
+src/stm32f4_dac.c \
+src/system_stm32f4xx.c \
+src/startup_stm32f4xx.s \
+src/init.c
+
+SM1000_SRCS += $(CODEC2_SRCS)
+
+sm1000.elf: $(SM1000_SRCS)
$(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS)
clean:
+++ /dev/null
-/*---------------------------------------------------------------------------*\
-
- FILE........: leds_switches.h
- AUTHOR......: David Rowe
- DATE CREATED: 18 July 2014
-
- Functions for controlling LEDs and reading switches on SM1000.
-
-\*---------------------------------------------------------------------------*/
-
-/*
- Copyright (C) 2014 David Rowe
-
- All rights reserved.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License version 2.1, as
- published by the Free Software Foundation. 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 Lesser General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __LEDS_SWITCHES__
-#define __LEDS_SWITCHES__
-
-void leds_switches_init(void);
-void led_pwr(int state);
-void led_ptt(int state);
-void led_rt(int state);
-void led_err(int state);
-
-#endif
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: sm1000_leds_switches.h
+ AUTHOR......: David Rowe
+ DATE CREATED: 18 July 2014
+
+ Functions for controlling LEDs and reading switches on SM1000.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. 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 Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LEDS_SWITCHES__
+#define __LEDS_SWITCHES__
+
+void sm1000_leds_switches_init(void);
+
+void led_pwr(int state);
+void led_ptt(int state);
+void led_rt(int state);
+void led_err(int state);
+
+int switch_ptt(void);
+int switch_select(void);
+int switch_back(void);
+
+#endif
+++ /dev/null
-/*---------------------------------------------------------------------------*\
-
- FILE........: leds_switches.c
- AUTHOR......: David Rowe
- DATE CREATED: 18 July 2014
-
- Functions for controlling LEDs and reading switches on SM1000.
-
-\*---------------------------------------------------------------------------*/
-
-/*
- Copyright (C) 2014 David Rowe
-
- All rights reserved.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License version 2.1, as
- published by the Free Software Foundation. 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 Lesser General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#define LED_PWR 12
-#define LED_PTT 13
-#define LED_RT 14
-#define LED_ERR 15
-
-#include "stm32f4xx_conf.h"
-#include "stm32f4xx.h"
-#include "leds_switches.h"
-
-void leds_switches_init(void) {
- RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // enable the clock to GPIOD
-
- // Set pins as general purpose IOs
-
- GPIOD->MODER = (2 << LED_PWR) | (2 << LED_PTT) | (2 << LED_RT) | (2 << LED_ERR);
-}
-
-void led_pwr(int state) {
- if (state)
- GPIOD->ODR = (1 << LED_PWR);
- else
- GPIOD->ODR &= ~(1 << LED_PWR);
-}
-
-void led_ptt(int state) {
- if (state)
- GPIOD->ODR = (1 << LED_PTT);
- else
- GPIOD->ODR &= ~(1 << LED_PTT);
-}
-
-void led_rt(int state) {
- if (state)
- GPIOD->ODR = (1 << LED_RT);
- else
- GPIOD->ODR &= ~(1 << LED_RT);
-}
-
-void led_err(int state) {
- if (state)
- GPIOD->ODR = (1 << LED_ERR);
- else
- GPIOD->ODR &= ~(1 << LED_ERR);
-}
-
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: sm1000_leds_switches.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 18 July 2014
+
+ Functions for controlling LEDs and reading switches on the SM1000.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. 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 Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define LED_PWR 12
+#define LED_PTT 13
+#define LED_RT 14
+#define LED_ERR 15
+#define SWITCH_PTT 7
+#define SWITCH_SELECT 0
+#define SWITCH_BACK 1
+
+#include <stm32f4xx.h>
+#include <stm32f4xx_gpio.h>
+#include "sm1000_leds_switches.h"
+
+void sm1000_leds_switches_init(void) {
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
+
+ /* output pins */
+
+ GPIO_InitStruct.GPIO_Pin = LED_PWR | LED_PTT | LED_RT | LED_ERR;
+ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(GPIOD, &GPIO_InitStruct);
+
+ /* input pins */
+
+ GPIO_InitStruct.GPIO_Pin = SWITCH_PTT | SWITCH_SELECT | SWITCH_BACK;
+ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
+ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; /* we have our own external pull ups */
+ GPIO_Init(GPIOD, &GPIO_InitStruct);
+ }
+
+void led_pwr(int state) {
+ if (state)
+ GPIOD->ODR = (1 << LED_PWR);
+ else
+ GPIOD->ODR &= ~(1 << LED_PWR);
+}
+
+void led_ptt(int state) {
+ if (state)
+ GPIOD->ODR = (1 << LED_PTT);
+ else
+ GPIOD->ODR &= ~(1 << LED_PTT);
+}
+
+void led_rt(int state) {
+ if (state)
+ GPIOD->ODR = (1 << LED_RT);
+ else
+ GPIOD->ODR &= ~(1 << LED_RT);
+}
+
+void led_err(int state) {
+ if (state)
+ GPIOD->ODR = (1 << LED_ERR);
+ else
+ GPIOD->ODR &= ~(1 << LED_ERR);
+}
+
+int switch_ptt(void) {
+ return GPIOA->IDR & SWITCH_PTT;
+}
+
+int switch_select(void) {
+ return GPIOA->IDR & SWITCH_SELECT;
+}
+
+int switch_back(void) {
+ return GPIOA->IDR & SWITCH_BACK;
+}
--- /dev/null
+/*---------------------------------------------------------------------------*\\r
+\r
+ FILE........: sm1000_leds_switches_ut.c\r
+ AUTHOR......: David Rowe\r
+ DATE CREATED: August 5 2014\r
+\r
+ Unit Test program for the SM1000 switches and LEDs driver.\r
+\r
+\*---------------------------------------------------------------------------*/\r
+\r
+/*\r
+ Copyright (C) 2014 David Rowe\r
+\r
+ All rights reserved.\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU Lesser General Public License version 2.1, as\r
+ published by the Free Software Foundation. This program is\r
+ distributed in the hope that it will be useful, but WITHOUT ANY\r
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
+ License for more details.\r
+\r
+ You should have received a copy of the GNU Lesser General Public License\r
+ along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include <assert.h>\r
+#include "sm1000_leds_switches.h"\r
+\r
+int main(void) {\r
+ sm1000_leds_switches_init();\r
+ while(1) {\r
+ led_pwr(switch_select());\r
+ led_ptt(switch_ptt());\r
+ led_rt(switch_back());\r
+ led_err(!switch_back());\r
+ }\r
+}\r
+\r
--- /dev/null
+/*---------------------------------------------------------------------------*\\r
+\r
+ FILE........: sm1000_main.c\r
+ AUTHOR......: David Rowe\r
+ DATE CREATED: August 5 2014\r
+\r
+ Main program for SM1000.\r
+\r
+\*---------------------------------------------------------------------------*/\r
+\r
+/*\r
+ Copyright (C) 2014 David Rowe\r
+\r
+ All rights reserved.\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU Lesser General Public License version 2.1, as\r
+ published by the Free Software Foundation. This program is\r
+ distributed in the hope that it will be useful, but WITHOUT ANY\r
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
+ License for more details.\r
+\r
+ You should have received a copy of the GNU Lesser General Public License\r
+ along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include "stm32f4_adc.h"\r
+#include "stm32f4_dac.h"\r
+#include "freedv_api.h"\r
+#include "sm1000_leds_switches.h"\r
+\r
+int main(void) {\r
+ struct freedv *f;\r
+ short buf[FREEDV_NSAMPLES];\r
+ int nin, nout;\r
+\r
+ /* init all the drivers for various peripherals */\r
+\r
+ sm1000_leds_switches_init();\r
+ dac_open();\r
+ adc_open();\r
+ f = freedv_open(FREEDV_MODE_1600);\r
+\r
+ /* LEDs into a known state */\r
+\r
+ led_pwr(1); led_ptt(0); led_rt(0); led_err(0);\r
+\r
+ /* \r
+ TODO:\r
+ [ ] UT analog interfaces from file IO\r
+ [ ] UTs for simultaneous tx & rx on analog interfaces\r
+ [ ] measure CPU load of various parts with a blinky\r
+ [ ] detect program assert type errors with a blinky\r
+ [ ] timer tick function to measure 10ms-ish type times\r
+ [ ] switch debouncing?\r
+ [ ] light led with bit errors\r
+ */\r
+\r
+ while(1) {\r
+\r
+ if(switch_ptt()) {\r
+\r
+ /* Transmit -------------------------------------------------------------------------*/\r
+\r
+ /* ADC2 is the SM1000 microphone, DAC1 is the modulator signal we send to radio tx */\r
+\r
+ if (adc2_read(buf, FREEDV_NSAMPLES) == FREEDV_NSAMPLES) {\r
+ freedv_tx(f, buf, buf);\r
+ dac1_write(buf, FREEDV_NSAMPLES);\r
+ led_ptt(1); led_rt(0); led_err(0);\r
+ }\r
+ }\r
+ else {\r
+ \r
+ /* Receive --------------------------------------------------------------------------*/\r
+\r
+ /* ADC1 is the demod in signal from the radio rx, DAC2 is the SM1000 speaker */\r
+\r
+ nin = freedv_nin(f);\r
+ f->total_bit_errors = 0;\r
+ \r
+ if (adc1_read(buf, nin) == nin) {\r
+ nout = freedv_rx(f, buf, buf);\r
+ dac2_write(buf, nout);\r
+ led_ptt(0); led_rt(f->fdmdv_stats.sync); led_err(f->total_bit_errors);\r
+ }\r
+\r
+ }\r
+ \r
+ } /* while(1) ... */\r
+}\r
+\r