OTA through Ethernet with Teensy 4.1

AndyA, are you saying that including flasherX in my code should be enough to meet this check?
Well that didn't seem to work for me. I had to use it somewhere in the code before it would work.
Although that makes sense I'll check it again.
 
You shouldn't need to manually include it. I never did. For the code to check whether a string is there it needs to include that string so it knowns what to look for. It's a self fulfilling requirement which does make it a very smart way to implement a basic sanity check that code has been built for the correct target before installing it.
I'm not sure why it didn't work for you, I suppose the compiler could have been too clever when it comes to optimising things but it does seem odd.

If you do need to manually include something then rather than having a Serial.print("fw_teensy41"); in your code I'd recommend using Serial.print(FLASH_ID); that way you'll always include the correct string that it is looking for based on the device you're compiling for.
 
I'm working on using this flasherX to remote update over Ethernet. I got the transfer of the hex file to the teensy4.1 working, but I not sure how to get the lines of hex into the buffer. Does the (flash_write_block) keep track of the address to write the lines to or do I need to do that?
I looked at the async web server example but I dont want to use that code in the final write.
Thought about saving the hex lines to the sd card and them using the sd example in flasherX to finish.
Any Ideas?
 
The buffer must contain the binary image, not the hex lines. Since the hex lines are being sent via Ethernet, you can either convert to binary as the packets are received, similar to receiving via UART, or you can write the hex lines to SD and then read the file and convert to binary. Either one will work. I don't know how the async web server works, so I don't know whether one would be simpler/easier. If the async web server directly supports file transfer, then it would probably be easier to think of the process as transferring the hex file to SD, then updating from SD.
 
Define a variable to track the hex decode status
C:
hex_info_t hex = {
    // intel hex info struct
    data, 0, 0, 0,     //   data,addr,num,code
    0, 0xFFFFFFFF, 0,  //   base,min,max,
    0, 0               //   eof,lines
  };

Once you have received the HEX file data in a loop split the received hex data into text lines based on 0x0a or 0x0d characters
Filter out any lines with 0 length
Then call function below with a pointer to the start of each line in turn.
If it returns false at any point abort the upgrade.
C:
bool processHexLine(const char* line) {
  if (parse_hex_line(line, hex.data, &hex.addr, &hex.num, &hex.code) == 0) {
    Serial.printf("abort - bad hex line %s\n", line);
    return false;
   } else if (process_hex_record(&hex) != 0) {  // error on bad hex code
     Serial.printf("abort - invalid hex code %d\n", hex.code);
    return false;
   } else if (hex.code == 0) {  // if data record decoded OK
      uint32_t addr = buffer_addr + hex.base + hex.addr - FLASH_BASE_ADDR;
      if (hex.max > (FLASH_BASE_ADDR + buffer_size)) {
        Serial.printf("abort - max address %08lX too large\n", hex.max);
        return false;
      } else if (!IN_FLASH(buffer_addr)) { // copy to buffer in ram
        memcpy((void*)addr, (void*)hex.data, hex.num);
      } else if (IN_FLASH(buffer_addr)) {  // copy to buffer in flash
        int error = flash_write_block(addr, hex.data, hex.num);
        if (error) {
          Serial.printf("abort - error %02X in flash_write_block()\n", error);
          return false;
        }
      }
    }
    hex.lines++;
  }
  return true;
}

Once whole input has been processed you will have the binary firmware image in the flasherX buffer.
You can then run a basic check on it and if that passes install it using flash_move.
C:
if (check_flash_id(buffer_addr, hex.max - hex.min))
    flash_move(FLASH_BASE_ADDR, buffer_addr, hex.max - hex.min);

In addition to the flashID check that flasherX uses I also run my own sanity check that the image has the correct header.
This is teensy4 / 4.1 only:
C:
bool VerifyValidImage(uint8_t *imageStart) {
  uint32_t SPIFlashConfigMagicWord = *((uint32_t*)imageStart);
  uint32_t VectorTableMagicWord = *((uint32_t*)(imageStart+0x1000));
  if ((SPIFlashConfigMagicWord == 0x42464346) && (VectorTableMagicWord==0x432000D1)) {
    uint32_t imageEntryPoint = *((uint32_t*)(imageStart+0x1004));
    if ((imageEntryPoint < (FLASH_BASE_ADDR+0x1000)) || (imageEntryPoint > (FLASH_BASE_ADDR+0x2000))) {
      Serial.printf("Image indicates a code entry point at 0x%08X, this is outside the expected range.\r\n", imageEntryPoint);
      return false;
    }
    Serial.printf("Image indicates a code entry point at 0x%08X.\r\n",imageEntryPoint);
    return true;
  }
  Serial.printf("Image doesn't have expected ivt table magic number\r\n");
  return false;
}


