portserial.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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 4800:
  127. xNewSpeed = B4800;
  128. break;
  129. case 9600:
  130. xNewSpeed = B9600;
  131. break;
  132. case 19200:
  133. xNewSpeed = B19200;
  134. break;
  135. case 38400:
  136. xNewSpeed = B38400;
  137. break;
  138. case 57600:
  139. xNewSpeed = B57600;
  140. break;
  141. case 115200:
  142. xNewSpeed = B115200;
  143. break;
  144. default:
  145. bStatus = FALSE;
  146. }
  147. if( bStatus )
  148. {
  149. if( cfsetispeed( &xNewTIO, xNewSpeed ) != 0 )
  150. {
  151. vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %s\n",
  152. ctx->ulBaudRate, strerror( errno ) );
  153. }
  154. else if( cfsetospeed( &xNewTIO, xNewSpeed ) != 0 )
  155. {
  156. vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %s\n",
  157. ctx->ulBaudRate, szDevice, strerror( errno ) );
  158. }
  159. else if( tcsetattr( ctx->iSerialFd, TCSANOW, &xNewTIO ) != 0 )
  160. {
  161. vMBPortLog( MB_LOG_ERROR, "SER-INIT", "Can't set settings for port %s: %s\n",
  162. szDevice, strerror( errno ) );
  163. }
  164. else
  165. {
  166. vMBPortSerialEnable(ctx, FALSE, FALSE );
  167. bStatus = TRUE;
  168. }
  169. }
  170. }
  171. return bStatus;
  172. }
  173. BOOL
  174. xMBPortSerialSetTimeout(fmodbus_t* ctx, ULONG ulNewTimeoutMs )
  175. {
  176. if( ulNewTimeoutMs > 0 )
  177. {
  178. ctx->ulTimeoutMs = ulNewTimeoutMs;
  179. }
  180. else
  181. {
  182. ctx->ulTimeoutMs = 1;
  183. }
  184. return TRUE;
  185. }
  186. void
  187. vMBPortClose( fmodbus_t* ctx )
  188. {
  189. if( ctx->iSerialFd != -1 )
  190. {
  191. ( void )tcsetattr( ctx->iSerialFd, TCSANOW, &ctx->xOldTIO );
  192. ( void )close( ctx->iSerialFd );
  193. ctx->iSerialFd = -1;
  194. }
  195. }
  196. BOOL
  197. prvbMBPortSerialRead(fmodbus_t* ctx, UCHAR * pucBuffer, USHORT usNBytes, USHORT * usNBytesRead )
  198. {
  199. BOOL bResult = TRUE;
  200. ssize_t res;
  201. fd_set rfds;
  202. struct timeval tv;
  203. tv.tv_sec = 0;
  204. tv.tv_usec = 50000;
  205. FD_ZERO( &rfds );
  206. FD_SET( ctx->iSerialFd, &rfds );
  207. /* Wait until character received or timeout. Recover in case of an
  208. * interrupted read system call. */
  209. do
  210. {
  211. if( select( ctx->iSerialFd + 1, &rfds, NULL, NULL, &tv ) == -1 )
  212. {
  213. if( errno != EINTR )
  214. {
  215. bResult = FALSE;
  216. }
  217. }
  218. else if( FD_ISSET( ctx->iSerialFd, &rfds ) )
  219. {
  220. if( ( res = read( ctx->iSerialFd, pucBuffer, usNBytes ) ) == -1 )
  221. {
  222. bResult = FALSE;
  223. }
  224. else
  225. {
  226. *usNBytesRead = ( USHORT ) res;
  227. break;
  228. }
  229. }
  230. else
  231. {
  232. *usNBytesRead = 0;
  233. break;
  234. }
  235. }
  236. while( bResult == TRUE );
  237. return bResult;
  238. }
  239. BOOL
  240. prvbMBPortSerialWrite(fmodbus_t* ctx, UCHAR * pucBuffer, USHORT usNBytes )
  241. {
  242. ssize_t res;
  243. size_t left = ( size_t ) usNBytes;
  244. size_t done = 0;
  245. while( left > 0 )
  246. {
  247. if( ( res = write( ctx->iSerialFd, pucBuffer + done, left ) ) == -1 )
  248. {
  249. if( errno != EINTR )
  250. {
  251. break;
  252. }
  253. /* call write again because of interrupted system call. */
  254. continue;
  255. }
  256. done += res;
  257. left -= res;
  258. }
  259. return left == 0 ? TRUE : FALSE;
  260. }
  261. BOOL
  262. xMBPortSerialPoll( fmodbus_t* ctx )
  263. {
  264. BOOL bStatus = TRUE;
  265. USHORT usBytesRead;
  266. int i;
  267. //printf("a %d %d\n",ctx->bRxEnabled,ctx->bTxEnabled);//dbg wanggao
  268. while( ctx->bRxEnabled )
  269. {
  270. if( prvbMBPortSerialRead(ctx, &(ctx->ucBuffer[0]), BUF_SIZE, &usBytesRead ) )
  271. {
  272. if( usBytesRead == 0 )
  273. {
  274. /* timeout with no bytes. */
  275. break;
  276. }
  277. else if( usBytesRead > 0 )
  278. {
  279. for( i = 0; i < usBytesRead; i++ )
  280. {
  281. /* Call the modbus stack and let him fill the buffers. */
  282. ( void )ctx->pxMBFrameCBByteReceived( ctx );
  283. }
  284. ctx->uiRxBufferPos = 0;
  285. }
  286. }
  287. else
  288. {
  289. vMBPortLog( MB_LOG_ERROR, "SER-POLL", "read failed on serial device: %s\n",
  290. strerror( errno ) );
  291. bStatus = FALSE;
  292. }
  293. }
  294. //printf("b %d %d\n",ctx->bRxEnabled,ctx->bTxEnabled);//dbg wanggao
  295. if( ctx->bTxEnabled )
  296. {
  297. //printf("c %d %d\n",ctx->bRxEnabled,ctx->bTxEnabled);//dbg wanggao
  298. while( ctx->bTxEnabled )
  299. {
  300. ( void )ctx->pxMBFrameCBTransmitterEmpty( ctx );
  301. /* Call the modbus stack to let him fill the buffer. */
  302. }
  303. if( !prvbMBPortSerialWrite(ctx, &ctx->ucBuffer[0], ctx->uiTxBufferPos ) )
  304. {
  305. vMBPortLog( MB_LOG_ERROR, "SER-POLL", "write failed on serial device: %s\n",
  306. strerror( errno ) );
  307. bStatus = FALSE;
  308. }
  309. }
  310. return bStatus;
  311. }
  312. BOOL
  313. xMBPortSerialPutByte(fmodbus_t* ctx, CHAR ucByte )
  314. {
  315. assert( ctx->uiTxBufferPos < BUF_SIZE );
  316. ctx->ucBuffer[ctx->uiTxBufferPos] = ucByte;
  317. ctx->uiTxBufferPos++;
  318. return TRUE;
  319. }
  320. BOOL
  321. xMBPortSerialGetByte(fmodbus_t* ctx, CHAR * pucByte )
  322. {
  323. assert( ctx->uiRxBufferPos < BUF_SIZE );
  324. *pucByte = ctx->ucBuffer[ctx->uiRxBufferPos];
  325. ctx->uiRxBufferPos++;
  326. return TRUE;
  327. }