/*
 * Copyright (c) 2004  Brian S. Dean <bsd@bdmicro.com>
 * All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 * 
 */

/* $Id: uart.c,v 1.4 2007/08/02 01:15:10 bsd Exp $ */

#include <avr/io.h>
#include <avr/interrupt.h>

#include <inttypes.h>
#include <stdio.h>

#include "led.h"
#include "pkt.h"
#include "ringbuf.h"
#include "uart.h"

extern volatile uint16_t ms_count;

/*
 * UART data, rxbyte is assigned from within the rx interrupt handler
 */
#define UART_BUF_LEN 32
static uint8_t uart_buffer[UART_BUF_LEN];
volatile RINGBUF8 uartbuf;

#if PKT_TRACE
/*
 * UART data, rxbyte is assigned from within the rx interrupt handler
 */
#define UART1_BUF_LEN 128
static uint8_t uart1_buffer[UART1_BUF_LEN];
volatile RINGBUF8 uart1buf;
volatile uint8_t uart1_bit9;
volatile uint8_t uart1_rx;
#endif

/* flag to indicate a byte has been received from the UART */
volatile uint8_t uart0_rx;


/*
 * initialize UARTs
 */
void uarts_init(uint16_t uart0_brr, uint16_t uart1_brr)
{

  /*
   * initialize UART input ring buffer
   */
  ringbuf8_init(&uartbuf, uart_buffer, sizeof(uart_buffer));
  uart0_rx = 0;

#if PKT_TRACE
  ringbuf8_init(&uart1buf, uart1_buffer, sizeof(uart1_buffer));
  uart1_rx = 0;
#endif


  /*
   * enable UART0 - the command interface, 8N1
   */
  UBRR0H = (uart0_brr >> 8) & 0xff;
  UBRR0L = uart0_brr & 0xff;
  UCSR0B = _BV(RXEN)|_BV(TXEN)|_BV(RXCIE);

  /*
   * enable UART1 - the RS485 bus UART, 9N1, set for multiprocessor
   * mode to optimize packet handling 
   */
  UBRR1H  = (uart1_brr >> 8) & 0xff;
  UBRR1L  = uart1_brr & 0xff;
  UCSR1B  = _BV(RXEN)|_BV(TXEN)|_BV(RXCIE)|_BV(TXCIE);
#if DATA9
#if !PKT_TRACE
  UCSR1A |= _BV(MPCM);                /* multi-processor mode */
#endif
  UCSR1B |= _BV(UCSZ12);              /* 9 data bits */
  UCSR1C |= _BV(UCSZ11) | _BV(UCSZ10); /* 9 data bits */
#endif
}


/*
 * UART character output routine (polled)
 */
void uart_putc(uint8_t uart, char c)
{
  if (uart == 0) {
    while ((UCSR0A & _BV(UDRE)) == 0)
      ;
    UDR0 = c;
  }
  else if (uart == 1) {
    while ((UCSR1A & _BV(UDRE)) == 0)
      ;
    UDR1 = c;
  }
}


/*
 * UART0 byte received interrupt handler - fetch the character, check
 * for framing error, put it in the UART buffer, flag the event, wake
 * up the main thread.
 */
SIGNAL(SIG_UART0_RECV)
{
  uint8_t c;

  led_on();
  c = UDR0;
  if (bit_is_clear(UCSR0A, FE)) {
    ringbuf8_put(&uartbuf, c);
    uart0_rx = 1;
  }
}



