xref: /nrf52832-nimble/rt-thread/libcpu/unicore32/sep6200/serial.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * File      : serial.c
3  * This file is part of RT-Thread RTOS
4  * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License along
17  *  with this program; if not, write to the Free Software Foundation, Inc.,
18  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Change Logs:
21  * Date           Author       Notes
22  * 2013-03-16	    Peng Fan     Modified from sep4020
23  */
24 #include <rtthread.h>
25 #include <rthw.h>
26 #include "serial.h"
27 
28 /**
29  * @addtogroup sep6200
30  */
31 /*@{*/
32 
33 /* RT-Thread Device Interface */
34 /**
35  * This function initializes serial
36  */
rt_serial_init(rt_device_t dev)37 static rt_err_t rt_serial_init (rt_device_t dev)
38 {
39 	struct serial_device* uart = (struct serial_device*) dev->user_data;
40 
41 	if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
42 	{
43 
44 		if (dev->flag & RT_DEVICE_FLAG_INT_RX)
45 		{
46 			rt_memset(uart->int_rx->rx_buffer, 0,
47 				sizeof(uart->int_rx->rx_buffer));
48 			uart->int_rx->read_index = uart->int_rx->save_index = 0;
49 		}
50 
51 		if (dev->flag & RT_DEVICE_FLAG_INT_TX)
52 		{
53 			rt_memset(uart->int_tx->tx_buffer, 0,
54 				sizeof(uart->int_tx->tx_buffer));
55 			uart->int_tx->write_index = uart->int_tx->save_index = 0;
56 		}
57 
58 		dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
59 	}
60 
61 	return RT_EOK;
62 }
63 
64 /* save a char to serial buffer */
rt_serial_savechar(struct serial_device * uart,char ch)65 static void rt_serial_savechar(struct serial_device* uart, char ch)
66 {
67 	rt_base_t level;
68 
69 	/* disable interrupt */
70 	level = rt_hw_interrupt_disable();
71 
72 	uart->int_rx->rx_buffer[uart->int_rx->save_index] = ch;
73 	uart->int_rx->save_index ++;
74 	if (uart->int_rx->save_index >= UART_RX_BUFFER_SIZE)
75 		uart->int_rx->save_index = 0;
76 
77 	/* if the next position is read index, discard this 'read char' */
78 	if (uart->int_rx->save_index == uart->int_rx->read_index)
79 	{
80 		uart->int_rx->read_index ++;
81 		if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE)
82 			uart->int_rx->read_index = 0;
83 	}
84 
85 	/* enable interrupt */
86 	rt_hw_interrupt_enable(level);
87 }
88 
rt_serial_open(rt_device_t dev,rt_uint16_t oflag)89 static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag)
90 {
91 	RT_ASSERT(dev != RT_NULL);
92 	return RT_EOK;
93 }
94 
rt_serial_close(rt_device_t dev)95 static rt_err_t rt_serial_close(rt_device_t dev)
96 {
97 	RT_ASSERT(dev != RT_NULL);
98 	return RT_EOK;
99 }
100 
rt_serial_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)101 static rt_size_t rt_serial_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
102 {
103 	rt_uint8_t* ptr;
104 	rt_err_t err_code;
105 	struct serial_device* uart;
106 
107 	ptr = buffer;
108 	err_code = RT_EOK;
109 	uart = (struct serial_device*)dev->user_data;
110 
111 	if (dev->flag & RT_DEVICE_FLAG_INT_RX)
112 	{
113 		rt_base_t level;
114 
115 		/* interrupt mode Rx */
116 		while (size)
117 		{
118 			if (uart->int_rx->read_index != uart->int_rx->save_index)
119 			{
120 				*ptr++ = uart->int_rx->rx_buffer[uart->int_rx->read_index];
121 				size --;
122 
123 				/* disable interrupt */
124 				level = rt_hw_interrupt_disable();
125 
126 				uart->int_rx->read_index ++;
127 				if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE)
128 					uart->int_rx->read_index = 0;
129 
130 				/* enable interrupt */
131 				rt_hw_interrupt_enable(level);
132 			}
133 			else
134 			{
135 				/* set error code */
136 				err_code = -RT_EEMPTY;
137 				break;
138 			}
139 		}
140 	}
141 	else
142 	{
143 		/* polling mode */
144 		while ((rt_uint32_t)ptr - (rt_uint32_t)buffer < size)
145 		{
146 			while (uart->uart_device->lsr & USTAT_RCV_READY)
147 			{
148 				*ptr = uart->uart_device->dlbl_fifo.txfifo & 0xff;
149 				ptr ++;
150 			}
151 		}
152 	}
153 
154 	/* set error code */
155 	rt_set_errno(err_code);
156 	return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
157 }
158 
rt_serial_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)159 static rt_size_t rt_serial_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
160 {
161 	rt_uint8_t* ptr;
162 	rt_err_t err_code;
163 	struct serial_device* uart;
164 
165 	err_code = RT_EOK;
166 	ptr = (rt_uint8_t*)buffer;
167 	uart = (struct serial_device*)dev->user_data;
168 
169 	if (dev->flag & RT_DEVICE_FLAG_INT_TX)
170 	{
171 		/* interrupt mode Tx */
172 		while (uart->int_tx->save_index != uart->int_tx->write_index)
173 		{
174 			/* save on tx buffer */
175 			uart->int_tx->tx_buffer[uart->int_tx->save_index] = *ptr++;
176 
177 			-- size;
178 
179 			/* move to next position */
180 			uart->int_tx->save_index ++;
181 
182 			/* wrap save index */
183 			if (uart->int_tx->save_index >= UART_TX_BUFFER_SIZE)
184 				uart->int_tx->save_index = 0;
185 		}
186 
187 		/* set error code */
188 		if (size > 0)
189 			err_code = -RT_EFULL;
190 	}
191 	else
192 	{
193 		/* polling mode */
194 		while (size)
195 		{
196 			/*
197 			 * to be polite with serial console add a line feed
198 			 * to the carriage return character
199 			 */
200 			if (*ptr == '\n' && (dev->flag & RT_DEVICE_FLAG_STREAM))
201 			{
202 				while (!(uart->uart_device->lsr & USTAT_TXB_EMPTY));
203 				uart->uart_device->dlbl_fifo.txfifo = '\r';
204 			}
205 
206 			while (!(uart->uart_device->lsr & USTAT_TXB_EMPTY));
207 			uart->uart_device->dlbl_fifo.txfifo = (*ptr & 0x1FF);
208 
209 			++ptr; --size;
210 		}
211 	}
212 
213 	/* set error code */
214 	rt_set_errno(err_code);
215 
216 	return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
217 }
218 
rt_serial_control(rt_device_t dev,int cmd,void * args)219 static rt_err_t rt_serial_control (rt_device_t dev, int cmd, void *args)
220 {
221 	RT_ASSERT(dev != RT_NULL);
222 
223 	switch (cmd)
224 	{
225 	case RT_DEVICE_CTRL_SUSPEND:
226 		/* suspend device */
227 		dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
228 		break;
229 
230 	case RT_DEVICE_CTRL_RESUME:
231 		/* resume device */
232 		dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
233 		break;
234 	}
235 
236 	return RT_EOK;
237 }
238 
239 /*
240  * serial register
241  */
rt_hw_serial_register(rt_device_t device,const char * name,rt_uint32_t flag,struct serial_device * serial)242 rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct serial_device *serial)
243 {
244 	RT_ASSERT(device != RT_NULL);
245 
246 	device->type 		= RT_Device_Class_Char;
247 	device->rx_indicate = RT_NULL;
248 	device->tx_complete = RT_NULL;
249 	device->init 		= rt_serial_init;
250 	device->open		= rt_serial_open;
251 	device->close		= rt_serial_close;
252 	device->read 		= rt_serial_read;
253 	device->write 		= rt_serial_write;
254 	device->control 	= rt_serial_control;
255 	device->user_data   = serial;
256 
257 	/* register a character device */
258 	return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
259 }
260 
261 /* ISR for serial interrupt */
rt_hw_serial_isr(rt_device_t device)262 void rt_hw_serial_isr(rt_device_t device)
263 {
264 	struct serial_device* uart = (struct serial_device*) device->user_data;
265 
266 	/* interrupt mode receive */
267 	RT_ASSERT(device->flag & RT_DEVICE_FLAG_INT_RX);
268 
269 	/* save on rx buffer */
270 	while (uart->uart_device->lsr & USTAT_RCV_READY)
271 	{
272 		rt_serial_savechar(uart, uart->uart_device->dlbl_fifo.rxfifo & 0xff);
273 	}
274 
275 	/* invoke callback */
276 	if (device->rx_indicate != RT_NULL)
277 	{
278 		rt_size_t rx_length;
279 
280 		/* get rx length */
281 		rx_length = uart->int_rx->read_index > uart->int_rx->save_index ?
282 			UART_RX_BUFFER_SIZE - uart->int_rx->read_index + uart->int_rx->save_index :
283 			uart->int_rx->save_index - uart->int_rx->read_index;
284 
285 		device->rx_indicate(device, rx_length);
286 	}
287 }
288 
289 /*@}*/
290