|
- // Copyright 2009 Olivier Gillet.
- //
- // Author: Olivier Gillet (ol.gillet@gmail.com)
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- // 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 General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- // -----------------------------------------------------------------------------
- //
- // Fast serial (for the onboard UART), using compile time optimizations.
- //
- // Can be used in buffered mode, or in polled mode (to save space or avoid
- // interruptions if there is an even higher priority task than the serial I/O).
- //
- // Usage:
- //
- // Set-up:
- // typedef Serial<SerialPort0, 31250, BUFFERED, POLLED> Serial;
- // then, in the setup() hook: Serial::Init()
- //
- // Write:
- // Serial::Write(40) // Will block until data is written.
- // write_has_succeeded = Serial::NonBlockingWrite(40) // Will not block.
- //
- // Buffer manipulation (for buffered I/O):
- // Serial::available() // Number of bytes ready to be read. For polled read too
- // my_value = Serial::Read() // Will wait until data arrives.
- // my_value = Serial::NonBlockingRead() // Will return -1 if no data is there.
- // my_value = Serial::ImmediateRead() // Assumes you are sure about what you
- // are doing and you know that data is here.
- //
- // Flushing a buffer:
- // Serial::InputBuffer::Flush()
- //
- // TODO(pichenettes): Buffered writes not supported for now (should look up
- // the right interrupt handler).
-
- #ifndef AVRLIB_SERIAL_H_
- #define AVRLIB_SERIAL_H_
-
- #include "avrlib/avrlib.h"
- #include "avrlib/gpio.h"
- #include "avrlib/ring_buffer.h"
-
- namespace avrlib {
-
- const uint8_t kSerialOutputBufferSize = 32;
- const uint8_t kSerialInputBufferSize = 32;
-
- // Low-level interface to the low-level UART registers. Several specializations
- // may be declared for each serial port. This class could theoretically be used
- // for non-blocking write or polling reads.
- template<typename TxEnableBit, typename TxReadyBit,
- typename RxEnableBit, typename RxReadyBit,
- typename RxInterruptBit,
- typename TurboBit,
- typename PrescalerRegisterH, typename PrescalerRegisterL,
- typename DataRegister,
- uint8_t input_buffer_size_,
- uint8_t output_buffer_size_>
- struct SerialPort {
- typedef TxEnableBit Tx;
- typedef RxEnableBit Rx;
- typedef RxInterruptBit RxInterrupt;
- typedef TurboBit Turbo;
- enum {
- input_buffer_size = input_buffer_size_,
- output_buffer_size = output_buffer_size_
- };
- static inline void set_prescaler(uint16_t value) {
- *PrescalerRegisterH::ptr() = value >> 8;
- *PrescalerRegisterL::ptr() = value;
- }
- static inline uint8_t tx_ready() { return TxReadyBit::value(); }
- static inline uint8_t rx_ready() { return RxReadyBit::value(); }
- static inline uint8_t data() { return *DataRegister::ptr(); }
- static inline void set_data(uint8_t value) { *DataRegister::ptr() = value; }
- };
-
- template<typename SerialPort>
- struct SerialInput : public Input {
- enum {
- buffer_size = SerialPort::input_buffer_size,
- data_size = 8
- };
- typedef uint8_t Value;
-
- // Blocking!
- static inline Value Read() { while (!readable()); return ImmediateRead(); }
-
- // Number of bytes available for read.
- static inline uint8_t readable() { return SerialPort::rx_ready(); }
-
- // A byte, or -1 if reading failed.
- static inline int16_t NonBlockingRead() { return readable() ? Read() : -1; }
-
- // No check for ready state.
- static inline Value ImmediateRead() { return SerialPort::data(); }
-
- // Called in data reception interrupt.
- static inline void Received() {
- if (!readable()) {
- return;
- }
- // This will discard data if the buffer is full.
- RingBuffer<SerialInput<SerialPort> >::NonBlockingWrite(ImmediateRead());
- }
- };
-
- template<typename SerialPort>
- struct SerialOutput : public Output {
- enum {
- buffer_size = SerialPort::output_buffer_size,
- data_size = 8
- };
- typedef uint8_t Value;
-
- // Blocking!
- static inline void Write(Value v) { while (!writable()); Overwrite(v); }
-
- // Number of bytes that can be fed.
- static inline uint8_t writable() { return SerialPort::tx_ready(); }
-
- // 1 if success.
- static inline uint8_t NonBlockingWrite(Value v) {
- if (!writable()) {
- return 0;
- }
- Overwrite(v);
- return 1;
- }
-
- // No check for ready state.
- static inline void Overwrite(Value v) { SerialPort::set_data(v); }
-
- // Called in data emission interrupt.
- static inline Value Requested() {
- Value v = RingBuffer<SerialOutput<SerialPort> >::NonBlockingRead();
- if (v >= 0) {
- Overwrite(v);
- }
- }
- };
-
- template<typename SerialPort, PortMode input = POLLED, PortMode output = POLLED>
- struct SerialImplementation { };
-
- template<typename SerialPort>
- struct SerialImplementation<SerialPort, DISABLED, DISABLED> {
- typedef InputOutput<DisabledInput, DisabledOutput> IO;
- };
- template<typename SerialPort>
- struct SerialImplementation<SerialPort, DISABLED, POLLED> {
- typedef InputOutput<DisabledInput, SerialOutput<SerialPort> > IO;
- };
- template<typename SerialPort>
- struct SerialImplementation<SerialPort, DISABLED, BUFFERED> {
- typedef RingBuffer<SerialOutput<SerialPort> > OutputBuffer;
- typedef InputOutput<DisabledInput, OutputBuffer > IO;
- };
- template<typename SerialPort>
- struct SerialImplementation<SerialPort, POLLED, DISABLED> {
- typedef InputOutput<SerialInput<SerialPort>, DisabledOutput> IO;
- };
- template<typename SerialPort>
- struct SerialImplementation<SerialPort, POLLED, POLLED> {
- typedef InputOutput<SerialInput<SerialPort>, SerialOutput<SerialPort> > IO;
- };
- template<typename SerialPort>
- struct SerialImplementation<SerialPort, POLLED, BUFFERED> {
- typedef RingBuffer<SerialOutput<SerialPort> > OutputBuffer;
- typedef InputOutput<SerialInput<SerialPort>, OutputBuffer> IO;
- };
- template<typename SerialPort>
- struct SerialImplementation<SerialPort, BUFFERED, DISABLED> {
- typedef RingBuffer<SerialInput<SerialPort> > InputBuffer;
- typedef InputOutput<InputBuffer, DisabledOutput> IO;
- };
- template<typename SerialPort>
- struct SerialImplementation<SerialPort, BUFFERED, POLLED> {
- typedef RingBuffer<SerialInput<SerialPort> > InputBuffer;
- typedef InputOutput<InputBuffer, SerialOutput<SerialPort> > IO;
- };
- template<typename SerialPort>
- struct SerialImplementation<SerialPort, BUFFERED, BUFFERED> {
- typedef RingBuffer<SerialInput<SerialPort> > InputBuffer;
- typedef RingBuffer<SerialOutput<SerialPort> > OutputBuffer;
- typedef InputOutput<InputBuffer, OutputBuffer> IO;
- };
-
- template<typename SerialPort, uint32_t baud_rate, PortMode input = POLLED,
- PortMode output = POLLED, bool turbo = false>
- struct Serial {
- typedef SerialImplementation<SerialPort, input, output> Impl;
- typedef uint8_t Value;
- typedef typename Impl::IO::Input Input;
- typedef typename Impl::IO::Output Output;
- static inline void Init() {
- Init<baud_rate>();
- }
- template<uint32_t new_baud_rate>
- static inline void Init() {
- if (turbo) {
- SerialPort::Turbo::set();
- uint16_t prescaler = F_CPU / (8L * baud_rate) - 1;
- SerialPort::set_prescaler(prescaler);
- } else {
- SerialPort::Turbo::clear();
- uint16_t prescaler = F_CPU / (16 * baud_rate) - 1;
- SerialPort::set_prescaler(prescaler);
- }
- if (output != DISABLED) {
- SerialPort::Tx::set();
- }
- if (input != DISABLED) {
- SerialPort::Rx::set();
- }
- if (input == BUFFERED) {
- SerialPort::RxInterrupt::set();
- }
- }
-
- static inline void Disable() {
- SerialPort::Tx::clear();
- SerialPort::Rx::clear();
- SerialPort::RxInterrupt::clear();
- }
-
- static inline void Write(Value v) { Impl::IO::Write(v); }
- static inline uint8_t writable() { return Impl::IO::writable(); }
- static inline uint8_t NonBlockingWrite(Value v) {
- return Impl::IO::NonBlockingWrite(v);
- }
- static inline void Overwrite(Value v) { Impl::IO::Overwrite(v); }
- static inline Value Read() { return Impl::IO::Read(); }
- static inline uint8_t readable() { return Impl::IO::readable(); }
- static inline int16_t NonBlockingRead() {
- return Impl::IO::NonBlockingRead();
- }
- static inline Value ImmediateRead() { return Impl::IO::ImmediateRead(); }
- };
-
-
- #ifdef HAS_USART0
-
- IORegister(UBRR0H);
- IORegister(UBRR0L);
- IORegister16(UBRR0);
- IORegister(UCSR0A);
- IORegister(UCSR0B);
- IORegister(UCSR0C);
- IORegister(UDR0);
-
- typedef SerialPort<
- BitInRegister<UCSR0BRegister, TXEN0>,
- BitInRegister<UCSR0ARegister, UDRE0>,
- BitInRegister<UCSR0BRegister, RXEN0>,
- BitInRegister<UCSR0ARegister, RXC0>,
- BitInRegister<UCSR0BRegister, RXCIE0>,
- BitInRegister<UCSR0ARegister, U2X0>,
- UBRR0HRegister,
- UBRR0LRegister,
- UDR0Register,
- kSerialOutputBufferSize,
- kSerialInputBufferSize> SerialPort0;
-
- #endif // #ifdef HAS_USART0
-
-
- #ifdef HAS_USART1
-
- IORegister(UBRR1H);
- IORegister(UBRR1L);
- IORegister16(UBRR1);
- IORegister(UCSR1A);
- IORegister(UCSR1B);
- IORegister(UCSR1C);
- IORegister(UDR1);
-
- typedef SerialPort<
- BitInRegister<UCSR1BRegister, TXEN1>,
- BitInRegister<UCSR1ARegister, UDRE1>,
- BitInRegister<UCSR1BRegister, RXEN1>,
- BitInRegister<UCSR1ARegister, RXC1>,
- BitInRegister<UCSR1BRegister, RXCIE1>,
- BitInRegister<UCSR1ARegister, U2X1>,
- UBRR1HRegister,
- UBRR1LRegister,
- UDR1Register,
- kSerialOutputBufferSize,
- kSerialInputBufferSize> SerialPort1;
-
- #endif // #ifdef HAS_USART1
-
-
- #ifdef HAS_USART2
-
- IORegister(UBRR2H);
- IORegister(UBRR2L);
- IORegister16(UBRR2);
- IORegister(UCSR2A);
- IORegister(UCSR2B);
- IORegister(UCSR2C);
- IORegister(UDR2);
-
- typedef SerialPort<
- BitInRegister<UCSR2BRegister, TXEN2>,
- BitInRegister<UCSR2ARegister, UDRE2>,
- BitInRegister<UCSR2BRegister, RXEN2>,
- BitInRegister<UCSR2ARegister, RXC2>,
- BitInRegister<UCSR2BRegister, RXCIE2>,
- BitInRegister<UCSR2ARegister, U2X2>,
- UBRR2HRegister,
- UBRR2LRegister,
- UDR2Register,
- kSerialOutputBufferSize,
- kSerialInputBufferSize> SerialPort2;
-
- #endif // #ifdef HAS_USART2
-
- #ifdef HAS_USART3
-
- IORegister(UBRR3H);
- IORegister(UBRR3L);
- IORegister16(UBRR3);
- IORegister(UCSR3A);
- IORegister(UCSR3B);
- IORegister(UCSR3C);
- IORegister(UDR3);
-
- typedef SerialPort<
- BitInRegister<UCSR3BRegister, TXEN3>,
- BitInRegister<UCSR3ARegister, UDRE3>,
- BitInRegister<UCSR3BRegister, RXEN3>,
- BitInRegister<UCSR3ARegister, RXC3>,
- BitInRegister<UCSR3BRegister, RXCIE3>,
- BitInRegister<UCSR3ARegister, U2X3>,
- UBRR3HRegister,
- UBRR3LRegister,
- UDR3Register,
- kSerialOutputBufferSize,
- kSerialInputBufferSize> SerialPort3;
-
- #endif // #ifdef HAS_USART3
-
- } // namespace avrlib
-
-
- #endif // AVRLIB_SERIAL_H_
|