IFU Update Error

I am downloading an application file over cellular, it takes about 6 minutes or so. The byte count at the end of the download matches the file size. An error gets thrown at updater.VerifyApplication().

    static void DownloadFile()
    {
        var url = "http://myurl/myfile";

        Debug.WriteLine("Start Download");
        int read = 0, total = 0;
        byte[] result = new byte[2048];

        var qspiDrive = StorageController.FromName(SC20260.StorageController.QuadSpi);
        var updater = new InFieldUpdate(qspiDrive);


        try
        {
            updater.ResetChunks();
            var appKey = new byte[] { 0x00, 0xMyKey, 0xbd };
            updater.LoadApplicationKey(appKey);
            
            using (var req = HttpWebRequest.Create(url) as HttpWebRequest)
            {
                req.KeepAlive = true;

                using (var res = req.GetResponse() as HttpWebResponse)
                {
                    var loops = 0;

                    using (var stream = res.GetResponseStream())
                    {
                        do
                        {
                            read = stream.Read(result, 0, result.Length);
                            updater.LoadApplicationChunk(result,0, result.Length);

                            total += read;

                            loops++;
                            if (loops >= 10)
                            {
                                Debug.WriteLine("total : " + total);
                                loops = 0;
                            }
                            
                        }

                        while (read != 0);
                    }
                }
            }
            Debug.WriteLine("Total : " + total);
            Debug.WriteLine("Start Verify");
            var firmwareVersion = updater.VerifyApplication();
            Debug.WriteLine("Verify Done: " + firmwareVersion.ToString());

        }
        catch (Exception ex)
        {
            Debug.WriteLine("Download Error: " + ex.Message);
        }

    }

Debug output

Total : 1896448
Start Verify
    #### Exception System.ArgumentException - 0xfd000000 (6) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Update.InFieldUpdate::NativeAuthenticateApplication [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Update.InFieldUpdate::VerifyApplication [IP: 0016] ####
    #### ssg3_v0_0_1.HologramComms::Start [IP: 01ec] ####
Exception thrown: 'System.ArgumentException' in GHIElectronics.TinyCLR.Update.dll

Did you try the same file from SD card or other means beside cell? This will tell you if the file is bad or the cell download is corrupting the file.

Quick look as I don’t think it is good:

read = stream.Read(result, 0, result.Length);
updater.LoadApplicationChunk(result,0, result.Length);

It should be:

read = stream.Read(result, 0, result.Length);
updater.LoadApplicationChunk(result,0, read );

If the file is 9K but you write always multiply of 2, mean 8K or 10K because your buffer is 2K

Or change your buff to 1K.

1 Like

Nice catch Dat!

I changed the result size to 1K, as well as the following:

read = stream.Read(result, 0, result.Length);
updater.LoadApplicationChunk(result,0, read);

I still get the same error at Verify Application.

Start Verify
    #### Exception System.ArgumentException - 0xfd000000 (6) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.Update.InFieldUpdate::NativeAuthenticateApplication [IP: 0000] ####
    #### GHIElectronics.TinyCLR.Update.InFieldUpdate::VerifyApplication [IP: 0018] ####
    #### ssg3_v0_0_1.HologramComms::DownloadFile [IP: 0100] ####

Any additional thoughts?

I see there is 1.8MB application. Did you enable extern deployment?

Do you mean “Extend deployment”? If so then yes. The application file works fine on multiple devices.

Instead of saving to IFU, save to SD, or calculate MD5, make sure what you get from network are correct.

Or make a simple project so we can test qucikly.

Is this a legit way to calculate MD5 while downloading?

static void DownloadFile()
{
    var url = "http://my.url/myfile";

Debug.WriteLine("Start Download");
int read = 0, total = 0;
byte[] result = new byte[1024];

var qspiDrive = StorageController.FromName(SC20260.StorageController.QuadSpi);
var updater = new InFieldUpdate(qspiDrive);
var md5 = MD5.Create();

byte[] md5Hash = new byte[16];

try
{
    updater.ResetChunks();
    md5.Clear();

    var appKey = new byte[] { 0x22, myappKey, 0xbd };
    updater.LoadApplicationKey(appKey);
            
    using (var req = HttpWebRequest.Create(url) as HttpWebRequest)
    {
        req.KeepAlive = true;

        using (var res = req.GetResponse() as HttpWebResponse)
        {
            using (var stream = res.GetResponseStream())
            {
                do
                {
                    read = stream.Read(result, 0, result.Length);
                            
                    updater.LoadApplicationChunk(result, 0, read);
                    md5Hash = md5.ComputeHash(result, 0, read);
                    Array.Clear(result, 0, result.Length);
                            
                    total += read;
                }while (read != 0);
            }
        }
    }
    md5Hash = md5.Hash;
    var Hash = "";
    foreach(byte b in md5Hash)
    {
        Hash += b.ToString("x2");
    }
    Debug.WriteLine("Hash: " + Hash);

    Debug.WriteLine("Total : " + total);
    Debug.WriteLine("Start Verify");
    var firmwareVersion = updater.VerifyApplication();
    Debug.WriteLine("Verify Done: " + firmwareVersion.ToString());

}
catch (Exception ex)
{
    Debug.WriteLine("Download Error: " + ex.Message);
}


_DownLoadFile = false;

}

