17 #if PLATFORM_IS_LINUX || PLATFORM_IS_APPLE 22 #include <sys/ioctl.h> 23 #include <sys/types.h> 26 #include <sys/statvfs.h> 34 #include <sys/socket.h> 39 #include <CoreFoundation/CoreFoundation.h> 40 #include <IOKit/IOKitLib.h> 41 #include <IOKit/serial/IOSerialKeys.h> 42 #include <IOKit/serial/ioss.h> 43 #include <IOKit/IOBSD.h> 48 #define error_message printf 52 #define B460800 460800 55 #define B921600 921600 58 #define B1500000 1500000 61 #define B2000000 2000000 64 #define B2500000 2500000 67 #define B3000000 3000000 76 #if PLATFORM_IS_WINDOWS 90 #if PLATFORM_IS_WINDOWS 92 #define WINDOWS_OVERLAPPED_BUFFER_SIZE 8192 99 unsigned char* buffer;
100 } readFileExCompletionStruct;
102 static void CALLBACK readFileExCompletion(
DWORD errorCode,
DWORD bytesTransferred, LPOVERLAPPED ov)
104 readFileExCompletionStruct* c = (readFileExCompletionStruct*)ov;
105 c->externalCompletion(c->serialPort, c->buffer, bytesTransferred, errorCode);
116 case 300:
return B300;
117 case 600:
return B600;
118 case 1200:
return B1200;
119 case 2400:
return B2400;
120 case 4800:
return B4800;
121 case 9600:
return B9600;
122 case 19200:
return B19200;
123 case 38400:
return B38400;
124 case 57600:
return B57600;
125 case 115200:
return B115200;
126 case 230400:
return B230400;
127 case 460800:
return B460800;
128 case 921600:
return B921600;
129 case 1500000:
return B1500000;
130 case 2000000:
return B2000000;
131 case 2500000:
return B2500000;
132 case 3000000:
return B3000000;
139 memset(&tty, 0,
sizeof tty);
140 if (tcgetattr(fd, &tty) != 0)
142 error_message(
"error %d from tcgetattr",
errno);
146 #if PLATFORM_IS_APPLE 149 cfsetospeed(&tty, 230400);
150 cfsetispeed(&tty, 230400);
153 if (ioctl(fd, IOSSIOSPEED, &speed) == -1)
155 error_message(
"error %d from ioctl IOSSIOSPEED",
errno);
161 cfsetospeed(&tty, speed);
162 cfsetispeed(&tty, speed);
166 tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
169 tty.c_iflag &= ~IGNBRK;
176 tty.c_iflag &= ~(IXON | IXOFF | IXANY);
178 tty.c_cflag |= (CLOCAL | CREAD);
180 tty.c_cflag &= ~(PARENB | PARODD);
181 tty.c_cflag |= parity;
182 tty.c_cflag &= ~CSTOPB;
183 tty.c_cflag &= ~CRTSCTS;
185 if (tcsetattr(fd, TCSANOW, &tty) != 0)
187 error_message(
"error %d from tcsetattr",
errno);
192 memset(&tty, 0,
sizeof(tty));
201 if (tcgetattr(fd, &tty) < 0)
239 tty.c_cflag &= ~(CSIZE | PARENB);
254 if (tcsetattr(fd, TCSAFLUSH, &tty) < 0)
266 if (serialPort->
handle != 0)
274 #if PLATFORM_IS_WINDOWS 276 void* platformHandle = 0;
277 platformHandle = CreateFileA(serialPort->
port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, blocking ? FILE_FLAG_OVERLAPPED : 0, 0);
278 if (platformHandle == INVALID_HANDLE_VALUE)
282 sprintf_s(tmpPort,
sizeof(tmpPort),
"\\\\.\\%s", port);
283 platformHandle = CreateFileA(tmpPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, blocking ? FILE_FLAG_OVERLAPPED : 0, 0);
284 if (platformHandle == INVALID_HANDLE_VALUE)
291 serialParams.DCBlength =
sizeof(DCB);
292 if (GetCommState(platformHandle, &serialParams))
294 serialParams.BaudRate = baudRate;
295 serialParams.ByteSize = DATABITS_8;
296 serialParams.StopBits = ONESTOPBIT;
297 serialParams.Parity = NOPARITY;
298 serialParams.fBinary = 1;
299 serialParams.fInX = 0;
300 serialParams.fOutX = 0;
301 serialParams.fAbortOnError = 0;
302 serialParams.fNull = 0;
303 serialParams.fErrorChar = 0;
304 serialParams.fDtrControl = DTR_CONTROL_ENABLE;
305 serialParams.fRtsControl = RTS_CONTROL_ENABLE;
306 if (!SetCommState(platformHandle, &serialParams))
317 COMMTIMEOUTS timeouts = { (blocking ? 1 : MAXDWORD), (blocking ? 1 : 0), (blocking ? 1 : 0), 0, 0 };
318 if (!SetCommTimeouts(platformHandle, &timeouts))
325 handle->platformHandle = platformHandle;
328 handle->ovRead.hEvent = CreateEvent(0, 1, 0, 0);
329 handle->ovWrite.hEvent = CreateEvent(0, 1, 0, 0);
331 serialPort->
handle = handle;
335 int fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
343 serialPort->
handle = handle;
353 #if PLATFORM_IS_WINDOWS 356 serialParams.DCBlength =
sizeof(DCB);
358 return GetCommState(handle->platformHandle, &serialParams);
363 return (stat(serialPort->
port, &sb) == 0);
378 #if PLATFORM_IS_WINDOWS 380 CancelIo(handle->platformHandle);
383 CloseHandle(handle->ovRead.hEvent);
384 CloseHandle(handle->ovWrite.hEvent);
386 CloseHandle(handle->platformHandle);
387 handle->platformHandle = 0;
406 #
if PLATFORM_IS_WINDOWS
408 if (!PurgeComm(handle->platformHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR))
415 tcflush(handle->
fd, TCIOFLUSH);
422 #if PLATFORM_IS_WINDOWS 424 static int serialPortReadTimeoutPlatformWindows(
serialPortHandle* handle,
unsigned char* buffer,
int readCount,
int timeoutMilliseconds)
433 ULONGLONG startTime = GetTickCount64();
436 if (ReadFile(handle->platformHandle, buffer + totalRead, readCount - totalRead, &dwRead, handle->
blocking ? &handle->ovRead : 0))
440 GetOverlappedResult(handle->platformHandle, &handle->ovRead, &dwRead, 1);
446 DWORD dwRes = GetLastError();
447 if (dwRes == ERROR_IO_PENDING)
449 dwRes = WaitForSingleObject(handle->ovRead.hEvent,
_MAX(1, timeoutMilliseconds - (
int)(GetTickCount64() - startTime)));
453 if (!GetOverlappedResult(handle->platformHandle, &handle->ovRead, &dwRead, 0))
455 CancelIo(handle->platformHandle);
465 CancelIo(handle->platformHandle);
466 GetOverlappedResult(handle->platformHandle, &handle->ovRead, &dwRead, 1);
473 CancelIo(handle->platformHandle);
483 if (!handle->
blocking && totalRead < readCount && timeoutMilliseconds > 0)
488 while (totalRead < readCount && GetTickCount64() - startTime < timeoutMilliseconds);
499 struct timeval start, curr;
500 if (timeoutMilliseconds > 0)
502 gettimeofday(&start,
NULL);
507 if (timeoutMilliseconds > 0)
509 struct pollfd fds[1];
510 fds[0].fd = handle->
fd;
511 fds[0].events = POLLIN;
512 int pollrc = poll(fds, 1, timeoutMilliseconds);
513 if (pollrc <= 0 || !(fds[0].revents & POLLIN))
518 n = read(handle->
fd, buffer + totalRead, readCount - totalRead);
521 error_message(
"error %d from read, fd %d",
errno, handle->
fd);
528 if (timeoutMilliseconds > 0 && totalRead < readCount)
530 gettimeofday(&curr,
NULL);
531 dtMs = ((curr.tv_sec - start.tv_sec) * 1000) + ((curr.tv_usec - start.tv_usec) / 1000);
532 if (dtMs >= timeoutMilliseconds)
538 timeoutMilliseconds =
_MAX(0, timeoutMilliseconds - dtMs);
553 if (timeoutMilliseconds < 0)
558 #if PLATFORM_IS_WINDOWS 560 return serialPortReadTimeoutPlatformWindows(handle, buffer, readCount, timeoutMilliseconds);
574 #
if PLATFORM_IS_WINDOWS
576 readFileExCompletionStruct c;
577 c.externalCompletion = completion;
578 c.serialPort = serialPort;
580 memset(&(c.ov), 0,
sizeof(c.ov));
582 if (!ReadFileEx(handle->platformHandle, buffer, readCount, (LPOVERLAPPED)&c, readFileExCompletion))
590 int n = read(handle->
fd, buffer, readCount);
591 completion(serialPort, buffer, (n < 0 ? 0 : n), (n >= 0 ? 0 : n));
602 #
if PLATFORM_IS_WINDOWS
605 if (!WriteFile(handle->platformHandle, buffer, writeCount, &dwWritten, handle->
blocking ? &handle->ovWrite : 0))
607 DWORD result = GetLastError();
608 if (result != ERROR_IO_PENDING)
610 CancelIo(handle->platformHandle);
617 if (!GetOverlappedResult(handle->platformHandle, &handle->ovWrite, &dwWritten, 1))
619 CancelIo(handle->platformHandle);
628 return write(handle->
fd, buffer, writeCount);
646 return serialPort->
pfnWrite(serialPort, buffer, writeCount);
659 #
if PLATFORM_IS_WINDOWS
662 if (ClearCommError(handle->platformHandle, 0, &commStat))
664 return commStat.cbInQue;
671 ioctl(handle->
fd, FIONREAD, &bytesAvailable);
672 return bytesAvailable;
697 #if PLATFORM_IS_WINDOWS 699 Sleep(sleepMilliseconds);
703 usleep(sleepMilliseconds * 1000);
pfnSerialPortIsOpen pfnIsOpen
char port[MAX_SERIAL_PORT_NAME_LENGTH+1]
pfnSerialPortAsyncRead pfnAsyncRead
#define MAX_SERIAL_PORT_NAME_LENGTH
pfnSerialPortGetByteCountAvailableToWrite pfnGetByteCountAvailableToWrite
void serialPortSetPort(serial_port_t *serialPort, const char *port)
pfnSerialPortOpen pfnOpen
void(* pfnSerialPortAsyncReadCompletion)(serial_port_t *serialPort, unsigned char *buf, int len, int errorCode)
pfnSerialPortRead pfnRead
pfnSerialPortFlush pfnFlush
int SERIAL_PORT_DEFAULT_TIMEOUT
int serialPortClose(serial_port_t *serialPort)
pfnSerialPortSleep pfnSleep
NMI_API sint8 close(SOCKET sock)
pfnSerialPortClose pfnClose
pfnSerialPortGetByteCountAvailableToRead pfnGetByteCountAvailableToRead
pfnSerialPortWrite pfnWrite
void * calloc(size_t nitems, size_t size)