-#include <cfg/macros.h> /* DIV_ROUND */
-#include <cfg/debug.h>
-#include <cfg/cfg_arch.h> // ARCH_NIGHTTEST
-
-#include <drv/ser.h>
-#include <drv/ser_p.h>
-#include <drv/timer.h>
-
-#include <struct/fifobuf.h>
-
-#include <avr/io.h>
-
-#if defined(__AVR_LIBC_VERSION__) && (__AVR_LIBC_VERSION__ >= 10400UL)
- #include <avr/interrupt.h>
-#else
- #include <avr/signal.h>
-#endif
-
-
-#if !CONFIG_SER_HWHANDSHAKE
- /**
- * \name Hardware handshake (RTS/CTS).
- * \{
- */
- #define RTS_ON do {} while (0)
- #define RTS_OFF do {} while (0)
- #define IS_CTS_ON true
- #define EIMSKF_CTS 0 /**< Dummy value, must be overridden */
- /*\}*/
-#endif
-
-#if CPU_AVR_ATMEGA1281
- #define BIT_RXCIE0 RXCIE0
- #define BIT_RXEN0 RXEN0
- #define BIT_TXEN0 TXEN0
- #define BIT_UDRIE0 UDRIE0
-
- #define BIT_RXCIE1 RXCIE1
- #define BIT_RXEN1 RXEN1
- #define BIT_TXEN1 TXEN1
- #define BIT_UDRIE1 UDRIE1
-#elif CPU_AVR_ATMEGA168 || CPU_AVR_ATMEGA328P
- #define BIT_RXCIE0 RXCIE0
- #define BIT_RXEN0 RXEN0
- #define BIT_TXEN0 TXEN0
- #define BIT_UDRIE0 UDRIE0
-
- #define BIT_RXCIE1 RXCIE0
- #define BIT_RXEN1 RXEN0
- #define BIT_TXEN1 TXEN0
- #define BIT_UDRIE1 UDRIE0
-#else
- #define BIT_RXCIE0 RXCIE
- #define BIT_RXEN0 RXEN
- #define BIT_TXEN0 TXEN
- #define BIT_UDRIE0 UDRIE
-
- #define BIT_RXCIE1 RXCIE
- #define BIT_RXEN1 RXEN
- #define BIT_TXEN1 TXEN
- #define BIT_UDRIE1 UDRIE
-#endif
-
-
-/**
- * \name Overridable serial bus hooks
- *
- * These can be redefined in hw.h to implement
- * special bus policies such as half-duplex, 485, etc.
- *
- *
- * \code
- * TXBEGIN TXCHAR TXEND TXOFF
- * | __________|__________ | |
- * | | | | | | | | |
- * v v v v v v v v v
- * ______ __ __ __ __ __ __ ________________
- * \/ \/ \/ \/ \/ \/ \/
- * ______/\__/\__/\__/\__/\__/\__/
- *
- * \endcode
- *
- * \{
- */
-#ifndef SER_UART0_BUS_TXINIT
- /**
- * Default TXINIT macro - invoked in uart0_init()
- *
- * - Enable both the receiver and the transmitter
- * - Enable only the RX complete interrupt
- */
- #define SER_UART0_BUS_TXINIT do { \
- UCSR0B = BV(BIT_RXCIE0) | BV(BIT_RXEN0) | BV(BIT_TXEN0); \
- } while (0)
-#endif
-
-#ifndef SER_UART0_BUS_TXBEGIN
- /**
- * Invoked before starting a transmission
- *
- * - Enable both the receiver and the transmitter
- * - Enable both the RX complete and UDR empty interrupts
- */
- #define SER_UART0_BUS_TXBEGIN do { \
- UCSR0B = BV(BIT_RXCIE0) | BV(BIT_UDRIE0) | BV(BIT_RXEN0) | BV(BIT_TXEN0); \
- } while (0)
-#endif
-
-#ifndef SER_UART0_BUS_TXCHAR
- /**
- * Invoked to send one character.
- */
- #define SER_UART0_BUS_TXCHAR(c) do { \
- UDR0 = (c); \
- } while (0)
-#endif
-
-#ifndef SER_UART0_BUS_TXEND
- /**
- * Invoked as soon as the txfifo becomes empty
- *
- * - Keep both the receiver and the transmitter enabled
- * - Keep the RX complete interrupt enabled
- * - Disable the UDR empty interrupt
- */
- #define SER_UART0_BUS_TXEND do { \
- UCSR0B = BV(BIT_RXCIE0) | BV(BIT_RXEN0) | BV(BIT_TXEN0); \
- } while (0)
-#endif
-
-#ifndef SER_UART0_BUS_TXOFF
- /**
- * \def SER_UART0_BUS_TXOFF
- *
- * Invoked after the last character has been transmitted
- *
- * The default is no action.
- */
- #ifdef __doxygen__
- #define SER_UART0_BUS_TXOFF
- #endif
-#endif
-
-#ifndef SER_UART1_BUS_TXINIT
- /** \sa SER_UART0_BUS_TXINIT */
- #define SER_UART1_BUS_TXINIT do { \
- UCSR1B = BV(BIT_RXCIE1) | BV(BIT_RXEN1) | BV(BIT_TXEN1); \
- } while (0)
-#endif
-#ifndef SER_UART1_BUS_TXBEGIN
- /** \sa SER_UART0_BUS_TXBEGIN */
- #define SER_UART1_BUS_TXBEGIN do { \
- UCSR1B = BV(BIT_RXCIE1) | BV(BIT_UDRIE1) | BV(BIT_RXEN1) | BV(BIT_TXEN1); \
- } while (0)
-#endif
-#ifndef SER_UART1_BUS_TXCHAR
- /** \sa SER_UART0_BUS_TXCHAR */
- #define SER_UART1_BUS_TXCHAR(c) do { \
- UDR1 = (c); \
- } while (0)
-#endif
-#ifndef SER_UART1_BUS_TXEND
- /** \sa SER_UART0_BUS_TXEND */
- #define SER_UART1_BUS_TXEND do { \
- UCSR1B = BV(BIT_RXCIE1) | BV(BIT_RXEN1) | BV(BIT_TXEN1); \
- } while (0)
-#endif
-#ifndef SER_UART1_BUS_TXOFF
- /**
- * \def SER_UART1_BUS_TXOFF
- *
- * \see SER_UART0_BUS_TXOFF
- */
- #ifdef __doxygen__
- #define SER_UART1_BUS_TXOFF
- #endif
-#endif
-/*\}*/
-
-
-/**
- * \name Overridable SPI hooks
- *
- * These can be redefined in hw.h to implement
- * special bus policies such as slave select pin handling, etc.
- *
- * \{
- */
-#ifndef SER_SPI_BUS_TXINIT
- /**
- * Default TXINIT macro - invoked in spi_init()
- * The default is no action.
- */
- #define SER_SPI_BUS_TXINIT
-#endif
-
-#ifndef SER_SPI_BUS_TXCLOSE
- /**
- * Invoked after the last character has been transmitted.
- * The default is no action.
- */
- #define SER_SPI_BUS_TXCLOSE
-#endif
-/*\}*/
-
-
-/* SPI port and pin configuration */
-#if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA103 || CPU_AVR_ATMEGA1281
- #define SPI_PORT PORTB
- #define SPI_DDR DDRB
- #define SPI_SS_BIT PB0
- #define SPI_SCK_BIT PB1
- #define SPI_MOSI_BIT PB2
- #define SPI_MISO_BIT PB3
-// TODO: these bits are the same as ATMEGA8 but the defines in avr-gcc are different.
-// They should be the same!
-#elif CPU_AVR_ATMEGA328P
- #define SPI_PORT PORTB
- #define SPI_DDR DDRB
- #define SPI_SS_BIT PORTB2
- #define SPI_SCK_BIT PORTB5
- #define SPI_MOSI_BIT PORTB3
- #define SPI_MISO_BIT PORTB4
-#elif CPU_AVR_ATMEGA8 || CPU_AVR_ATMEGA168
- #define SPI_PORT PORTB
- #define SPI_DDR DDRB
- #define SPI_SS_BIT PB2
- #define SPI_SCK_BIT PB5
- #define SPI_MOSI_BIT PB3
- #define SPI_MISO_BIT PB4
-#else
- #error Unknown architecture
-#endif
-
-/* USART register definitions */
-#if CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA1281
- #define AVR_HAS_UART1 1
-#elif CPU_AVR_ATMEGA168 || CPU_AVR_ATMEGA328P
- #define AVR_HAS_UART1 0
- #define USART0_UDRE_vect USART_UDRE_vect
- #define USART0_RX_vect USART_RX_vect
- #define SIG_UART0_TRANS SIG_UART_TRANS
-#elif CPU_AVR_ATMEGA8
- #define AVR_HAS_UART1 0
- #define UCSR0A UCSRA
- #define UCSR0B UCSRB
- #define UCSR0C UCSRC
- #define UDR0 UDR
- #define UBRR0L UBRRL
- #define UBRR0H UBRRH
-/* TODO: The following SIGs are old style interrupts, must be refactored */
- #define SIG_UART0_DATA SIG_UART_DATA
- #define SIG_UART0_RECV SIG_UART_RECV
- #define SIG_UART0_TRANS SIG_UART_TRANS
-#elif CPU_AVR_ATMEGA103
- #define AVR_HAS_UART1 0
- #define UCSR0B UCR
- #define UDR0 UDR
- #define UCSR0A USR
- #define UBRR0L UBRR
-/* TODO: The following SIGs are old style interrupts, must be refactored */
- #define SIG_UART0_DATA SIG_UART_DATA
- #define SIG_UART0_RECV SIG_UART_RECV
- #define SIG_UART0_TRANS SIG_UART_TRANS
-#else
- #error Unknown architecture
-#endif
-
-
-/* From the high-level serial driver */
-extern struct Serial *ser_handles[SER_CNT];
-
-/* TX and RX buffers */
-static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
-static unsigned char uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
-#if AVR_HAS_UART1
- static unsigned char uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
- static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
-#endif
-static unsigned char spi_txbuffer[CONFIG_SPI_TXBUFSIZE];
-static unsigned char spi_rxbuffer[CONFIG_SPI_RXBUFSIZE];
-
-
-/**
- * Internal hardware state structure
- *
- * The \a sending variable is true while the transmission
- * interrupt is retriggering itself.
- *
- * For the USARTs the \a sending flag is useful for taking specific
- * actions before sending a burst of data, at the start of a trasmission
- * but not before every char sent.
- *
- * For the SPI, this flag is necessary because the SPI sends and receives
- * bytes at the same time and the SPI IRQ is unique for send/receive.
- * The only way to start transmission is to write data in SPDR (this
- * is done by spi_starttx()). We do this *only* if a transfer is
- * not already started.
- */
-struct AvrSerial
-{
- struct SerialHardware hw;
- volatile bool sending;
-};
-
-
-
-/*
- * Callbacks
- */
-static void uart0_init(
- UNUSED_ARG(struct SerialHardware *, _hw),
- UNUSED_ARG(struct Serial *, ser))
-{
- SER_UART0_BUS_TXINIT;
- RTS_ON;
- SER_STROBE_INIT;
-}
-
-static void uart0_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
-{
- UCSR0B = 0;
-}
-
-static void uart0_enabletxirq(struct SerialHardware *_hw)
-{
- struct AvrSerial *hw = (struct AvrSerial *)_hw;
-
- /*
- * WARNING: racy code here! The tx interrupt sets hw->sending to false
- * when it runs with an empty fifo. The order of statements in the
- * if-block matters.
- */
- if (!hw->sending)
- {
- hw->sending = true;
- SER_UART0_BUS_TXBEGIN;
- }
-}
-
-static void uart0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
-{
- /* Compute baud-rate period */
- uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1;
-
-#if !CPU_AVR_ATMEGA103
- UBRR0H = (period) >> 8;
-#endif
- UBRR0L = (period);
-
- //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
-}
-
-static void uart0_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
-{
-#if !CPU_AVR_ATMEGA103
- UCSR0C = (UCSR0C & ~(BV(UPM01) | BV(UPM00))) | ((parity) << UPM00);
-#endif
-}
-
-#if AVR_HAS_UART1
-
-static void uart1_init(
- UNUSED_ARG(struct SerialHardware *, _hw),
- UNUSED_ARG(struct Serial *, ser))
-{
- SER_UART1_BUS_TXINIT;
- RTS_ON;
- SER_STROBE_INIT;
-}
-
-static void uart1_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
-{
- UCSR1B = 0;
-}
-
-static void uart1_enabletxirq(struct SerialHardware *_hw)
-{
- struct AvrSerial *hw = (struct AvrSerial *)_hw;
-
- /*
- * WARNING: racy code here! The tx interrupt
- * sets hw->sending to false when it runs with
- * an empty fifo. The order of the statements
- * in the if-block matters.
- */
- if (!hw->sending)
- {
- hw->sending = true;
- SER_UART1_BUS_TXBEGIN;
- }
-}
-
-static void uart1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
-{
- /* Compute baud-rate period */
- uint16_t period = DIV_ROUND(CPU_FREQ / 16UL, rate) - 1;
-
- UBRR1H = (period) >> 8;
- UBRR1L = (period);
-
- //DB(kprintf("uart1_setbaudrate(rate=%ld): period=%d\n", rate, period);)
-}
-
-static void uart1_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
-{
- UCSR1C = (UCSR1C & ~(BV(UPM11) | BV(UPM10))) | ((parity) << UPM10);
-}
-
-#endif // AVR_HAS_UART1
-
-static void spi_init(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(struct Serial *, ser))
-{
- /*
- * Set MOSI and SCK ports out, MISO in.
- *
- * The ATmega64/128 datasheet explicitly states that the input/output
- * state of the SPI pins is not significant, as when the SPI is
- * active the I/O port are overrided.
- * This is *blatantly FALSE*.
- *
- * Moreover, the MISO pin on the board_kc *must* be in high impedance
- * state even when the SPI is off, because the line is wired together
- * with the KBus serial RX, and the transmitter of the slave boards
- * would be unable to drive the line.
- */
- ATOMIC(SPI_DDR |= (BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT)));
-
- /*
- * If the SPI master mode is activated and the SS pin is in input and tied low,
- * the SPI hardware will automatically switch to slave mode!
- * For proper communication this pins should therefore be:
- * - as output
- * - as input but tied high forever!
- * This driver set the pin as output.
- */
- #warning FIXME:SPI SS pin set as output for proper operation, check schematics for possible conflicts.
- ATOMIC(SPI_DDR |= BV(SPI_SS_BIT));
-
- ATOMIC(SPI_DDR &= ~BV(SPI_MISO_BIT));
- /* Enable SPI, IRQ on, Master */
- SPCR = BV(SPE) | BV(SPIE) | BV(MSTR);
-
- /* Set data order */
- #if CONFIG_SPI_DATA_ORDER == SER_LSB_FIRST
- SPCR |= BV(DORD);
- #endif
-
- /* Set SPI clock rate */
- #if CONFIG_SPI_CLOCK_DIV == 128
- SPCR |= (BV(SPR1) | BV(SPR0));
- #elif (CONFIG_SPI_CLOCK_DIV == 64 || CONFIG_SPI_CLOCK_DIV == 32)
- SPCR |= BV(SPR1);
- #elif (CONFIG_SPI_CLOCK_DIV == 16 || CONFIG_SPI_CLOCK_DIV == 8)
- SPCR |= BV(SPR0);
- #elif (CONFIG_SPI_CLOCK_DIV == 4 || CONFIG_SPI_CLOCK_DIV == 2)
- // SPR0 & SDPR1 both at 0