The Hash that I get is different than what I get from the file that is on the webserver. (webserver file and dev pc MD5 match.) However, I am not sure I am calculating it correctly.

The byte count matches between the server and the total I am receiving. If the data is getting corrupted on download then I am not sure where to go next.

The MD5 and HttpWebRequest api is similar to Desktop. You can try on PC to compare.

Or, Crc16 or just download to SDCard… few ways to compare what you get by code above is correct or not.

Using a C# console app to calculate the MD5 and here are my results.

When doing the MD5.ComputeHash inline with the download I get the same I get on SitCore:
MD5 done inline: d41d8cd98f00b204e9800998ecf8427e

In the console app, I save the file to disk and calculate the MD5:
MD5 full file: 1a52799318f7b40d42412113b46bb51d

The full file hash matches the server and original .TCA file. So it appears that all the bytes are making it through the cellular download. But there is a difference between the inline compute and the full file compute. I would need to run the full hash on what gets saved to qspi flash. Is there a clever way to do that?

I don’t think you can do inline like that.

You should read them all, keep it memory (I see you use SC20260 with 32MB memory). Then do MD5 for all file one time. It is much more simple. Do same with PC.

Compare two values.

What we care about is the content of your download. You can download to SDCard and bring to PC to compare with orginal file.

You can make a program 1.8MB (add some rescources), extract TCA, and send project to us so we can run quickly. Make sure you can reproduce with that project first.

Any thing news so far?

We need to make sure IFU has no issue. Can you reproduce by a simple project and send to us?

I will be working on it again this evening. Out in the field visiting customers last few days.

I will get back to you.

Okay here is where I am at:
Downloading to SPI Flash does not work.

Downloading the file to SD card, closing, then reopening and verifying works.

I can make the SD card work but it would be simpler if SPI Flash would work.

Edit:
I am running updater in debug mode. I can see the “Writting to flash” messages. (yes, the spelling is wrong. :wink: )

Start Download
Erasing flash: 0x00321000
Writting to flash: 0x00321000, size 0x0000035a
. . . .after 6 to 10 minutes . . . 
Writting to flash: 0x004efc92, size 0x00000030
Writting to flash: 0x004efcc2, size 0x0000033e
Writting to flash: 0x004f0000, size 0x00000000

The total file size is 1896448 (0x1cf000) bytes. (0x4f0000 - 0x321000 = 0x1cf000) So the bytes written seems to match.

Can you please buffer 1K and write 1K each time?

Loading Application in 1K chunks works!

I also noticed that every 4K there was an “Erase Flash” message, that wasn’t there with random chunk sizes.

Test Code:

using (var stream = res.GetResponseStream())
{
	do
	{
		if (stream.Length >= 1024)
		{
			read = stream.Read(result, 0, result.Length);
			updaterSPI.LoadApplicationChunk(result, 0, read);                                   
			md5Hash = md5.ComputeHash(result, 0, read);
			Array.Clear(result, 0, result.Length);

			total += read;

		}

	} while (stream.Length > 0);  // (read != 0);

   
	md5Hash = md5.Hash;
	var Hash = "";
	foreach (byte b in md5Hash)
	{
		Hash += b.ToString("x2");
	}
	Debug.WriteLine("Hash: " + Hash);

	Debug.WriteLine("Total : " + total);
	Debug.WriteLine("Start SPI Verify");
	updaterSPI.LoadApplicationKey(appKey);
	var firmwareVersion = updaterSPI.VerifyApplication();
	Debug.WriteLine("Verify SPI Done: " + firmwareVersion.ToString());
}

}

Will the TCA files always be in 1K increments? The test code above doesn’t have a provision for less than 1K at the end. If the TCA file is always 1K increments then I won’t have to worry about it, or will I?

I am still calculating the MD5 hash as a test. The end result is that the MD5 hash calculated in line with the download doesn’t match the hash generated on the server or PC.

Frist:

  • the buffer can be 512, 1K, 2K, 4K, 8K…
  • every time write the size need to be same. You can’t write 1K then next 2K. If decided 1K then all must be 1K. If decided 2K then all must be 2K, except for last block.
  • Tca is always multiply of 1K.

Second:

  • I don’t think do MD5 inline will work. As your log, I see every time reading data from network, the size is different, so MD5 will give different result of couse.
  • if tried 1K worked, then no worry, we know what your problem is. You can tried 2K, 4K for sure, but not 3K or 5K because sector size is 4K.
  • If tried 2K, 4K… then need to take care last block. Example tca 9K = 4 + 4 + 1. If do 4 +4 +4 then exception :)).

@Dat_Tran Thanks for the help. I hope I didn’t miss something in the docs that could have saved everyone’s time. If I did I apologize.
I will stick with 1K buffer size. I don’t have 32MB ram and with MQTT connected to Azure my RAM is a bit tight.

I don’t think MD5 is important since the IFU verify will fail if the file is corrupt.

When VerifyApplication() fails are there different exceptions indicate if it was due to a bad Application Key or corrupted file?

Now the hard part, creating the back end to support over-the-air updates on a fleet of devices.