Mobile Broadband API: "Pin is required" exception but pin is set

1

I'm trying to get up & running with the Mobile Broadband API. I'm using it from C#, using the instructions found here.

I have a problem with it though: when the modem device is locked (i.e., PIN is required), I want to set the pin programmatically and the continue to make a connection, but the latter fails with "Pin is required", even though I just correctly set the PIN.

The Mobile Broadband API offers the IMbnPin interface to set the pin, but this is an asynchronous operation, so you have to register for the OnEnterComplete event (part of the IMbnPinEvents interface) which signals that the operation has completed. I assumed this should be enough, but apparently it isn't.

The class below is a minimal, self-contained sample that demonstrates the problem. You can use it in a console application like this:

var testInstance = new MbnTest();
testInstance.Test("XXXX"); // replace with actual PIN code

(You will also need an Interop dll to compile it, which you can find here)

The test class contains a ManualResetEvent field to coordinate between the Enter and OnEnterComplete methods.

In the Test method, I subscribe to the IMbnPinEvents, instantiate the IMbnPin, call the (asynchronous) Enter method and call ManualResetEvent.WaitOne to block the current thread. In OnEnterComplete, I can verify that the pin was correctly set and then signal the ManualResetEvent so the Test method continues execution. If I continue immediately after that with the TryToGetConnectionState() call, I get an exception E_MBN_PIN_REQUIRED (0x80548210). If I wait 'long enough' using Console.ReadLine(), everything works fine. So it looks like I need to wait for another event, but I can't find which one.

Any ideas? What am I missing?

// warning: this is sample code, needs to be better structured for production use
class MbnTest : IMbnPinEvents
{
    private readonly ManualResetEvent _resetEventPin = new ManualResetEvent(false);

    public void Test(string pinCode)
    {
        var interfacemanager = (IMbnInterfaceManager)new MbnInterfaceManager();

        SubscribeToPinEvents(interfacemanager);

        var mbnPin = GetPin(interfacemanager);

        uint requestId;
        Trace.WriteLine("Setting PIN");
        mbnPin.Enter(pinCode, out requestId);
        Trace.WriteLine("Waiting for OnEnterComplete");

        // wait for the OnEnterComplete event
        _resetEventPin.WaitOne();

        Trace.WriteLine("press enter to retrieve connection state");
        Console.ReadLine();

        TryToGetConnectionState();
    }

    void IMbnPinEvents.OnEnterComplete(IMbnPin pin, ref MBN_PIN_INFO pinInfo, uint requestID, int status)
    {
        // reports MBN_PIN_STATE_NONE which means no pin is required
        Trace.WriteLine(string.Format("OnEnterComplete: pin state = {0}", pinInfo.pinState));
        // signal the ManualResetEvent to unblock the thread waiting for the Enter Pin operation to complete
        _resetEventPin.Set();
    }

    private void SubscribeToPinEvents(IMbnInterfaceManager interfacemanager)
    {
        Trace.WriteLine("Subscribing to IMbnPinEvents");
        var guidPinEvents = typeof (IMbnPinEvents).GUID;
        var connectionPointContainer = (IConnectionPointContainer) interfacemanager;
        IConnectionPoint connectionPoint;
        connectionPointContainer.FindConnectionPoint(ref guidPinEvents, out connectionPoint);
        uint cookie;
        connectionPoint.Advise(this, out cookie);
    }

    private static IMbnPin GetPin(IMbnInterfaceManager interfacemanager)
    {
        IMbnInterface mbnInterface = interfacemanager.GetInterfaces().OfType<IMbnInterface>().First();
        Trace.WriteLine(string.Format("mbnInterface: {0}", mbnInterface.GetReadyState()));

        var pinMgr = (IMbnPinManager)mbnInterface;
        var mbnPin = pinMgr.GetPin(MBN_PIN_TYPE.MBN_PIN_TYPE_PIN1);
        return mbnPin;
    }

    private static void TryToGetConnectionState()
    {
        Trace.WriteLine("Retrieving mbn connection");
        var connectionManager = (IMbnConnectionManager)new MbnConnectionManager();
        var mbnConnection = connectionManager.GetConnections().OfType<IMbnConnection>().First();
        Trace.WriteLine(string.Format("connection: {0}", mbnConnection.ConnectionID));
        MBN_ACTIVATION_STATE state;
        string profilename;
        mbnConnection.GetConnectionState(out state, out profilename);
    }


    void IMbnPinEvents.OnChangeComplete(IMbnPin pin, ref MBN_PIN_INFO pinInfo, uint requestID, int status)
    {
        throw new NotImplementedException();
    }

    void IMbnPinEvents.OnEnableComplete(IMbnPin pin, ref MBN_PIN_INFO pinInfo, uint requestID, int status)
    {
        throw new NotImplementedException();
    }

    void IMbnPinEvents.OnDisableComplete(IMbnPin pin, ref MBN_PIN_INFO pinInfo, uint requestID, int status)
    {
        throw new NotImplementedException();
    }


    void IMbnPinEvents.OnUnblockComplete(IMbnPin pin, ref MBN_PIN_INFO pinInfo, uint requestID, int status)
    {
        throw new NotImplementedException();
    }

}
c#
com
mobile-broadband-api
asked on Stack Overflow Mar 30, 2012 by jeroenh

1 Answer

1

I found the answer: I needed to wait for the network registration to become active before making the connection. Kind of obvious in hindsight. To make it work, I made the following changes:

  • before setting the pin, subscribe to the IMbnRegistrationEvents interface
  • in the IMbnRegistrationEvents.OnRegisterStateChange method, check whether the registration state is 'registered' (i.e., one of the values MBN_REGISTER_STATE_HOME, MBN_REGISTER_STATE_ROAMING or MBN_REGISTER_STATE_PARTNER).

From then on, you can use the IMbnConnection.Connect method to create a broadband connection.

Kinda hard to find documentation on this... There is the Mobile Broadband Connection Manager Development Guide on msdn, but I couldn't find any specifics in there. Also, I'm not sure if there is anything provider- or device-specific in this behaviour.

answered on Stack Overflow Apr 11, 2012 by jeroenh

User contributions licensed under CC BY-SA 3.0