In-Field Update from URL

I am trying to do an in-field update from an URL. My problem is after it reboots it never starts the new or the old firmware if i only load application.hex. If i try to load my application.hex and config.hex i get the following exception when i load the second file the first one loads without error.

#### Exception System.ArgumentException - 0xfd000000 (1) ####
    #### Message: 
    #### GHI.Processor.InFieldUpdate::NativeLoad [IP: 0000] ####
    #### GHI.Processor.InFieldUpdate::Load [IP: 004d] ####
    #### In_Field_Update.Program::LoadFile [IP: 00b7] ####
    #### In_Field_Update.Program::FlashFirmware [IP: 0030] ####
    #### In_Field_Update.Program::Main [IP: 0091] ####
A first chance exception of type 'System.ArgumentException' occurred in GHI.Hardware.dll
    #### Exception System.Exception - 0x00000000 (1) ####
    #### Message: Error saving file from url:Exception was thrown: System.ArgumentException
    #### In_Field_Update.Program::LoadFile [IP: 00ed] ####
    #### In_Field_Update.Program::FlashFirmware [IP: 0030] ####
    #### In_Field_Update.Program::Main [IP: 0091] ####
A first chance exception of type 'System.Exception' occurred in In-Field_Update_URL.exe
An unhandled exception of type 'System.Exception' occurred in In-Field_Update_URL.exe
Additional information: Error saving file from url:Exception was thrown: System.ArgumentException

Version info:

Loader (TinyBooter) version information:
4.3.4.0 on this computer.
4.3.4.0 on this device.

The Loader (TinyBooter) is up to date. <<<

Firmware (TinyCLR) version information:
4.3.6.0 on this computer.
4.3.6.0 on this device.

The Firmware (TinyCLR) is up to date. <<<

Code:

public static void FlashFirmware()
        {
            OutputPort Power_LED = new OutputPort(G120.P1_15, false);
            OutputPort Status_LED = new OutputPort(G120.P1_9, false);

            Power_LED.Write(true);
            Status_LED.Write(true);

            InFieldUpdate.Initialize(InFieldUpdate.Types.Application | InFieldUpdate.Types.Configuration | InFieldUpdate.Types.Firmware);

            LoadFile("http://myurl.com/Application.hex", InFieldUpdate.Types.Application);
            LoadFile("http://myurl.com/Config.hex", InFieldUpdate.Types.Configuration);
            LoadFile("http://myurl.com/Firmware.hex", InFieldUpdate.Types.Firmware);
            LoadFile("http://myurl.com/Firmware2.hex", InFieldUpdate.Types.Firmware);

            InFieldUpdate.FlashAndReset();
        }

        public static void LoadFile(string url, InFieldUpdate.Types type)
        {
            HttpWebRequest MyRequest = (HttpWebRequest)WebRequest.Create(url);

            try
            {
                HttpWebResponse MyResponse = (HttpWebResponse)MyRequest.GetResponse();

                if (HttpStatusCode.OK == MyResponse.StatusCode)
                {
                    using (Stream MyResponseStream = MyResponse.GetResponseStream())
                    {
                        Debug.Print("Length: " + MyResponseStream.Length);

                        // Create a 64K buffer to chunk the file
                        var data = new byte[BLOCK_SIZE];                                            

                        for (int i = 0; i < MyResponseStream.Length / BLOCK_SIZE; i++)
                        {
                            MyResponseStream.Read(data, 0, BLOCK_SIZE);
                            InFieldUpdate.Load(type, data, BLOCK_SIZE);  
                        }

                        Debug.Print("Size: " + MyResponseStream.Length % BLOCK_SIZE);

                        int Size = (int)MyResponseStream.Length % BLOCK_SIZE;

                        MyResponseStream.Read(data, 0, Size);
                        InFieldUpdate.Load(type, data, Size); 

                        MyResponseStream.Close();
                        MyResponse.Close();
                    }         
                }
            }
            catch (Exception err)
            {
                throw new Exception("Error saving file from url:" + err.Message, err);
            }
        }

