MKR GSM 1400 - WiFi101 OTA library

Does the WiFi101 OTA library work with the MKR GSM 1400?

yes, but only over WiFi101 module, not over GSM.

over GSM you can code you own trasport of th ebinary and then use the InternalStorage object to store and apply the binary. I guess WiFi101OTA doesn't support this way but my ArduinoOTA library does it.

there were multiple people doing this, some of them successful, but I didn't find it now in a short time.

I tried with your library and the process is done well but the sketch apparently did not store well in the MKR GSM 1400 since after rebooting the MKR GSM 1400 it does not have functionality, as if it did not have any stored sketch.

Maybe it has something to do with "trasport" which is something I really do not understand. I will appreciate any guidance in this regard.

by transport I meant transport over the GSM.
the WiFi101 library works with WiFi101 shield or module or on MKR1000.
ArdoinoOTA library supports many networking libraries but not the MKR GSM library. How would you upload from IDE this way? IDE can only upload to a local IP address.

The Arduino OTA library can be used to apply a downloaded library, but doesn't handle the download over network, only supports storing a applying of the binary.
https://github.com/jandrassy/ArduinoOTA#ota-update-as-download

I have changed to the the TinyGSM library. I am trying to run the "WebClient_MKRGSM1400" example, but I am getting the compiler error:

In file included from C:\Program Files (x86)\Arduino1p8p13\portable\sketchbook\libraries\TinyGSM\src/TinyGsmClient.h:52:0,
                 from C:\Users\LMario\AppData\Local\Temp\arduino_modified_sketch_95859\WebClient_MKRGSM1400.ino:24:
C:\Program Files (x86)\Arduino1p8p13\portable\sketchbook\libraries\TinyGSM\src/TinyGsmClientU201.h: In member function 'bool TinyGsmU201::isGprsConnected()':
C:\Program Files (x86)\Arduino1p8p13\portable\sketchbook\libraries\TinyGSM\src/TinyGsmClientU201.h:474:22: error: ambiguous overload for 'operator!=' (operand types are 'arduino::IPAddress' and 'int')
     return localIP() != 0;
            ~~~~~~~~~~^~~~
C:\Program Files (x86)\Arduino1p8p13\portable\sketchbook\libraries\TinyGSM\src/TinyGsmClientU201.h:474:22: note: candidate: operator!=(uint32_t {aka long unsigned int}, int) <built-in>
In file included from C:\Program Files (x86)\Arduino1p8p13\Portable\Packages\arduino\hardware\samd\1.8.11\cores\arduino/api/ArduinoAPI.h:30:0,
                 from C:\Program Files (x86)\Arduino1p8p13\Portable\Packages\arduino\hardware\samd\1.8.11\cores\arduino/Arduino.h:23,
                 from sketch\WebClient_MKRGSM1400.ino.cpp:1:
C:\Program Files (x86)\Arduino1p8p13\Portable\Packages\arduino\hardware\samd\1.8.11\cores\arduino/api/IPAddress.h:62:10: note: candidate: bool arduino::IPAddress::operator!=(const arduino::IPAddress&) const
     bool operator!=(const IPAddress& addr) const { return _address.dword != addr._address.dword; };
          ^~~~~~~~
exit status 1
Error compiling for board Arduino MKR GSM 1400.

I am using the Arduino IDE 1.8.13 and 1.8.16 (same error)

the example is not up to date

@Juraj
Sounds interesting. May i ask some beginners questions?

  • What size of sketch do you think is possible on a mkr1400 with this OTA lib?
  • How is it working, i mean if a code is already running? On which memory? Substitute itself?
  • Is it using tcp/upd/both?
  • As an alternative, i though about copy a UPDATE.bin to a SD card and reset the board with SDU.h lib loaded. What do you think?

the sketch must be less than half of the sketch size. the update binary is stored in the upper half of the flash. the copy to run location is done with a function running in RAM, then a reset starts the new version. The network transport supported by the library is a TCP server. Sketch can implement a different transport way and use InternalStorage object to store and apply the binary.

The library supports storing of the uploaded binary to SD card or external flash. Loading from SD card or external flash is supported by SDU or SFU library.

Most of this is inherited from Arduino WiFi101 OTA library which supports only the WiFi101 library with SAMD (MKR1000, Zero with WiFi101 shield and any other SAMD board with module for WiFi101).

I see. So for me is the SD card/SDU(i like that lib very much) method the only way because my sketch uses 80%. I just tried with a data stream to the SD card but it struggles in a flaky way. Sometimes the whole binary is stored, sometimes it freezes after some moments. Probably the limitations of a single threading system or the FAT filesytem implementation.
I have to implement a integrity check with a checksum.
Thx Juraj

I use OTA over SD card on ATmega1284 without problems

Ok, i missunderstood you. Make sense. I will try this also.
Do you have a link to a code/example as a entry point?

VERY nice! Thx for inspiration. I will try to adopt to a mkr1400.
Maybe mqtt instead of http?
And then read out the socket with:

while (length > 0) {
    if (!client.readBytes(&b, 1)) // reading a byte with timeout
      break;
    file.write(b);
    length--;
  }

Uff... Happy holidays!

I have corrected the TinyGSM library compile error I was getting and now the MKR GSM 1400 example works very well. The OTA functionality update goes smoothly.

Thanks for the support.

Can you provide a link to a example sketch?

Attached is the Tiny library I have used. The sample which makes the job is WebClient_MKRGSM1400.ino. You only need to fix a compile error which is easy.

TinyGSM.zip (79.7 KB)

Thank you. But i don't see any OTA functionality in the example?!? It's just a http download with a output on ther serial monitor. I don't get the OTA part.
Good party 2nite!

I attach the sketch that I am using. I have modified the MKR GSM 1400 example adding the OTA code. Too I have added a lot of stuff to skip the headers of the server HTTP response as well as to review its content and only use OTA when necessary. Also I add an LED which changes its blinking according to the last version of the sketch. From this I check if OTA is working correctly.

You can ignore those changes and only consider the lines that handle OTA:

#include <ArduinoOTA.h>
InternalStorage.open ();
InternalStorage.write ();
InternalStorage.close ();
InternalStorage.apply ();

SKETCH:

#define nop __asm__ __volatile__ ("nop\n\t")

// Select your modem:
#define TINY_GSM_MODEM_U201

// Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512

#include <TinyGsmClient.h>
#include <ArduinoOTA.h>

#define VERSION 1.00
#define DELAY_CHECK_NEW_FIRMWARE 3600000L
#define TIME_WAIT_HTTP_CONNECTION 30000L

// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS

// Use Hardware Serial on MKR GSM
#define SerialAT SerialGSM

// Your GPRS credentials
// Leave empty, if missing user or pass
char GPRS_APN[]  = "Your APN";
char GPRS_LOGIN[] = "Your Login";
char GPRS_PASSWORD[] = "Your Password";

// Server details
char server[] = "Your file server";
char resource[] = "Your UPDATE file";
const int  port=80;

#ifdef DUMP_AT_COMMANDS
  #include <StreamDebugger.h>
  StreamDebugger debugger(SerialAT, Serial);
  TinyGsm modem(debugger);
#else
  TinyGsm modem(SerialAT);
#endif

TinyGsmClient client(modem);

boolean flagUpdateFirmware=false,flagNewFirmwareDownloaded=false;

long timeLastEventBlink,timeLastOTAUpdateFirmwareCheck;
boolean flagButtonON=false,flagLEDOFF=true;
char *dateFirmwareMPU="Sun, 26 Dec 2021 02:33:51 GMT";
char dateFirmwareFile[50];

int i;

void setup()
{
  // Set console baud rate
  Serial.begin(115200);
  long timeStartRunning = millis();
  while (!Serial&&millis()-timeStartRunning<=3000)
    nop;

  Serial.print("Version: ");   Serial.println(VERSION);

  // Set GSM module baud rate
  SerialAT.begin(115200);

  // FOR THE MKR GSM 1400
  // reset / powerup the modem
  pinMode(GSM_RESETN, OUTPUT);
  digitalWrite(GSM_RESETN, HIGH);
  delay(100);
  digitalWrite(GSM_RESETN, LOW);
  
  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  Serial.println("Initializing modem...");
  modem.restart();

  String modemInfo = modem.getModemInfo();
  Serial.print("Modem: ");
  Serial.println(modemInfo);

  Serial.print(F("Waiting for network..."));
  if (!modem.waitForNetwork()) {
    Serial.println(" fail");
    delay(10000);
    return;
  }
  Serial.println(" OK");

  Serial.print("Connecting to ");
  Serial.print(GPRS_APN);
  if (!modem.gprsConnect(GPRS_APN,GPRS_LOGIN,GPRS_PASSWORD)) {
    Serial.println(" fail");
    delay(10000);
    return;
  }
  Serial.println("... OK");

  // Unlock your SIM card with a PIN
  //modem.simUnlock("1234");

  pinMode(7,OUTPUT);
  timeLastEventBlink=millis();
  timeLastOTAUpdateFirmwareCheck = millis() - DELAY_CHECK_NEW_FIRMWARE;
}

void loop()
{
  // Check for update every hour
  if(millis()-timeLastOTAUpdateFirmwareCheck>DELAY_CHECK_NEW_FIRMWARE)
    checkForNewFirmwareUpdate();

  blink();
}

void checkForNewFirmwareUpdate()
{
  // Make a HTTP GET request:
  Serial.print("Connecting to ");
  Serial.print(server);
  Serial.print(".");
  long timeStartTryingConnectHTTP=millis();
  while(millis()-timeStartTryingConnectHTTP<TIME_WAIT_HTTP_CONNECTION)
  {
    if (client.connect(server, port))
      break;
    else
    {
      Serial.print(".");
      delay(10000);
    }
  }
  if(millis()-timeStartTryingConnectHTTP>TIME_WAIT_HTTP_CONNECTION)
  {
    Serial.print("Fail to connect to: ");   Serial.print(server);
    timeLastOTAUpdateFirmwareCheck = millis();
    return;
  }
  Serial.println(" OK");

  client.print(String("GET ") + resource + " HTTP/1.0\r\n");
  client.print(String("Host: ") + server + "\r\n");
  client.print("Connection: close\r\n\r\n");
  timeStartTryingConnectHTTP = millis();
  Serial.print("Waiting for file server answer.");

  while(millis()-timeStartTryingConnectHTTP<=TIME_WAIT_HTTP_CONNECTION)
  {
    if(client.available())
      break;
    else
    {
      Serial.print(".");
      delay(1000);
    }
  }
  Serial.println("");
  if(millis()-timeStartTryingConnectHTTP>=TIME_WAIT_HTTP_CONNECTION)
  {
    Serial.println("No answer for file server. Does the SIM card have a balance?");
    disconnectGPRSLocal();
    return;
  }

  timeStartTryingConnectHTTP = millis();
  byte actualByte,previousByte;
  char line[80];
  long counterBytesRead,counterCharactersLine;
  boolean flagDataStarted=false,flagNewLine=false;
  if (client.available())
  {
    // Skip head stuff
    counterBytesRead = 0;
    counterCharactersLine = 0;
    previousByte = client.read();
    while (client.available())
    {
      actualByte = client.read();
      if(!flagDataStarted)
      {
        line[counterCharactersLine] = actualByte;
        counterCharactersLine++;
        if(actualByte==10&&previousByte==13)
        {
          line[counterCharactersLine] = '\0';
          Serial.print(line);
          // Check the "TTP/1.1" header
          if(strstr(line,"TTP/1.1")!=NULL)
          {
            if(strstr(line,"200")==NULL)
            {
              Serial.println("UPDATE.bin file does not exists on the server. Firmware is not changed");
              disconnectGPRSLocal();
              flagNewFirmwareDownloaded = true;
              return;
            }
          }
          // Check the "Last-Modified" header
          else if(strstr(line,"Last-Modified")!=NULL)
          {
            for(i=0;i<strlen(line)-17;i++)                                             // 17: 15: "Last-Modified" length + 2: char(10) and char(13)
              dateFirmwareFile[i] = line[15+i];
            dateFirmwareFile[i] = '\0';
            if(strcmp(dateFirmwareFile,dateFirmwareMPU)==0)
            {
              Serial.print("Latest firmware version installed. It does not need to be updated");
              disconnectGPRSLocal();
              return;
            }
          }
          // Check the "Content-Length" header
          else if(strstr(line,"Content-Length")!=NULL)
          {
            char sizeBinFile[10];
            for(i=16;i<strlen(line);i++)
              sizeBinFile[i-16] = line[i];
            sizeBinFile[i-16] = '\0';
            InternalStorage.open(atoi(sizeBinFile));
          }
          if(flagNewLine)
          {
            Serial.println("Download update file start...");
            flagDataStarted = true;
          }
          counterCharactersLine = 0;
          line[0] = '\0';
          flagNewLine = true;
        }
        else if(actualByte!=13||previousByte!=10)
          flagNewLine = false;
      }
      else
      {
        InternalStorage.write(actualByte);
        counterBytesRead++;
      }
      previousByte = actualByte;
    }
    Serial.print("Bytes downloaded: ");   Serial.println(counterBytesRead);
    InternalStorage.close();
    flagNewFirmwareDownloaded = true;
    // DISCONNECT
    Serial.println("New firmware installed");
    disconnectGPRSLocal();
    InternalStorage.apply(); // this doesn't return
  }
  if(millis()-timeStartTryingConnectHTTP>TIME_WAIT_HTTP_CONNECTION*2)
    Serial.println("NO answer from the file server");
}

void disconnectGPRSLocal()
{
  client.stop();
  Serial.println(F("\nServer disconnected"));
  modem.gprsDisconnect();
  Serial.println(F("GPRS disconnected"));
  Serial.println("done.");
  timeLastOTAUpdateFirmwareCheck = millis();
}

void blink()
{
  if(millis()-timeLastEventBlink>5000)
  {
    if(flagLEDOFF)
    {
      digitalWrite(7,HIGH);
      flagLEDOFF = false;
    }
    else
    {
      digitalWrite(7,LOW);
      flagLEDOFF = true;
    }
    timeLastEventBlink = millis();
  }
}

@intstarep OTASketchDownload example shows download essentials

Thank you and a happy new year!!