OTA through Ethernet with Teensy 4.1

1) Connect to a WiFi network
2) Receive the firmware update via a UDP port, write it someplace
3) Once the entire firmware update has been received and stored, do the update.

Lots of hand waving at this point, but if I have the new firmware binary stored someplace can't I use FlasherX to update the firmware?

Short answer is yes. I was also very confused at first by the term OTA (over the air) for what was actually OTW (over the wire). What you outline above is exactly what @shuptuu and @AndyA are doing, with the exception that they are sending the hex (text) file over http, parsing the hex records within the Teensy to get a binary image, then using the functions in FlasherX to erase the existing firmware and write the new firmware in its place. Since you are using T4.1, you can buffer the new firmware in RAM (if enough is available) or in FLASH, and then do the same erase/update. In my own applications, my HMI program reads the hex file, creates a binary image, and sends the binary image to Teensy via UART, so it's like what you want to do except via UART rather than Wifi.
 
mwomack

As @joepasquariello indicated doing this over wifi or over wired ethernet is basically the same. Either way you need to create your own network connection. Just about all of the code here would work fine for a wifi connection rather than wired, once you have an IP connection the underlying connection method doesn't matter much.

If you look at the flow this code uses it receives the .hex file, parses it into a binary image and stores that in flash (as default, ram is a #define option). Once that is done it checks the image is for the correct board type, copies the image to the boot address in flash and reboots. For your use case all you need to do is change how that binary image gets into the buffer.

I would however recommend using TCP rather than UTP, firmware files aren't the sort of thing that you want to risk missing packets on, UDP is only for when you don't care if bits of data get missed. Similarly using a .hex file rather than just sending raw binary data gives a certain level of protection against data corruption. Unlike a UART the ethernet checksums should protect you from random data corruption but when doing firmware updates an invalid image = bricked hardware, in situations like that so little paranoia is a good thing.
For my system I require the .hex file be modified to include an additional text header that includes a version number. This reduces the risk of accidental uploads of the wrong .hex file or of an older version. Trivial to get around so it's not a security thing, it's purely to reduce the risk of human error.

Also if this is for development builds of firmware then always test your new versions on a tethered version of the hardware on your desk first. This upload only works if your code is running, if you put in a bug that causes it to crash you are going to have to plug a cable in to fix it. Testing on something easy to get to first could save you a lot of hassle in the long run.
 
I can second much of AndyA's recommendations here, but also express support for UDP if you need it. In my own applications, I update firmware via hard UART connections, which I think of as equivalent to UDP (send and pray), so I think it's fine to send binary data over UDP as long as you add sufficient error checking in your application. My HMI application converts Intel hex to binary, then sends the binary data to Teensy in relatively large chunks, with a 16-bit CRC on each message. You can also do an overall CRC on the whole program for more protection. I've used this method for many years and have never bricked a board, so I'm quite confident it can be done safely.
 
I can second much of AndyA's recommendations here, but also express support for UDP if you need it. In my own applications, I update firmware via hard UART connections, which I think of as equivalent to UDP (send and pray), so I think it's fine to send binary data over UDP as long as you add sufficient error checking in your application. My HMI application converts Intel hex to binary, then sends the binary data to Teensy in relatively large chunks, with a 16-bit CRC on each message. You can also do an overall CRC on the whole program for more protection. I've used this method for many years and have never bricked a board, so I'm quite confident it can be done safely.

Joe,

I'd love to see the code for this. It leads me to my next question...where do I get the hex/binary file that I will send over UDP? I'm using the Arduino IDE (1.8.something) on Linux and/or Windows. It must store the binary it builds someplace, but I've never had to worry about that until now... (I am planning to start writing the Teensy-side of the code tonight. I probably won't get to a point where I brick my Teensy, but maybe soon! I hope there is a way to recover if I brick it.)

-Mark
 
mwomack