Hi,
1st: When your Application.hex is compiled against different firmware versions, you must update the firmware. This is why your device doesn’t start anymore if you only load your application hex file.

2nd:
Try to load the files in the following order:
Firmware.hex
Firmware2.hex
Config.hex
Application.hex

This is how it works for me all the time.

i have tried to load the files in that order. The order dosen’t matter i always get the exception when i load the second file.

I get the In exception on this line.

Any chance the 1st file was not loaded completely?

What is your BLOCK_SIZE?
I load my data in chunks of 10 * 1024 byte, and never had any issues.

What if
MyResponseStream.Length % BLOCK_SIZE
at the end is 0 (zero)
You would call InFieldUpdate.Load with size 0.
Not sure if this might cause a problem.

Are you sure that ResponseStream.Length is always the full file size?

@ janf - Dumb question but are you sure the hex file is arriving on the device uncorrupted?

Maybe receive a file and save on an sd card to make sure the file is correct.

Exactly; and I’ll give you a story…

Once upon a time, all my downloads were failing their crc checks. There were zip files, and they were impossible to unzip. I was angry for a long time at this strange and unique problem. Then one night in a fit of frustration I went nuts on my network: the laptop drivers, the router firmware, even the other servers in the environment. The problem turned out to be the network card device drivers. Any data transfer of a certain size or larger would arrive corrupt. While I don’t recall the exact details as to why it was happening, I became uniquely aware of the fact that data can show up corrupt, and that checksums and auto retransmission (hence the CAN question Gus) must be part of any network system.

@ Gus, isn’t there a CRC compute function in .netmf by default?

It looks like ResponseStream.Length is returning 2618 but the file size is 1.5MB so i am not getting the entire file.
My BLOCK_SIZE is 1024.

It is a custom board with a G120 and no sd card slot.

Question:
What am i doing wrong since i am not getting the full length of the file from ResponseStream.Length?

I would guess that your method is entered when the 1st bytes of the data arrive.
When you read the stream length you get only the amount of data already received.
So you should reread the length from the stream all the time.
But I’m not really sure how to find out if the transmission of the file is really finished with the HTTP client.

i have postet the updatet code and debug output below.
on this code it runs InFieldUpdate.Load four times in the while loop and then i get the exception as seen in the debug output.
the bytes in the data array looks ok.

Updatet Code:

public static void FlashFirmware()
        {
            OutputPort Power_LED = new OutputPort(G120.P1_15, false);
            OutputPort Status_LED = new OutputPort(G120.P1_9, false);

            Power_LED.Write(true);
            Status_LED.Write(true);

            InFieldUpdate.Initialize(InFieldUpdate.Types.Application | InFieldUpdate.Types.Configuration | InFieldUpdate.Types.Firmware);

            LoadFile("http://myurl.com/Firmware.hex", InFieldUpdate.Types.Firmware);
            LoadFile("http://myurl.com/Firmware2.hex", InFieldUpdate.Types.Firmware);
            LoadFile("http://myurl.com/Config.hex", InFieldUpdate.Types.Configuration);
            LoadFile("http://myurl.com/Application.hex", InFieldUpdate.Types.Application);

            InFieldUpdate.FlashAndReset();
        }

        public static void LoadFile(string url, InFieldUpdate.Types type)
        {
            int Size;
            long Lenght = 0;

            HttpWebRequest MyRequest = (HttpWebRequest)WebRequest.Create(url);

            try
            {
                HttpWebResponse MyResponse = (HttpWebResponse)MyRequest.GetResponse();

                if (HttpStatusCode.OK == MyResponse.StatusCode)
                {
                    using (Stream MyResponseStream = MyResponse.GetResponseStream())
                    {
                        Debug.Print("ContentLength: " + MyResponse.ContentLength);

                        // Create a 4K buffer to chunk the file
                        var data = new byte[BLOCK_SIZE];
                        
                        while(Lenght < MyResponse.ContentLength)
                        {
                            Size = (int)MyResponseStream.Length;
                            Lenght += MyResponseStream.Length;
                            Debug.Print("Size: " + Size);
                            Debug.Print("Lenght: " + Lenght);
                            MyResponseStream.Read(data, 0, Size);
                            InFieldUpdate.Load(type, data, Size);
                            Thread.Sleep(50); 
                        }
                        
                        MyResponseStream.Close();
                        MyResponseStream.Dispose();
                        MyResponse.Close();                        
                        MyResponse.Dispose();
                    }         
                }
            }
            catch (Exception err)
            {
                throw new Exception("Error saving file from url:" + err.Message, err);
            }
        }

