Any PPP experience in the newest SDK

I have been searching for experience with PPP in the newest SDK. I know that John has been working hard to stabilize both the driver and PPP-parts of the firmware. But before diving into it again, I just wanted to check if there was any advice? ::slight_smile:

Your timing is impeccable. :wink: Today I just started playing with the GHI Cellular Radio with a Spider II.

I got the PPP example working found here: https://www.ghielectronics.com/catalog/product/322

I do have a problem with the modem starting correctly after Build and Deploy. It relates to the powering ON of the modem. The SIM900 takes a pulse on the PWRKEY pin to power ON or OFF. When the software reboots it actually turns OFF the module. I am providing external 5V so the power is not under USB control. To work around I put a Debug.Print(ā€œThread Startā€) at the beginning of the thread. When I see that I pull the ribbon cable from the modem and plug it back in. If I donā€™t it hangs at:


Its a pain but it got me going.
My guess is that the modem is in an unknown state until the power is cycled.  When the debugger is not attached it seems to work okay when I cycle the power.

I expanded the example to query an HTTP web service every 10 seconds then publish the result to a MQTT topic

So far it is working as expected.  I just need to figure out a more reliable power up/reboot sequence.
1 Like

@ skeller - The issue with power on is still something weā€™re working on improving.

@ njbuch - Except for the above power issue and PPP not working on a certain model of SIM modem, all our tests work fine on the cellular radio module and PPP.

@ John - I havenā€™t check with my scope but is it possible to monitor the CTS pin to determine if the modem is already powered ON?

If the cellular connection drops is up to me to re-initialize the connection or does the PPP driver do that automatically? In my testing I have had my connection drop occasionally. I give it a few minutes to see if it can come back on its own or not. I never seems to but maybe I am not waiting long enough.

1 Like

@ skeller - Checking CTS might be an option. When the connection is dropped, do you dispose and try to recreate the connection?

Makes sense to test thatā€¦? Unstable connection was among the big challenges last time I triedā€¦

What is exactly wrong with the power-up?

@ John - So far I have run for about 4 days and it is continuing to push updates through mqtt. I donā€™t know if any have dropped and if so for how long but if the modem lost connection it came back on its own. (I havenā€™t touched it in the last 4 days.)

This was going to lead me to my next question. Should I dispose and recreate everything in the event of a lost connection? It sounds like I should. I was planning on putting a connection watch dog that if there were connection errors for more than a set period of time I would dispose of everything and recreate.

@ njbuch - I explained in my first post the issues I had with modem power up when I deployed to the device when it was already powered up and running. If the modem is already physically ON when the software attempts to turn it ā€œONā€ it actually turns it OFF. Currently the software ON/OFF functions donā€™t seem to know what state the modem is in. The SIM900 modem only takes a pulse on the PWRKEY pin to cycle the power.

1 Like

I handle this when my application starts by sending AT to the modem. If I get a response, I know the modem is already ON so I jump past the power ON function. If I get no response after 3 attempts. I assume it is OFF and do a power ON call. I then go back and do the AT command checks. Eventually it will get through this stage which means the modem is ON and ready and then I do the rest of the setup before the call to PPP (which is currently waiting for the November release with the fix for other modems)

1 Like

During my searches relating to similar problems with the Cellular Radio Module (CRM) I read all the comments on this post, and a few others.

During testing, I have tried a number of approaches which relate to what @ John asked in Reply #5.

I could not find an answer to @ Johnā€™s question.

In Reply #7 @ skeller says

@ John - Could you please elaborate on how best to handle the situation when a connection is lost for some reason.

@ Oldevel - If the connection is lost, the safest bet is to close all connections, the PPP interface, and the serial port. Reset the modem on the other end and bring everything back up.

@ John - Thanks John.

I have a further question which is related.

