serial.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. // SerialClass.cpp: implementation of the SSerialClass class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "serial.h"
  5. #include "public.h"
  6. // #include <string.h>
  7. ////////////////////////////////////////////////////////////////////////////////////////////////////
  8. //数据位 停止位 校验位 流控
  9. void SSerial::SetCtrl (int iDataBit, int iStopBit, Parity ParityBit, FlowCtl iFlow)
  10. {
  11. m_cDataBit = iDataBit;
  12. m_cParityBit = ParityBit;
  13. m_cStopBit = iStopBit;
  14. m_cFlow = iFlow;
  15. }
  16. #ifdef WIN32
  17. //串口操作类,初始化
  18. SSerial::SSerial ( void )
  19. {
  20. m_cDataBit = 8;
  21. m_cParityBit = Parity_NO;
  22. m_cStopBit = 1;
  23. m_cFlow = Flow_NO;
  24. m_hCom = NULL;
  25. }
  26. SSerial::~SSerial ( void )
  27. {
  28. CloseHandle(m_hCom);
  29. m_hCom=0;
  30. }
  31. // //端口(如COM3),波特率(如9600)
  32. bool SSerial::Open (const char* sPort, const int baut )
  33. {
  34. if (m_hCom) return true;
  35. char sOpenPort[32];
  36. sprintf(sOpenPort,"\\\\.\\%s",sPort);
  37. m_hCom = CreateFileA(sOpenPort, GENERIC_READ|GENERIC_WRITE,
  38. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  39. if (m_hCom < 0 || m_hCom > (HANDLE)0x7fffffff ) {
  40. m_hCom = NULL;
  41. return false;
  42. }
  43. if( ! ::SetCommMask( m_hCom, 0 ) )
  44. {
  45. ::CloseHandle( m_hCom );
  46. return false;
  47. }
  48. ::SetCommMask(m_hCom, EV_RXCHAR | EV_CTS | EV_DSR | EV_RLSD | EV_BREAK | EV_ERR);
  49. if( ! ::SetupComm( m_hCom, 10000L, 10000L ) )
  50. {
  51. ::CloseHandle( m_hCom );
  52. return false;
  53. }
  54. // 超时时间参数设置
  55. COMMTIMEOUTS ComTim;
  56. ComTim.ReadIntervalTimeout = MAXDWORD;
  57. ComTim.ReadTotalTimeoutMultiplier = 0;
  58. ComTim.ReadTotalTimeoutConstant = 0;
  59. ComTim.WriteTotalTimeoutMultiplier = 0;
  60. ComTim.WriteTotalTimeoutConstant = 20000;
  61. // 设置超时
  62. if( ! ::SetCommTimeouts( m_hCom, &ComTim ) )
  63. {
  64. ::CloseHandle( m_hCom );
  65. return false;
  66. }
  67. DCB dcb;
  68. GetCommState(m_hCom, &dcb);
  69. dcb.fBinary = TRUE;
  70. dcb.fAbortOnError = TRUE;
  71. dcb.fNull = FALSE;
  72. m_nBaut = baut;
  73. dcb.BaudRate = m_nBaut;
  74. dcb.ByteSize = m_cDataBit;
  75. switch (m_cStopBit) {
  76. case 1: /*one stop bit*/
  77. dcb.StopBits = ONESTOPBIT;
  78. //SetCommConfig(m_hDeviceFile, &mConfig, sizeof(COMMCONFIG));
  79. break;
  80. case 2: /*two stop bits*/
  81. dcb.StopBits = TWOSTOPBITS;
  82. //SetCommConfig(m_hDeviceFile, &mConfig, sizeof(COMMCONFIG));
  83. break;
  84. default:
  85. dcb.StopBits = ONE5STOPBITS;
  86. }
  87. switch (m_cParityBit) {
  88. case Parity_NO: /*no parity*/
  89. dcb.fParity = NOPARITY;
  90. dcb.Parity = 0;
  91. break;
  92. case Parity_ODD: /*odd parity*/
  93. dcb.fParity = TRUE;
  94. dcb.Parity = 1; //None,Odd,Even,Mark,Space
  95. break;
  96. case Parity_EVEN: /*even parity*/
  97. dcb.fParity = TRUE;
  98. dcb.Parity = 2; //None,Odd,Even,Mark,Space
  99. break;
  100. default:
  101. dcb.fParity = NOPARITY;
  102. dcb.Parity = 0;
  103. }
  104. dcb.fRtsControl = RTS_CONTROL_ENABLE;
  105. dcb.fDtrControl = DTR_CONTROL_ENABLE;
  106. //硬件,流控参数
  107. dcb.fOutxCtsFlow = FALSE;
  108. dcb.fOutxDsrFlow = FALSE;
  109. dcb.fOutX = FALSE;
  110. dcb.fInX = FALSE;
  111. switch(m_cFlow) { //流控
  112. case Flow_NO: /*no flow control*/
  113. break;
  114. case Flow_XONOFF: /*software (XON/XOFF) flow control*/
  115. dcb.fOutxCtsFlow = FALSE;
  116. dcb.fOutxDsrFlow = FALSE;
  117. dcb.fOutX = TRUE;
  118. dcb.fInX = TRUE;
  119. break;
  120. case Flow_CTS: //CtsRtsFlowControl CtsDtrFlowControl:
  121. dcb.fOutxCtsFlow = TRUE;
  122. dcb.fOutxDsrFlow = FALSE;
  123. dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  124. break;
  125. case Flow_DSR: // DsrRtsFlowControl DsrDtrFlowControl:
  126. dcb.fOutxCtsFlow = FALSE;
  127. dcb.fOutxDsrFlow = TRUE;
  128. dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  129. break;
  130. default:
  131. break;
  132. }
  133. SetCommState(m_hCom, &dcb);
  134. PurgeComm(m_hCom, PURGE_TXABORT | PURGE_TXCLEAR);
  135. PurgeComm(m_hCom, PURGE_RXABORT | PURGE_RXCLEAR);
  136. return true;
  137. }
  138. bool SSerial::IsOpen()
  139. {
  140. return m_hCom!=NULL;
  141. }
  142. void SSerial::Close ()
  143. {
  144. if ( m_hCom )
  145. {
  146. CloseHandle(m_hCom);
  147. m_hCom = 0;
  148. }
  149. }
  150. //清除缓存
  151. void SSerial::Flush()
  152. {
  153. FlushFileBuffers(m_hCom);
  154. }
  155. //设置超时,单位毫秒
  156. void SSerial::SetTimeout(unsigned int msec)
  157. {
  158. if (msec<0) msec=100;
  159. if (msec>120000) msec=120000;
  160. int Timeout_Sec = msec/1000;
  161. int msec = (msec%1000);
  162. COMMTIMEOUTS mTimeouts;
  163. //ReadIntervalTimeout:指定通信线路上两个字符到达之间的最大时间
  164. //ReadTotalTimeoutMultiplier:用于设定读总超时时间的系数.
  165. //ReadTotalTimeoutConstant:设定读总超时时间的常量值.读总超时时间
  166. //WriteTotalTimeoutMultiplier:用于设定写总超时时间的系数.写总超时时间
  167. //WriteTotalTimeoutConstant:用于设定写总超时时间的常量值.写总超时时间
  168. mTimeouts.ReadIntervalTimeout = 0;
  169. mTimeouts.ReadTotalTimeoutMultiplier = 0;
  170. mTimeouts.ReadTotalTimeoutConstant = Timeout_Sec*1000+Timeout_Millisec;
  171. mTimeouts.WriteTotalTimeoutMultiplier = 0;
  172. mTimeouts.WriteTotalTimeoutConstant = Timeout_Sec*1000+Timeout_Millisec;
  173. SetCommTimeouts(m_hCom, &mTimeouts);
  174. }
  175. // 通过串口向外发N个字节
  176. // data: 发送字节首地址
  177. // datalen: 发送字节长度
  178. // Return: -1: 发送失败 >0:已经发送的字节
  179. int SSerial::SendOnce(const char *sData, int iLen, int timeout )
  180. {
  181. SetTimeout(timeout);
  182. unsigned long iWrite = 0;
  183. WriteFile(m_hCom, sData, iLen, &iWrite, NULL);
  184. return iWrite;
  185. }
  186. // 从串口读入N个字节
  187. // Input: data: 读入字节首地址
  188. // datalen: 发送字节长度
  189. // timeout: 超时时间,单位秒 <0 时代表无限期等待
  190. // Return: -1: 读入失败 >0:已经读入的字节
  191. int SSerial::ReceiveOnce ( char *sData, int iLen, int iTimeout )
  192. {
  193. COMSTAT stat;
  194. DWORD errmask=0;
  195. ClearCommError(m_hCom, &errmask, &stat);
  196. if (iTimeout < 0) iTimeout = 100;
  197. if (iTimeout > 120000) iTimeout = 120000;
  198. SetTimeout(iTimeout);
  199. unsigned long lRead = 0;
  200. ReadFile(m_hCom, (void*)(sData), (DWORD)iLen, &lRead, NULL);
  201. return lRead;
  202. }
  203. #else
  204. //串口操作类,初始化
  205. SSerial::SSerial ( void )
  206. {
  207. m_cDataBit = 8;
  208. m_cParityBit = Parity_NO;
  209. m_cStopBit = 1;
  210. m_cFlow = Flow_NO;
  211. m_hCom = -1;
  212. }
  213. SSerial::~SSerial ( void )
  214. {
  215. if ( m_hCom != -1 )
  216. close(m_hCom);
  217. }
  218. //端口(如ttymxc3),波特率(如9600)
  219. bool SSerial::Open (const char* sPort, const int iBaut )
  220. {
  221. if ( m_hCom != -1 )
  222. {
  223. close(m_hCom);
  224. m_hCom = -1;
  225. }
  226. char sPortstr[32] = { 0 };
  227. sprintf ( sPortstr, "/dev/%s", sPort );
  228. //打开串口
  229. //O_NOCTTY: 通知系统,该程序不想成为此端口的“控制终端”。
  230. // 如果不设,则任何输入(如键盘的中断信号)都会影响程序的运行
  231. //O_NODELAY: 该程序不关注DCD信号线所处的状态,即不管对端设备是在运行还是挂起。
  232. // 若不设置,则程序会被置为睡眠状态,直到DCD信号低为止(可能无流控制时无效)
  233. //非阻塞模式: read没有读到数据立即返回-1
  234. //超时0秒时: read没有读到数据立即返回 0 (设置了超时的阻塞模式)
  235. m_hCom = open ( sPortstr, O_RDWR | O_NOCTTY ); //O_NDELAY 非阻塞,未读到数据立即返回
  236. if ( m_hCom == -1 )
  237. return false;
  238. tcflush(m_hCom, TCIOFLUSH); //溢出的数据可以接收,但不读
  239. m_nBaut = iBaut;
  240. int iSpeed = 0;
  241. int iSpeedSet[] =
  242. {
  243. B50, B75, B110, B134, B150,
  244. B200, B300, B600, B1200, B1800,
  245. B2400, B4800, B9600, B19200, B38400,
  246. B57600, B115200,B230400,B460800,B576000,
  247. B1152000
  248. };
  249. int iSpeedIn[] =
  250. {
  251. 50, 75, 110, 134, 150,
  252. 200, 300, 600, 1200, 1800,
  253. 2400, 4800, 9600, 19200, 38400,
  254. 57600, 115200, 230400, 460800, 576000,
  255. 1152000
  256. };
  257. for (int ipos = 0; ipos < sizeof(iSpeedSet); ipos++)
  258. {
  259. if (iBaut == iSpeedIn[ipos])
  260. {
  261. iSpeed = iSpeedSet[ipos];
  262. break;
  263. }
  264. }
  265. termios tios;
  266. //------------设置端口属性----------------
  267. //baudrates
  268. memset(&tios, 0, sizeof(tios));
  269. tcgetattr(m_hCom, &tios); //get the serial port attributions
  270. cfsetispeed(&tios, iSpeed); //填入串口输入端的波特率
  271. cfsetospeed(&tios, iSpeed); //填入串口输出端的波特率
  272. tios.c_cflag &= ~CSIZE; //3、以下为设置串口属性
  273. //控制模式,data bits
  274. tios.c_cflag &= ~CSIZE; //控制模式,屏蔽字符大小位
  275. switch(m_cDataBit)
  276. {
  277. case 5:
  278. tios.c_cflag |= CS5;
  279. case 6:
  280. tios.c_cflag |= CS6;
  281. case 7:
  282. tios.c_cflag |= CS7;
  283. default:
  284. tios.c_cflag |= CS8;
  285. }
  286. //控制模式 奇偶检验位
  287. switch(m_cParityBit)
  288. {
  289. case Parity_ODD:
  290. tios.c_cflag |= (PARODD | PARENB);
  291. tios.c_iflag |= (INPCK);
  292. break;
  293. case Parity_EVEN:
  294. tios.c_cflag |= PARENB;
  295. tios.c_cflag &= ~PARODD;
  296. tios.c_iflag |= (INPCK); //Disnable parity checking
  297. break;
  298. default:
  299. tios.c_cflag &= ~PARENB; //no parity check
  300. tios.c_iflag &= ~INPCK; //Disnable parity checking
  301. break;
  302. }
  303. //控制模式,stop bits
  304. switch ( m_cStopBit )
  305. {
  306. case 2:
  307. tios.c_cflag |= CSTOPB; //2 stop bits
  308. break;
  309. default:
  310. tios.c_cflag &= ~CSTOPB; //1 stop bits
  311. break;
  312. }
  313. //*
  314. tios.c_cflag &= ~CRTSCTS; //no flow control
  315. tios.c_iflag &= ~(IXON | IXOFF | IXANY); //software flow control
  316. // 控制模式,flow control
  317. switch(m_cFlow)
  318. {
  319. case Flow_CTS:
  320. tios.c_cflag |= CRTSCTS; //hardware flow control
  321. break;
  322. case Flow_XONOFF:
  323. tios.c_iflag |= (IXON | IXOFF | IXANY); //software flow control
  324. break;
  325. default:
  326. break;
  327. }
  328. tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
  329. tios.c_oflag &= ~OPOST; /*Output*/
  330. tios.c_oflag &= ~(ONLCR | OCRNL);
  331. tios.c_iflag &= ~(INLCR | ICRNL);
  332. //other attributions default
  333. tios.c_cc[VMIN] = 0; //控制字符, 所要读取字符的最小数量
  334. tios.c_cc[VTIME] = 0; //控制字符, 读取第一个字符的等待时间 unit: (1/10)second
  335. if (tcsetattr(m_hCom, TCSANOW, &tios) < 0)
  336. {
  337. close(m_hCom);
  338. m_hCom = -1;
  339. return false;
  340. } //8、使以上设置的属性立即生效
  341. int modemcontrl;
  342. modemcontrl = TIOCM_DTR;
  343. ioctl(m_hCom,TIOCMBIS,&modemcontrl);
  344. modemcontrl = TIOCM_RTS;
  345. ioctl(m_hCom,TIOCMBIS,&modemcontrl);
  346. return true;
  347. }
  348. bool SSerial::IsOpen()
  349. {
  350. return m_hCom != -1;
  351. }
  352. // 串口清理
  353. void SSerial::Close ()
  354. {
  355. if ( m_hCom != -1 )
  356. {
  357. close(m_hCom);
  358. m_hCom = -1;
  359. }
  360. }
  361. //清除缓存
  362. void SSerial::Flush()
  363. {
  364. tcflush(m_hCom, TCIOFLUSH);
  365. }
  366. // 通过串口向外发N个字节
  367. // data: 发送字节首地址
  368. // datalen: 发送字节长度
  369. // Return: -1: 发送失败 >0:已经发送的字节
  370. int SSerial::SendOnce(const char *sData, int iLen, int timeout )
  371. {
  372. SetTimeout(timeout);
  373. return write( m_hCom, sData, iLen); //实际写入的长度
  374. }
  375. // 从串口读入N个字节
  376. // Input: data: 读入字节首地址
  377. // datalen: 发送字节长度
  378. // timeout: 超时时间,单位秒 <0 时代表无限期等待
  379. // Return: -1: 读入失败 >0:已经读入的字节
  380. int SSerial::ReceiveOnce ( char *sData, int iLen, int iTimeout )
  381. {
  382. SetTimeout(iTimeout);
  383. return read(m_hCom, sData, iLen);
  384. }
  385. //设置超时,单位毫秒
  386. void SSerial::SetTimeout(unsigned int msec)
  387. {
  388. fd_set fs_read;
  389. struct timeval tv_timeout;
  390. FD_ZERO(&fs_read);
  391. FD_SET(m_hCom, &fs_read);
  392. if (msec < 0) msec = 100;
  393. if (msec > 120000) msec = 120000;
  394. tv_timeout.tv_sec = msec / 1000; //time out : unit sec
  395. tv_timeout.tv_usec = (msec % 1000) * 1000;
  396. select( m_hCom+1, &fs_read, NULL, NULL, &tv_timeout);
  397. }
  398. #endif
  399. // data: 发送字节首地址
  400. // datalen: 发送字节长度
  401. // Return: -1: 发送失败 >0:已经发送的字节
  402. int SSerial::Send(const char *sData, int iLen, int iTimeout)
  403. {
  404. if (IsOpen() == false) //串口未被打开
  405. return -1;
  406. int nBytesSent = 0;
  407. int nBytesThisTime;
  408. if (iTimeout <= 0) iTimeout = 100;
  409. INT64 iNow = GetSystemTime();
  410. INT64 iEnd = iNow + iTimeout;
  411. do{
  412. int iTimeWait = iEnd - iNow;
  413. if (iTimeWait < 100) iTimeWait = 100;
  414. nBytesThisTime = SendOnce(sData, iLen - nBytesSent, iTimeWait);
  415. if (nBytesThisTime < 0) return -1;
  416. nBytesSent += nBytesThisTime;
  417. sData += nBytesThisTime;
  418. Sleep(10);
  419. iNow = GetSystemTime();
  420. }while(nBytesSent < iLen && iNow < iEnd);
  421. return nBytesSent;
  422. }
  423. // Input: data: 读入字节首地址
  424. // datalen: 发送字节长度
  425. // timeout: 超时时间,单位ms <0 时代表无限期等待
  426. // Return: -1: 读入失败 >0:已经读入的字节
  427. int SSerial::Receive ( char *sData, int iLen, int iTimeout )
  428. {
  429. int nBytesRead = 0;
  430. int nBytesThisTime=0;
  431. if (iTimeout <= 0) iTimeout = 100;
  432. INT64 iNow = GetSystemTime();
  433. INT64 iEnd = iNow + iTimeout;
  434. do{
  435. int iTimeWait = iEnd - iNow;
  436. if (iTimeWait < 100) iTimeWait = 100;
  437. nBytesThisTime = ReceiveOnce(sData, iLen - nBytesRead, iTimeWait);
  438. if (nBytesThisTime < 0) return nBytesRead;
  439. nBytesRead += nBytesThisTime;
  440. sData += nBytesThisTime;
  441. Sleep(10);
  442. iNow = GetSystemTime();
  443. }while(nBytesRead < iLen && iNow < iEnd);
  444. if (nBytesRead)
  445. return nBytesRead;
  446. else
  447. return 0;
  448. }