-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: sm1000_main.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: August 5 2014\r
-\r
- Main program for SM1000.\r
-\r
- TODO\r
-\r
- [ ] make led blink 1-2-3 times for "mode"\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 "codec2_fdmdv.h"\r
-#include "sm1000_leds_switches.h"\r
-#include <stm32f4xx_gpio.h>\r
-#include <stdlib.h>\r
-\r
-#define FREEDV_NSAMPLES_16K (2*FREEDV_NSAMPLES)\r
-\r
-#define FIFTY_MS 50\r
-#define MAX_MODES 3\r
-#define ANALOG 0\r
-#define DV 1\r
-#define TONE 2\r
-\r
-#define SS_IDLE 0\r
-#define SS_DEBOUNCE_DOWN 1\r
-#define SS_WAIT_BUTTON_UP 2\r
-#define SS_DEBOUNCE_UP 3\r
-\r
-typedef struct {\r
- int state;\r
- int mode;\r
-} SWITCH_STATE;\r
-\r
-unsigned int downTicker;\r
-\r
-void SysTick_Handler(void);\r
-void iterate_select_state_machine(SWITCH_STATE *ss);\r
-\r
-#define SINE_SAMPLES 32\r
-\r
-/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples\r
- are 16 bit 2's complement, the DAC driver convertsto 12 bit\r
- unsigned. */\r
-\r
-short aSine[] = {\r
- -16, 6384, 12528, 18192, 23200, 27232, 30256, 32128,\r
- 32752, 32128, 30256, 27232, 23152, 18192, 12528, 6384,\r
- -16, -6416, -12560, -18224, -23184, -27264, -30288, -32160,\r
- -32768, -32160, -30288, -27264, -23184, -18224, -12560, -6416\r
-};\r
-\r
-int main(void) {\r
- struct freedv *f;\r
- SWITCH_STATE ss;\r
- int nin, nout, i;\r
- int n_samples, n_samples_16k;\r
-\r
- /* init all the drivers for various peripherals */\r
-\r
- SysTick_Config(SystemCoreClock/168000); /* 1 kHz SysTick */\r
- sm1000_leds_switches_init();\r
- dac_open(4*DAC_BUF_SZ);\r
- adc_open(4*ADC_BUF_SZ);\r
- f = freedv_open(FREEDV_MODE_1600);\r
- n_samples = freedv_get_n_speech_samples(f);\r
- n_samples_16k = 2*n_samples;\r
-\r
- short adc16k[FDMDV_OS_TAPS_16K+n_samples_16k];\r
- short dac16k[n_samples_16k];\r
- short adc8k[n_samples];\r
- short dac8k[FDMDV_OS_TAPS_8K+n_samples];\r
-\r
- /* put outputs into a known state */\r
-\r
- led_pwr(1); led_ptt(0); led_rt(0); led_err(0); not_cptt(1);\r
-\r
- /* clear filter memories */\r
-\r
- for(i=0; i<FDMDV_OS_TAPS_16K; i++)\r
- adc16k[i] = 0.0;\r
- for(i=0; i<FDMDV_OS_TAPS_8K; i++)\r
- dac8k[i] = 0.0;\r
-\r
- ss.state = SS_IDLE;\r
- ss.mode = ANALOG;\r
-\r
- while(1) {\r
- \r
- iterate_select_state_machine(&ss);\r
-\r
- if (switch_ptt() || (ext_ptt() == 0)) {\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(&adc16k[FDMDV_OS_TAPS_16K], n_samples_16k) == 0) {\r
- GPIOE->ODR = (1 << 3);\r
-\r
- /* clipping indicator */\r
-\r
- led_err(0);\r
- for (i=0; i<n_samples_16k; i++) {\r
- if (abs(adc16k[FDMDV_OS_TAPS_16K+i]) > 28000)\r
- led_err(1);\r
- }\r
-\r
- fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], n_samples);\r
-\r
- if (ss.mode == ANALOG) {\r
- for(i=0; i<n_samples; i++)\r
- dac8k[FDMDV_OS_TAPS_8K+i] = adc8k[i];\r
- fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], n_samples); \r
- dac1_write(dac16k, n_samples_16k);\r
- }\r
- if (ss.mode == DV) {\r
- freedv_tx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k);\r
- for(i=0; i<n_samples; i++)\r
- dac8k[FDMDV_OS_TAPS_8K+i] *= 0.398; /* 8dB back off from peak */\r
- fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], n_samples); \r
- dac1_write(dac16k, n_samples_16k);\r
- }\r
- if (ss.mode == TONE) {\r
- short buf[SINE_SAMPLES];\r
- for(i=0; i<n_samples; i++)\r
- buf[i] = aSine[i]*0.398; /* 8dB back off from peak */ \r
- while(dac1_write(buf, SINE_SAMPLES) == 0);\r
- }\r
-\r
- led_ptt(1); led_rt(0); led_err(0); not_cptt(0);\r
- GPIOE->ODR &= ~(1 << 3);\r
- }\r
-\r
- }\r
- else {\r
- \r
- /* Receive --------------------------------------------------------------------------*/\r
-\r
- not_cptt(1); led_ptt(0); \r
-\r
- /* ADC1 is the demod in signal from the radio rx, DAC2 is the SM1000 speaker */\r
-\r
- if (ss.mode == ANALOG) {\r
-\r
- if (adc1_read(&adc16k[FDMDV_OS_TAPS_16K], n_samples_16k) == 0) {\r
- fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], n_samples);\r
- for(i=0; i<n_samples; i++)\r
- dac8k[FDMDV_OS_TAPS_8K+i] = adc8k[i];\r
- fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], n_samples); \r
- dac2_write(dac16k, n_samples_16k);\r
- led_rt(0); led_err(0);\r
- }\r
- }\r
- else {\r
-\r
- /* regular DV mode */\r
-\r
- nin = freedv_nin(f); \r
- nout = nin;\r
- freedv_zero_total_bit_errors(f);\r
-\r
- if (adc1_read(&adc16k[FDMDV_OS_TAPS_16K], 2*nin) == 0) {\r
- GPIOE->ODR = (1 << 3);\r
- fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], nin);\r
- nout = freedv_rx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k);\r
- fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], nout); \r
- dac2_write(dac16k, 2*nout);\r
- led_rt(freedv_get_sync(f)); led_err(freedv_get_total_bit_errors(f));\r
- GPIOE->ODR &= ~(1 << 3);\r
- }\r
- }\r
-\r
- }\r
- } /* while(1) ... */\r
-}\r
-\r
-/*\r
- * SysTick Interrupt Handler\r
- */\r
-\r
-void SysTick_Handler(void)\r
-{\r
- if (downTicker > 0) {\r
- downTicker--;\r
- }\r
-}\r
-\r
-/* Select button state machine. Debounces switches and enables cycling\r
- through ANALOG-DV-TONE modes */\r
-\r
-void iterate_select_state_machine(SWITCH_STATE *ss) {\r
- int next_state;\r
-\r
- next_state = ss->state;\r
- switch(ss->state) {\r
- case SS_IDLE:\r
- if (switch_select() == 0) {\r
- downTicker = FIFTY_MS;\r
- next_state = SS_DEBOUNCE_DOWN;\r
- }\r
- break;\r
- case SS_DEBOUNCE_DOWN:\r
- if (downTicker == 0) {\r
- ss->mode++;\r
- if (ss->mode >= MAX_MODES)\r
- ss->mode = 0;\r
- next_state = SS_WAIT_BUTTON_UP;\r
- }\r
- break;\r
- case SS_WAIT_BUTTON_UP:\r
- if (switch_select() == 1) {\r
- downTicker = FIFTY_MS;\r
- next_state = SS_DEBOUNCE_UP;\r
- }\r
- break;\r
- case SS_DEBOUNCE_UP:\r
- if (downTicker == 0) {\r
- next_state = SS_IDLE;\r
- }\r
- break;\r
- }\r
- ss->state = next_state;\r
-}\r
- \r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: sm1000_main.c
+ AUTHOR......: David Rowe
+ DATE CREATED: August 5 2014
+
+ Main program for SM1000.
+
+ TODO
+
+ [ ] make led blink 1-2-3 times for "mode"
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ 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/>.
+*/
+
+#include "stm32f4_adc.h"
+#include "stm32f4_dac.h"
+#include "freedv_api.h"
+#include "codec2_fdmdv.h"
+#include "sm1000_leds_switches.h"
+#include <stm32f4xx_gpio.h>
+#include <stdlib.h>
+
+#define FREEDV_NSAMPLES_16K (2*FREEDV_NSAMPLES)
+
+#define FIFTY_MS 50
+#define MAX_MODES 3
+#define ANALOG 0
+#define DV 1
+#define TONE 2
+
+#define SS_IDLE 0
+#define SS_DEBOUNCE_DOWN 1
+#define SS_WAIT_BUTTON_UP 2
+#define SS_DEBOUNCE_UP 3
+
+typedef struct {
+ int state;
+ int mode;
+} SWITCH_STATE;
+
+unsigned int downTicker;
+
+void SysTick_Handler(void);
+void iterate_select_state_machine(SWITCH_STATE *ss);
+
+#define SINE_SAMPLES 32
+
+/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples
+ are 16 bit 2's complement, the DAC driver convertsto 12 bit
+ unsigned. */
+
+short aSine[] = {
+ -16, 6384, 12528, 18192, 23200, 27232, 30256, 32128,
+ 32752, 32128, 30256, 27232, 23152, 18192, 12528, 6384,
+ -16, -6416, -12560, -18224, -23184, -27264, -30288, -32160,
+ -32768, -32160, -30288, -27264, -23184, -18224, -12560, -6416
+};
+
+int main(void) {
+ struct freedv *f;
+ SWITCH_STATE ss;
+ int nin, nout, i;
+ int n_samples, n_samples_16k;
+
+ /* init all the drivers for various peripherals */
+
+ SysTick_Config(SystemCoreClock/168000); /* 1 kHz SysTick */
+ sm1000_leds_switches_init();
+ dac_open(4*DAC_BUF_SZ);
+ adc_open(4*ADC_BUF_SZ);
+ f = freedv_open(FREEDV_MODE_1600);
+ n_samples = freedv_get_n_speech_samples(f);
+ n_samples_16k = 2*n_samples;
+
+ short adc16k[FDMDV_OS_TAPS_16K+n_samples_16k];
+ short dac16k[n_samples_16k];
+ short adc8k[n_samples];
+ short dac8k[FDMDV_OS_TAPS_8K+n_samples];
+
+ /* put outputs into a known state */
+
+ led_pwr(1); led_ptt(0); led_rt(0); led_err(0); not_cptt(1);
+
+ /* clear filter memories */
+
+ for(i=0; i<FDMDV_OS_TAPS_16K; i++)
+ adc16k[i] = 0.0;
+ for(i=0; i<FDMDV_OS_TAPS_8K; i++)
+ dac8k[i] = 0.0;
+
+ ss.state = SS_IDLE;
+ ss.mode = ANALOG;
+
+ while(1) {
+
+ iterate_select_state_machine(&ss);
+
+ if (switch_ptt() || (ext_ptt() == 0)) {
+
+ /* Transmit -------------------------------------------------------------------------*/
+
+ /* ADC2 is the SM1000 microphone, DAC1 is the modulator signal we send to radio tx */
+
+ if (adc2_read(&adc16k[FDMDV_OS_TAPS_16K], n_samples_16k) == 0) {
+ GPIOE->ODR = (1 << 3);
+
+ /* clipping indicator */
+
+ led_err(0);
+ for (i=0; i<n_samples_16k; i++) {
+ if (abs(adc16k[FDMDV_OS_TAPS_16K+i]) > 28000)
+ led_err(1);
+ }
+
+ fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], n_samples);
+
+ if (ss.mode == ANALOG) {
+ for(i=0; i<n_samples; i++)
+ dac8k[FDMDV_OS_TAPS_8K+i] = adc8k[i];
+ fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], n_samples);
+ dac1_write(dac16k, n_samples_16k);
+ }
+ if (ss.mode == DV) {
+ freedv_tx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k);
+ for(i=0; i<n_samples; i++)
+ dac8k[FDMDV_OS_TAPS_8K+i] *= 0.398; /* 8dB back off from peak */
+ fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], n_samples);
+ dac1_write(dac16k, n_samples_16k);
+ }
+ if (ss.mode == TONE) {
+ short buf[SINE_SAMPLES];
+ for(i=0; i<n_samples; i++)
+ buf[i] = aSine[i]*0.398; /* 8dB back off from peak */
+ while(dac1_write(buf, SINE_SAMPLES) == 0);
+ }
+
+ led_ptt(1); led_rt(0); led_err(0); not_cptt(0);
+ GPIOE->ODR &= ~(1 << 3);
+ }
+
+ }
+ else {
+
+ /* Receive --------------------------------------------------------------------------*/
+
+ not_cptt(1); led_ptt(0);
+
+ /* ADC1 is the demod in signal from the radio rx, DAC2 is the SM1000 speaker */
+
+ if (ss.mode == ANALOG) {
+
+ if (adc1_read(&adc16k[FDMDV_OS_TAPS_16K], n_samples_16k) == 0) {
+ fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], n_samples);
+ for(i=0; i<n_samples; i++)
+ dac8k[FDMDV_OS_TAPS_8K+i] = adc8k[i];
+ fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], n_samples);
+ dac2_write(dac16k, n_samples_16k);
+ led_rt(0); led_err(0);
+ }
+ }
+ else {
+
+ /* regular DV mode */
+
+ nin = freedv_nin(f);
+ nout = nin;
+ freedv_set_total_bit_errors(f, 0);
+ if (adc1_read(&adc16k[FDMDV_OS_TAPS_16K], 2*nin) == 0) {
+ GPIOE->ODR = (1 << 3);
+ fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], nin);
+ nout = freedv_rx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k);
+ fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], nout);
+ dac2_write(dac16k, 2*nout);
+ led_rt(freedv_get_sync(f)); led_err(freedv_get_total_bit_errors(f));
+ GPIOE->ODR &= ~(1 << 3);
+ }
+ }
+
+ }
+ } /* while(1) ... */
+}
+
+/*
+ * SysTick Interrupt Handler
+ */
+
+void SysTick_Handler(void)
+{
+ if (downTicker > 0) {
+ downTicker--;
+ }
+}
+
+/* Select button state machine. Debounces switches and enables cycling
+ through ANALOG-DV-TONE modes */
+
+void iterate_select_state_machine(SWITCH_STATE *ss) {
+ int next_state;
+
+ next_state = ss->state;
+ switch(ss->state) {
+ case SS_IDLE:
+ if (switch_select() == 0) {
+ downTicker = FIFTY_MS;
+ next_state = SS_DEBOUNCE_DOWN;
+ }
+ break;
+ case SS_DEBOUNCE_DOWN:
+ if (downTicker == 0) {
+ ss->mode++;
+ if (ss->mode >= MAX_MODES)
+ ss->mode = 0;
+ next_state = SS_WAIT_BUTTON_UP;
+ }
+ break;
+ case SS_WAIT_BUTTON_UP:
+ if (switch_select() == 1) {
+ downTicker = FIFTY_MS;
+ next_state = SS_DEBOUNCE_UP;
+ }
+ break;
+ case SS_DEBOUNCE_UP:
+ if (downTicker == 0) {
+ next_state = SS_IDLE;
+ }
+ break;
+ }
+ ss->state = next_state;
+}
+