In order to test Cellular Radio GPRS connectivity behaviour, I wrote the following code.
(please note that I downloaded CellularRadio_43.cs and inverted the initial state of this.power , and the this.power.Write(ā€¦) statements in order to correct the PWRKEY signal inversion. I also added a wire to the Status output of the SIM900 and fed this to a DigitalInput in order to obtain more definitive control over the state of power of the module. Also see some of @ Daveā€™s comments regarding this.).

using System;
using System.Net;
using System.Text;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Net.NetworkInformation;

using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using Gadgeteer.SocketInterfaces;
using GHI.Networking;

namespace GadgeteerCellular
{
    public partial class Program
    {
        private CellularRadio cellularRadio;
        private GT.SocketInterfaces.DigitalInput cellularStatusInput;
        private bool cellularStatus;
        private static AutoResetEvent cellularEvent = new AutoResetEvent(false);

        void ProgramStarted()
        {
            cellularStatusInput = breakout.CreateDigitalInput(GT.Socket.Pin.Three, GlitchFilterMode.Off, ResistorMode.Disabled);
            cellularRadio = new CellularRadio(4);
            cellularRadio.SmsReceived += cellularRadio_SmsReceived;
            cellularRadio.IncomingCall += cellularRadio_IncomingCall;
            cellularRadio.SmsListReceived += cellularRadio_SmsListReceived;
            cellularRadio.LineReceived += cellularRadio_LineReceived;
            cellularRadio.LineSent += cellularRadio_LineSent;
            cellularRadio.CallConnected += cellularRadio_CallConnected;
            cellularRadio.CallEnded += cellularRadio_CallEnded;
            cellularRadio.GprsAttached += cellularRadio_GprsAttached;
            cellularRadio.GprsNetworkRegistrationChanged += cellularRadio_GprsNetworkRegistrationChanged;
            cellularRadio.GsmNetworkRegistrationChanged += cellularRadio_GsmNetworkRegistrationChanged;
            cellularRadio.NetworkDown += cellularRadio_NetworkDown;
            cellularRadio.NetworkUp += cellularRadio_NetworkUp;

            NetworkChange.NetworkAvailabilityChanged += (a, b) => Debug.Print("Network availability changed: " + b.IsAvailable.ToString());
            NetworkChange.NetworkAddressChanged += (a, b) => Debug.Print("Network address changed");

            button.ButtonReleased += button_ButtonReleased;

            Thread.Sleep(2000);
            cellularStatus = cellularStatusInput.Read();
            if (!cellularStatus)
            {
                cellularRadio.PowerOn();
                Thread.Sleep(2000);
            }


            Debug.Print("Program Started");
        }


        private void button_ButtonReleased(Button sender, Button.ButtonState state)
        {
            DoWebRequest();
        }

        #region Methods

        private void DoWebRequest()
        {
            string result = "";

            try
            {
                if (Attach())
                {
                    result = WebRequest();
                    Debug.Print(result);
                }
            }
            catch (Exception ex)
            {
                Debug.Print("Exception in DoWebRequest(): - " + ex.Message);
            }
            finally
            {
                Detach();
                //cellularRadio.PowerOff();
            }
        }

        private bool Attach()
        {
            int dhcpCount = 0;
            bool attached = false;

            try
            {
                cellularRadio.UseThisNetworkInterface("internet", "", "", PPPSerialModem.AuthenticationType.Pap);
                Thread.Sleep(2000);

                while (cellularRadio.NetworkInterface.IPAddress == "0.0.0.0")
                {
                    dhcpCount++;
                    Debug.Print("Waiting on DHCP - " + dhcpCount.ToString());
                    Thread.Sleep(1000);
                }

                cellularRadio.NetworkSettings.EnableDynamicDns();
                Thread.Sleep(1000);

                if (cellularRadio.NetworkInterface.IPAddress != "0.0.0.0")
                {
                    Debug.Print("IP Address = " + cellularRadio.NetworkInterface.IPAddress);
                    attached = true;
                }
                else
                    throw new SystemException("DHCP unsuccessful");

            }
            catch (Exception ex)
            {
                Debug.Print("Attach(): Exception - " + ex.Message);
            }

            return attached;
        }

