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

Apple M1 Mac OS X Big Sur FT232R can't control DTR / CTS #2243

Open
brandonros opened this issue May 1, 2021 · 6 comments
Open

Apple M1 Mac OS X Big Sur FT232R can't control DTR / CTS #2243

brandonros opened this issue May 1, 2021 · 6 comments
Labels
macOS Mac OS X / OS X needs-info Additional information required never-stale

Comments

@brandonros
Copy link

image

image

https://www.amazon.com/gp/product/B00IJXZQ7C/

I made this test case to see what is happening at the ioctl level

#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>

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

    // open device
    if ((fd = open("/dev/tty.usbserial-A50285BI", 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_CTS;  // Disable the CTS bit
    ret = ioctl(fd, TIOCMSET, &flags);

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

    return 0;
}
Flags are 6.
TIOCMSET failed 25
const SerialPort = require('serialport')

const initConnection = async (baudRate) => {
  const connection = new SerialPort('/dev/tty.usbserial-A50285BI', { baudRate })
  await new Promise((resolve, reject) => connection.on('open', resolve))
  return connection
}

const getControlFlags = (connection) => {
  return new Promise((resolve, reject) => {
    connection.get((err, data) => {
      if (err) {
        return reject(err)
      }
      resolve(data)
    })
  })
}

const setControlFlags = (connection, options) => {
  return new Promise((resolve, reject) => {
    connection.set(options, (err) => {
      if (err) {
        return reject(err)
      }
      resolve()
    })
  })
}

const run = async () => {
  const connection = await initConnection(250000)
  console.log(await getControlFlags(connection))
  await setControlFlags(connection, { cts: true })
  console.log(await getControlFlags(connection))
  await setControlFlags(connection, { cts: false })
  console.log(await getControlFlags(connection))
}

run()
  serialport/bindings loading DarwinBinding +0ms
  serialport/stream opening path: /dev/tty.usbserial-A50285BI +0ms
  serialport/binding-abstract open +0ms
  serialport/bindings/poller Creating poller +0ms
  serialport/stream opened path: /dev/tty.usbserial-A50285BI +6ms
  serialport/stream #get +0ms
  serialport/binding-abstract get +6ms
  serialport/stream binding.get finished +1ms
{ cts: true, dsr: false, dcd: false, lowLatency: false }
  serialport/stream #set { brk: false, cts: true, dtr: true, dts: false, rts: true } +3ms
  serialport/binding-abstract set +4ms
  serialport/stream binding.set finished +1ms
  serialport/stream #get +0ms
  serialport/binding-abstract get +1ms
  serialport/stream binding.get finished +0ms
{ cts: true, dsr: false, dcd: false, lowLatency: false }
  serialport/stream #set { brk: false, cts: false, dtr: true, dts: false, rts: true } +0ms
  serialport/binding-abstract set +0ms
  serialport/stream binding.set finished +1ms
  serialport/stream #get +0ms
  serialport/binding-abstract get +1ms
  serialport/stream binding.get finished +1ms
{ cts: true, dsr: false, dcd: false, lowLatency: false }

Notice how CTS never changes but an exception/error is never thrown.

Any other kind of debug logs I can provide?

@GazHank
Copy link
Contributor

GazHank commented May 5, 2021

Hi @brandonros it might be useful for you to tag or highlight if this issue is only occuring on the new M1 chip or is present on intel based macs too?

I may be wrong but it may be that explicit changes need to be made to enable the USB control on the new chips. After all, USB is listed as one of the aspects of the Linux M1 updates which is still to be completed, therefore it sounds like we may need to make some changes to support the new chip.

In particular, at present serialport uses IOKit and it looks like this needs to be migrated to DriverKit per the porting guide on the apple dev documentation.

@brandonros brandonros changed the title Mac OS X Big Sur FT232R can't control DTR / CTS Apple M1 Mac OS X Big Sur FT232R can't control DTR / CTS May 6, 2021
@brandonros
Copy link
Author

One easy fix might be to at least catch if ioctl is failing (as per the C test case I provided)

I do not know if C level ioctl calls are supposed to fail because it is an M1 chip as well? lol

@reconbot
Copy link
Member

reconbot commented May 7, 2021

@GazHank thanks for that link, that's going to be some work....

@GazHank
Copy link
Contributor

GazHank commented May 30, 2021

Hi @brandonros sorry I'd not responded to your point about the error handling before, but I think the code is trying to trap those errors in the same way as you suggested :

if (-1 == ioctl(data->fd, TIOCMSET, &bits)) {
snprintf(data->errorString, sizeof(data->errorString), "Error: %s, cannot set", strerror(errno));
return;

The error codes just don't seem to be getting thrown for some reason :-(

I've been looking through the SDK for IOKit and while the Apple dev docs seem to be pushing everyone to use DriverKit for most purposes, it doesn't seem to be a blanket rule. They have also made some accomodations for the new ARM chips within the IOKit, so perhaps it's not dead just yet...

I've compared SDK 10.15 to 11.3, and while there are a few bits of code they have deprecated it all seems to be tied to things which shouldnt affect us. For example they have deprecated, some highlevel stuff (like keyboard or other device specific logic which is moved to DriverKit instead), and removed access to some items outside of the Kernel mode for security:

#if !defined(KERNEL_PRIVATE)
extern const OSSymbol *gIOSerialBSDServiceValue __deprecated_msg("Use DriverKit");
extern const OSSymbol *gIOSerialBSDTypeKey __deprecated_msg("Use DriverKit");
extern const OSSymbol *gIOSerialBSDAllTypes __deprecated_msg("Use DriverKit");
extern const OSSymbol *gIOSerialBSDModemType __deprecated_msg("Use DriverKit");
extern const OSSymbol *gIOSerialBSDRS232Type __deprecated_msg("Use DriverKit");
extern const OSSymbol *gIOTTYDeviceKey __deprecated_msg("Use DriverKit");
extern const OSSymbol *gIOTTYBaseNameKey __deprecated_msg("Use DriverKit");
extern const OSSymbol *gIOTTYSuffixKey __deprecated_msg("Use DriverKit");
extern const OSSymbol *gIOCalloutDeviceKey __deprecated_msg("Use DriverKit");
extern const OSSymbol *gIODialinDeviceKey __deprecated_msg("Use DriverKit");
#else

But the things we use seem unchanged:

classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
if (classesToMatch != NULL) {
CFDictionarySetValue(classesToMatch,
CFSTR(kIOSerialBSDTypeKey),
CFSTR(kIOSerialBSDAllTypes));

Given the dependencies on other areas of the SDK that may exist, I fear I could be chasing my tail a little trying to get to the bottom of this.

Since the current build process is only configured to produce a Mac version for the intel machines (x64), I can't check it's build log for any interesting info, and don't have access to a mac myself (M1 or otherwise). I can't help think that the compiler may be thowing out some warnings or some clues when compiling for the new processor, that may help identify what needs to be fixed.

@reconbot would it be possible to build for the M1 (arm64) too? even if only in an experimental branch for now until we bottom this out? (while access to ios11 machines is not possible at the moment I'd assume the fact that the machines are running SDK 1.2+ would make this feasible?)

@brandonros would you be able to share any logs from when you (re)compiled SerialPort for the M1? or even just the Bindings package initially that should cut things down a bit, and it seems to be where the current errors you mentioned are getting thrown from

Many thanks

Gaz

@reconbot
Copy link
Member

reconbot commented May 30, 2021

I've heard rumors that an m1 Mac is being tested for GitHub actions in a private beta but I don't have access to the beta or a physical machine at the moment either.

I'm not aware of any way to cross compile to the m1 arch either.

@GazHank
Copy link
Contributor

GazHank commented May 31, 2021

Hi @brandonros I probably should have asked this before, but can you please confirm if the errors you are seeing are when running the precompiled binaries, or after a local recompile of Serialport?

if possible could you also confirm the versions of the Node and SerialPort that you are using, along with any other packages (especially anything like electron). Given how many packages may need to be reworked or recompiled for the new chips, I'd just like to make sure we arent accidentally troubleshooting an issue with Nodejs etc

cheers

Gaz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
macOS Mac OS X / OS X needs-info Additional information required never-stale
Development

No branches or pull requests

3 participants