mrdanielfsch wrote: ↑22 May 2020, 14:36How could you find those 4 serial ports?
I started off with
usb-serial-for-android when I began work on PPP Widget 2. It's good for the initial learning but I ended up with implementing my own drivers.
First thing to note is that "flow control" (the pseudo 'modem lines' provided by the respective interrupt endpoints) is not really a requirement. You can just poll (repeatedly read) the input from the port you are using. Just treat USB endpoints like file streams.
As far as I understand, the
usb-serial-for-android project is made for talking to an actual USB to Serial adapter where the flow control is used to drive the respective electrical lines.
Finding all ports is simple footwork ...
I walk through the whole device tree and note all configurations, their interfaces and corresponding values like class, subclass and protocol.
A
simplified code snippet for the first configuration that should get you going (of course, you need to pick only the ports of your modem; the other types are just for demonstration):
Code: Select all
void interfaceWalk() {
UsbComPort cP = null;
G.PortType t;
int ifcl, subcl, prot, alts=0;
// Globally set in original code
int mConfiguration = 1;
// see below for method 'getInterfaces'
List<UsbInterface> ifList = getInterfaces(mConfiguration);
for (UsbInterface mif : ifList) {
ifcl = mif.getInterfaceClass();
if (mif.getId() == 0 && ifcl == 8)
// new STORAGE interface
;
subcl = mif.getInterfaceSubclass();
prot = mif.getInterfaceProtocol();
switch (ifcl) {
case 0x02:
switch (subcl) {
case 0x02:
if (prot == 1) {
// new ACM interface
} else if (prot == 0xff) {
if (mVids.contentEquals("12d1"))
// weird Huawei modem
;
}
break;
case 0x06:
if (prot == 0) {
// new ECM interface
}
break;
case 0x0d:
if (prot == 0) {
// new NCM interface
if (mVids.contentEquals("12d1"))
// Huawei union flavour
;
else
// NCM port as in the specs (hopefully)
;
}
break;
}
break;
case 0x0a:
if (cP != null) {
t = cP.getType();
if (t == G.PortType.ACM || t == G.PortType.ECM || t == G.PortType.NCM
|| t == G.PortType.HUAWEI_NCM) {
if (mif.getEndpointCount() <= 1)
cP.setHasAltSetting(true);
else
cP.setDataInterface(mif);
}
}
break;
case 0xff:
switch (subcl) {
case 0x00:
if (prot == 0)
// new SERIAL interface
;
break;
case 0x01:
// QMI detection now via QmiTable (layout/ID matching)
break;
case 0x02:
if (prot == 1)
// new SERIAL interface
;
else if (prot == 0x10 || prot == 3 || prot == 0x12)
// new SER_CTRL interface
;
else if (mVids.contentEquals("12d1") && (prot == 0x16 || prot == 0x46 || prot == 0x76)) {
// combined NCM (Huawei) interface, prot values from Linux kernel (huawei_cdc_ncm)
} else
// assume new SER_CTRL interface
;
break;
case 0xff:
if (prot == 0xff)
// new SERIAL interface
;
else
// assume new SER_CTRL interface
;
break;
default:
// assume new SER_CTRL interface
}
break;
default:
}
}
}
@SuppressLint("NewApi")
private List<UsbInterface> getInterfaces(int configuration) {
int ifCount, i;
if (mDevice == null)
return null;
List<UsbInterface> mList = new ArrayList<>();
// API prior to 21 doesn't have 'getConfiguration' in 'UsbDevice'
if (G.SDKV > 20) {
if (mDevice.getConfiguration(configuration-1) == null)
return null;
usbLog("Active configuration ID: "+mDevice.getConfiguration(configuration-1).getId());
ifCount = mDevice.getConfiguration(configuration-1).getInterfaceCount();
for (i = 0; i < ifCount; i++)
mList.add(mDevice.getConfiguration(configuration-1).getInterface(i));
} else {
ifCount = mDevice.getInterfaceCount();
for (i = 0; i < ifCount; i++)
mList.add(mDevice.getInterface(i));
}
return mList;
}
- UsbComPort is my own class that represents a complete port - which can include one or more interfaces, depending on the type. In your case, it's likely the simple variant with one interface per port.
- G.PortType is a simple enum to have tags for the various types of modem ports