如何在Mac插件中使用ioctl()设置RTS?

问题描述:

我可以在一个小型终端应用程序中设置带有ioctl的RTS,但不能在我的Mac插件代码中设置,尽管它们都运行相同的代码。在插件中,我只能“获取”串行端口标志/引脚,但不能“设置”它们。在终端应用程序中,我可以“设置”它们,我得到一个ENODEV的错误,错误号是19,并且消息是“操作不支持设备。”如何在Mac插件中使用ioctl()设置RTS?

如果这是一个安全问题在浏览器的上下文中)有没有办法获得修改ioctl标志的权限?我有一个连接到usb端口的串行设备。我使用的是FTDI vcp(虚拟COM端口)驱动程序。 。一边顺便说一句,我得到同时使用Safari和Firefox相同的结果下面是我的代码:

int disableRTS() 
{ 
    char fd, ret, flags; 

    // open device 
    if ((fd = open("/dev/cu.mydevice", O_RDWR | O_NDELAY)) < 0) 
    { 
     fprintf(stderr, "failed to open device"); 
     return -1; 
    } 

    // Get the current state of the bits 
    ioctl(fd, TIOCMGET, &flags); 
    fprintf(stderr, "Flags are %x.\n", flags);  

    flags &= ~TIOCM_RTS; // Disable the RTS bit 
    ret = ioctl(fd, TIOCMSET, &flags); 

    if (ret == -1) 
     fprintf(stderr, "TIOCMSET failed\n"); 
    else 
     fprintf(stderr, "TIOCMSET succeeded. flags: %x.\n", flags); 

    return 0; 
} 

=========

更新

如果我刷新浏览器页面,迫使代码再次执行,ioctl()返回0,表示成功。不幸的是,我需要它第一次工作。即使我使用usleep()方法暂时编写一个循环并暂停,然后进行后续尝试,它也会失败。但是,当我刷新它成功。我还在第二个专门复制了NPAPI项目“BasicPlugin.xcodeproj”的问题中提供了Mozilla。我的第一个插件项目是Firebreath项目。他们一开始都失败,然后在页面重新加载成功。我也有2个独立的Mac应用程序可以正常工作。一个是SerialTools,它使用与我的终端应用程序和插件完全相同的设置RTS(和DTR off)的方法。

========

更新2

我已经能够得到这个代码级的苹果的支持,所以解决可以到来。这位工程师说,代码在一个插件中的运行方式不同于一个,而且与Safari插件工程师进行了交流是“奇怪的”。

+0

将'fprintf'错误情况更改为对'perror(“TIOCMSET”)的调用并查看错误说的内容。 –

+0

对不起,我忘了提。错误消息是“操作不受设备支持”。它的错误号是19. ENODEV。 – Alyoshak

+0

至于即将到期的赏金还没有正确的答案,我不知道该怎么办。即使苹果工程师已经接受了这个问题并试图找到解决方案,我想我会失去它。说插件代码与非插件代码的工作方式不同,这是“奇怪的”。至少我可以为它提供的任何帮助添加正确的答案。 – Alyoshak

答案是,只要TIOCMSET或TIOCMGET在呼叫来的ioctl()的第三个参数必须是一个int。我正在使用字符。咄。不能相信我错过了这一点。 TIOCMSET和TIOCMGET定义如下:

#define TIOCMSET _IOW('t', 109, int) /* set all modem bits */ 
    … 
    #define TIOCMGET _IOR('t', 106, int) /* get all modem bits */ 

,因此就不难想象,用一个字符作为类型为我的“标志”变种可能会导致不可预知的行为。

您可以制作一个AppleScript插件,该插件将在特定时间或登录时自动运行,或者连续在后台运行。

AppleScript可以运行终端代码。所以你可以很容易地让它自动运行你在终端中运行的get/set代码。

的AppleScript的插件的代码会是这样::

tell application "Finder" 
    display dialog explanation buttons {"GET", "SET"} default button "GET" 
    if result = {button returned:"GET"} then 
     tell application "Terminal" 
       set status to (do shell script "terminal code for getting the RTS here") 
      end tell 
    else if result = {button returned:"SET"} then 
      tell application "Terminal" 
       set status to (do shell script "terminal code for setting the RTS here") 
      end tell 
    end if 
end tell