IOKit: Creating a MacOS device instance to provide coordinate input for a USB-OTG device - iokit

I'm working on a project that involves connecting a single-board computer (either a BeagleBone Black, or a BeagleBoard X15) to a Mac via USB OTG, and then delivering basic mouse/touch input (pointer coordinates and left/right-click events).
This process should be technically very similar to connecting a mouse (or, more accurately, a touchscreen-style device that receives precise mouse coordinates) and passing some ordinary HID input to MacOS. So I don't need most of the complexity of IOKit - I don't think I need to create a kernel extension; I should just be able to create an instance of a HID for which MacOS already has generic kernel extensions.
So I'm delving into IOKit to figure out how to create the device instance and provide input. However, nearly everything I'm reading about IOKit involves creating and registering new kernel extensions, services, etc. - none of which is germane to my project.
So far, the only relevant leads I've got are the I/O Registry Explorer and the contents of /System/Library/Extensions. Several items in there look promising, such as AppleDHIDMouse.kext. However, I cannot find any examples of code to bridge the gap: how my USB-connected device can connect with the kernel extension, create an instance for itself, and send commands.
Any help? Thanks in advance.

Either your device is fully USB HID compliant, in which case you shouldn't need any code at all on the Mac side, or you'll need to create a kernel extension.
How far have you got? What does your device look like in ioreg/IORegistryExplorer? (The latter is from the "Additional Tools for Xcode", downloadable from https://developer.apple.com/download/more/ )
Does your USB device's interface report as HID? (bInterfaceClass 3) The device itself normally reports as a composite device (bDeviceType 0). bInterfaceProtocol and bInterfacSubClass also have defined meanings in the context of HID, and should probably both be 0 for a "tablet" style device. With that in place, macOS should pick up your device as a HID device and try to drive it with one of its built in HID device drivers.
The way HID devices work is through "reports" - event data structures with a flexible format/layout, which is defined via the device's "report descriptor". What buttons, input axes, etc. your device has is defined there.
For an example of a USB "tablet" device (absolute coordinate pointing device) that works with macOS, check out the code for the USB Tablet device that Qemu emulates. That might be a good starting point for the report descriptor of your own device.
If your device doesn't conform to general USB HID conventions and uses some custom protocol, you'll need a custom kext (up to macOS 10.14) or dext (from macOS 10.15 onwards) which will most likely implement a IOHIDDevice subclass. An example of such a driver is the open source Mac driver for the Xbox 360's game controller, which doesn't behave like a standard USB HID device.

Related

Prevent cdc-acm driver from loading device

I'm trying to connect a serial device with Webusb, under linux.
I have been able to list the device and open it, but I can't claim the interface. Chrome complains that the device is busy, and to fix that I need to unregister the CDC-ACM driver.
Is there a way to prevent the CDC-ACM driver from loading the device, without changes on the destkop? maybe I can change the USB descriptors?
If you can change the device descriptors then modify the protocol, class and sub-class reported by the CDC-ACM interface so that it is marked as vendor-specific (0xff). The CDC-ACM driver will no longer recognize the interface and bind to it.
Just for completeness, if you could make changes to the desktop then you can either blacklist the usb-serial driver entirely in /etc/modprobe.d/blacklist or you could write a udev rule which runs for that device in particular (recognized be either bus path or vendor and product ID) and executes a script to unbind the driver.

Espressif Wifi not connecting or showing AP

First of all, I won't go into details, cause there are a lot of them, and I dont want to write (a too long) essay. There is TL;DR section at the end, because I have a specific question, but maybe some additional info can help.
I have a device that is made of a GRU (glass room unit) and espressif (esp8266).
GRU and esp8266 communicate via serial, with GRU as master. GRU is programmed with an internal tool, and I can monitor everything on it, including the info it gets from esp8266.
There is a test/development device, that has espressif on top of the GRU, so I can easily take it off, reprogram/reconfigure it, and put it on.
Espressif is inside of a GRU, and downloading stuff to flash is a real pain. There is whole process including a OS switch (from Win7 to Linux and back). Console output on espressif cannot be done, or at least not in the time frame I have.
For esp8266 I use non-os SDK V2.0.0_16_08_10.
Espressif can be configured with downloading a configuration to flash, or via UDP (over a network if connected, over its AP if its not connected).
Algorithm for Wifi:
1. Try to connect to a network from configuration
2. If it succeeds, raise a flag for that
3. If it fails, enter dual (STATION+AP) mode and raise a flag for that
The reason espressif is not always in dual mode is that it affects multi-cast operations.
Configuration over network is done by a Java aplication I wrote.
Scenario 1
I've configured a wifi router, configured all (x19) of the devices (espressif in devices that is) to connect to its network. When I turned them on, they would connect one by one. The ones that didn't entered dual mode and could be configured via the app.
All well.
Scenario 2
I've wanted to test the system in real world, so I reconfigured them to connect to the our firms network. Additionally when I was already going thru the whole process I've downloaded latest firmare to flash.
I expected that they would connect or enter dual mode and create their own APs. But they did not.
I tested then the code and configuration on espressif whose console output I could monitor, and everything worked.
I tested then the code and configuration on the test device, and it worked again.
I've then redownloaded the code and configuration to one device, and it didn't work.
TL;DR
I have two devices, espressif on a GRU and espressif inside of a GRU. Both connected to one network. Esp on a GRU work for another, Esp inside of a GRU doesn't work for that other network.
They have identical code and configuration, so it shouldn't be a software issue.
Does having espressif inside of a device jams its signal enough that it can't go trough? Device is not big (5x5x2cm).
UPDATE 1:
While I was writing, the espressif inside of a GRU managed to connect to network. I then restarted it so I can check that it can do it again, and it can't connect again.
It took me about 10 minutes to write the whole question.
There are two things that seem to have caused the problem.
When I removed gpio_init(), network stuff became faster, much much faster. Everything on it, connecting to AP, creating AP etc...
I've changed my config and wifi code, so that it now stores the ap and station config to flash via API.
I only check if its internal config is the same as mine from flash. If it isn't, it saves it. Now, I only control the current opmode.

Serial Port not working on Surface Book

I have a Microsoft Surface Book that I've dual booted Linux Mint on. I'm writing a program that needs to read in data from a serial port, but my serial ports don't seem to be working. The behavior is consistent across Mint and Windows (Testing done through Cygwin). It gets a bit of data the first 2-5 seconds that the device is plugged in (viewing the data through screen, same thing happens if I just use pyserial to print data incoming from serial port), then nothing.
What could be happening? I think I've isolated the problem to the serial ports - the Surface Book has 2 USB ports and the same thing happens on both of them, and I've tested the hardware that I'm plugging into it on 2 other computers (One Linux and one Mac OS), and it works fine on both of those.
Your MS Surface, seemingly, has a yellow triangle exclamation mark icon (over the adapter icon) without any driver to install/download. And properties in the device status box window say This device cannot start. (Code 10) or A device which does not exist was specified. Right?
If it's so you should wait for an update from MS. It's notorious problem.
I ended up getting the computer replaced on warranty for an unrelated issue months later, and what do you know, on the new computer the serial ports work fine. That indicates to me some sort of hardware problem, given that the issue persisted across OS's.
maybe this will help:
see Arduino examples for serial port communication - search google:
arduino serial c++
arduino serial c#
arduino serial c++ linux
the point is to open port properly you need to open a file, not a port. not with usual c - assembly write to port code.
another option you are using an unintentionally bought fake USB to serial cable with a Fake PL2303 chip
then you need to install the old version of the driver.
search in google:
Fake PL2303 + your os name:
install driver Fake PL2303 windows 10
another option is maybe it conserves energy and closes the port because it feels it is unused.
in windows> device manager,> properties of a device - usually USB root hub > power management - allow the computer to turn off this device to save power - uncheck it.
https://superuser.com/questions/408683/why-my-usb-mouse-gets-suspended-after-3-seconds-of-inactivity
https://blogs.msdn.microsoft.com/usbcoreblog/2013/11/08/help-after-installing-windows-8-1-my-usb-device-doesnt-charge-or-it-disconnects-and-reconnects-frequently/
also, you could look in windows events - to see what happens. usually, failures like this are registered in the events log.
an unlikely option is it consumes too much current, like a short circuit. and the device protection circuit shuts the chip off. also probably it does not have such circuit. one possibility is to try with an external powered hub.
the most probable of these is the power saving mechanism
I was experiencing the same problem - came across the solution on another site. The USB 3 ports on Surface Book aren't compatible with something or other to do with Com Port but running the device through a cheap USB hub solved my problem straight away and it was instantly recognised by the Arduino IDE

Hardware Devices and Standardization

I'm not sure if each hardware type (display screen, USB, printer, etc) has to follow a unified standard in order to communicate with the CPU. For example, the bits transmitted back and forth between a display screen interface and the CPU are interpreted by the CPU as a specific command, and this interpretation is also correct (for the same bits) even if another display screen is used (from another manufacturer).
If this is not true, how BIOS is supposed to communicate with hundreds of different hardware devices with varying methods of interpreting bits going back and forth from the device interface to the CPU?
I find the standardization notion to be much more practical.
The BIOS itself actually only needs to understand a limited set of hardware required to boot the CPU. It does not need to understand "hundreds" of devices. For example, the BIOS has no idea what a USB printer is.
In general, the BIOS only understands the following devices:
The CPU/Chipset "core" hardware - e.g. the DDR3 memory controller
Basic PCI/PCI Express initialization - nothing device-specific
The video controller - just enough code for basic initialization, typically provided by an Option ROM
The SATA controller - as long as it is IDE/ACHI compatible.
The USB controller - possibly just USB 2.0
Standard USB storage devices
Standard USB keyboard/mouse devices
Ethernet controller - typically provided by an Option ROM
Any other device is ignored by the BIOS, unless the vendor included an Option ROM on the board. (You typically see this on SAS/SCSI controllers or Ethernet cards.)
Note most of the devices listed above conform to a standard specification, so they are software compatible regardless of who made it. For example, a USB 2.0 controller should comply with the EHCI spec, it would be compatible across all BIOSes. SATA controllers should follow the AHCI spec.
Once the Operating System loads, it takes over from the BIOS and loads its own drivers to interface with the hardware.
There is specific way(i.e. protocol) for each hardware to communicate with CPU. Maybe we can regard it as "device specification". To communicate with hundreds of different hardware devices BIOS should implement corresponding protocols within it. Thus we can say BIOS is actually a "collection" of specifications.
Whenever new spec is announced, BIOS should be modified to support it, or BIOS does not identify the corresponding device,not to speak of configuring it !

List machine's serial ports

I have an Arduino-based device which connects through USB.
I'd like to detect it from my Qt 4 application, using QExtSerialPort (or whatever necessary), when it's plugged in.
If this weren't possible, I thought I could somehow get a list of the system's port names and just try all of them in search for my Arduino (where I'd implement some kind of handshaking procedure for it to detect it correctly). My concern in this approach is that I'm not sure if a device (for example, printer) would get damaged if I send some kind of handshaking ack at a different baud rate.
So, I don't really know where to start for any of them. Which would be the best approach? How would I implement it?
I believe you can find list of serial ports on Windows by looking into
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
registry key
Each serial port on a UNIX system has one or more device files (files in the /dev directory) associated with it:
System Port 1 Port 2
IRIX® /dev/ttyf1 /dev/ttyf2
HP-UX /dev/tty1p0 /dev/tty2p0
Solaris®/SunOS® /dev/ttya /dev/ttyb
Linux® /dev/ttyS0 /dev/ttyS1
Digital UNIX® /dev/tty01 /dev/tty02
more details on serial programing on POSIX systems here
Since your device is USB, your UART port will be emulated by some kind of conversor in his hardware. So first you must understand what driver is being used on your system.
The most common SERIAL->USB conversor uses PL2303/PL2301 chip, so it would create a path on /dev, if its the first device, it will appear as "/dev/ttyUSB0", but you may also see the list reading the proc path (like "cat /proc/bus/usb/devices").
Under Windows it usually creates a virtual "COM", just go to device manager and check the port.
When you are sure about how the HW talks to your system, you may use QExtSerialPort for wrapping the system API and talk to the device.
Way too hard and too platform specific, using weird Windows Registry keys or rely on hard wired device nodes on Linux.
You are on the right way. Get QextSerialPort or QSerialDevice (which I preffer in my projects, because it got integrated in Qt5), have a look at the examples and simply use it. In both libraries you get some kind of port enumerator class which returns you a list of all configures serial ports. Only platform/device specific settings you will have to do manually (like getting RS485 in half-duplex mode on my current embedded project), but "standard" problems are perfectly encapsulated in a QIODevice implementation.
You can use both QextSerialPort and QSerialDevice like a file. Open it (instead of a filename you specify the device name ie. "COM1" on Windows or "/dev/tty0" on Linux, depending on your configuration) and then read or write like you are doing it with an ordinary QFile, QBuffer, Qwhatever-inherits-from-QIODevice.
If you have any problems opening the port and communicating, don't hesitate to ask! :)

Resources