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 -----------------------------*/ 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 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 158 void vMBPortClose(void) 159 { 160 serial->parent.close(&(serial->parent)); 161 } 162 163 BOOL xMBPortSerialPutByte(CHAR ucByte) 164 { 165 serial->parent.write(&(serial->parent), 0, &ucByte, 1); 166 return TRUE; 167 } 168 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 */ 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 */ 193 void prvvUARTRxISR(void) 194 { 195 pxMBFrameCBByteReceived(); 196 } 197 198 /** 199 * Software simulation serial transmit IRQ handler. 200 * 201 * @param parameter parameter 202 */ 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 */ 223 static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) { 224 prvvUARTRxISR(); 225 return RT_EOK; 226 } 227