portserial.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * FreeModbus Libary: Linux Port
  3. * Copyright (C) 2006 Christian Walter <wolti@sil.at>
  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.3 2006/10/12 08:35:34 wolti Exp $
  20. */
  21. /* ----------------------- Standard includes --------------------------------*/
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <errno.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <sys/select.h>
  29. #include <fcntl.h>
  30. #include <termios.h>
  31. #include <unistd.h>
  32. #include "port.h"
  33. /* ----------------------- Modbus includes ----------------------------------*/
  34. #include "mb.h"
  35. #include "mbport.h"
  36. #include "mbconfig.h"
  37. #include "mbctx.h"
  38. /* ----------------------- Defines -----------------------------------------*/
  39. #if MB_ASCII_ENABLED == 1
  40. #define BUF_SIZE 513 /* must hold a complete ASCII frame. */
  41. #else
  42. #define BUF_SIZE 256 /* must hold a complete RTU frame. */
  43. #endif
  44. /* ----------------------- Static variables ---------------------------------*/
  45. static int iSerialFd = -1;
  46. static BOOL bRxEnabled;
  47. static BOOL bTxEnabled;
  48. static ULONG ulTimeoutMs;
  49. static UCHAR ucBuffer[BUF_SIZE];
  50. static int uiRxBufferPos;
  51. static int uiTxBufferPos;
  52. static struct termios xOldTIO;
  53. /* ----------------------- Function prototypes ------------------------------*/
  54. static BOOL prvbMBPortSerialRead(fmodbus_t* ctx, UCHAR * pucBuffer, USHORT usNBytes, USHORT * usNBytesRead );
  55. static BOOL prvbMBPortSerialWrite(fmodbus_t* ctx, UCHAR * pucBuffer, USHORT usNBytes );
  56. /* ----------------------- Begin implementation -----------------------------*/
  57. void
  58. vMBPortSerialEnable(fmodbus_t* ctx, BOOL bEnableRx, BOOL bEnableTx )
  59. {
  60. /* it is not allowed that both receiver and transmitter are enabled. */
  61. assert( !bEnableRx || !bEnableTx );
  62. if( bEnableRx )
  63. {
  64. ( void )tcflush( ctx->iSerialFd, TCIFLUSH );
  65. ctx->uiRxBufferPos = 0;
  66. ctx->bRxEnabled = TRUE;
  67. }
  68. else
  69. {
  70. ctx->bRxEnabled = FALSE;
  71. }
  72. if( bEnableTx )
  73. {
  74. ctx->bTxEnabled = TRUE;
  75. ctx->uiTxBufferPos = 0;
  76. }
  77. else
  78. {
  79. ctx->bTxEnabled = FALSE;
  80. }
  81. }
  82. //( UCHAR ucPort, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
  83. BOOL
  84. xMBPortSerialInit( fmodbus_t* ctx )
  85. {
  86. CHAR szDevice[32];
  87. BOOL bStatus = TRUE;
  88. struct termios xNewTIO;
  89. speed_t xNewSpeed;
  90. snprintf( szDevice, 32, "%s", ctx->szPort );
  91. if( ( ctx->iSerialFd = open( szDevice, O_RDWR | O_NOCTTY ) ) < 0 ){
  92. vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't open serial port %s: %s\n", szDevice, strerror( errno ) );
  93. }else if( tcgetattr( ctx->iSerialFd, &(ctx->xOldTIO) ) != 0 ){
  94. vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't get settings from port %s: %s\n", szDevice, strerror( errno ) );
  95. }else{
  96. vMBPortLog( MB_LOG_INFO, "SER-INIT", "init ok %s\n", szDevice );
  97. bzero( &xNewTIO, sizeof( struct termios ) );
  98. xNewTIO.c_iflag |= IGNBRK | INPCK;
  99. xNewTIO.c_cflag |= CREAD | CLOCAL;
  100. switch ( ctx->eParity )
  101. {
  102. case MB_PAR_NONE:
  103. break;
  104. case MB_PAR_EVEN:
  105. xNewTIO.c_cflag |= PARENB;
  106. break;
  107. case MB_PAR_ODD:
  108. xNewTIO.c_cflag |= PARENB | PARODD;
  109. break;
  110. default:
  111. bStatus = FALSE;
  112. }
  113. switch ( ctx->ucDataBits )
  114. {
  115. case 8:
  116. xNewTIO.c_cflag |= CS8;
  117. break;
  118. case 7:
  119. xNewTIO.c_cflag |= CS7;
  120. break;
  121. default:
  122. bStatus = FALSE;
  123. }
  124. switch ( ctx->ulBaudRate )
  125. {
  126. case 9600:
  127. xNewSpeed = B9600;
  128. break;
  129. case 19200:
  130. xNewSpeed = B19200;
  131. break;
  132. case 38400:
  133. xNewSpeed = B38400;
  134. break;
  135. case 57600:
  136. xNewSpeed = B57600;
  137. break;
  138. case 115200:
  139. xNewSpeed = B115200;
  140. break;
  141. default:
  142. bStatus = FALSE;
  143. }
  144. if( bStatus )
  145. {
  146. if( cfsetispeed( &xNewTIO, xNewSpeed ) != 0 )
  147. {
  148. vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %s\n",
  149. ctx->ulBaudRate, strerror( errno ) );
  150. }
  151. else if( cfsetospeed( &xNewTIO, xNewSpeed ) != 0 )
  152. {
  153. vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %s\n",
  154. ctx->ulBaudRate, szDevice, strerror( errno ) );
  155. }
  156. else if( tcsetattr( ctx->iSerialFd, TCSANOW, &xNewTIO ) != 0 )
  157. {
  158. vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't set settings for port %s: %s\n",
  159. szDevice, strerror( errno ) );
  160. }
  161. else
  162. {
  163. vMBPortSerialEnable(ctx, FALSE, FALSE );
  164. bStatus = TRUE;
  165. }
  166. }
  167. }
  168. return bStatus;
  169. }
  170. BOOL
  171. xMBPortSerialSetTimeout(fmodbus_t* ctx, ULONG ulNewTimeoutMs )
  172. {
  173. if( ulNewTimeoutMs > 0 )
  174. {
  175. ctx->ulTimeoutMs = ulNewTimeoutMs;
  176. }
  177. else
  178. {
  179. ctx->ulTimeoutMs = 1;
  180. }
  181. return TRUE;
  182. }
  183. void
  184. vMBPortClose( fmodbus_t* ctx )
  185. {
  186. if( ctx->iSerialFd != -1 )
  187. {
  188. ( void )tcsetattr( ctx->iSerialFd, TCSANOW, &ctx->xOldTIO );
  189. ( void )close( ctx->iSerialFd );
  190. ctx->iSerialFd = -1;
  191. }
  192. }
  193. BOOL
  194. prvbMBPortSerialRead(fmodbus_t* ctx, UCHAR * pucBuffer, USHORT usNBytes, USHORT * usNBytesRead )
  195. {
  196. BOOL bResult = TRUE;
  197. ssize_t res;
  198. fd_set rfds;
  199. struct timeval tv;
  200. tv.tv_sec = 0;
  201. tv.tv_usec = 50000;
  202. FD_ZERO( &rfds );
  203. FD_SET( ctx->iSerialFd, &rfds );
  204. /* Wait until character received or timeout. Recover in case of an
  205. * interrupted read system call. */
  206. do
  207. {
  208. if( select( ctx->iSerialFd + 1, &rfds, NULL, NULL, &tv ) == -1 )
  209. {
  210. if( errno != EINTR )
  211. {
  212. bResult = FALSE;
  213. }
  214. }
  215. else if( FD_ISSET( ctx->iSerialFd, &rfds ) )
  216. {
  217. if( ( res = read( ctx->iSerialFd, pucBuffer, usNBytes ) ) == -1 )
  218. {
  219. bResult = FALSE;
  220. }
  221. else
  222. {
  223. *usNBytesRead = ( USHORT ) res;
  224. break;
  225. }
  226. }
  227. else
  228. {
  229. *usNBytesRead = 0;
  230. break;
  231. }
  232. }
  233. while( bResult == TRUE );
  234. return bResult;
  235. }
  236. BOOL
  237. prvbMBPortSerialWrite(fmodbus_t* ctx, UCHAR * pucBuffer, USHORT usNBytes )
  238. {
  239. ssize_t res;
  240. size_t left = ( size_t ) usNBytes;
  241. size_t done = 0;
  242. while( left > 0 )
  243. {
  244. if( ( res = write( ctx->iSerialFd, pucBuffer + done, left ) ) == -1 )
  245. {
  246. if( errno != EINTR )
  247. {
  248. break;
  249. }
  250. /* call write again because of interrupted system call. */
  251. continue;
  252. }
  253. done += res;
  254. left -= res;
  255. }
  256. return left == 0 ? TRUE : FALSE;
  257. }
  258. BOOL
  259. xMBPortSerialPoll( fmodbus_t* ctx )
  260. {
  261. BOOL bStatus = TRUE;
  262. USHORT usBytesRead;
  263. int i;
  264. //printf("a %d %d\n",ctx->bRxEnabled,ctx->bTxEnabled);//dbg wanggao
  265. while( ctx->bRxEnabled )
  266. {
  267. if( prvbMBPortSerialRead(ctx, &(ctx->ucBuffer[0]), BUF_SIZE, &usBytesRead ) )
  268. {
  269. if( usBytesRead == 0 )
  270. {
  271. /* timeout with no bytes. */
  272. break;
  273. }
  274. else if( usBytesRead > 0 )
  275. {
  276. for( i = 0; i < usBytesRead; i++ )
  277. {
  278. /* Call the modbus stack and let him fill the buffers. */
  279. ( void )ctx->pxMBFrameCBByteReceived( ctx );
  280. }
  281. ctx->uiRxBufferPos = 0;
  282. }
  283. }
  284. else
  285. {
  286. vMBPortLog( MB_LOG_ERROR, "SER-POLL", "read failed on serial device: %s\n",
  287. strerror( errno ) );
  288. bStatus = FALSE;
  289. }
  290. }
  291. //printf("b %d %d\n",ctx->bRxEnabled,ctx->bTxEnabled);//dbg wanggao
  292. if( ctx->bTxEnabled )
  293. {
  294. //printf("c %d %d\n",ctx->bRxEnabled,ctx->bTxEnabled);//dbg wanggao
  295. while( ctx->bTxEnabled )
  296. {
  297. ( void )ctx->pxMBFrameCBTransmitterEmpty( ctx );
  298. /* Call the modbus stack to let him fill the buffer. */
  299. }
  300. if( !prvbMBPortSerialWrite(ctx, &ctx->ucBuffer[0], ctx->uiTxBufferPos ) )
  301. {
  302. vMBPortLog( MB_LOG_ERROR, "SER-POLL", "write failed on serial device: %s\n",
  303. strerror( errno ) );
  304. bStatus = FALSE;
  305. }
  306. }
  307. return bStatus;
  308. }
  309. BOOL
  310. xMBPortSerialPutByte(fmodbus_t* ctx, CHAR ucByte )
  311. {
  312. assert( ctx->uiTxBufferPos < BUF_SIZE );
  313. ctx->ucBuffer[ctx->uiTxBufferPos] = ucByte;
  314. ctx->uiTxBufferPos++;
  315. return TRUE;
  316. }
  317. BOOL
  318. xMBPortSerialGetByte(fmodbus_t* ctx, CHAR * pucByte )
  319. {
  320. assert( ctx->uiRxBufferPos < BUF_SIZE );
  321. *pucByte = ctx->ucBuffer[ctx->uiRxBufferPos];
  322. ctx->uiRxBufferPos++;
  323. return TRUE;
  324. }