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