Debug Output:

ContentLength: 1510512
Size: 2618
Lenght: 2618
Size: 2920
Lenght: 5538
Size: 2920
Lenght: 8458
Size: 2920
Lenght: 11378
Size: 2920
Lenght: 14298
    #### Exception System.ArgumentException - 0xfd000000 (1) ####
    #### Message: 
    #### GHI.Processor.InFieldUpdate::NativeLoad [IP: 0000] ####
    #### GHI.Processor.InFieldUpdate::Load [IP: 004d] ####
    #### In_Field_Update.Program::LoadFile [IP: 008c] ####
    #### In_Field_Update.Program::FlashFirmware [IP: 0028] ####
    #### In_Field_Update.Program::Main [IP: 0091] ####
A first chance exception of type 'System.ArgumentException' occurred in GHI.Hardware.dll
    #### Exception System.Exception - 0x00000000 (1) ####
    #### Message: Error saving file from url:Exception was thrown: System.ArgumentException
    #### In_Field_Update.Program::LoadFile [IP: 00e7] ####
    #### In_Field_Update.Program::FlashFirmware [IP: 0028] ####
    #### In_Field_Update.Program::Main [IP: 0091] ####
A first chance exception of type 'System.Exception' occurred in In-Field_Update_URL.exe
An unhandled exception of type 'System.Exception' occurred in In-Field_Update_URL.exe
Additional information: Error saving file from url:Exception was thrown: System.ArgumentException

Code looks good except for this:
You do not limit Size to BLOCK_SIZE anymore. By this if you have more data in the stream available then BLOCK_SIZE it will crash.

@ Mr. John Smith -
I get an exception at the second call to InFieldUpdate.Load() Does Load() evaluate the data?

                        var data = new byte[BLOCK_SIZE];
                        InFieldUpdate.Load(InFieldUpdate.Types.Configuration, data, 4096); //Used to load the new firmware.
                        InFieldUpdate.Load(InFieldUpdate.Types.Configuration, data, 4096); //Used to load the new firmware.

@ JacobSC - Wait why are you calling it twice?

@ JacobSC - The size value must be the actual number of bytes which are valid in the array, not the actual size of the array.
if the config has for example 5000 bytes, the you load the 1st 4096 bytes ito data and call load like your 1st call.
the you load the remaining 904 bytes to data and call load again, but only with 904 as size.

@ Mr. John Smith -
It was just an example.
I read a file from a webserver via HttpWebResponse.GetResponseStream() and and iterator through the stream, but at my second call to InFieldUpdate.Load(InFieldUpdate.Types.Configuration, data, 4096); I get an exception, thus I wonder if the exception is generated due to invalid data in my stream or it is something else.
/Jacob

@ JacobSC -
Strange. If I debug and singlestep I get an exception at the second call to InFieldUpdate.Load() but if I just run in debug I can call InFieldUpdate.Load() 5 times and then I get an exception.
/Jacob

@ JacobSC -
I have now managed to firmware upgrade my G120.
I have found out that if I write 64 byte to InFieldUpdate.Load() it works. If I write more I get an exceptions after a number of calls to InFieldUpdate.Load() if I write less bytes I get a timeout from my stream, it stops deliver data before I have read lenght