示例#1
0
/*
 * ISR for DMA mode Tx
 */
void rt_hw_serial_dma_tx_isr(struct rt_serial_device *serial)
{
    const void *data_ptr;
    rt_size_t data_size;

    if (RT_EOK == rt_data_queue_pop(&(serial->tx_dq), &data_ptr, &data_size, 0))
    {
        /* transmit next data node */
        serial->ops->dma_transmit(serial, data_ptr, data_size);
    }
    else
    {
        serial->dma_flag = RT_FALSE;
    }

    /* invoke callback */
    if (serial->parent.tx_complete != RT_NULL)
    {
        serial->parent.tx_complete(&serial->parent, RT_NULL);
    }
}
/* ISR for serial interrupt */
void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
{
    switch (event & 0xff)
    {
        case RT_SERIAL_EVENT_RX_IND:
        {
            int ch = -1;
            rt_base_t level;
            struct rt_serial_rx_fifo* rx_fifo;

            /* interrupt mode receive */
            rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
            RT_ASSERT(rx_fifo != RT_NULL);

            while (1)
            {
                ch = serial->ops->getc(serial);
                if (ch == -1) break;

                
                /* disable interrupt */
                level = rt_hw_interrupt_disable();
                
                rx_fifo->buffer[rx_fifo->put_index] = ch;
                rx_fifo->put_index += 1;
                if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;
                
                /* if the next position is read index, discard this 'read char' */
                if (rx_fifo->put_index == rx_fifo->get_index)
                {
                    rx_fifo->get_index += 1;
                    if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
                }
                
                /* enable interrupt */
                rt_hw_interrupt_enable(level);
            }
            
            /* invoke callback */
            if (serial->parent.rx_indicate != RT_NULL)
            {
                rt_size_t rx_length;
            
                /* get rx length */
                level = rt_hw_interrupt_disable();
                rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
                    (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));
                rt_hw_interrupt_enable(level);

                serial->parent.rx_indicate(&serial->parent, rx_length);
            }
            break;
        }
        case RT_SERIAL_EVENT_TX_DONE:
        {
            struct rt_serial_tx_fifo* tx_fifo;

            tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx;
            rt_completion_done(&(tx_fifo->completion));
            break;
        }
        case RT_SERIAL_EVENT_TX_DMADONE:
        {
            const void *data_ptr;
            rt_size_t data_size;
            const void *last_data_ptr;
            struct rt_serial_tx_dma* tx_dma;

            tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx;
            
            rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0);
            if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK)
            {
                /* transmit next data node */
                tx_dma->activated = RT_TRUE;
                serial->ops->dma_transmit(serial, data_ptr, data_size, RT_SERIAL_DMA_TX);
            }
            else
            {
                tx_dma->activated = RT_FALSE;
            }
            
            /* invoke callback */
            if (serial->parent.tx_complete != RT_NULL)
            {
                serial->parent.tx_complete(&serial->parent, (void*)last_data_ptr);
            }
            break;
        }
        case RT_SERIAL_EVENT_RX_DMADONE:
        {
            int length;
            struct rt_serial_rx_dma* rx_dma;

            rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx;
            /* get DMA rx length */
            length = (event & (~0xff)) >> 8;
            serial->parent.rx_indicate(&(serial->parent), length);
            rx_dma->activated = RT_FALSE;
            break;
        }
    }
}
示例#3
0
static rt_size_t rt_serial_write(struct rt_device *dev,
                                 rt_off_t          pos,
                                 const void       *buffer,
                                 rt_size_t         size)
{
    rt_uint8_t *ptr;
    rt_size_t write_nbytes = 0;
    struct rt_serial_device *serial;

    RT_ASSERT(dev != RT_NULL);
    serial = (struct rt_serial_device *)dev;

    ptr = (rt_uint8_t*)buffer;

    if (dev->flag & RT_DEVICE_FLAG_INT_TX)
    {
        /* warning: data will be discarded if buffer is full */
        while (size)
        {
            if (serial_ringbuffer_putchar(serial->int_tx, *ptr) != -1)
            {
                ptr ++;
                size --;
            }
            else
                break;
        }
    }
    else if (dev->flag & RT_DEVICE_FLAG_DMA_TX)
    {
        const void *data_ptr = RT_NULL;
        rt_size_t data_size = 0;
        rt_base_t level;
        rt_err_t result;
        
        RT_ASSERT(0 == (dev->flag & RT_DEVICE_FLAG_STREAM));

        result = rt_data_queue_push(&(serial->tx_dq), buffer, size, 20); 
        if (result == RT_EOK)
        {
            level = rt_hw_interrupt_disable();
            if (serial->dma_flag == RT_FALSE)
            {
                serial->dma_flag = RT_TRUE;
                rt_hw_interrupt_enable(level);
            
                if (RT_EOK == rt_data_queue_pop(&(serial->tx_dq), &data_ptr, &data_size, 0))
                {
                    serial->ops->dma_transmit(serial, data_ptr, data_size);
                }
            }
            else
                rt_hw_interrupt_enable(level);

            return size;
        }
        else
        {
            rt_set_errno(result);

            return 0;
        }
    }
    else
    {
        /* polling mode */
        while (size)
        {
            /*
             * to be polite with serial console add a line feed
             * to the carriage return character
             */
            if (*ptr == '\n' && (dev->flag & RT_DEVICE_FLAG_STREAM))
            {
                serial->ops->putc(serial, '\r');
            }

            serial->ops->putc(serial, *ptr);

            ++ ptr;
            -- size;
        }
    }

    write_nbytes = (rt_uint32_t)ptr - (rt_uint32_t)buffer;
    if (write_nbytes == 0)
    {
        rt_set_errno(-RT_EFULL);
    }

    return write_nbytes;
}