#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <IOKit/serial/ioss.h>
#include "IOSerialTestLib.h"
int _testIOSSIOSPEEDIoctl(int fd, speed_t speed);
int _modifyAttributes(int fd, struct termios *originalOptions);
int _modifyModemLines(int fd);
#pragma mark -
int _testIOSSIOSPEEDIoctl(int fd, speed_t speed)
{
struct termios options;
if (ioctl(fd, IOSSIOSPEED, &speed) == -1) {
printf("[WARN] ioctl(..., IOSSIOSPEED, %lu).\n", speed);
goto fail;
}
if (tcgetattr(fd, &options) == -1) {
printf("[WARN] _modifyAttributes: tcgetattr failed\n");
goto fail;
}
if (cfgetispeed(&options) != speed ||
cfgetospeed(&options) != speed) {
printf("[WARN] _modifyAttributes: cfsetspeed failed, %lu, %lu.\n",
speed,
cfgetispeed(&options));
goto fail;
}
return 0;
fail:
return -1;
}
int _modifyAttributes(int fd, struct termios *originalOptions)
{
int result = 0;
unsigned long mics = 1UL;
struct termios options;
if (!originalOptions) {
printf("[FAIL] _modifyAttributes: NULL argument unexpected\n");
goto fail;
}
if (ioctl(fd, TIOCEXCL) == -1) {
printf("[FAIL] _modifyAttributes: ioctl TIOCEXCL failed\n");
goto fail;
}
if (fcntl(fd, F_SETFL, 0) == -1) {
printf("[FAIL] _modifyAttributes: fcntl failed\n");
goto fail;
}
if (tcgetattr(fd, originalOptions) == -1) {
printf("[FAIL] _modifyAttributes: tcgetattr failed\n");
goto fail;
}
options = *originalOptions;
cfmakeraw(&options);
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
if (cfsetspeed(&options, B19200) == -1) {
printf("[FAIL] _modifyAttributes: cfsetspeed failed\n");
goto fail;
}
options.c_cflag |= (CS7 | PARENB | CCTS_OFLOW | CRTS_IFLOW);
if (tcsetattr(fd, TCSANOW, &options) == -1) {
printf("[FAIL] _modifyAttributes: tcsetattr failed\n");
goto fail;
}
if (tcgetattr(fd, &options) == -1) {
printf("[FAIL] _modifyAttributes: tcgetattr failed\n");
goto fail;
}
if ((options.c_cflag & (CS7 | PARENB | CCTS_OFLOW | CRTS_IFLOW)) !=
(CS7 | PARENB | CCTS_OFLOW | CRTS_IFLOW)) {
printf("[FAIL] _modifyAttributes: tcsetattr/tcgetattr failed\n");
goto fail;
}
if (cfgetispeed(&options) != B19200 ||
cfgetospeed(&options) != B19200) {
printf("[FAIL] _modifyAttributes: cfsetspeed failed\n");
goto fail;
}
if (ioctl(fd, IOSSDATALAT, &mics) == -1) {
printf("[FAIL] _modifyAttributes: ioctl IOSSDATALAT failed\n");
goto fail;
}
return result;
fail:
return -1;
}
int _modifyModemLines(int fd)
{
int handshake;
if (ioctl(fd, TIOCSDTR) == -1) {
printf("[FAIL] _modifyModemLines: ioctl TIOCSDTR failed\n");
goto fail;
}
if (ioctl(fd, TIOCCDTR) == -1) {
printf("[FAIL] _modifyModemLines: ioctl TIOCCDTR failed\n");
goto fail;
}
handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
if (ioctl(fd, TIOCMSET, &handshake) == -1) {
printf("[FAIL] _modifyModemLines: ioctl TIOCMSET failed\n");
goto fail;
}
if (ioctl(fd, TIOCMGET, &handshake) == -1) {
printf("[FAIL] _modifyModemLines: ioctl TIOCMGET failed\n");
goto fail;
}
return 0;
fail:
return -1;
}
#pragma mark -
int testOpenClose(const char *path)
{
int fd = -1;
int result = 0;
fd = open(path, O_RDWR|O_NONBLOCK);
if (fd == -1) {
return -1;
}
result = close(fd);
if (result) {
return -1;
}
return 0;
}
int testModifyConfig(const char *path)
{
int fd = -1;
int result = 0;
speed_t speed;
struct termios originalTTYAttrs;
fd = open(path, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (fd == -1) {
printf("[FAIL] testModifyConfig: open failed\n");
goto fail;
}
if (_modifyAttributes(fd, &originalTTYAttrs)) {
printf("[FAIL] testModifyConfig: config failed\n");
goto fail;
}
if (_modifyModemLines(fd)) {
printf("[FAIL] testModifyConfig: config failed\n");
goto fail;
}
speed = 40000;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 58000;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 250000;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 10400;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 8192;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 128000;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 31250;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[WARN] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
}
speed = 38400;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[FAIL] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
goto fail;
}
speed = 115200;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[FAIL] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
goto fail;
}
speed = 19200;
if (_testIOSSIOSPEEDIoctl(fd, speed)) {
printf("[FAIL] testModifyConfig: IOSSIOSPEED ioctl with %lu failed\n", speed);
goto fail;
}
tcsetattr(fd, TCSANOW, &originalTTYAttrs);
result = close(fd);
if (result == -1) {
printf("[FAIL] testModifyConfig: close failed\n");
goto fail;
}
return 0;
fail:
if (fd != -1) close(fd);
return -1;
}
#define kHelloWorldString "Hello World"
int testReadWrite(const char *readPath, const char *writePath, const char *message)
{
int readFd = -1;
int writeFd = -1;
int result = 0;
ssize_t numBytes;
char myMessage[256];
char buffer[256]; char *bufPtr;
struct termios originalReadTTYAttrs;
struct termios originalWriteTTYAttrs;
if (!message) {
if (strlcpy(myMessage, kHelloWorldString, sizeof(myMessage)) >=
sizeof(myMessage)) {
myMessage[sizeof(myMessage)-1] = '\0';
}
}
else {
if (strlcpy(myMessage, message, sizeof(myMessage)) >= sizeof(myMessage)) {
myMessage[sizeof(myMessage)-1] = '\0';
}
}
readFd = open(readPath, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (readFd == -1) {
printf("[FAIL] testReadWrite: open failed\n");
goto fail;
}
if (_modifyAttributes(readFd, &originalReadTTYAttrs)) {
printf("[FAIL] testReadWrite: _modifyAttributes failed\n");
goto fail;
}
writeFd = open(writePath, O_RDWR|O_NOCTTY|O_NONBLOCK);
if (writeFd == -1) {
printf("[FAIL] testReadWrite: open failed\n");
goto fail;
}
if (_modifyAttributes(writeFd, &originalWriteTTYAttrs)) {
printf("[FAIL] testReadWrite: _modifyAttributes failed\n");
goto fail;
}
if (_modifyModemLines(readFd) ||
_modifyModemLines(writeFd)) {
printf("[FAIL] testReadWrite: _modifyModemLines failed\n");
goto fail;
}
numBytes = write(writeFd, myMessage, strnlen(myMessage, 256));
if (numBytes == -1) {
printf("[FAIL] write returned -1\n");
goto fail;
}
if ((size_t)numBytes < strnlen(myMessage, 256)) {
printf("[FAIL] write did not complete\n");
goto fail;
}
memset(buffer, 0, sizeof(buffer));
bufPtr = buffer;
do {
numBytes = read(readFd, bufPtr, &buffer[sizeof(buffer)] - bufPtr - 1);
if (numBytes > 0) {
bufPtr += numBytes;
if (*(bufPtr - 1) == '\n' || *(bufPtr - 1) == '\r') {
break;
}
}
} while (numBytes > 0);
if (strncmp(buffer, myMessage, sizeof(myMessage))) {
printf("[FAIL] testReadWrite: read string was: \"%s\", "
"expected: \"%s\"\n", buffer, myMessage);
goto fail;
}
tcsetattr(readFd, TCSANOW, &originalReadTTYAttrs);
tcsetattr(writeFd, TCSANOW, &originalWriteTTYAttrs);
result = close(readFd);
readFd = -1;
if (result == -1) {
printf("[FAIL] testReadWrite: close failed\n");
goto fail;
}
result = close(writeFd);
writeFd = -1;
if (result == -1) {
printf("[FAIL] testReadWrite: close failed\n");
goto fail;
}
return 0;
fail:
if (readFd != -1) close(readFd);
if (writeFd != -1) close(writeFd);
return -1;
}