4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2008 Develer S.r.l. (http://www.develer.com/)
33 * \brief AFSK1200 modem.
36 * \author Francesco Sacchi <asterix@develer.com>
40 #include "cfg/cfg_afsk.h"
41 #include "hw/hw_afsk.h"
43 #include <drv/timer.h>
45 #include <cfg/module.h>
47 #include <cpu/power.h>
48 #include <struct/fifobuf.h>
50 #include <string.h> /* memset */
52 // Demodulator constants
53 #define SAMPLERATE 9600
56 #define SAMPLEPERBIT (SAMPLERATE / BITRATE)
60 #define PHASE_MAX (SAMPLEPERBIT * PHASE_BIT)
61 #define PHASE_THRES (PHASE_MAX / 2) // - PHASE_BIT / 2)
63 // Modulator constants
64 #define MARK_FREQ 1200
65 #define MARK_INC (uint16_t)(DIV_ROUND(SIN_LEN * (uint32_t)MARK_FREQ, CONFIG_AFSK_DAC_SAMPLERATE))
67 #define SPACE_FREQ 2200
68 #define SPACE_INC (uint16_t)(DIV_ROUND(SIN_LEN * (uint32_t)SPACE_FREQ, CONFIG_AFSK_DAC_SAMPLERATE))
70 //Ensure sample rate is a multiple of bit rate
71 STATIC_ASSERT(!(CONFIG_AFSK_DAC_SAMPLERATE % BITRATE));
73 #define DAC_SAMPLEPERBIT (CONFIG_AFSK_DAC_SAMPLERATE / BITRATE)
76 /** Current sample of bit for output data. */
77 static uint8_t sample_count;
79 /** Current character to be modulated */
80 static uint8_t curr_out;
82 /** Mask of current modulated bit */
83 static uint8_t tx_bit;
85 /** True if bit stuff is allowed, false otherwise */
86 static bool bit_stuff;
88 /** Counter for bit stuffing */
89 static uint8_t stuff_cnt;
92 * Sine table for the first quarter of wave.
93 * The rest of the wave is computed from this first quarter.
94 * This table is used to generate the modulated data.
96 static const uint8_t sin_table[] =
99 128, 129, 131, 132, 134, 135, 137, 138, 140, 142, 143, 145, 146, 148, 149, 151,
100 152, 154, 155, 157, 158, 160, 162, 163, 165, 166, 167, 169, 170, 172, 173, 175,
101 176, 178, 179, 181, 182, 183, 185, 186, 188, 189, 190, 192, 193, 194, 196, 197,
102 198, 200, 201, 202, 203, 205, 206, 207, 208, 210, 211, 212, 213, 214, 215, 217,
103 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
104 234, 234, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, 243, 244, 245,
105 245, 246, 246, 247, 248, 248, 249, 249, 250, 250, 250, 251, 251, 252, 252, 252,
106 253, 253, 253, 253, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255,
109 #define SIN_LEN 512 ///< Full wave length
111 STATIC_ASSERT(sizeof(sin_table) == SIN_LEN / 4);
114 * DDS phase accumulator for generating modulated data.
116 static uint16_t phase_acc;
118 /** Current phase increment for current modulated bit */
119 static uint16_t phase_inc = MARK_INC;
123 * Given the index, this function computes the correct sine sample
124 * based only on the first quarter of wave.
126 INLINE uint8_t sin_sample(uint16_t idx)
128 ASSERT(idx < SIN_LEN);
129 uint16_t new_idx = idx % (SIN_LEN / 2);
130 new_idx = (new_idx >= (SIN_LEN / 4)) ? (SIN_LEN / 2 - new_idx - 1) : new_idx;
131 return (idx >= (SIN_LEN / 2)) ? (255 - sin_table[new_idx]) : sin_table[new_idx];
135 static FIFOBuffer delay_fifo;
138 * Buffer for delay FIFO.
139 * The 1 is added because the FIFO macros need
140 * 1 byte more to handle a buffer (SAMPLEPERBIT / 2) bytes long.
142 static int8_t delay_buf[SAMPLEPERBIT / 2 + 1];
144 static FIFOBuffer rx_fifo;
145 static uint8_t rx_buf[CONFIG_AFSK_RX_BUFLEN];
147 static FIFOBuffer tx_fifo;
148 static uint8_t tx_buf[CONFIG_AFSK_TX_BUFLEN];
150 static int16_t iir_x[2];
151 static int16_t iir_y[2];
152 static uint8_t sampled_bits;
153 static uint8_t found_bits;
154 static uint8_t demod_bits;
155 static int8_t curr_phase;
157 static bool hdlc_rxstart;
158 static uint8_t hdlc_currchar;
159 static uint8_t hdlc_bit_idx;
161 #define BIT_DIFFER(bitline1, bitline2) (((bitline1) ^ (bitline2)) & 0x01)
162 #define EDGE_FOUND(bitline) BIT_DIFFER((bitline), (bitline) >> 1)
164 static void hdlc_parse(bool bit)
167 demod_bits |= bit ? 1 : 0;
170 if (demod_bits == HDLC_FLAG)
172 if (!fifo_isfull_locked(&rx_fifo))
174 fifo_push(&rx_fifo, HDLC_FLAG);
178 hdlc_rxstart = false;
185 if ((demod_bits & HDLC_RESET) == HDLC_RESET)
187 hdlc_rxstart = false;
195 if ((demod_bits & 0x3f) == 0x3e)
198 if (demod_bits & 0x01)
199 hdlc_currchar |= 0x80;
201 if (++hdlc_bit_idx >= 8)
203 if ((hdlc_currchar == HDLC_FLAG
204 || hdlc_currchar == HDLC_RESET
205 || hdlc_currchar == AFSK_ESC)
206 && !fifo_isfull_locked(&rx_fifo))
207 fifo_push(&rx_fifo, AFSK_ESC);
209 hdlc_rxstart = false;
211 if (!fifo_isfull_locked(&rx_fifo))
212 fifo_push(&rx_fifo, hdlc_currchar);
214 hdlc_rxstart = false;
224 DEFINE_AFSK_ADC_ISR()
227 int8_t curr_sample = AFSK_READ_ADC();
230 * Frequency discriminator and LP IIR filter.
231 * This filter is designed to work
232 * at the given sample rate and bit rate.
234 STATIC_ASSERT(SAMPLERATE == 9600);
235 STATIC_ASSERT(BITRATE == 1200);
238 * Frequency discrimination is achieved by simply multiplying
239 * the sample with a delayed sample of (bits per sample) / 2.
240 * Then the signal is lowpass filtered with a first order, 600 Hz
241 * Butterworth filter.
245 iir_x[1] = ((int8_t)fifo_pop(&delay_fifo) * curr_sample) >> 2;
249 * This strange sum + shift is an optimization for iir_y[0] * 0.668.
250 * iir * 0.668 ~= (iir * 21) / 32 =
251 * = (iir * 16) / 32 + (iir * 4) / 32 + iir / 32 =
252 * = iir / 2 + iir / 8 + iir / 32 =
253 * = iir >> 1 + iir >> 3 + iir >> 5
255 iir_y[1] = iir_x[0] + iir_x[1] + (iir_y[0] >> 1) + (iir_y[0] >> 3) + (iir_y[0] >> 5);
257 /* Save this sampled bit in a delay line */
259 sampled_bits |= (iir_y[1] > 0) ? 1 : 0;
261 /* Store current ADC sample in the delay_fifo */
262 fifo_push(&delay_fifo, curr_sample);
264 /* If there is an edge, adjust phase sampling */
265 if (EDGE_FOUND(sampled_bits))
267 if (curr_phase < PHASE_THRES)
268 curr_phase += PHASE_INC;
270 curr_phase -= PHASE_INC;
272 curr_phase += PHASE_BIT;
275 if (curr_phase >= PHASE_MAX)
277 curr_phase %= PHASE_MAX;
279 /* Shift 1 position in the shift register of the found bits */
283 * TODO: maybe a better algorithm to find the sample bit
284 * other than reading the last one.
286 found_bits |= sampled_bits & 1;
289 * NRZI coding: if 2 consecutive bits have the same value
290 * a 1 is received, otherwise it's a 0.
292 hdlc_parse(!EDGE_FOUND(found_bits));
298 /* True while modem sends data */
299 static volatile bool sending;
301 static void afsk_txStart(void)
305 phase_inc = MARK_INC;
309 AFSK_DAC_IRQ_START();
313 #define BIT_STUFF_LEN 5
315 #define SWITCH_TONE(inc) (((inc) == MARK_INC) ? SPACE_INC : MARK_INC)
317 DEFINE_AFSK_DAC_ISR()
319 /* Check if we are at a start of a sample cycle */
320 if (sample_count == 0)
324 /* We have just finished transimitting a char, get a new one. */
325 if (fifo_isempty(&tx_fifo))
334 * If we have just finished sending an unstuffed byte,
335 * reset bitstuff counter.
341 curr_out = fifo_pop(&tx_fifo);
343 /* Handle char escape */
344 if (curr_out == AFSK_ESC)
346 if (fifo_isempty(&tx_fifo))
353 curr_out = fifo_pop(&tx_fifo);
355 else if (curr_out == HDLC_FLAG || curr_out == HDLC_RESET)
356 /* If these chars are not escaped disable bit stuffing */
359 /* Start with LSB mask */
363 /* check for bit stuffing */
364 if (bit_stuff && stuff_cnt >= BIT_STUFF_LEN)
366 /* If there are more than 5 ones in a row insert a 0 */
369 phase_inc = SWITCH_TONE(phase_inc);
374 * NRZI: if we want to transmit a 1 the modulated frequency will stay
375 * unchanged; with a 0, there will be a change in the tone.
377 if (curr_out & tx_bit)
381 * - Stay on the previous tone
382 * - Increace bit stuff count
390 * - Reset bit stuff count
394 phase_inc = SWITCH_TONE(phase_inc);
397 /* Go to the next bit */
400 sample_count = DAC_SAMPLEPERBIT;
403 /* Get new sample and put it out on the DAC */
404 phase_acc += phase_inc;
405 phase_acc %= SIN_LEN;
407 AFSK_SET_DAC(sin_sample(phase_acc));
412 static size_t afsk_read(UNUSED_ARG(KFile *, fd), void *_buf, size_t size)
414 uint8_t *buf = (uint8_t *)_buf;
416 #if CONFIG_AFSK_RXTIMEOUT == 0
417 while (size-- && !fifo_isempty_locked(&rx_fifo))
422 #if CONFIG_AFSK_RXTIMEOUT != -1
423 ticks_t start = timer_clock();
429 #if CONFIG_AFSK_RXTIMEOUT != -1
430 if (timer_clock() - start > ms_to_ticks(CONFIG_AFSK_RXTIMEOUT))
431 return buf - (uint8_t *)_buf;
434 while (fifo_isempty_locked(&rx_fifo));
436 *buf++ = fifo_pop_locked(&rx_fifo);
439 return buf - (uint8_t *)_buf;
442 static size_t afsk_write(UNUSED_ARG(KFile *, fd), const void *_buf, size_t size)
444 const uint8_t *buf = (const uint8_t *)_buf;
448 while (fifo_isfull_locked(&tx_fifo))
451 fifo_push_locked(&tx_fifo, *buf++);
455 return buf - (const uint8_t *)_buf;
458 static int afsk_flush(UNUSED_ARG(KFile *, fd))
466 void afsk_init(Afsk *af)
468 #if CONFIG_AFSK_RXTIMEOUT != -1
472 fifo_init(&delay_fifo, (uint8_t *)delay_buf, sizeof(delay_buf));
473 fifo_init(&rx_fifo, rx_buf, sizeof(rx_buf));
475 /* Fill sample FIFO with 0 */
476 for (int i = 0; i < SAMPLEPERBIT / 2; i++)
477 fifo_push(&delay_fifo, 0);
479 fifo_init(&tx_fifo, tx_buf, sizeof(tx_buf));
482 kprintf("MARK_INC %d, SPACE_INC %d\n", MARK_INC, SPACE_INC);
484 memset(af, 0, sizeof(*af));
485 DB(af->fd._type = KFT_AFSK);
486 af->fd.write = afsk_write;
487 af->fd.read = afsk_read;
488 af->fd.flush = afsk_flush;