Fix doc.
[bertos.git] / bertos / net / afsk.c
index 6fea471bd69f971b10a9ad63ddfa63d1906b86b3..2b7fe0bedaa5df37b4e18e8f6283cae1f13e2073 100644 (file)
 
 #include <cfg/module.h>
 
+#define LOG_LEVEL   AFSK_LOG_LEVEL
+#define LOG_FORMAT  AFSK_LOG_FORMAT
+#include <cfg/log.h>
+
 #include <cpu/power.h>
+#include <cpu/pgm.h>
 #include <struct/fifobuf.h>
 
 #include <string.h> /* memset */
@@ -74,9 +79,8 @@ STATIC_ASSERT(!(CONFIG_AFSK_DAC_SAMPLERATE % BITRATE));
  * The rest of the wave is computed from this first quarter.
  * This table is used to generate the modulated data.
  */
-static const uint8_t sin_table[] =
+static const uint8_t PROGMEM sin_table[] =
 {
-       //TODO put in flash!
        128, 129, 131, 132, 134, 135, 137, 138, 140, 142, 143, 145, 146, 148, 149, 151,
        152, 154, 155, 157, 158, 160, 162, 163, 165, 166, 167, 169, 170, 172, 173, 175,
        176, 178, 179, 181, 182, 183, 185, 186, 188, 189, 190, 192, 193, 194, 196, 197,
@@ -101,77 +105,113 @@ INLINE uint8_t sin_sample(uint16_t idx)
        ASSERT(idx < SIN_LEN);
        uint16_t new_idx = idx % (SIN_LEN / 2);
        new_idx = (new_idx >= (SIN_LEN / 4)) ? (SIN_LEN / 2 - new_idx - 1) : new_idx;
-       return (idx >= (SIN_LEN / 2)) ? (255 - sin_table[new_idx]) : sin_table[new_idx];
+
+       #if CPU_HARVARD
+               uint8_t data = pgm_read_char(&sin_table[new_idx]);
+       #else
+               uint8_t data = sin_table[new_idx];
+       #endif
+
+       return (idx >= (SIN_LEN / 2)) ? (255 - data) : data;
 }
 
 
 #define BIT_DIFFER(bitline1, bitline2) (((bitline1) ^ (bitline2)) & 0x01)
 #define EDGE_FOUND(bitline)            BIT_DIFFER((bitline), (bitline) >> 1)
 
