Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fails on Apple Silicon #142

Open
bobjacobsen opened this issue Jun 28, 2023 · 8 comments
Open

Fails on Apple Silicon #142

bobjacobsen opened this issue Jun 28, 2023 · 8 comments

Comments

@bobjacobsen
Copy link

JMRI is an application that works cross-platform with PureJavaComm just fine across multiple platforms, including macOS Intel and macOS Rosetta2 on Apple Silicon.

When running on Apple Silicon, attempting to set a control line on a port gives:

     [java] purejavacomm.PureJavaIllegalStateException: ioctl(m_FD, TIOCMGET, m_ioctl) == -1
     [java] 	at purejavacomm.PureJavaSerialPort.setControlLineState(PureJavaSerialPort.java:1277)
     [java] 	at purejavacomm.PureJavaSerialPort.setRTS(PureJavaSerialPort.java:313)
     [java] 	at jmri.jmrix.AbstractSerialPortController.configureLeadsAndFlowControl(AbstractSerialPortController.java:121)
     [java] 	at jmri.jmrix.AbstractSerialPortController.configureLeadsAndFlowControl(AbstractSerialPortController.java:142)

The JMRI code line where it occurs:

        serialPort.setRTS(rts);

The port seems to have been successfully opened. At least, there was no exception at that point.

If I bypass setting the control lines, I get an I/O exception the first time I attempt to access the port's input stream:

     [java] java.io.IOException
     [java] 	at purejavacomm.PureJavaSerialPort$2.available(PureJavaSerialPort.java:721)
     [java] 	at jmri.jmrix.AbstractPortController.purgeStream(AbstractPortController.java:566)

Happens with Azul JDKs from Java 11 (earliest supported by application) through JDK 20. Observed on macOS Ventura with both M1 and M2 chips.

Working on debugging this, but would greatly appreciate any suggestions on how to go about it.

@nyholku
Copy link
Owner

nyholku commented Jun 28, 2023 via email

@bobjacobsen
Copy link
Author

Thank you for the quick reply!

This is the minimal test program I'm using:

import purejavacomm.*;
import java.io.*;

class JavaCommTest {

    static String portName = "cu.Bluetooth-Incoming-Port";
    // static String portName = "cu.usbmodem2100412E1";

    public static void main(String[] args) {
        System.out.println("starting");

        SerialPort activeSerialPort = null;

        try {
            // get and open the primary port
            CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(portName);
            try {
                activeSerialPort = (SerialPort) portID.open("JMRI", 2000);  // name of program, msec to wait
            } catch (PortInUseException p) {
                System.err.println("PortInUseException");
            }

            // These operations pass
            try {
                activeSerialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
            } catch (UnsupportedCommOperationException e) {
                System.err.println("Setting serial params failed");
            }

            // These operations fail
            activeSerialPort.setRTS(true);
            activeSerialPort.setDTR(true);

        } catch (NoSuchPortException e1) {
            System.err.println("NoSuchPortException "+e1);
            e1.printStackTrace();
        } catch (RuntimeException e2) {
            System.err.println("RuntimeException "+e2);
            e2.printStackTrace();
        }

        System.out.println("ending");
    }
}

It gives:

starting
ending
RuntimeException purejavacomm.PureJavaIllegalStateException: ioctl(m_FD, TIOCMGET, m_ioctl) == -1
purejavacomm.PureJavaIllegalStateException: ioctl(m_FD, TIOCMGET, m_ioctl) == -1
	at purejavacomm.PureJavaSerialPort.setControlLineState(PureJavaSerialPort.java:1277)
	at purejavacomm.PureJavaSerialPort.setRTS(PureJavaSerialPort.java:313)
	at JavaCommTest.main(JavaCommTest.java:31)

Thanks again.

@bobjacobsen
Copy link
Author

Using com.sun.jna.Native.getLastError() I find that the errno is 14:

 14 EFAULT Bad address. The system detected an invalid address in attempting to use an argument of a call.

@nyholku
Copy link
Owner

nyholku commented Jun 28, 2023 via email

@bobjacobsen
Copy link
Author

See a possible solution descend on the JNA list. There's an odd dependence on debugging output, unfortunately.

@nyholku
Copy link
Owner

nyholku commented Jul 2, 2023 via email

@PeteSL
Copy link
Contributor

PeteSL commented Dec 16, 2024

I do not have a Mac to test but would the following work? I am guessing that the Mx ioctl is looking for a pointer to a 64 bit aligned value, even though it is only an integer. Theoretically, using NativeLong should get us an aligned value. This requires the add of import com.sun.jna.ptr.*; and updating the C_lib and C_lib_DirectMappng ioctl to use NativeLongByReference for the third value. I also used the unsigned version of NativeLong to ensure it doesn't try to reinterpret the integer as signed.


	public int ioctl(int fd, int cmd, int... data) {
                // At this time, all ioctl commands we have defined are either no parameter or 4 byte parameter.
                NativeLongByReference pdata = new NativeLongByReference(new NativeLong(0xFFFFFFFFL & data[0], true));
                int retval = m_Clib.ioctl(fd, new NativeLong(0xFFFFFFFFL & cmd, true), pdata);
                data[0] = pdata.getValue().intValue();
                return retval;
	}

@PeteSL
Copy link
Contributor

PeteSL commented Dec 17, 2024

Good news! At least in one instance, the above code prior comment was all that was necessary for PureJavaComm to work on an Apple M4! It appears that the "bad address" was complaining about 64 bit allignment. The basic configuration tested was:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants