UDP broadcasts and SYSTEM_MODE(MANUAL)

The following code sometimes runs properly immediately after it is flashed. But after a restart the UDP datagrams are not sent and the core hangs for a long time inside udp.stop(). Note that if I press the button to tell the code to Spark.connect() then the sketch runs flawlessly. But, of course, I want to broadcast datagrams without the cloud. This dummy code isn’t the real app but it demonstrates the problem. So, for example, I know it isn’t efficient to set up and tear down a socket for every datagram but I do this to demonstrate it isn’t the “old socket” problem we already know about.
(1) no datagrams are sent.
(2) the core hangs inside udp.stop().
(3) It works in AUTOMATIC mode, but not in MANUAL.

I can see by the Blink()s that the code is hanging inside udp.stop(). So I press the button on D0. After a minute(!) the core connects to Cloud (breathing green -> breathing cyan) and then the UDP datagrams are sent but the iter counter has been reset - there’s been some initialisation soft-boot thing happening upon 1st connection to the cloud. So I press the button again to disconnect (back to breathing green) and now the UDP packets continue to be sent. iter is not re-initialised. So I press the button again, and this time the core connects to the cloud promptly without resetting the iter counter. All very odd. Complete code below.

The problem remains because I cannot cycle through connecting to and from the cloud - I want this app to work entirely without the cloud.

SYSTEM_MODE(MANUAL);

int modePin = D0;       //raise this pin to connect to Cloud
int lightPin = D7;      //LED

int gb_cloud_button = 0;
int gb_ignore_button = 0;

int UDPbroadcast( char *buf);

void setup() {
  pinMode(  modePin, INPUT);
  pinMode( lightPin, OUTPUT);
  Blink(3);
  Blink(1);
  Blink(3);
  attachInterrupt( modePin, SignalConnectCloud, FALLING);
  WiFi.connect();
}

void loop() {
  static int iter = 0;
  char sbuf[10];

  if( ! Spark.connected() && gb_cloud_button)
    Connect2Cloud();

  if( Spark.connected() && gb_cloud_button)
    DisConnectCloud();

  gb_ignore_button = 0;

  if( Spark.connected())
    Spark.process();

  sprintf( sbuf, "%d", ++iter);
  if( WiFi.ready())
    if( UDPbroadcast( sbuf)) {
      Blink( 3);
    } else {
      WiFi.disconnect();
      Blink( 5);
      WiFi.connect();
    }
  delay( 3000);

}

int UDPbroadcast( char *sbuf) {

  IPAddress remote_IP( 255, 255, 255, 255); // broadcast to entire LAN
  unsigned int remote_port = 32001;
  unsigned int local_port = 32002;

  UDP gudp;
  Blink(1);
  gudp.begin( local_port);
  //Blink(2);
  //gudp.parsePacket();
  //Blink(3);
  //gudp.flush();

  Blink(5);
  gudp.beginPacket( remote_IP, remote_port);
  Blink(4);
  int nwritten = gudp.write((unsigned char *)sbuf, strlen(sbuf)+1);
  Blink(3);
  gudp.endPacket();
  Blink(2);
  gudp.stop();
  Blink(1);

  return(nwritten);
}

void SignalConnectCloud( void) {
  if( ! gb_ignore_button) {
    digitalWrite( lightPin, HIGH);
    gb_cloud_button = 1;
    gb_ignore_button = 1;
  }
}

void DisConnectCloud( void) {
  gb_cloud_button = 0;
  Spark.disconnect();
  if( WiFi.ready())
    UDPbroadcast( "D");
  Blink( 5);
}

void Connect2Cloud( void) {
  gb_cloud_button = 0;
  if( ! Spark.connected()) {
    if( WiFi.ready())
      UDPbroadcast( "C");
    Spark.connect();
    while( ! Spark.connected()) {
      Blink( 2);
      delay(1000);
    }
    if( WiFi.ready())
      UDPbroadcast( "CC");
  }
  Blink( 5);
}

void Blink( int n) {
    int i;
    for( i=0; i<n; i++) {
      if( Spark.connected())
        Spark.process();
      digitalWrite( lightPin, HIGH);
      delay(200);
      if( Spark.connected())
        Spark.process();
      digitalWrite( lightPin, LOW);
      delay(200);
    }
    if( Spark.connected())
      Spark.process();
    delay(400);
}

See also https://community.spark.io/t/udp-broadcast-only-works-when-connected-to-the-cloud-why/7971/8