-
-static void hdlc_parse(Afsk *af, bool bit)
+/**
+ * High-Level Data Link Control parsing function.
+ * Parse bitstream in order to find characters.
+ *
+ * \param hdlc HDLC context.
+ * \param bit  current bit to be parsed.
+ * \param fifo FIFO buffer used to push characters.
+ *
+ * \return true if all is ok, false if the fifo is full.
+ */
+static bool hdlc_parse(Hdlc *hdlc, bool bit, FIFOBuffer *fifo)
 {
-       af->hdlc_demod_bits <<= 1;
-       af->hdlc_demod_bits |= bit ? 1 : 0;
+       bool ret = true;
+
+       hdlc->demod_bits <<= 1;
+       hdlc->demod_bits |= bit ? 1 : 0;
 
        /* HDLC Flag */
-       if (af->hdlc_demod_bits == HDLC_FLAG)
+       if (hdlc->demod_bits == HDLC_FLAG)
        {
-               if (!fifo_isfull(&af->rx_fifo))
+               if (!fifo_isfull(fifo))
                {
-                       fifo_push(&af->rx_fifo, HDLC_FLAG);
-                       af->hdlc_rxstart = true;
+                       fifo_push(fifo, HDLC_FLAG);
+                       hdlc->rxstart = true;
                }
                else
-                       af->hdlc_rxstart = false;
+               {
+                       ret = false;
+                       hdlc->rxstart = false;
+               }
 
-               af->hdlc_currchar = 0;
-               af->hdlc_bit_idx = 0;
-               return;
+               hdlc->currchar = 0;
+               hdlc->bit_idx = 0;
+               return ret;
        }
 
        /* Reset */
-       if ((af->hdlc_demod_bits & HDLC_RESET) == HDLC_RESET)
+       if ((hdlc->demod_bits & HDLC_RESET) == HDLC_RESET)
        {
-               af->hdlc_rxstart = false;
-               return;
+               hdlc->rxstart = false;
+               return ret;
        }
 
-       if (!af->hdlc_rxstart)
-               return;
+       if (!hdlc->rxstart)
+               return ret;
 
        /* Stuffed bit */
-       if ((af->hdlc_demod_bits & 0x3f) == 0x3e)
-               return;
+       if ((hdlc->demod_bits & 0x3f) == 0x3e)
+               return ret;
 
-       if (af->hdlc_demod_bits & 0x01)
-               af->hdlc_currchar |= 0x80;
+       if (hdlc->demod_bits & 0x01)
+               hdlc->currchar |= 0x80;
 
-       if (++af->hdlc_bit_idx >= 8)
+       if (++hdlc->bit_idx >= 8)
        {
-               if ((af->hdlc_currchar == HDLC_FLAG
-                       || af->hdlc_currchar == HDLC_RESET
-                       || af->hdlc_currchar == AX25_ESC))
+               if ((hdlc->currchar == HDLC_FLAG
+                       || hdlc->currchar == HDLC_RESET
+                       || hdlc->currchar == AX25_ESC))
                {
-                       if (!fifo_isfull(&af->rx_fifo))
-                               fifo_push(&af->rx_fifo, AX25_ESC);
+                       if (!fifo_isfull(fifo))
+                               fifo_push(fifo, AX25_ESC);
                        else
-                               af->hdlc_rxstart = false;
+                       {
+                               hdlc->rxstart = false;
+                               ret = false;
+                       }
                }
 
-               if (!fifo_isfull(&af->rx_fifo))
-                       fifo_push(&af->rx_fifo, af->hdlc_currchar);
+               if (!fifo_isfull(fifo))
+                       fifo_push(fifo, hdlc->currchar);
                else
-                       af->hdlc_rxstart = false;
+               {
+                       hdlc->rxstart = false;
+                       ret = false;
+               }
 
-               af->hdlc_currchar = 0;
-               af->hdlc_bit_idx = 0;
-               return;
+               hdlc->currchar = 0;
+               hdlc->bit_idx = 0;
        }
+       else
+               hdlc->currchar >>= 1;
 
-       af->hdlc_currchar >>= 1;
+       return ret;
 }
 
+
+/**
+ * ADC ISR callback.
+ * This function has to be called by the ADC ISR when a sample of the configured
+ * channel is available.
+ * \param af Afsk context to operate on.
+ * \param curr_sample current sample from the ADC.
+ */
 void afsk_adc_isr(Afsk *af, int8_t curr_sample)
 {
        AFSK_STROBE_ON();
@@ -254,7 +294,9 @@ void afsk_adc_isr(Afsk *af, int8_t curr_sample)
                 * 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.
+                * This algorithm presumes that there are 8 samples per bit.
                 */
+               STATIC_ASSERT(SAMPLEPERBIT == 8);
                uint8_t bits = af->sampled_bits & 0x07;
                if (bits == 0x07 // 111, 3 bits set to 1
                 || bits == 0x06 // 110, 2 bits
@@ -267,12 +309,12 @@ void afsk_adc_isr(Afsk *af, int8_t curr_sample)
                 * NRZI coding: if 2 consecutive bits have the same value
                 * a 1 is received, otherwise it's a 0.
                 */
-               hdlc_parse(af, !EDGE_FOUND(af->found_bits));
+               if (!hdlc_parse(&af->hdlc, !EDGE_FOUND(af->found_bits), &af->rx_fifo))
+                       af->status |= AFSK_RXFIFO_OVERRUN;
        }
 
 
        AFSK_STROBE_OFF();
-       AFSK_ADC_IRQ_END();
 }
 
 static void afsk_txStart(Afsk *af)
@@ -284,7 +326,7 @@ static void afsk_txStart(Afsk *af)
                af->stuff_cnt = 0;
                af->sending = true;
                af->preamble_len = DIV_ROUND(CONFIG_AFSK_PREAMBLE_LEN * BITRATE, 8000);
-               AFSK_DAC_IRQ_START();
+               AFSK_DAC_IRQ_START(af->dac_ch);
        }
        ATOMIC(af->trailer_len  = DIV_ROUND(CONFIG_AFSK_TRAILER_LEN  * BITRATE, 8000));
 }
@@ -293,8 +335,19 @@ static void afsk_txStart(Afsk *af)
 
 #define SWITCH_TONE(inc)  (((inc) == MARK_INC) ? SPACE_INC : MARK_INC)
 