With the exception of the extra verification step this is essentially the process both the web version and the SD card file reading are doing, the only difference is where they get the hex file from. In your case it will be a buffer in memory that was populated with data from a network socket.
 
Thanks AndyA, question the hex.data, &hex.addr, &hex.num, &hex.code are not declared, nor are process_hex_record, parse_hex_line
what library am I missing that these come from?
 
As @joepasquariello indicated they are from flasherX

I moved the lines
Code:
typedef struct {  
  char* data;         // pointer to array allocated elsewhere
  unsigned int addr;  // address in intel hex record
  unsigned int code;  // intel hex record type (0=data, etc.)
  unsigned int num;   // number of data bytes in intel hex record

  uint32_t base;  // base address to be added to intel hex 16-bit addr
  uint32_t min;   // min address in hex file
  uint32_t max;   // max address in hex file

  int eof;    // set true on intel hex EOF (code = 1)
  int lines;  // number of hex records received
} hex_info_t;
int parse_hex_line(const char* theline, char* bytes, unsigned int* addr, unsigned int* num, unsigned int* code);

Into fxutil.h and then #included that in my code.
hex is then a variable of type hex_info_t.
Sorry I'd forgotten I'd made that change.
 
Hi. I am trying to load the hex file on the teensy 4.1 with the demo code. I get this report back :

15:39:06.840 -> Starting OTA...
15:39:06.840 -> created buffer = 0K FLASH (607FC000 - 607FC000)
15:39:06.840 -> abort - max address 60000010 too large

What am I doing wrong ?
 
Are you using EEPROM and/or LittleFS?

In Flashtxx.h, in the section for TEENSY41, if the FLASH_RESERVE is 4 sectors, increase it to 64 sectors as shown below.

Code:
  #define FLASH_RESERVE         (64*FLASH_SECTOR_SIZE)   // reserve top of flash
 
Eeprom or LitleFS ? Maybe I get it wrong. I put the demo code on the teensy 4.1 thru usb and thru webinterface over ethernet I am trying to upload the hex file. So it should replace the original code. At least that ist my understanding.
 
The Flasherx library needs a place to put a temporary copy of the new code as it receives it. Once it's received the whole thing it does a basic sanity check on it and then replaces the current code with the new one. This way if something goes wrong during the upload it doesn't break things.

FlasherX defaults to putting this buffer in flash, it works out where is safe to put it by starting at the highest address and then looking backwards until it finds a part of flash with data in. It then assumes anything after that last bit of data is OK to use.
If you are using (or have in the past used) the eeprom or littleFS libraries then these use that top area of flash to store their data. The flasherX library sees that and thinks the flash is full up and doesn't have space for the buffer.

The change @joepasquariello gave you tells the flasher library to skip that very top area of the flash that the other libraries use and put the buffer at a slightly lower address in the flash.
 
Thank you for your help. I have erased the memory with the push button. When I try to reflash the teensy_ ota demo code it looks like it is working. So I made just a simple code that sends over Serial print update successfull. When uploading I get report about missing string "fw_teensy41" so there needs to be the flasher library anyway in the code ?
 
As a simple way to verify that you are uploading the correct firmware the library looks for the board version string to be somewhere in the uploaded file, "fw_teensy41" in your case. This stops you accidentally trying to load teensy3 firmware onto a teensy 4.
Since the library includes this string in order to check for it this condition is automatically met if the new firmware you are loading also includes the flasherx library. This is a reasonable assumption since it's rare for someone to want to update firmware to a new version that doesn't have the ability to update the firmware.

If you don't want the new firmware to include the flasherX library then simply ensure that string is somewhere in your code. Or modify the library to skip the check or look for a different string that is in your code.
 
I just commented out that part in the demo code about the string and it looks like it is working now. I know it is not a solution it is just one time flash over the ethernet, but now I can see that it works. Dont understand how exactly should be putted the string "fw_teensy41" in the code. Tried the thing to define the flash_ID as it is mentioned earlier in the comments about the sdcard but did not worked for me.
 
A few things would work.
The nice way is to define a const char[] with that value and then make sure your code uses it so that the compiler doesn't optimise it out.
Or the most basic solution would be to including the line
Serial.print("fw_teensy41");
somewhere in your setup() code.

If you look a few posts earlier I posed a VerifyValidImage() function that can be used as an alternative way of performing a basic sanity check on the uploaded code either in addition to or instead of the string check. This is only valid for Teensy4.x devices and verifies that the start of the uploaded file has the expected structure. It won't catch a 4.0 image being loaded onto a 4.1 board but is far better than nothing and means that a bit of code that just happens to list all the teensy variants won't automatically pass the tests.
 
Back
Top