シリアル ポートでデバイスをエミュレートするプログラムを書きたいと思います。これを達成するために疑似端末を使用しようとしています。マスターを制御する 1 つの異なるプロセスが必要です。このプロセスは、シリアル デバイス エミュレータとして機能します。別のプロセス (kermit など) がスレーブ端末を使用してマスターと通信できるようにします。明確なプロセス要件のため、フォークは使用していません。インターネット上のほぼすべての疑似端末の例は、マスター/スレーブに fork() を使用することを示しています。
私はそれを一方向に動かしています。つまり、スレーブプロセスがスレーブ疑似端末にデータを書き込むことができ、マスターはマスター疑似端末からそれを読み取ることができます。
問題は別の方向にあります。マスターにデータを書き込み、スレーブにデータを読み取ることができません。
動作しない双方向コードと動作する単方向コードの両方を示します。
非稼働双方向マスター:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
// get the master fd
int masterfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if(masterfd < 0)
{
perror("getpt");
exit(1);
}
// grant access to the slave
if(grantpt(masterfd) < 0)
{
perror("grantpt");
exit(1);
}
// unlock the slave
if(unlockpt(masterfd) < 0)
{
perror("unlockpt");
exit(1);
}
// get the path to the slave
char slavepath[64];
if(ptsname_r(masterfd, slavepath, sizeof(slavepath)) < 0)
{
perror("ptsname_r");
exit(1);
}
printf("Using %s\n", slavepath);
char bufout = 'D';
char bufin;
int c;
while(1)
{
printf("reading\n");
c = read(masterfd, &bufin, 1);
printf("read %i bytes: %c\n", c, bufin);
if(c == -1) break;
if(bufout == 'D') bufout = 'E';
else if(bufout == 'E') bufout = 'D';
printf("writing %c\n", bufout);
c = write(masterfd, &bufout, 1);
printf("wrote %i bytes\n", c);
if(c == -1) break;
sleep(1);
}
close(masterfd);
return 0;
}
非稼働双方向スレーブ:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/pts/15", O_RDWR | O_NOCTTY);
if(fd < 0)
{
perror("open");
exit(1);
}
char bufout = 'A';
char bufin;
int c;
while(1)
{
if(bufout == 'A') bufout = 'B';
else if(bufout == 'B') bufout = 'A';
printf("writing %c\n", bufout);
c = write(fd, &bufout, 1);
if(c == -1) break;
printf("reading\n");
c = read(fd, &bufin, 1);
printf("read %i bytes: %c\n", c, bufin);
if(c == -1) break;
sleep(1);
}
close(fd);
}
非稼働マスターの出力: (受信した最初の文字はスレーブからのもので、残りはマスターによって書き込まれた文字であることに注意してください。つまり、マスターはマスター pts に書き込んだのと同じ文字を読み取っていて、スレーブが何を無視しているのかを無視しています。最初の文字を除いて書いています。)
Using /dev/pts/15
reading
read 1 bytes: B [<--- FROM THE SLAVE]
writing E
wrote 1 bytes
reading
read 1 bytes: E [<--- REST FROM THE MASTER]
writing D
wrote 1 bytes
reading
read 1 bytes: D
writing E
wrote 1 bytes
reading
read 1 bytes: E
writing D
wrote 1 bytes
reading
read 1 bytes: D
^C
非稼働スレーブの出力: (マスターが書き込んでいるものを受け取りません。)
writing B
reading
^C
作業中の単方向マスター:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
// get the master fd
int masterfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if(masterfd < 0)
{
perror("getpt");
exit(1);
}
// grant access to the slave
if(grantpt(masterfd) < 0)
{
perror("grantpt");
exit(1);
}
// unlock the slave
if(unlockpt(masterfd) < 0)
{
perror("unlockpt");
exit(1);
}
// get the path to the slave
char slavepath[64];
if(ptsname_r(masterfd, slavepath, sizeof(slavepath)) < 0)
{
perror("ptsname_r");
exit(1);
}
printf("Using %s\n", slavepath);
char bufout = 'D';
char bufin;
int c;
while(1)
{
printf("reading\n");
c = read(masterfd, &bufin, 1);
printf("read %i bytes: %c\n", c, bufin);
if(c == -1) break;
sleep(1);
}
close(masterfd);
return 0;
}
単方向スレーブの作業:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int fd = open("/dev/pts/15", O_RDWR | O_NOCTTY);
if(fd < 0)
{
perror("open");
exit(1);
}
char bufout = 'A';
char bufin;
int c;
while(1)
{
if(bufout == 'A') bufout = 'B';
else if(bufout == 'B') bufout = 'A';
printf("writing %c\n", bufout);
c = write(fd, &bufout, 1);
if(c == -1) break;
sleep(1);
}
close(fd);
}
作業マスターの出力: (スレーブが正常に書き込む内容を読み取ります。)
Using /dev/pts/15
reading
read 1 bytes: B
reading
read 1 bytes: A
reading
read 1 bytes: B
reading
read 1 bytes: A
reading
read 1 bytes: B
^C
作業スレーブの出力:
writing B
writing A
writing B
writing A
writing B
^C