xref: /nrf52832-nimble/rt-thread/components/net/freemodbus/port/portserial.c (revision 104654410c56c573564690304ae786df310c91fc)
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