As @joepasquariello indicated doing this over wifi or over wired ethernet is basically the same. Either way you need to create your own network connection. Just about all of the code here would work fine for a wifi connection rather than wired, once you have an IP connection the underlying connection method doesn't matter much.

If you look at the flow this code uses it receives the .hex file, parses it into a binary image and stores that in flash (as default, ram is a #define option). Once that is done it checks the image is for the correct board type, copies the image to the boot address in flash and reboots. For your use case all you need to do is change how that binary image gets into the buffer.

I would however recommend using TCP rather than UTP, firmware files aren't the sort of thing that you want to risk missing packets on, UDP is only for when you don't care if bits of data get missed. Similarly using a .hex file rather than just sending raw binary data gives a certain level of protection against data corruption. Unlike a UART the ethernet checksums should protect you from random data corruption but when doing firmware updates an invalid image = bricked hardware, in situations like that so little paranoia is a good thing.
For my system I require the .hex file be modified to include an additional text header that includes a version number. This reduces the risk of accidental uploads of the wrong .hex file or of an older version. Trivial to get around so it's not a security thing, it's purely to reduce the risk of human error.

Also if this is for development builds of firmware then always test your new versions on a tethered version of the hardware on your desk first. This upload only works if your code is running, if you put in a bug that causes it to crash you are going to have to plug a cable in to fix it. Testing on something easy to get to first could save you a lot of hassle in the long run.

AndyA,

Thank you for the advice and insights. I will take them to heart as I get ready to start writing my code. I'm not wedded to UDP, TCP would be just as fine as far as I am concerned. Just some pipe to send the data through. I'll update the thread as I progress.

thanks again,
-Mark
 
Joe,

I'd love to see the code for this. It leads me to my next question...where do I get the hex/binary file that I will send over UDP? I'm using the Arduino IDE (1.8.something) on Linux and/or Windows. It must store the binary it builds someplace, but I've never had to worry about that until now... (I am planning to start writing the Teensy-side of the code tonight. I probably won't get to a point where I brick my Teensy, but maybe soon! I hope there is a way to recover if I brick it.)

-Mark

In the Arduino 1.8.xx IDE, if you click on the menu item File::preferences. In the lower left of the preferences dialog you'll see a link to the location of your "preferences.txt" file. By default, your hex and lst and other temporary files go to a folder somewhere under your User account folder. You can edit preferences.txt to specify an alternate location. I added the line below to my file to move them to a location I find easier to access. Note that the files in this folder will be overwritten each time you do a build. As far as I can tell, there is no way to do this in the Arduino 2.x IDE.

build.path=C:\ArduinoTemp
 
As far as I can tell, there is no way to do this in the Arduino 2.x IDE.

In 2.0 on windows it appears to put the files in C:\Users\[user name]\AppData\Local\Temp\arduino\sketches\[some random long hex value] for me.
This is presumably <user account temp directory>\arduino\sketches\[some random long hex value] so while for most people I'd expect it to be similar to the address above it could be different if you have non-default paths set.

The random value used seems to be semi-consistent. I've had it change on me a couple of times for the same project but it's not often, certainly not every build. I'm not sure exactly what triggers the change.

Fortunately there is a very simple way to find where it's putting the files.
If you try to upload the firmware over the USB link then the Teensey upgrader application starts.
In the loader application if you select File->Open HEX file it will open a file dialog pointing at the directory of the most recently used HEX file, the one you just built.
You can then copy and past that location into a file explorer window. Or copy the files directly out of that dialog box.
 
Thanks for the pointers to the build file. I'll see what I find.

Instead of posting my source on the thread, I have it in a github: https://github.com/markwomack/TeensyOTAViaTCP

You can check out the latest version. Right now I have it running a normal sketch, and when data is detected on the TCP port it stops everything and processes the "update". Right now the update is just a text file I am sending to the TCP port using netcat. And then it does a hard restart of the Teensy chip (which would eventually be the FlasherX update). So, I think I have the bones in the right places for now. I'll start looking at fleshing out the actual data and updating.

