シリアル通信のラッパー書いてみた

WindowsでもLinuxでも使えるシリアル通信ラッパー書いてみた。

ロボットにPC載せて、もっと賢いことをしてみようと計画中。これをやろうとすると、PCと周辺機器との通信が必要になるわけですね。方法はいろあるのでしょうが、最近大活躍のFT232RLを使ってUSB-シリアル変換するのが一番お手軽そう。

PCの環境としてはRTミドルウェアを検討中。RTミドルウェア自体はWindowsでもLinuxでも動くから、自分の書いた部分もどっちでも動くようにしたいな。ってことで適当ラッパー。


参考

#include <iostream>
#include <string>
#include <sstream>

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
typedef int HANDLE;
#endif

class SerialPort {
	HANDLE hCom;

public:
	SerialPort(int port, int baudRate/*, int parity, int dataBits, int stopBits*/) {
#if defined(_WIN32) || defined(_WIN64)
		std::wostringstream comName;
		comName << "\\\\.\\COM" << port;
		hCom = CreateFile(comName.str().c_str(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if(hCom==INVALID_HANDLE_VALUE)
			throw new std::ios_base::failure("cannot open com port");

		DCB dcb;
		GetCommState(hCom, &dcb);

		dcb.BaudRate = baudRate;
		SetCommState(hCom, &dcb);
#else
		std::ostringstream comName;
		comName << "/dev/ttyS" << port;
		hCom = open(comName.str().c_str(),O_RDWR|O_NOCTTY);
		if(hCom==-1)
			throw new std::ios_base::failure("cannot open com port");
		
		struct termios tty;
		memset(&tty,0,sizeof(tty));
		tty.c_cflag=CS8|CLOCAL|CREAD;
		tty.c_cc[VMIN]=1;
		tty.c_cc[VTIME]=0;
		cfsetospeed(&tty, baudRate);
		cfsetispeed(&tty, baudRate);
		tcflush(hCom,TCIFLUSH);
		tcsetattr(hCom,TCSANOW,&tty);
#endif
	}

	int read(unsigned char *buf, int size) {
#if defined(_WIN32) || defined(_WIN64)
		DWORD rcv_size;
		if(!ReadFile(hCom, buf, size, &rcv_size, NULL))
			throw new std::ios_base::failure("Failed to read serial port");
		return (int)rcv_size;
#else
		return ::read(hCom, (void*)buf, size);
#endif
	}

	int write(unsigned char *buf, int size) {
#if defined(_WIN32) || defined(_WIN64)
		DWORD xmit_size;
		if(!WriteFile(hCom, buf, size, &xmit_size, NULL))
			throw new std::ios_base::failure("Failed to write serial port");
		return (int)xmit_size;
#else
		return ::write(hCom, (void*)buf, size);
#endif
	}

	~SerialPort() {
#if defined(_WIN32) || defined(_WIN64)
		CloseHandle(hCom);
		hCom = NULL;
#else
		close(hCom);
#endif
	}
};

int main(void) {
	SerialPort port(19, 9600);
	unsigned char a[10] = {0,1,2,3,4,5,6,7,8,9};
	for(int i=0;i<1000;i++) port.write(a, sizeof(a));
	return 0;
}