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_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions $ 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 #if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 31 /* ----------------------- Static variables ---------------------------------*/ 32 ALIGN(RT_ALIGN_SIZE) 33 /* software simulation serial transmit IRQ handler thread stack */ 34 static rt_uint8_t serial_soft_trans_irq_stack[512]; 35 /* software simulation serial transmit IRQ handler thread */ 36 static struct rt_thread thread_serial_soft_trans_irq; 37 /* serial event */ 38 static struct rt_event event_serial; 39 /* modbus master serial device */ 40 static rt_serial_t *serial; 41 42 /* ----------------------- Defines ------------------------------------------*/ 43 /* serial transmit event */ 44 #define EVENT_SERIAL_TRANS_START (1<<0) 45 46 /* ----------------------- static functions ---------------------------------*/ 47 static void prvvUARTTxReadyISR(void); 48 static void prvvUARTRxISR(void); 49 static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size); 50 static void serial_soft_trans_irq(void* parameter); 51 52 /* ----------------------- Start implementation -----------------------------*/ 53 BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, 54 eMBParity eParity) 55 { 56 /** 57 * set 485 mode receive and transmit control IO 58 * @note MODBUS_MASTER_RT_CONTROL_PIN_INDEX need be defined by user 59 */ 60 #if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN) 61 rt_pin_mode(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT); 62 #endif 63 64 /* set serial name */ 65 if (ucPORT == 1) { 66 #if defined(RT_USING_UART1) || defined(RT_USING_REMAP_UART1) 67 extern struct rt_serial_device serial1; 68 serial = &serial1; 69 #endif 70 } else if (ucPORT == 2) { 71 #if defined(RT_USING_UART2) 72 extern struct rt_serial_device serial2; 73 serial = &serial2; 74 #endif 75 } else if (ucPORT == 3) { 76 #if defined(RT_USING_UART3) 77 extern struct rt_serial_device serial3; 78 serial = &serial3; 79 #endif 80 } 81 /* set serial configure parameter */ 82 serial->config.baud_rate = ulBaudRate; 83 serial->config.stop_bits = STOP_BITS_1; 84 switch(eParity){ 85 case MB_PAR_NONE: { 86 serial->config.data_bits = DATA_BITS_8; 87 serial->config.parity = PARITY_NONE; 88 break; 89 } 90 case MB_PAR_ODD: { 91 serial->config.data_bits = DATA_BITS_9; 92 serial->config.parity = PARITY_ODD; 93 break; 94 } 95 case MB_PAR_EVEN: { 96 serial->config.data_bits = DATA_BITS_9; 97 serial->config.parity = PARITY_EVEN; 98 break; 99 } 100 } 101 /* set serial configure */ 102 serial->ops->configure(serial, &(serial->config)); 103 104 /* open serial device */ 105 if (!rt_device_open(&serial->parent, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX)) { 106 rt_device_set_rx_indicate(&serial->parent, serial_rx_ind); 107 } else { 108 return FALSE; 109 } 110 111 /* software initialize */ 112 rt_event_init(&event_serial, "master event", RT_IPC_FLAG_PRIO); 113 rt_thread_init(&thread_serial_soft_trans_irq, 114 "master trans", 115 serial_soft_trans_irq, 116 RT_NULL, 117 serial_soft_trans_irq_stack, 118 sizeof(serial_soft_trans_irq_stack), 119 10, 5); 120 rt_thread_startup(&thread_serial_soft_trans_irq); 121 122 return TRUE; 123 } 124 125 void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable) 126 { 127 rt_uint32_t recved_event; 128 if (xRxEnable) 129 { 130 /* enable RX interrupt */ 131 serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); 132 /* switch 485 to receive mode */ 133 #if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN) 134 rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_LOW); 135 #endif 136 } 137 else 138 { 139 /* switch 485 to transmit mode */ 140 #if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN) 141 rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_HIGH); 142 #endif 143 /* disable RX interrupt */ 144 serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX); 145 } 146 if (xTxEnable) 147 { 148 /* start serial transmit */ 149 rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START); 150 } 151 else 152 { 153 /* stop serial transmit */ 154 rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, 155 RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0, 156 &recved_event); 157 } 158 } 159 160 void vMBMasterPortClose(void) 161 { 162 serial->parent.close(&(serial->parent)); 163 } 164 165 BOOL xMBMasterPortSerialPutByte(CHAR ucByte) 166 { 167 serial->parent.write(&(serial->parent), 0, &ucByte, 1); 168 return TRUE; 169 } 170 171 BOOL xMBMasterPortSerialGetByte(CHAR * pucByte) 172 { 173 serial->parent.read(&(serial->parent), 0, pucByte, 1); 174 return TRUE; 175 } 176 177 /* 178 * Create an interrupt handler for the transmit buffer empty interrupt 179 * (or an equivalent) for your target processor. This function should then 180 * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that 181 * a new character can be sent. The protocol stack will then call 182 * xMBPortSerialPutByte( ) to send the character. 183 */ 184 void prvvUARTTxReadyISR(void) 185 { 186 pxMBMasterFrameCBTransmitterEmpty(); 187 } 188 189 /* 190 * Create an interrupt handler for the receive interrupt for your target 191 * processor. This function should then call pxMBFrameCBByteReceived( ). The 192 * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the 193 * character. 194 */ 195 void prvvUARTRxISR(void) 196 { 197 pxMBMasterFrameCBByteReceived(); 198 } 199 200 /** 201 * Software simulation serial transmit IRQ handler. 202 * 203 * @param parameter parameter 204 */ 205 static void serial_soft_trans_irq(void* parameter) { 206 rt_uint32_t recved_event; 207 while (1) 208 { 209 /* waiting for serial transmit start */ 210 rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR, 211 RT_WAITING_FOREVER, &recved_event); 212 /* execute modbus callback */ 213 prvvUARTTxReadyISR(); 214 } 215 } 216 217 /** 218 * This function is serial receive callback function 219 * 220 * @param dev the device of serial 221 * @param size the data size that receive 222 * 223 * @return return RT_EOK 224 */ 225 static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) { 226 prvvUARTRxISR(); 227 return RT_EOK; 228 } 229 230 #endif 231