One issue I have run into is that after about 3-4 'restarts', my AirLift board gets into a state where it just starts continually rebooting and causing restarts. I feel like this AirLift has been nothing but trouble (see some of my other threads in the forum). I have to track this down, or switch to a different solution. It won't be any good if the robot gets into a continuous boot state after an OTA. Shutting everything off for a while fixes things, but that is a lousy fix. What solution do others use for connecting to WiFI?
 
I used the trick using the Teensy loader to find the hex file. The Arduino 1.8.XX IDE on Linux creates temp build directories in the /tmp directory. Looks like a directory is created for each sketch and the directory sticks around until the IDE is closed. Nifty.
 
So, I fixed my issue with AirLift getting into a bad state, and I started on the code to perform the actual update.

I'm sorry if this is completely stupid, but now I am getting link errors when trying to build the sketch.

I added FXUtil.cpp/.h and FlashTxx.cpp/.h to my Arduino project, and in the sketch I have:

Code:
#include "FXUtil.h"
extern "C" {
  #include "FlashTxx.h"    // TLC/T3x/T4x/TMM flash primitives
}

and I am getting errors:

Code:
/tmp/arduino_build_790788/sketch/TeensyOTAViaTCP.ino.cpp.o: In function `performUpdate(WiFiClient)':
/home/mwomack/development/TeensyOTAViaTCP/TeensyOTAViaTCP.ino:82: undefined reference to `firmware_buffer_init'
/home/mwomack/development/TeensyOTAViaTCP/TeensyOTAViaTCP.ino:97: undefined reference to `firmware_buffer_free'
/tmp/arduino_build_790788/sketch/FXUtil.cpp.o: In function `update_firmware(Stream*, Stream*, unsigned long, unsigned long)':
/home/mwomack/development/TeensyOTAViaTCP/FXUtil.cpp:80: undefined reference to `flash_write_block'
/home/mwomack/development/TeensyOTAViaTCP/FXUtil.cpp:106: undefined reference to `check_flash_id'
/home/mwomack/development/TeensyOTAViaTCP/FXUtil.cpp:132: undefined reference to `flash_move'
collect2: error: ld returned 1 exit status

What stupid thing am I missing?

The complete TeensyOTAViaTCP.ino file:

Code:
//
// Licensed under the MIT license.
// See accompanying LICENSE file for details.
//

//
// This is an example of updating the Teensy firmware using the FlasherX
// library after receiving the new firmware binary via TCP.
// This example will listen to a TCP port for the data. You can send
// the data using the following command in Linux (Ubuntu):
//   netcat -N [IP ADDRESS] [PORT] <data.txt
//  where data.txt is a file that contains the data.
//

// Arduino includes
#include <Arduino.h>

// My includes
#include <DebugMsgs.h>   // https://github.com/markwomack/ArduinoLogging
#include <TaskManager.h> // https://github.com/markwomack/TaskManager

// Third party includes
#include <WiFiServer.h>
#include <WiFiClient.h>

// Local includes
#include "pin_assignments.h"
#include "constants.h"
#include "MyNetworkHub.h"
#include "FXUtil.h"
extern "C" {
  #include "FlashTxx.h"    // TLC/T3x/T4x/TMM flash primitives
}

MyNetworkHub networkHub;

class CheckForOTATask : public Task {
  public:
    void setTCPServer(WiFiServer* tcpServer) {
      _tcpServer = tcpServer;
    }

    WiFiClient getTCPClient(void) {
      return _tcpClient;
    }
    
    void start(void) { 
      if (_tcpServer == 0) {
        DebugMsgs.debug().println("TCP Server not specified!");
      }
      
      _otaIsAvailable = false;
    }
    
    void update(void) {
      WiFiClient tcpClient = _tcpServer->available();

      // If a client was returned, store it for future use
      // and indicate an OTA is now available
      if (tcpClient) {
        _tcpClient = tcpClient;
        _otaIsAvailable = true;
      }
    }
    
    boolean otaIsAvailable(void) {
      return _otaIsAvailable;
    }

  private:
    WiFiServer* _tcpServer = 0;
    WiFiClient _tcpClient = 0;
    boolean _otaIsAvailable;
};
CheckForOTATask checkForOTATask;

void performUpdate(WiFiClient tcpClient) {
  uint32_t buffer_addr;
  uint32_t buffer_size;

  // create flash buffer to hold new firmware
  if (firmware_buffer_init( &buffer_addr, &buffer_size ) == 0) {
    Serial.printf( "unable to create buffer\n" );
    Serial.flush();
    return;
  }
  
  Serial.printf( "created buffer = %1luK %s (%08lX - %08lX)\n",
   buffer_size/1024, IN_FLASH(buffer_addr) ? "FLASH" : "RAM",
    buffer_addr, buffer_addr + buffer_size );

  update_firmware((Stream*)&tcpClient, (Stream*)&Serial, buffer_addr, buffer_size);
  
  // return from update_firmware() means error or user abort, so clean up and
  // reboot to ensure that static vars get boot-up initialized before retry
  Serial.printf( "erase FLASH buffer / free RAM buffer...\n" );
  firmware_buffer_free( buffer_addr, buffer_size );
  Serial.flush();
  REBOOT;
}

void setup() {
  Serial.begin(115200);
  while (!Serial) {;}
  
  DebugMsgs.enableLevel(DEBUG);

  pinMode(LED_STATUS_PIN, OUTPUT);

  // Connect to WiFi network
  if (networkHub.start() == 0) {
    WiFiServer* tcpServer = networkHub.getTCPServer(TCP_SERVER_PORT);
    checkForOTATask.setTCPServer(tcpServer);
  } else {
    DebugMsgs.debug().println("Unable to connect to WiFi!");
    while (true) {;}
  }

  taskManager.addTask(&checkForOTATask, 1000);
  taskManager.addBlinkTask(LED_STATUS_PIN, 500);
  taskManager.start();
}

void loop() {
  // Normal processing
  taskManager.update();

  // If there is an OTA, stop everything and process
  if (checkForOTATask.otaIsAvailable()) {
    DebugMsgs.debug().println("OTA available, processing...");

    // stop normal processing
    taskManager.stop();

    // perform the OTA update
    performUpdate(checkForOTATask.getTCPClient());
  }
}
 
Those errors are consistent with FlashTxx.c not being included in the project.
All the headers are getting pulled in correctly which is why it builds. But as long as they are in the right directories that will happen automatically without explicitly adding them.
But then you get link errors for functions defined in that c file which indicates that it's not trying to include that file in the final binary. The most common reason for this is because it never built it in the first place.
 
Ah. OK, I see what happened. I tried using the 2.3 release zip, was confused as to why the 4 files were not included, copied over the two that were there (one of which was a FlashTxx.cpp), and then hand copied the FXUtil files. I didn't notice that the current repo has FlashTxx.c instead. You might want to create a newer, more up to date release, or delete the 2.3 release and just tell people to copy the source from head. After I deleted my 4 weird files and replaced them with clean files from head, everything compiled.

And I got it working great, first try! The only modification I had to make to the FlasherX source was to comment out the portion that asked for user confirmation to perform the update. I didn't want that. I created an updated sketch that added a counter task to output some counts to serial, sent that hex file over TCP, code did the update, restarted, and there was my new code counting away.

Perfect. I updated my github repo with the working version of the code (https://github.com/markwomack/TeensyOTAViaTCP). I'm just going to clean it up a bit for clarity and documentation.

Thanks for all your help, Joe! And the awesome code, of course!

-Mark
 
You might want to create a newer, more up to date release, or delete the 2.3 release and just tell people to copy the source from head. After I deleted my 4 weird files and replaced them with clean files from head, everything compiled.

Yes, I need to do some updates. Will do as soon as I get a few other things off my plate. Glad you got it working. Just FYI, I have a large C code base, and I'm gradually migrating everything to C++.
 
I started using my OTA via TCP code for a project I am working on, and some times it would brick my Teensy (which was fixed by connecting to the USB and uploading directly). So, I started looking into adding some kind of CRC check.

I have a script that will take the .hex file and prepend the CRC32 value from the linux crc32 tool. The beginning of the resulting file looks something like this:

Code:
122896c8!:0200000460009A
:100000004643464200000156000000000103030081
:1000100000000000000000000000000000000000E0
...

The "122896c8!" is the portion that I prepended.

On the Teensy side, I have code to accept the tcp connection and then read in the bytes. It processes the prepended crc value, and then goes to read the rest of the stream.

The problem is that it does not read the entire file. It only read between 5K and 10K bytes (the actual value seems random, but consistently around that range).

Is there some sort of buffer that I need to declare for WiFi clients?

Here is my relevant class. I haven't gotten to the FlasherX part yet, but I guess I just got incredibly lucky with a small sketch with my original example?

The class DynamicArray used below is just a small class I write to have an array that will dynamically expand in size as data is appended to it.

Code:
class GetBytesTask : public Task {
  public:
    void setTCPServer(WiFiServer* tcpServer) {
      _tcpServer = tcpServer;
    }
    
    void start(void) { 
      if (_tcpServer == 0) {
        DebugMsgs.debug().println("TCP Server not specified!");
      }
    }
    
    void update(void) {
      WiFiClient tcpClient = _tcpServer->available();
      if (!tcpClient) {
        return;
      }

      DebugMsgs.debug().println("reading data");

      uint32_t expectedCRC = 0;

      int data;
      while (tcpClient.available()) {
        data = tcpClient.read();
        if (data == '!') {
          _dataArray.append(0);
          expectedCRC = strtoul((const char*)_dataArray.getDataPtr(), 0, 16);
          _dataArray.reset();
          break;
        } else {
          _dataArray.append((uint8_t)data);
        }
      }

      DebugMsgs.debug().printfln("expected crc: %8x", expectedCRC);

      uint32_t totalSize = 0;
      uint8_t buffer[1024];
      while (tcpClient.available()) {
        uint32_t size = tcpClient.read(buffer, 1024);
        _dataArray.append(buffer, size);
        totalSize += size;
      }

      DebugMsgs.debug().printfln("read %d bytes", totalSize);
      DebugMsgs.debug().printfln("read %d bytes", _dataArray.getSize());
      
      uint32_t crc = 0;
      crc32(_dataArray.getDataPtr(), _dataArray.getSize(), &crc);
    
      DebugMsgs.debug().printfln("calculated CRC: %x", crc);

      tcpClient.stop();
      
      _dataArray.reset();
    }

  private:
    WiFiServer* _tcpServer = 0;
    WiFiClient _tcpClient = 0;
    DynamicArray _dataArray;
};
 
On the Teensy side, I have code to accept the tcp connection and then read in the bytes. It processes the prepended crc value, and then goes to read the rest of the stream.

The problem is that it does not read the entire file. It only read between 5K and 10K bytes (the actual value seems random, but consistently around that range). Is there some sort of buffer that I need to declare for WiFi clients?

Here is my relevant class. I haven't gotten to the FlasherX part yet, but I guess I just got incredibly lucky with a small sketch with my original example? The class DynamicArray used below is just a small class I write to have an array that will dynamically expand in size as data is appended to it.

Yes, you may have gotten lucky in the sense that your array was able to grow large enough to hold your original test program. Are you reading the ASCII hex data into your array? Do you know how big the file is and whether you have enough RAM to hold it?

I haven't done this with Ethernet yet, but I would do the same thing that I do when using UART:

- on the PC side, read/parse the hex file and create an array of the binary image
- on the Teensy side, create a buffer large enough to hold the binary image
- send custom packets from PC to Teensy, each one containing N (512?) bytes of the image
- for each packet received by Teensy, send ack to PC, and write data to flash buffer
- on the PC side, if you don't get the ack, do a retry
- when the transfer is complete
- verify the image on the Teensy side
- erase the existing firmware and write the new firmware in its place
- reboot
 
TCP is already splitting the data into packets, acknowledging each one and handling re-transmissions for you. Unless you have a very unreliable network you shouldn't need to add anything extra at that level.

But you will need a large enough receive buffer to store the data as it arrives, splitting the file up into blocks will help with that since you can then put each block into flash or some other storage as it arrives. If you let it all arrive in the ethernet rx buffers then you could easily overflow.

This is where some fun and games can come into it. Just because your transmit application sent 3 packets of 1k of data don't assume your receiving application will get 3 packets of 1k. The transmitting network layer is free to combine, split and generally re-package the data as it feels like. The correct data will arrive at the other end in the correct order but the size and number of blocks you get could be different.
 
Yes, you may have gotten lucky in the sense that your array was able to grow large enough to hold your original test program. Are you reading the ASCII hex data into your array? Do you know how big the file is and whether you have enough RAM to hold it?

I'd have to go back and check, but I think this program is around 175K bytes for the hex file. But I don't think the problem is with actual space on the Teensy 4.0. The dynamic array only grows to the 5-10K size and then the data just stops. And if I look at the data received, it ends up being from someplace in the middle of the file. So, I think that the buffer used for the tcp is getting overrun. Frankly, I'm not sure how this ever worked before. Even my example program from earlier should have been large enough to overrun a small buffer.

I haven't done this with Ethernet yet, but I would do the same thing that I do when using UART:

- on the PC side, read/parse the hex file and create an array of the binary image
- on the Teensy side, create a buffer large enough to hold the binary image
- send custom packets from PC to Teensy, each one containing N (512?) bytes of the image
- for each packet received by Teensy, send ack to PC, and write data to flash buffer
- on the PC side, if you don't get the ack, do a retry
- when the transfer is complete
- verify the image on the Teensy side
- erase the existing firmware and write the new firmware in its place
- reboot

Yeah, I was already thinking that sending the entire hex file with just one crc was being optimistic. I was just making sure I could actually send a blob of data (the hex file in this case) and have the crc values match. I was also hoping I could avoid writing a bunch of custom code on the computer side, everything I have done so far is just bash scripts. I'll have to figure out how to send tcp from regular C and such. But I agree this sounds like a better solution.
 
TCP is already splitting the data into packets, acknowledging each one and handling re-transmissions for you. Unless you have a very unreliable network you shouldn't need to add anything extra at that level.

But you will need a large enough receive buffer to store the data as it arrives, splitting the file up into blocks will help with that since you can then put each block into flash or some other storage as it arrives. If you let it all arrive in the ethernet rx buffers then you could easily overflow.

I was hoping there is some way to control/set the buffer used for the internet/wifi/tcp transactions. But I haven't found anything so far. Like I mentioned to Joe, I'm not sure how this ever worked before with my original tcp example. I feel like the example program would have been larger than buffer then too.

This is where some fun and games can come into it. Just because your transmit application sent 3 packets of 1k of data don't assume your receiving application will get 3 packets of 1k. The transmitting network layer is free to combine, split and generally re-package the data as it feels like. The correct data will arrive at the other end in the correct order but the size and number of blocks you get could be different.

Yeah, I think that is fine. Like you say, as long as each chunk shows up in the right order, and I know how many bytes overall to expect per chunk, I can manage things on the Teensy side. I just need to send the data in chunks in sizes and at a rate that won't over flow the buffer.

Does anyone have a pointer to some C example code of sending bytes over tcp from the computer side?
 
OK, I think that a big part of the problem I was seeing yesterday was with the DynamicArray itself. I think it might have been growing, but the data wasn't being appended correctly. I also think there was something funky with the way I was using available and read.

Regardless, I switched gears to get rid of DynamicArray and created a CRCStream class that tracks the size and CRC as the data is being read in (the hex file or any file really), and at the end it verifies that the final size and CRC are equal to the expected size and CRC. This requires that the size and CRC be prepended to the data file in an expected format. Right now I have a bash script that can do this. Also, while it does require all of the data to be read, it doesn't require that it be held all in memory at once so that the CRC can be checked. I can still use it as the stream given to the FlasherX update_firmware method. I just need to modify my local update_firmware to verify the size and CRC after reading in the hex file data, and if they don't match up, just abort the update and free up the invalid memory it has built up.

Here is a working example of the CRCStream in action, minus any FlasherX code. I'm not getting any overwrites or dropped data at this point. And with the addition of the expected size and CRC, I should detect when something does go wrong.

I'm going to update my previous TeensyOTAViaTCP example to use the CRCStream as well.

-Mark
 
Alright, I updated my TeensyOTAViaTCP repository to integrate CRCStream into the FlasherX code.

It ALMOST worked like a charm the first time, except for the read_ascii_line method was leaving the last line feed unread. I modified that method as below, detecting when a stream has CRLF at the end of each line. I don't know if that is a change you might like to take, Joe. It only matters when CRCStream needs to CRC the entire stream contents. Leaving one byte out throws a wrench in the works. Let me know if you want me to submit a change for approval.

Now I'm going to integrate this into my actual project and see if I get any CRC or size errors.

-Mark

Code:
//******************************************************************************
// read_ascii_line()	read ascii characters until '\n', '\r', or max bytes
//******************************************************************************
void read_ascii_line( Stream *serial, char *line, int maxbytes, bool* streamHasCRLF )
{
  int c=0, nchar=0;
  while (serial->available()) {
    c = serial->read();
    if (c == '\n' || c == '\r') {
      *streamHasCRLF = true;
      continue;
    }
    else {
      line[nchar++] = c;
      break;
    }
  }
  while (nchar < maxbytes && !(c == '\n' || c == '\r')) {
    if (serial->available()) {
      c = serial->read();
      line[nchar++] = c;
    }
  }
  line[nchar-1] = 0;	// null-terminate

  // drop the extra cr/lf now
  if (*streamHasCRLF && serial->available()) {
    serial->read();
  }
}
 
Alright, I updated my TeensyOTAViaTCP repository to integrate CRCStream into the FlasherX code.

It ALMOST worked like a charm the first time, except for the read_ascii_line method was leaving the last line feed unread. I modified that method as below, detecting when a stream has CRLF at the end of each line. I don't know if that is a change you might like to take, Joe. It only matters when CRCStream needs to CRC the entire stream contents. Leaving one byte out throws a wrench in the works. Let me know if you want me to submit a change for approval.

Hi Mark. Thanks. I can't review right now, but I will this weekend.
 
Has anyone been successful with FlasherX and the SD mode?

Hi folks,

I'm trying FlasherX to flash a hex file to my Teensy 4.0 using the SD card.

I've uploaded the hex file to the SD which is 64.7kb big.

When I run the program and enter 2 for SD I get the error:

abort - new code missing string fw_teensy40

which is thrown from FXUtil.cpp line 110.

See output below, it seems like the file size isn't correct, it says 23552 bytes.


Thanks for your help, Ben

Code:
FlasherX v2.3 - May 12 2023 13:13:55
WARNING: this can ruin your device!
target = fw_teensy40 (2048K flash in 4K sectors)
created buffer = 256K RAM (20203068 - 20243068)
enter 1 for hex file via serial, 2 for hex file via SD
SD initialization OK
SD file open OK
reading hex lines...

hex file: 1478 lines 23552 bytes (60000000 - 60005C00)
abort - new code missing string fw_teensy40
unable to create buffer
 
The hex file on the SD card must contain the string "fw_teensy40", or a similar string that defines whatever type of teensy you are trying to program. This is meant to prevent loading a T3.6 program on a T3.2, etc.

Try putting the hex file for the FlasherX example program on the SD card, as it will contain the correct string.
 
Back
Top