1 /*
2 * FreeModbus Libary: RT-Thread Port
3 * Copyright (C) 2013 Armink <[email protected]>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * File: $Id: portserial.c,v 1.60 2013/08/13 15:07:05 Armink $
20 */
21
22 #include "port.h"
23
24 /* ----------------------- Modbus includes ----------------------------------*/
25 #include "mb.h"
26 #include "mbport.h"
27 #include "rtdevice.h"
28 #include "board.h"
29
30 /* ----------------------- Static variables ---------------------------------*/
31 ALIGN(RT_ALIGN_SIZE)
32 /* software simulation serial transmit IRQ handler thread stack */
33 static rt_uint8_t serial_soft_trans_irq_stack[512];
34 /* software simulation serial transmit IRQ handler thread */
35 static struct rt_thread thread_serial_soft_trans_irq;
36 /* serial event */
37 static struct rt_event event_serial;
38 /* modbus slave serial device */
39 static rt_serial_t *serial;
40
41 /* ----------------------- Defines ------------------------------------------*/
42 /* serial transmit event */
43 #define EVENT_SERIAL_TRANS_START (1<<0)
44
45 /* ----------------------- static functions ---------------------------------*/
46 static void prvvUARTTxReadyISR(void);
47 static void prvvUARTRxISR(void);
48 static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size);
49 static void serial_soft_trans_irq(void* parameter);
50
51 /* ----------------------- Start implementation -----------------------------*/
xMBPortSerialInit(UCHAR ucPORT,ULONG ulBaudRate,UCHAR ucDataBits,eMBParity eParity)52 BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
53 eMBParity eParity)
54 {
55 /**
56 * set 485 mode receive and transmit control IO
57 * @note MODBUS_SLAVE_RT_CONTROL_PIN_INDEX need be defined by user
58 */
59 #if defined(RT_MODBUS_SLAVE_USE_CONTROL_PIN)
60 rt_pin_mode(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT);
61 #endif
62 /* set serial name */
63 if (ucPORT == 1) {
64 #if defined(RT_USING_UART1) || defined(RT_USING_REMAP_UART1)
65 extern struct rt_serial_device serial1;
66 serial = &serial1;
67 #endif
68 } else if (ucPORT == 2) {
69 #if defined(RT_USING_UART2)
70 extern struct rt_serial_device serial2;
71 serial = &serial2;
72 #endif
73 } else if (ucPORT == 3) {
74 #if defined(RT_USING_UART3)
75 extern struct rt_serial_device serial3;
76 serial = &serial3;
77 #endif
78 }
79 /* set serial configure parameter */
80 serial->config.baud_rate = ulBaudRate;
81 serial->config.stop_bits = STOP_BITS_1;
82 switch(eParity){
83 case MB_PAR_NONE: {
84 serial->config.data_bits = DATA_BITS_8;
85 serial->config.parity = PARITY_NONE;
86 break;
87 }
88 case MB_PAR_ODD: {
89 serial->config.data_bits = DATA_BITS_9;
90 serial->config.parity = PARITY_ODD;
91 break;
92 }
93 case MB_PAR_EVEN: {
94 serial->config.data_bits = DATA_BITS_9;
95 serial->config.parity = PARITY_EVEN;
96 break;
97 }
98 }
99 /* set serial configure */
100 serial->ops->configure(serial, &(serial->config));
101
102 /* open serial device */
103 if (!rt_device_open(&serial->parent, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX)) {
104 rt_device_set_rx_indicate(&serial->parent, serial_rx_ind);
105 } else {
106 return FALSE;
107 }
108
109 /* software initialize */
110 rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO);
111 rt_thread_init(&thread_serial_soft_trans_irq,
112 "slave trans",
113 serial_soft_trans_irq,
114 RT_NULL,
115 serial_soft_trans_irq_stack,
116 sizeof(serial_soft_trans_irq_stack),
117 10, 5);
118 rt_thread_startup(&thread_serial_soft_trans_irq);
119
120 return TRUE;
121 }
122
vMBPortSerialEnable(BOOL xRxEnable,BOOL xTxEnable)123 void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
124 {
125 rt_uint32_t recved_event;
126 if (xRxEnable)
127 {
128 /* enable RX interrupt */
129 serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
130 /* switch 485 to receive mode */
131 #if defined(RT_MODBUS_SLAVE_USE_CONTROL_PIN)
132 rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_LOW);
133 #endif
134 }
135 else
136 {
137 /* switch 485 to transmit mode */
138 #if defined(RT_MODBUS_SLAVE_USE_CONTROL_PIN)
139 rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_HIGH);
140 #endif
141 /* disable RX interrupt */
142 serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
143 }
144 if (xTxEnable)
145 {
146 /* start serial transmit */
147 rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START);
148 }
149 else
150 {
151 /* stop serial transmit */
152 rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START,
153 RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0,
154 &recved_event);
155 }
156 }
157
vMBPortClose(void)158 void vMBPortClose(void)
159 {
160 serial->parent.close(&(serial->parent));
161 }
162
xMBPortSerialPutByte(CHAR ucByte)163 BOOL xMBPortSerialPutByte(CHAR ucByte)
164 {
165 serial->parent.write(&(serial->parent), 0, &ucByte, 1);
166 return TRUE;
167 }
168
xMBPortSerialGetByte(CHAR * pucByte)169 BOOL xMBPortSerialGetByte(CHAR * pucByte)
170 {
171 serial->parent.read(&(serial->parent), 0, pucByte, 1);
172 return TRUE;
173 }
174
175 /*
176 * Create an interrupt handler for the transmit buffer empty interrupt
177 * (or an equivalent) for your target processor. This function should then
178 * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
179 * a new character can be sent. The protocol stack will then call
180 * xMBPortSerialPutByte( ) to send the character.
181 */
prvvUARTTxReadyISR(void)182 void prvvUARTTxReadyISR(void)
183 {
184 pxMBFrameCBTransmitterEmpty();
185 }
186
187 /*
188 * Create an interrupt handler for the receive interrupt for your target
189 * processor. This function should then call pxMBFrameCBByteReceived( ). The
190 * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
191 * character.
192 */
prvvUARTRxISR(void)193 void prvvUARTRxISR(void)
194 {
195 pxMBFrameCBByteReceived();
196 }
197
198 /**
199 * Software simulation serial transmit IRQ handler.
200 *
201 * @param parameter parameter
202 */
serial_soft_trans_irq(void * parameter)203 static void serial_soft_trans_irq(void* parameter) {
204 rt_uint32_t recved_event;
205 while (1)
206 {
207 /* waiting for serial transmit start */
208 rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR,
209 RT_WAITING_FOREVER, &recved_event);
210 /* execute modbus callback */
211 prvvUARTTxReadyISR();
212 }
213 }
214
215 /**
216 * This function is serial receive callback function
217 *
218 * @param dev the device of serial
219 * @param size the data size that receive
220 *
221 * @return return RT_EOK
222 */
serial_rx_ind(rt_device_t dev,rt_size_t size)223 static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) {
224 prvvUARTRxISR();
225 return RT_EOK;
226 }
227