ECE 4760 Final Project
 All Files Functions Variables Enumerations Enumerator Macros
uart.c
Go to the documentation of this file.
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch
7  * ----------------------------------------------------------------------------
8  *
9  * Stdio demo, UART implementation
10  *
11  * $Id: uart.c,v 1.1 2005/12/28 21:38:59 joerg_wunsch Exp $
12  *
13  * Mod for mega644 BRL Jan2009
14  */
15 
16 
17 /* CPU frequency */
18 #define F_CPU 16000000UL
19 
20 /* UART baud rate */
21 #define UART_BAUD 57600
22 
23 
24 #include <stdint.h>
25 #include <stdio.h>
26 
27 #include <avr/io.h>
28 
29 #include "uart.h"
30 
31 /*
32  * Initialize the UART to 9600 Bd, tx/rx, 8N1.
33  */
34 void
35 uart_init(void)
36 {
37 #if F_CPU < 2000000UL && defined(U2X)
38  UCSR0A = _BV(U2X); /* improve baud rate error by using 2x clk */
39  UBRR0L = (F_CPU / (8UL * UART_BAUD)) - 1;
40 #else
41  UBRR0L = (F_CPU / (16UL * UART_BAUD)) - 1;
42 #endif
43  UCSR0B = _BV(TXEN0) | _BV(RXEN0); /* tx/rx enable */
44 }
45 
46 /*
47  * Send character c down the UART Tx, wait until tx holding register
48  * is empty.
49  */
50 int
51 uart_putchar(char c, FILE *stream)
52 {
53 
54  if (c == '\a')
55  {
56  fputs("*ring*\n", stderr);
57  return 0;
58  }
59 
60  if (c == '\n')
61  uart_putchar('\r', stream);
62  loop_until_bit_is_set(UCSR0A, UDRE0);
63  UDR0 = c;
64 
65  return 0;
66 }
67 
68 /*
69  * Receive a character from the UART Rx.
70  *
71  * This features a simple line-editor that allows to delete and
72  * re-edit the characters entered, until either CR or NL is entered.
73  * Printable characters entered will be echoed using uart_putchar().
74  *
75  * Editing characters:
76  *
77  * . \b (BS) or \177 (DEL) delete the previous character
78  * . ^u kills the entire input buffer
79  * . ^w deletes the previous word
80  * . ^r sends a CR, and then reprints the buffer
81  * . \t will be replaced by a single space
82  *
83  * All other control characters will be ignored.
84  *
85  * The internal line buffer is RX_BUFSIZE (80) characters long, which
86  * includes the terminating \n (but no terminating \0). If the buffer
87  * is full (i. e., at RX_BUFSIZE-1 characters in order to keep space for
88  * the trailing \n), any further input attempts will send a \a to
89  * uart_putchar() (BEL character), although line editing is still
90  * allowed.
91  *
92  * Input errors while talking to the UART will cause an immediate
93  * return of -1 (error indication). Notably, this will be caused by a
94  * framing error (e. g. serial line "break" condition), by an input
95  * overrun, and by a parity error (if parity was enabled and automatic
96  * parity recognition is supported by hardware).
97  *
98  * Successive calls to uart_getchar() will be satisfied from the
99  * internal buffer until that buffer is emptied again.
100  */
101 int
102 uart_getchar(FILE *stream)
103 {
104  uint8_t c;
105  char *cp, *cp2;
106  static char b[RX_BUFSIZE];
107  static char *rxp;
108 
109  if (rxp == 0)
110  for (cp = b;;)
111  {
112  loop_until_bit_is_set(UCSR0A, RXC0);
113  if (UCSR0A & _BV(FE0))
114  return _FDEV_EOF;
115  if (UCSR0A & _BV(DOR0))
116  return _FDEV_ERR;
117  c = UDR0;
118  /* behaviour similar to Unix stty ICRNL */
119  if (c == '\r')
120  c = '\n';
121  if (c == '\n')
122  {
123  *cp = c;
124  uart_putchar(c, stream);
125  rxp = b;
126  break;
127  }
128  else if (c == '\t')
129  c = ' ';
130 
131  if ((c >= (uint8_t)' ' && c <= (uint8_t)'\x7e') ||
132  c >= (uint8_t)'\xa0')
133  {
134  if (cp == b + RX_BUFSIZE - 1)
135  uart_putchar('\a', stream);
136  else
137  {
138  *cp++ = c;
139  uart_putchar(c, stream);
140  }
141  continue;
142  }
143 
144  switch (c)
145  {
146  case 'c' & 0x1f:
147  return -1;
148 
149  case '\b':
150  case '\x7f':
151  if (cp > b)
152  {
153  uart_putchar('\b', stream);
154  uart_putchar(' ', stream);
155  uart_putchar('\b', stream);
156  cp--;
157  }
158  break;
159 
160  case 'r' & 0x1f:
161  uart_putchar('\r', stream);
162  for (cp2 = b; cp2 < cp; cp2++)
163  uart_putchar(*cp2, stream);
164  break;
165 
166  case 'u' & 0x1f:
167  while (cp > b)
168  {
169  uart_putchar('\b', stream);
170  uart_putchar(' ', stream);
171  uart_putchar('\b', stream);
172  cp--;
173  }
174  break;
175 
176  case 'w' & 0x1f:
177  while (cp > b && cp[-1] != ' ')
178  {
179  uart_putchar('\b', stream);
180  uart_putchar(' ', stream);
181  uart_putchar('\b', stream);
182  cp--;
183  }
184  break;
185  }
186  }
187 
188  c = *rxp++;
189  if (c == '\n')
190  rxp = 0;
191 
192  return c;
193 }
194 
#define RX_BUFSIZE
Definition: uart.h:27
void uart_init(void)
Definition: uart.c:35
int uart_putchar(char c, FILE *stream)
Definition: uart.c:51
int uart_getchar(FILE *stream)
Definition: uart.c:102
#define F_CPU
Definition: uart.c:18
#define UART_BAUD
Definition: uart.c:21