        private void Detach()
        {
            if (cellularRadio.NetworkInterface.Opened)
                cellularRadio.NetworkInterface.Close();
            cellularRadio.NetworkInterface.Dispose();
        }

        private string WebRequest()
        {
            string result = "";

            using (var req = HttpWebRequest.Create("http://httpbin.org/ip") as HttpWebRequest)
            {
                req.KeepAlive = false;
                req.ContentLength = 0;

                using (var res = req.GetResponse() as HttpWebResponse)
                {
                    using (var stream = res.GetResponseStream())
                    {
                        int read = 0, total = 0;
                        var buffer = new byte[1024];

                        do
                        {
                            read = stream.Read(buffer, 0, buffer.Length);
                            total += read;

                            Thread.Sleep(20);
                        } while (read != 0);

                        result = new string(Encoding.UTF8.GetChars(buffer));
                        //Debug.Print(result);
                    }
                }
            }
            return result;
        }

        #endregion Methods


        private void _celltimer_Tick(GT.Timer timer)
        {
            throw new SystemException("Cellular operation timed out.");
        }

        #region Cellular Radio Handlers

        void cellularRadio_SmsReceived(CellularRadio sender, CellularRadio.Sms message)
        {
            Debug.Print("SMS Received Event");
        }

        void cellularRadio_IncomingCall(CellularRadio sender, string caller)
        {
            Debug.Print("Incoming Call Event");
        }


        void cellularRadio_SmsListReceived(CellularRadio sender, CellularRadio.Sms[] smsList)
        {
            Debug.Print("SMS List Received Event");
        }

        private void cellularRadio_CallConnected(CellularRadio sender, string number)
        {
            Debug.Print("Call Connected with " + number);
        }

        private void cellularRadio_CallEnded(CellularRadio sender, CellularRadio.CallEndReason reason)
        {
            switch (reason)
            {
                case CellularRadio.CallEndReason.Busy:
                    Debug.Print("Call Ended - Busy");
                    break;
                case CellularRadio.CallEndReason.NoCarrier:
                    Debug.Print("Call Ended - No Carrier");
                    break;
                case CellularRadio.CallEndReason.NoDialTone:
                    Debug.Print("Call Ended - No Dial Tone");
                    break;
            }
        }

        private void cellularRadio_GprsAttached(CellularRadio sender, string ipAddress)
        {
            Debug.Print("GPRS Attached - IPAddress = " + ipAddress);
        }

        private void cellularRadio_GprsNetworkRegistrationChanged(CellularRadio sender, CellularRadio.NetworkRegistrationState networkState)
        {
            switch (networkState)
            {
                case CellularRadio.NetworkRegistrationState.Error:
                    Debug.Print("Gprs Network Registration Changed - Error");
                    break;
                case CellularRadio.NetworkRegistrationState.NotSearching:
                    Debug.Print("Gprs Network Registration Changed - Not Searching");
                    break;
                case CellularRadio.NetworkRegistrationState.Registered:
                    Debug.Print("Gprs Network Registration Changed - Registered");
                    //cellularRadio.UseThisNetworkInterface(apn, username, password, PPPSerialModem.AuthenticationType.Pap); //we have GPRS, so start up the PPP
                    break;
                case CellularRadio.NetworkRegistrationState.RegistrationDenied:
                    Debug.Print("Gprs Network Registration Changed - Registration Denied");
                    break;
                case CellularRadio.NetworkRegistrationState.Roaming:
                    Debug.Print("Gprs Network Registration Changed - Roaming");
                    break;
                case CellularRadio.NetworkRegistrationState.Searching:
                    Debug.Print("Gprs Network Registration Changed - Searching");
                    break;
                case CellularRadio.NetworkRegistrationState.Unknown:
                    Debug.Print("Gprs Network Registration Changed - Unknown");
                    break;
            }
        }

