Мы работаем с последовательным устройством, подключенным к Ma c по USB, и нам необходимо настроить параметры линии DTR / RTS. Технически это предполагает использование open(3)
, ioctl(3)
.
Мы реализовали это в C, и это сработало. Ниже приведен очень упрощенный фрагмент, показывающий основную часть.
Затем мы перенесли код в Java / JNA и столкнулись с проблемой, что перенесенный код не работал , а не . хотя это в основном построчное преобразование кода C.
Вопрос в том, где мы go ошибаемся?
Симптом сбоя в Java errno=25 'Inappropriate ioctl for device'
возвращается из вызова на ioctl()
. Поскольку он работает в C, кажется, что мы делаем что-то не так в JNA.
Что мы сделали:
- Проверены значения констант заголовка. Обратите внимание, что C -код генерирует Java -совместимые определения констант, которые используются в коде Java.
- Проверены подписи
ioctl()
. Кажется, это правильно в соответствии с man-страницей и включаемыми файлами. - Предположил, что проблема в том, что код ioctl для
TIOCMSET
не передается должным образом, поскольку он отрицательный.
Мы используем JNA 5.5.0.
Вот код C. Фрагмент просто читает настройки строк и записывает их без изменений в демонстрационных целях. Вот код (обратите внимание на жестко запрограммированное имя устройства).
int main(int argc, char **argv)
{
// Print constant values.
printf( "long TIOCMGET = 0x%x;\n", TIOCMGET );
printf( "long TIOCMSET = 0x%x;\n", TIOCMSET );
printf( "int O_RDWR = 0x%x;\n", O_RDWR );
printf( "int O_NDELAY = 0x%x;\n", O_NDELAY );
printf( "int O_NOCTTY = 0x%x;\n", O_NOCTTY );
int value = O_RDWR|O_NDELAY|O_NOCTTY;
printf( "value=%x\n", value );
int portfd = open("/dev/tty.usbmodem735ae091", value);
printf( "portfd=%d\n", portfd );
int lineStatus;
printf( "TIOCMGET %x\n", TIOCMGET );
int rc = ioctl( portfd, TIOCMGET, &lineStatus );
printf( "rc=%d, linestatus=%x\n", rc, lineStatus );
rc = ioctl( portfd, TIOCMSET, &lineStatus );
printf( "rc=%d, linestatus=%x\n", rc, lineStatus );
if ( rc == -1 )
printf( "Failure\n" );
else
printf( "Success\n" );
if ( portfd != -1 )
close( portfd );
return 0;
}
Вывод этого:
long TIOCMGET = 0x4004746a;
long TIOCMSET = 0x8004746d;
int O_RDWR = 0x2;
int O_NDELAY = 0x4;
int O_NOCTTY = 0x20000;
value=20006
portfd=3
TIOCMGET 4004746a
rc=0, linestatus=6
rc=0, linestatus=6
Success
Вот реализация Java:
public class Cli
{
/**
* Java mapping for lib c
*/
public interface MacCl extends Library {
String NAME = "c";
MacCl INSTANCE = Native.load(NAME, MacCl.class);
int open(String pathname, int flags);
int close(int fd);
int ioctl(int fd, long param, LongByReference request);
String strerror( int errno );
}
private static final MacCl C = MacCl.INSTANCE;
private static PrintStream out = System.err;
public static void main( String[] argv )
{
long TIOCMGET = 0x4004746a;
long TIOCMSET = 0x8004746d;
int O_RDWR = 0x2;
int O_NDELAY = 0x4;
int O_NOCTTY = 0x20000;
int value = O_RDWR|O_NDELAY|O_NOCTTY;
out.printf( "value=%x\n", value );
int portfd = C.open(
"/dev/tty.usbmodem735ae091",
value );
out.printf( "portfd=%d\n", portfd );
LongByReference lineStatus = new LongByReference();
int rc = C.ioctl( portfd, TIOCMGET, lineStatus );
out.printf(
"rc=%d, linestatus=%d\n", rc, lineStatus.getValue() );
rc = C.ioctl( portfd, TIOCMSET, lineStatus );
out.printf(
"rc=%d errno='%s'\n",
rc,
C.strerror( Native.getLastError() ) );
if ( rc == -1 )
out.print( "Failure." );
else
out.print( "Success." );
if ( portfd != -1 )
C.close( portfd );
}
}
Java вывод:
value=20006
portfd=23
rc=0, linestatus=6
rc=-1 errno='Inappropriate ioctl for device'
Failure.