-void afsk_dac_isr(Afsk *af)
+/**
+ * DAC ISR callback.
+ * This function has to be called by the DAC ISR when a sample of the configured
+ * channel has been converted out.
+ *
+ * \param af Afsk context to operate on.
+ *
+ * \return The next DAC output sample.
+ */
+uint8_t afsk_dac_isr(Afsk *af)
 {
+       AFSK_STROBE_ON();
+
        /* Check if we are at a start of a sample cycle */
        if (af->sample_count == 0)
        {
@@ -303,15 +356,15 @@ void afsk_dac_isr(Afsk *af)
                        /* We have just finished transimitting a char, get a new one. */
                        if (fifo_isempty(&af->tx_fifo) && af->trailer_len == 0)
                        {
-                               AFSK_DAC_IRQ_STOP();
+                               AFSK_DAC_IRQ_STOP(af->dac_ch);
                                af->sending = false;
-                               AFSK_DAC_IRQ_END();
-                               return;
+                               AFSK_STROBE_OFF();
+                               return 0;
                        }
                        else
                        {
                                /*
-                                * If we have just finished af->sending an unstuffed byte,
+                                * If we have just finished sending an unstuffed byte,
                                 * reset bitstuff counter.
                                 */
                                if (!af->bit_stuff)
@@ -343,10 +396,10 @@ void afsk_dac_isr(Afsk *af)
                                {
                                        if (fifo_isempty(&af->tx_fifo))
                                        {
-                                               AFSK_DAC_IRQ_STOP();
+                                               AFSK_DAC_IRQ_STOP(af->dac_ch);
                                                af->sending = false;
-                                               AFSK_DAC_IRQ_END();
-                                               return;
+                                               AFSK_STROBE_OFF();
+                                               return 0;
                                        }
                                        else
                                                af->curr_out = fifo_pop(&af->tx_fifo);
@@ -378,7 +431,7 @@ void afsk_dac_isr(Afsk *af)
                                /*
                                 * Transmit a 1:
                                 * - Stay on the previous tone
-                                * - Increace bit stuff count
+                                * - Increase bit stuff counter
                                 */
                                af->stuff_cnt++;
                        }
@@ -386,7 +439,7 @@ void afsk_dac_isr(Afsk *af)
                        {
                                /*
                                 * Transmit a 0:
-                                * - Reset bit stuff count
+                                * - Reset bit stuff counter
                                 * - Switch tone
                                 */
                                af->stuff_cnt = 0;
@@ -403,9 +456,9 @@ void afsk_dac_isr(Afsk *af)
        af->phase_acc += af->phase_inc;
        af->phase_acc %= SIN_LEN;
 
-       AFSK_SET_DAC(sin_sample(af->phase_acc));
        af->sample_count--;
-       AFSK_DAC_IRQ_END();
+       AFSK_STROBE_OFF();
+       return sin_sample(af->phase_acc);
 }
 
 
@@ -464,13 +517,36 @@ static int afsk_flush(KFile *fd)
        return 0;
 }
 
+static int afsk_error(KFile *fd)
+{
+       Afsk *af = AFSK_CAST(fd);
+       int err;
 
-void afsk_init(Afsk *af)
+       ATOMIC(err = af->status);
+       return err;
+}
+
+static void afsk_clearerr(KFile *fd)
+{
+       Afsk *af = AFSK_CAST(fd);
+       ATOMIC(af->status = 0);
+}
+
+
+/**
+ * Initialize an AFSK1200 modem.
+ * \param af Afsk context to operate on.
+ * \param adc_ch  ADC channel used by the demodulator.
+ * \param dac_ch  DAC channel used by the modulator.
+ */
+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(&af->delay_fifo, (uint8_t *)af->delay_buf, sizeof(af->delay_buf));
        fifo_init(&af->rx_fifo, af->rx_buf, sizeof(af->rx_buf));
@@ -481,13 +557,16 @@ void afsk_init(Afsk *af)
 
        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);
+       LOG_INFO("MARK_INC %d, SPACE_INC %d\n", MARK_INC, SPACE_INC);
 
        DB(af->fd._type = KFT_AFSK);
        af->fd.write = afsk_write;
        af->fd.read = afsk_read;
        af->fd.flush = afsk_flush;
+       af->fd.error = afsk_error;
+       af->fd.clearerr = afsk_clearerr;
        af->phase_inc = MARK_INC;
 }