        private void cellularRadio_GsmNetworkRegistrationChanged(CellularRadio sender, CellularRadio.NetworkRegistrationState networkState)
        {
            switch (networkState)
            {
                case CellularRadio.NetworkRegistrationState.Error:
                    Debug.Print("Gsm Network Registration Changed - Error");
                    break;
                case CellularRadio.NetworkRegistrationState.NotSearching:
                    Debug.Print("Gsm Network Registration Changed - Not Searching");
                    break;
                case CellularRadio.NetworkRegistrationState.Registered:
                    Debug.Print("Gsm Network Registration Changed - Registered");
                    //cellularRadio.UseThisNetworkInterface(apn, username, password, PPPSerialModem.AuthenticationType.Pap); //we have Gsm, so start up the PPP
                    break;
                case CellularRadio.NetworkRegistrationState.RegistrationDenied:
                    Debug.Print("Gsm Network Registration Changed - Registration Denied");
                    break;
                case CellularRadio.NetworkRegistrationState.Roaming:
                    Debug.Print("Gsm Network Registration Changed - Roaming");
                    break;
                case CellularRadio.NetworkRegistrationState.Searching:
                    Debug.Print("Gsm Network Registration Changed - Searching");
                    break;
                case CellularRadio.NetworkRegistrationState.Unknown:
                    Debug.Print("Gsm Network Registration Changed - Unknown");
                    break;
            }
        }

        private void cellularRadio_NetworkUp(GTM.Module.NetworkModule sender,
            GTM.Module.NetworkModule.NetworkState state)
        {
            switch (state)
            {
                case GTM.Module.NetworkModule.NetworkState.Down:
                    Debug.Print("Network Down Event - Down");
                    break;
                case GTM.Module.NetworkModule.NetworkState.Up:
                    Debug.Print("Network Down Event - Up");
                    break;
            }
        }

        private void cellularRadio_NetworkDown(GTM.Module.NetworkModule sender,
            GTM.Module.NetworkModule.NetworkState state)
        {
            switch (state)
            {
                case GTM.Module.NetworkModule.NetworkState.Down:
                    Debug.Print("Network Down Event - Down");
                    break;
                case GTM.Module.NetworkModule.NetworkState.Up:
                    Debug.Print("Network Down Event - Up");
                    break;
            }
        }

        void cellularRadio_LineReceived(CellularRadio sender, string line)
        {
            Debug.Print("Recv: " + line.TrimEnd('\r', '\n'));
        }

        void cellularRadio_LineSent(CellularRadio sender, string line)
        {
            Debug.Print("Sent: " + line.TrimEnd('\r', '\n'));
        }

        #endregion Cellular Radio Handlers

    }
}

When the code is debug-executed, it the debugger output is as follows.

Using mainboard GHI Electronics FEZ Spider II version 1.0
WARN: Total initialization time exceeds 10 seconds.
: ProgramStarted is blocking execution, which means events and timers will not run properly.
: Make sure not to use blocking code such as while(true) - use a GT.Timer instead.
Sent: AT
Sent: ATE0
Sent: AT+CMGF=1
Sent: AT+CSDH=0
Sent: AT+CPBS="SM"
Sent: AT+CPMS="SM"
Sent: AT+COLP=1
Sent: AT+CGREG=1
Sent: AT+CREG=1
Program Started
Network Down Event - Down
Recv: AT
Recv: OK
Recv: ATE0
Recv: OK
Recv: OK
Recv: OK
Recv: OK
Recv: +CPMS: 0,50,0,50,0,50
Recv: OK
Recv: OK
Recv: OK
Recv: OK
Recv: +CREG: 1
Gsm Network Registration Changed - Registered
Recv: +CGREG: 0
Gprs Network Registration Changed - Not Searching
The thread ā€˜ā€™ (0x3) has exited with code 0 (0x0).
Recv: +CGREG: 1
Gprs Network Registration Changed - Registered

