X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;ds=sidebyside;f=bertos%2Fnet%2Fafsk.c;h=a7273bdfd45789095091d6abe1fd5d9a1f92757c;hb=80d83c6b228d01d19f4c97650c4d88456b909637;hp=979848bf0a2c9f10d7156998e0f0e04e3647c59d;hpb=e0e183fc664ddfe6327c6c4c72bd81cde7572d71;p=bertos.git diff --git a/bertos/net/afsk.c b/bertos/net/afsk.c index 979848bf..a7273bdf 100644 --- a/bertos/net/afsk.c +++ b/bertos/net/afsk.c @@ -51,11 +51,6 @@ #include /* memset */ -// Demodulator constants -#define SAMPLERATE 9600 -#define BITRATE 1200 - -#define SAMPLEPERBIT (SAMPLERATE / BITRATE) #define PHASE_BIT 8 #define PHASE_INC 1 @@ -74,22 +69,6 @@ STATIC_ASSERT(!(CONFIG_AFSK_DAC_SAMPLERATE % BITRATE)); #define DAC_SAMPLEPERBIT (CONFIG_AFSK_DAC_SAMPLERATE / BITRATE) - -/** Current sample of bit for output data. */ -static uint8_t sample_count; - -/** Current character to be modulated */ -static uint8_t curr_out; - -/** Mask of current modulated bit */ -static uint8_t tx_bit; - -/** True if bit stuff is allowed, false otherwise */ -static bool bit_stuff; - -/** Counter for bit stuffing */ -static uint8_t stuff_cnt; - /** * Sine table for the first quarter of wave. * The rest of the wave is computed from this first quarter. @@ -112,14 +91,6 @@ static const uint8_t sin_table[] = STATIC_ASSERT(sizeof(sin_table) == SIN_LEN / 4); -/** - * DDS phase accumulator for generating modulated data. - */ -static uint16_t phase_acc; - -/** Current phase increment for current modulated bit */ -static uint16_t phase_inc = MARK_INC; - /** * Given the index, this function computes the correct sine sample @@ -134,99 +105,76 @@ INLINE uint8_t sin_sample(uint16_t idx) } -static FIFOBuffer delay_fifo; - -/** - * Buffer for delay FIFO. - * The 1 is added because the FIFO macros need - * 1 byte more to handle a buffer (SAMPLEPERBIT / 2) bytes long. - */ -static int8_t delay_buf[SAMPLEPERBIT / 2 + 1]; - -static FIFOBuffer rx_fifo; -static uint8_t rx_buf[CONFIG_AFSK_RX_BUFLEN]; - -static FIFOBuffer tx_fifo; -static uint8_t tx_buf[CONFIG_AFSK_TX_BUFLEN]; - -static int16_t iir_x[2]; -static int16_t iir_y[2]; -static uint8_t sampled_bits; -static uint8_t found_bits; -static uint8_t demod_bits; -static int8_t curr_phase; - -static bool hdlc_rxstart; -static uint8_t hdlc_currchar; -static uint8_t hdlc_bit_idx; - #define BIT_DIFFER(bitline1, bitline2) (((bitline1) ^ (bitline2)) & 0x01) #define EDGE_FOUND(bitline) BIT_DIFFER((bitline), (bitline) >> 1) -static void hdlc_parse(bool bit) + +static void hdlc_parse(Afsk *af, bool bit) { - demod_bits <<= 1; - demod_bits |= bit ? 1 : 0; + af->hdlc_demod_bits <<= 1; + af->hdlc_demod_bits |= bit ? 1 : 0; /* HDLC Flag */ - if (demod_bits == HDLC_FLAG) + if (af->hdlc_demod_bits == HDLC_FLAG) { - if (!fifo_isfull_locked(&rx_fifo)) + if (!fifo_isfull(&af->rx_fifo)) { - fifo_push(&rx_fifo, HDLC_FLAG); - hdlc_rxstart = true; + fifo_push(&af->rx_fifo, HDLC_FLAG); + af->hdlc_rxstart = true; } else - hdlc_rxstart = false; - hdlc_currchar = 0; - hdlc_bit_idx = 0; + af->hdlc_rxstart = false; + + af->hdlc_currchar = 0; + af->hdlc_bit_idx = 0; return; } /* Reset */ - if ((demod_bits & HDLC_RESET) == HDLC_RESET) + if ((af->hdlc_demod_bits & HDLC_RESET) == HDLC_RESET) { - hdlc_rxstart = false; + af->hdlc_rxstart = false; return; } - if (!hdlc_rxstart) + if (!af->hdlc_rxstart) return; /* Stuffed bit */ - if ((demod_bits & 0x3f) == 0x3e) + if ((af->hdlc_demod_bits & 0x3f) == 0x3e) return; - if (demod_bits & 0x01) - hdlc_currchar |= 0x80; + if (af->hdlc_demod_bits & 0x01) + af->hdlc_currchar |= 0x80; - if (++hdlc_bit_idx >= 8) + if (++af->hdlc_bit_idx >= 8) { - if ((hdlc_currchar == HDLC_FLAG - || hdlc_currchar == HDLC_RESET - || hdlc_currchar == AX25_ESC) - && !fifo_isfull_locked(&rx_fifo)) - fifo_push(&rx_fifo, AX25_ESC); - else - hdlc_rxstart = false; + if ((af->hdlc_currchar == HDLC_FLAG + || af->hdlc_currchar == HDLC_RESET + || af->hdlc_currchar == AX25_ESC)) + { + if (!fifo_isfull(&af->rx_fifo)) + fifo_push(&af->rx_fifo, AX25_ESC); + else + af->hdlc_rxstart = false; + } - if (!fifo_isfull_locked(&rx_fifo)) - fifo_push(&rx_fifo, hdlc_currchar); + if (!fifo_isfull(&af->rx_fifo)) + fifo_push(&af->rx_fifo, af->hdlc_currchar); else - hdlc_rxstart = false; + af->hdlc_rxstart = false; - hdlc_currchar = 0; - hdlc_bit_idx = 0; + af->hdlc_currchar = 0; + af->hdlc_bit_idx = 0; return; } - hdlc_currchar >>= 1; + af->hdlc_currchar >>= 1; } -DEFINE_AFSK_ADC_ISR() +void afsk_adc_isr(Afsk *af, int8_t curr_sample) { AFSK_STROBE_ON(); - int8_t curr_sample = AFSK_READ_ADC(); /* * Frequency discriminator and LP IIR filter. @@ -238,141 +186,183 @@ DEFINE_AFSK_ADC_ISR() /* * Frequency discrimination is achieved by simply multiplying - * the sample with a delayed sample of (bits per sample) / 2. - * Then the signal is lowpass filtered with a first order, 600 Hz - * Butterworth filter. + * the sample with a delayed sample of (samples per bit) / 2. + * Then the signal is lowpass filtered with a first order, + * 600 Hz filter. The filter implementation is selectable + * through the CONFIG_AFSK_FILTER config variable. */ - iir_x[0] = iir_x[1]; - iir_x[1] = ((int8_t)fifo_pop(&delay_fifo) * curr_sample) >> 2; - iir_y[0] = iir_y[1]; + af->iir_x[0] = af->iir_x[1]; - /* - * This strange sum + shift is an optimization for iir_y[0] * 0.668. - * iir * 0.668 ~= (iir * 21) / 32 = - * = (iir * 16) / 32 + (iir * 4) / 32 + iir / 32 = - * = iir / 2 + iir / 8 + iir / 32 = - * = iir >> 1 + iir >> 3 + iir >> 5 - */ - iir_y[1] = iir_x[0] + iir_x[1] + (iir_y[0] >> 1) + (iir_y[0] >> 3) + (iir_y[0] >> 5); + #if (CONFIG_AFSK_FILTER == AFSK_BUTTERWORTH) + af->iir_x[1] = ((int8_t)fifo_pop(&af->delay_fifo) * curr_sample) >> 2; + //af->iir_x[1] = ((int8_t)fifo_pop(&af->delay_fifo) * curr_sample) / 6.027339492; + #elif (CONFIG_AFSK_FILTER == AFSK_CHEBYSHEV) + af->iir_x[1] = ((int8_t)fifo_pop(&af->delay_fifo) * curr_sample) >> 2; + //af->iir_x[1] = ((int8_t)fifo_pop(&af->delay_fifo) * curr_sample) / 3.558147322; + #else + #error Filter type not found! + #endif + + af->iir_y[0] = af->iir_y[1]; + + #if CONFIG_AFSK_FILTER == AFSK_BUTTERWORTH + /* + * This strange sum + shift is an optimization for af->iir_y[0] * 0.668. + * iir * 0.668 ~= (iir * 21) / 32 = + * = (iir * 16) / 32 + (iir * 4) / 32 + iir / 32 = + * = iir / 2 + iir / 8 + iir / 32 = + * = iir >> 1 + iir >> 3 + iir >> 5 + */ + af->iir_y[1] = af->iir_x[0] + af->iir_x[1] + (af->iir_y[0] >> 1) + (af->iir_y[0] >> 3) + (af->iir_y[0] >> 5); + //af->iir_y[1] = af->iir_x[0] + af->iir_x[1] + af->iir_y[0] * 0.6681786379; + #elif CONFIG_AFSK_FILTER == AFSK_CHEBYSHEV + /* + * This should be (af->iir_y[0] * 0.438) but + * (af->iir_y[0] >> 1) is a faster approximation :-) + */ + af->iir_y[1] = af->iir_x[0] + af->iir_x[1] + (af->iir_y[0] >> 1); + //af->iir_y[1] = af->iir_x[0] + af->iir_x[1] + af->iir_y[0] * 0.4379097269; + #endif /* Save this sampled bit in a delay line */ - sampled_bits <<= 1; - sampled_bits |= (iir_y[1] > 0) ? 1 : 0; + af->sampled_bits <<= 1; + af->sampled_bits |= (af->iir_y[1] > 0) ? 1 : 0; - /* Store current ADC sample in the delay_fifo */ - fifo_push(&delay_fifo, curr_sample); + /* Store current ADC sample in the af->delay_fifo */ + fifo_push(&af->delay_fifo, curr_sample); /* If there is an edge, adjust phase sampling */ - if (EDGE_FOUND(sampled_bits)) + if (EDGE_FOUND(af->sampled_bits)) { - if (curr_phase < PHASE_THRES) - curr_phase += PHASE_INC; + if (af->curr_phase < PHASE_THRES) + af->curr_phase += PHASE_INC; else - curr_phase -= PHASE_INC; + af->curr_phase -= PHASE_INC; } - curr_phase += PHASE_BIT; + af->curr_phase += PHASE_BIT; /* sample the bit */ - if (curr_phase >= PHASE_MAX) + if (af->curr_phase >= PHASE_MAX) { - curr_phase %= PHASE_MAX; + af->curr_phase %= PHASE_MAX; /* Shift 1 position in the shift register of the found bits */ - found_bits <<= 1; + af->found_bits <<= 1; /* - * TODO: maybe a better algorithm to find the sample bit - * other than reading the last one. + * Determine bit value by reading the last 3 sampled bits. + * If the number of ones is two or greater, the bit value is a 1, + * otherwise is a 0. */ - found_bits |= sampled_bits & 1; + uint8_t bits = af->sampled_bits & 0x07; + if (bits == 0x07 // 111, 3 bits set to 1 + || bits == 0x06 // 110, 2 bits + || bits == 0x05 // 101, 2 bits + || bits == 0x03 // 011, 2 bits + ) + af->found_bits |= 1; /* * NRZI coding: if 2 consecutive bits have the same value * a 1 is received, otherwise it's a 0. */ - hdlc_parse(!EDGE_FOUND(found_bits)); + hdlc_parse(af, !EDGE_FOUND(af->found_bits)); } AFSK_STROBE_OFF(); - AFSK_ADC_IRQ_END(); } -/* True while modem sends data */ -static volatile bool sending; - -static void afsk_txStart(void) +static void afsk_txStart(Afsk *af) { - if (!sending) + if (!af->sending) { - phase_inc = MARK_INC; - phase_acc = 0; - stuff_cnt = 0; - sending = true; - AFSK_DAC_IRQ_START(); + af->phase_inc = MARK_INC; + af->phase_acc = 0; + af->stuff_cnt = 0; + af->sending = true; + af->preamble_len = DIV_ROUND(CONFIG_AFSK_PREAMBLE_LEN * BITRATE, 8000); + AFSK_DAC_IRQ_START(af->dac_ch); } + ATOMIC(af->trailer_len = DIV_ROUND(CONFIG_AFSK_TRAILER_LEN * BITRATE, 8000)); } #define BIT_STUFF_LEN 5 #define SWITCH_TONE(inc) (((inc) == MARK_INC) ? SPACE_INC : MARK_INC) -DEFINE_AFSK_DAC_ISR() +void afsk_dac_isr(Afsk *af) { /* Check if we are at a start of a sample cycle */ - if (sample_count == 0) + if (af->sample_count == 0) { - if (tx_bit == 0) + if (af->tx_bit == 0) { /* We have just finished transimitting a char, get a new one. */ - if (fifo_isempty(&tx_fifo)) + if (fifo_isempty(&af->tx_fifo) && af->trailer_len == 0) { - AFSK_DAC_IRQ_STOP(); - sending = false; - AFSK_DAC_IRQ_END(); + AFSK_DAC_IRQ_STOP(af->dac_ch); + af->sending = false; return; } else { /* - * If we have just finished sending an unstuffed byte, + * If we have just finished af->sending an unstuffed byte, * reset bitstuff counter. */ - if (!bit_stuff) - stuff_cnt = 0; + if (!af->bit_stuff) + af->stuff_cnt = 0; - bit_stuff = true; - curr_out = fifo_pop(&tx_fifo); + af->bit_stuff = true; + + /* + * Handle preamble and trailer + */ + if (af->preamble_len == 0) + { + if (fifo_isempty(&af->tx_fifo)) + { + af->trailer_len--; + af->curr_out = HDLC_FLAG; + } + else + af->curr_out = fifo_pop(&af->tx_fifo); + } + else + { + af->preamble_len--; + af->curr_out = HDLC_FLAG; + } /* Handle char escape */ - if (curr_out == AX25_ESC) + if (af->curr_out == AX25_ESC) { - if (fifo_isempty(&tx_fifo)) + if (fifo_isempty(&af->tx_fifo)) { - AFSK_DAC_IRQ_STOP(); - sending = false; - AFSK_DAC_IRQ_END(); + AFSK_DAC_IRQ_STOP(af->dac_ch); + af->sending = false; return; } else - curr_out = fifo_pop(&tx_fifo); + af->curr_out = fifo_pop(&af->tx_fifo); } - else if (curr_out == HDLC_FLAG || curr_out == HDLC_RESET) + else if (af->curr_out == HDLC_FLAG || af->curr_out == HDLC_RESET) /* If these chars are not escaped disable bit stuffing */ - bit_stuff = false; + af->bit_stuff = false; } /* Start with LSB mask */ - tx_bit = 0x01; + af->tx_bit = 0x01; } /* check for bit stuffing */ - if (bit_stuff && stuff_cnt >= BIT_STUFF_LEN) + if (af->bit_stuff && af->stuff_cnt >= BIT_STUFF_LEN) { /* If there are more than 5 ones in a row insert a 0 */ - stuff_cnt = 0; + af->stuff_cnt = 0; /* switch tone */ - phase_inc = SWITCH_TONE(phase_inc); + af->phase_inc = SWITCH_TONE(af->phase_inc); } else { @@ -380,14 +370,14 @@ DEFINE_AFSK_DAC_ISR() * NRZI: if we want to transmit a 1 the modulated frequency will stay * unchanged; with a 0, there will be a change in the tone. */ - if (curr_out & tx_bit) + if (af->curr_out & af->tx_bit) { /* * Transmit a 1: * - Stay on the previous tone * - Increace bit stuff count */ - stuff_cnt++; + af->stuff_cnt++; } else { @@ -396,32 +386,32 @@ DEFINE_AFSK_DAC_ISR() * - Reset bit stuff count * - Switch tone */ - stuff_cnt = 0; - phase_inc = SWITCH_TONE(phase_inc); + af->stuff_cnt = 0; + af->phase_inc = SWITCH_TONE(af->phase_inc); } /* Go to the next bit */ - tx_bit <<= 1; + af->tx_bit <<= 1; } - sample_count = DAC_SAMPLEPERBIT; + af->sample_count = DAC_SAMPLEPERBIT; } /* Get new sample and put it out on the DAC */ - phase_acc += phase_inc; - phase_acc %= SIN_LEN; + af->phase_acc += af->phase_inc; + af->phase_acc %= SIN_LEN; - AFSK_SET_DAC(sin_sample(phase_acc)); - sample_count--; - AFSK_DAC_IRQ_END(); + AFSK_DAC_SET(af->dac_ch, sin_sample(af->phase_acc)); + af->sample_count--; } -static size_t afsk_read(UNUSED_ARG(KFile *, fd), void *_buf, size_t size) +static size_t afsk_read(KFile *fd, void *_buf, size_t size) { + Afsk *af = AFSK_CAST(fd); uint8_t *buf = (uint8_t *)_buf; #if CONFIG_AFSK_RXTIMEOUT == 0 - while (size-- && !fifo_isempty_locked(&rx_fifo)) + while (size-- && !fifo_isempty_locked(&af->rx_fifo)) #else while (size--) #endif @@ -430,7 +420,7 @@ static size_t afsk_read(UNUSED_ARG(KFile *, fd), void *_buf, size_t size) ticks_t start = timer_clock(); #endif - do + while (fifo_isempty_locked(&af->rx_fifo)); { cpu_relax(); #if CONFIG_AFSK_RXTIMEOUT != -1 @@ -438,60 +428,65 @@ static size_t afsk_read(UNUSED_ARG(KFile *, fd), void *_buf, size_t size) return buf - (uint8_t *)_buf; #endif } - while (fifo_isempty_locked(&rx_fifo)); - *buf++ = fifo_pop_locked(&rx_fifo); + *buf++ = fifo_pop_locked(&af->rx_fifo); } return buf - (uint8_t *)_buf; } -static size_t afsk_write(UNUSED_ARG(KFile *, fd), const void *_buf, size_t size) +static size_t afsk_write(KFile *fd, const void *_buf, size_t size) { + Afsk *af = AFSK_CAST(fd); const uint8_t *buf = (const uint8_t *)_buf; while (size--) { - while (fifo_isfull_locked(&tx_fifo)) + while (fifo_isfull_locked(&af->tx_fifo)) cpu_relax(); - fifo_push_locked(&tx_fifo, *buf++); - afsk_txStart(); + fifo_push_locked(&af->tx_fifo, *buf++); + afsk_txStart(af); } return buf - (const uint8_t *)_buf; } -static int afsk_flush(UNUSED_ARG(KFile *, fd)) +static int afsk_flush(KFile *fd) { - while (sending) + Afsk *af = AFSK_CAST(fd); + while (af->sending) cpu_relax(); return 0; } -void afsk_init(Afsk *af) +void afsk_init(Afsk *af, int adc_ch, int dac_ch) { #if CONFIG_AFSK_RXTIMEOUT != -1 MOD_CHECK(timer); #endif + memset(af, 0, sizeof(*af)); + af->adc_ch = adc_ch; + af->dac_ch = dac_ch; - fifo_init(&delay_fifo, (uint8_t *)delay_buf, sizeof(delay_buf)); - fifo_init(&rx_fifo, rx_buf, sizeof(rx_buf)); + fifo_init(&af->delay_fifo, (uint8_t *)af->delay_buf, sizeof(af->delay_buf)); + fifo_init(&af->rx_fifo, af->rx_buf, sizeof(af->rx_buf)); /* Fill sample FIFO with 0 */ for (int i = 0; i < SAMPLEPERBIT / 2; i++) - fifo_push(&delay_fifo, 0); + fifo_push(&af->delay_fifo, 0); - fifo_init(&tx_fifo, tx_buf, sizeof(tx_buf)); + fifo_init(&af->tx_fifo, af->tx_buf, sizeof(af->tx_buf)); - AFSK_ADC_INIT(); + AFSK_ADC_INIT(adc_ch, af); + AFSK_DAC_INIT(dac_ch, af); AFSK_STROBE_INIT(); kprintf("MARK_INC %d, SPACE_INC %d\n", MARK_INC, SPACE_INC); - memset(af, 0, sizeof(*af)); DB(af->fd._type = KFT_AFSK); af->fd.write = afsk_write; af->fd.read = afsk_read; af->fd.flush = afsk_flush; + af->phase_inc = MARK_INC; }