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