------------------------- 1st button press -----------------------

Sent: AT+CGDCONT=1,ā€œIPā€,"internet"
Sent: ATDT99**1#
The thread ā€˜ā€™ (0x5) has exited with code 0 (0x0).
Waiting on DHCP - 1
Waiting on DHCP - 2
Waiting on DHCP - 3
Waiting on DHCP - 4
Waiting on DHCP - 5
Waiting on DHCP - 6
Waiting on DHCP - 7
Waiting on DHCP - 8
Waiting on DHCP - 9
Waiting on DHCP - 10
Waiting on DHCP - 11
Waiting on DHCP - 12
Waiting on DHCP - 13
Waiting on DHCP - 14
Waiting on DHCP - 15
Waiting on DHCP - 16
Waiting on DHCP - 17
Waiting on DHCP - 18
Waiting on DHCP - 19
Network address changed
Network availability changed: True
IP Address = 10.195.23.159
{
ā€œoriginā€: ā€œ41.13.220.50ā€
}

Recv: OK
Recv: CONNECT
Network Down Event - Up
Network address changed
Network availability changed: False
Network Down Event - Down
Network address changed
Network availability changed: False

--------------------------- 2nd button press ----------------------

Sent: AT+CGDCONT=1,ā€œIPā€,"internet"
Sent: ATDT99**1#

Netlight flashes 64msOn/300msOff for about 30 seconds indicating GPRS communication is established,
and then returns to 64msOn/3000msOff, and remains in this state ad infinitum.

I stepped through the CellularRadio_43.cs code in the second overload of the UseThisNetworkInterface(ā€¦) method,
and noticed that the code stalls after executing this.pppEvent.WaitOne();

this.pppEvent.Set(); only occurs once in the while (this.running) { ā€¦ } loop in the DoWork() method.

I thus assume that a CONNECT is never received.

What I am trying to achieve in this small test app is the following.
On program start, power up the cellular radio.

  1. Respond to some trigger (in this case a ButtonReleased event)
  2. Attach to the network to establish GPRS communication.
  3. Do some network request (in this case a very simple web request).
  4. Detach from the network.

I would like to be able to repeat 1 through 4 without having to cycle power if possible, unless the cellular radio gets stuck.

Is anyone able to shed light on why the code stalls as explained above please?

[quote=ā€œOldevelā€]
I also added a wire to the Status output of the SIM900 and fed this to a DigitalInput in order to obtain more definitive control over the state of power of the module. Also see some of @ Daveā€™s comments regarding this.).[/quote]

I would really much like at picture of that setupā€¦ do you also use the DTR pin?

@ njbuch - [quote]I would really much like at picture of that setupā€¦ do you also use the DTR pin?[/quote]

I have tried to upload 3 images. Youā€™re welcome to send me a private message with an email address if the image upload does not work.

I have connected wires to Netlight and Status, one can easily do the same for any other signals like DTR and RI, however there is a small catch.

If the signals are generated by the SIM900, and you just want to read them using a DigitalInput, then fine, solder a wire to the pin on the SIM900, and include say a 1K resistor between this and the DigitalInput.

But when you need to drive an input on the SIM900 from a DigitalOutput, you need to add a level shifting circuit. If you donā€™t, you stand a very good chance of damaging the SIM900. This is because the SIM900 input or I/O pins operate at 2.8V, and will tolerate a maximum of 3.0V. See the SIM900 datasheet for these details. The schematic of the Cellular Radio module shows 4 level shift circuits, each consisting of 2 x 10K resistors, and an N-Channel FET. These can also be built on a small piece of Vero Board using THP components.

If you are not familiar with fine pitch soldering, it shouldnā€™t be too difficult to find someone who can solder the wires for you.

I hope this helps.

2 Likes