我正在尝试使用c中的unistd.h Linux函数写入MAC OSX上的蓝牙设备。我很好地连接并且成功地写了前几个字节。当我尝试向其写入其他命令时(每15ms有一些字节添加到写缓冲区),即使write()函数返回1(写入成功),我也看不到任何结果。
如果您开始写入并且在尝试启动另一次写入时没有完成(因为它是非阻塞的),那么这可能会搞砸初始写入吗? (如果是这样,有没有办法检查写入是否已经完成?)这是我唯一能想到的事情,因为写入频繁发生并且前两个成功发送。
qwbyte()只是在输出数组中添加一个字节并增加其长度
开放端口功能:
BAMid = -1;
struct termios options;
struct termios originalTTYAttrs;
// Open the serial port read/write, nonblocking, with no controlling terminal, and don't wait for a connection.
BAMid = open(strPath, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (BAMid == -1)
{
printf("Error opening serial port %s - %s(%d).\n",
strPath, strerror(errno), errno);
goto error;
}
// Issue TIOCEXCL ioctl to prevent additional opens except by root-owned processes.
if (ioctl(BAMid, TIOCEXCL) == -1)
{
printf("Error setting TIOCEXCL on %s - %s(%d).\n",
strPath, strerror(errno), errno);
goto error;
}
// Get the current options and save them so we can restore the default settings later.
if (tcgetattr(BAMid, &originalTTYAttrs) == -1)
{
printf("Error getting tty attributes %s - %s(%d).\n",
strPath, strerror(errno), errno);
goto error;
}
// The serial port attributes such as timeouts and baud rate are set by modifying the termios
// structure and then calling tcsetattr() to cause the changes to take effect. Note that the
// changes will not become effective without the tcsetattr() call.
options = originalTTYAttrs;
// Set raw input (non-canonical) mode, with reads blocking until either a single character
// has been received or a one second timeout expires. [should be moot since we are leaving it as nonblocking]
cfmakeraw(&options);
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 10;
cfsetspeed(&options, B57600); // Set 57600 baud
options.c_cflag |= CS8; // Use 8 bit words
// Cause the new options to take effect immediately.
if (tcsetattr(BAMid, TCSANOW, &options) == -1)
{
printf("Error setting tty attributes %s - %s(%d).\n",
strPath, strerror(errno), errno);
goto error;
}
//flush old transmissions
if (tcflush(BAMid,TCIOFLUSH) == -1) {
printf("Error flushing BAM serial port - %s(%d).\n",
strerror(errno), errno);
}
oBufLength = 0;
// Ask it to start
if (! qwbyte(CmdStart) ) {
goto error;
}
if (! qwbyte(CmdFull) ) {
goto error;
}
//this transmit works
txbytes();
printf("success opening port!");
return -1;
// Failure path
error:
if (BAMid != -1) {
close(BAMid);
}
printf("returning an error--%d",errno);
return errno;
}
写函数(txbytes):
int i, bufSize, numBytes;
if(oBufLength != 0) { //if the output array isn't empty
//duplicating the output array and its size so it can
//be overwritten while this write is occuring
printf("about to transmit: ");
for(i = 0; i < oBufLength; i++) {
printf(" %u",oBuf[i]);
tempBuf[i] = oBuf[i];
}
printf("\n");
bufSize = oBufLength;
oBufLength = 0;
numBytes = write(BAMid, &tempBuf, bufSize);
printf("bytes written = %d\n",numBytes);
if (numBytes == -1) {
printf("Error writing to port - %s(%d).\n", strerror(errno), errno);
}
return (numBytes > 0);
}
else {
return 0;
}
答案 0 :(得分:1)
非阻塞写入无法满足您的期望。
如果无法立即完成写入,则write()会返回到您的代码 - 但不继续尝试在后台发送数据。它只是说“我现在不能写 - 稍后再试”。它通过返回-1来实现,将 errno 设置为EAGAIN。
另外,请记住,成功后,write()将返回成功写入的字节数。因此,当您要求写入2个字节时,如果获得的返回值为1,则表示它只是部分成功,并且需要在第二个字节的某个时间再次调用write()。
基本上,如果你正在使用非阻塞IO,你希望你的txbytes()函数在循环中调用write(),直到你的缓冲区为空,或者它返回-1。如果它返回-1你需要检查errno - 如果它是EAGAIN,你将不得不再次调用write();其他任何事情都可能是真正的错误。像这样:
ssize_t written = 0;
while (oBufLength > 0 && written > -1)
{
size_t i;
printf("about to transmit %d bytes: ", oBufLength);
for(i = 0; i < oBufLength; i++) {
printf(" %u",oBuf[i]);
}
printf("\n");
written = write(BAMid, oBuf, oBufLength);
printf("Write returned %d\n", written);
if (written > 0)
{
/* The first "written" number of bytes in the buffer have now been sent, so
* we discard them and move up the remaining bytes (if any) to the start of
* the buffer */
oBufLength -= written;
memmove(oBuf, oBuf + written, oBufLength);
printf("Now have %d bytes left to send.\n", oBufLength);
}
}
if (written > -1 || errno == EAGAIN)
{
/* No fatal errors... */
return 0;
} else
/* error left in errno for caller to inspect */
return -1;
}
请注意,不需要复制缓冲区 - 因为write()不会与您的代码并行执行任何操作。如果它说它写了字节,它就不再需要你的缓冲区了。希望有所帮助!