Batteries included
Post Reply
mrdanielfsch
Posts: 3
Joined: 21 May 2020, 19:00

ZTE MF110 mode switch sequence on Android

Post by mrdanielfsch » 21 May 2020, 19:37

Hi guys,

I've a ZTE MF110 modem and it works perfectly with PPP Widget 3 for providing a network connection to my Android TV with Android 6. I use this setup with a collection of sensors as an IOT solution and I'd like to send SMS messages with the same modem with AT commands.

The problem is that I can't disable this device internal storage. From dmesg, I'm assuming that I could eject the /dev/sr0 device to get to the modem mode and send some AT commands to the device. However this doesn't seem to work (the device doesn't exist).

The dmesg output is:

Code: Select all

[143613.532341@0] usb 1-1.1: new high-speed USB device number 22 using xhci-hcd
[143613.683652@0] usb-storage 1-1.1:1.0: USB Mass Storage device detected
[143613.693952@0] scsi22 : usb-storage 1-1.1:1.0
[143614.706617@0] scsi 22:0:0:0: CD-ROM            ZTE      USB SCSI CD-ROM  2.31 PQ: 0 ANSI: 2
[143614.729615@0] sr0: scsi-1 drive
[143614.754471@0] sr 22:0:0:0: Attached scsi CD-ROM sr0
Am I targeting the wrong device? How can I eject this storage and put the device into modem mode?

Thank you for your help.

Josh
Site Admin
Posts: 6570
Joined: 03 Nov 2007, 00:30

Re: ZTE MF110 mode switch sequence on Android

Post by Josh » 21 May 2020, 21:17

The issue is the available drivers in Android.

In very early versions - like 2.x - the kernels had lots of drivers and you could post-load modules to add further drivers.
Later, with 4.3 if I remember correctly, the module loading was disabled, for 'security reasons', and the modem drivers vanished - in some cases even the memory stick drivers were removed

The bottom line is that any additional USB devices that are not supported by the kernel cannot show up as a kernel device. All functionality has to be accessed on the Android API level which has rudimentary USB input/output. PPP Widget implements the PPP protocol and others like NCM, QMI, DHCP in Java.

Regarding the modem's storage device, newer modems often show their fake CD-ROMs in both the initial mode and the modem mode. So it's not an indication of the mode, and if you try the 'eject' in modem mode, it will likely just do nothing.

If you want to determine the current mode, you would have to monitor the USB ID of the stick. It changes when the mode is "switched". There are probably apps for it - or you check the "USB Log" from PPP Widget.

mrdanielfsch
Posts: 3
Joined: 21 May 2020, 19:00

Re: ZTE MF110 mode switch sequence on Android

Post by mrdanielfsch » 22 May 2020, 14:36

Hi Josh,

First of all, thank you for your response.
Searching around this forum and through stack overflow I found that "USB serial for Android" project on github (https://github.com/mik3y/usb-serial-for-android).
I've got a list of all vendorId/productId I want to interact with and I've managed to find my UsbDevice. The problem is that the device only shows 1 port (in the UsbSerialDriver) and/or 1 interface with two endpoints in the UsbDevice itself.

A successfull connection on the PPP Widget 3 produced the following log:

Code: Select all

Device manufacturer string: Amlogic
Total RAM: 1861 MB. Available RAM: 986 MB
 
Start manual search for USB devices
 on kernel level ...
 No known modem found in install mode
Start search for USB devices
 visible on Android OS level ...
 Looking at device: /dev/bus/usb/001/012 ...
  Check device 19d2:0091, interface 2, might be a modem
 Request permission from system to handle device ...
  System has permitted USB device handling
 Found possible 3G USB device 19d2:0091
New device on /dev/bus/usb/001/012
 Class of interface 0 is 0xFF
Looking at USB device 19d2:0091 with class 255
 Device top dir: /sys/bus/usb/devices/1-1.1, active cfg: 1
Active configuration ID: 1
Device layout (config 1) - cl:00  sc:00  pr:00
 if:0 as:0 -  cl:ff  sc:ff  pr:ff -  bi:81  bo:01
 if:1 as:0 -  cl:ff  sc:ff  pr:ff -  bi:82  bo:02
 if:2 as:0 -  cl:ff  sc:ff  pr:ff -  bi:83  bo:03
 if:3 as:0 -  cl:08  sc:06  pr:50 -  bo:04  bi:84
 if:4 as:0 -  cl:ff  sc:ff  pr:ff -  ir:85  bi:86  bo:05
 
Found 4 serial ports (0, 1, 2, 3)
Opening port type SERIAL (interface 4)
How could you find those 4 serial ports?

Thanks...

LOM
Posts: 1404
Joined: 11 Jul 2012, 15:14
Location: Koh Samui, TH

Re: ZTE MF110 mode switch sequence on Android

Post by LOM » 22 May 2020, 15:49

mrdanielfsch wrote: 22 May 2020, 14:36 I've got a list of all vendorId/productId I want to interact with and I've managed to find my UsbDevice. The problem is that the device only shows 1 port (in the UsbSerialDriver) and/or 1 interface with two endpoints in the UsbDevice itself.
What was the device initial USB Id? How did you switch the device? Which USB Id did you get after switching?

mrdanielfsch
Posts: 3
Joined: 21 May 2020, 19:00

Re: ZTE MF110 mode switch sequence on Android

Post by mrdanielfsch » 22 May 2020, 18:35

Hi LOM,

I didn't make the switch. The mode switch was performed by PPP Widget 3 during connection. When I'm connected to the 3G network through PPP Widget I can see the serial ports open. However, this connection is not always open. I'd like to be able to push out SMSs even when I'm not connected.

I don't know what I can send to this device for it to switch modes and expose the modem ports. Do you know where I can find this information?

LOM
Posts: 1404
Joined: 11 Jul 2012, 15:14
Location: Koh Samui, TH

Re: ZTE MF110 mode switch sequence on Android

Post by LOM » 23 May 2020, 09:04

Sorry, I thought you was trying to get it working without pppwidget and did the mode switching yourself.
I have now no idea why you don't see the same number of serial interfaces as pppwidget does.
mrdanielfsch wrote: 22 May 2020, 18:35 I'd like to be able to push out SMSs even when I'm not connected.
I didn't know that was possible.

Josh
Site Admin
Posts: 6570
Joined: 03 Nov 2007, 00:30

Re: ZTE MF110 mode switch sequence on Android

Post by Josh » 26 May 2020, 22:30

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 ... 8)

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

Post Reply