How does Teensy-Reboot.exe communicate ?

Status
Not open for further replies.

Elmue

Well-known member
Hello Paul

I want to write an automatic Firmware uploader.
I start Teensy.exe, then teensy_reboot.exe.

But the information I need is how teensy_reboot.exe informs the Arduino IDE of success or failure.

If the reboot was not successfull the IDE prints:

Code:
Teensy did not respond to a USB-based request to automatically reboot.
Please press the PROGRAM MODE BUTTON on your Teensy to upload your sketch.

How does the IDE know that ?
The exit code of the teensy_reboot.exe process is always zero.
 
How does the IDE know that ?

This info comes from Teensy Loader.

A localhost connection to repeatedly query whether Teensy Loader has seen the device. Use Help > Verbose Info in Teensy Loader to get a view of this communication. Or you could use TCP/IP snooping tools to monitor the localhost connection. It's simple ascii-based communication. The important point is Teensy Loader is responsible for detecting when a Teensy appears in bootloader mode. Other program query it.
 
Koromix figured it out in open code TYQT if you can't see it in the PJRC provided details Koromix used, maybe you can see it in his.
 
Hello Paul

Thanks for the answer.
But sadly it is lacking any details.

It seems to me that PJRC is not willing to publish details about the Teensy tools.
I saw a request for the source code of these tools here in the forum 2 years ago that has never been answered by you.
https://forum.pjrc.com/threads/2632...post_compile-quot-and-quot-teensy_reboot-quot


Please think that there are people who use Teensy not just for playing around.
I use Teensy in a professional hardware that is used in many countries.
I do not want to tell my clients that they have to read a manual how to use PJRC tools.
I want to offer them a single button in my GUI to program a Teensy and therefore I need more details.
I have to know if programming was successful or not.


> A local host connection.

To which port ?
In TCPView I see that it opens port 3149.
Is this a fix port that is always used ?

In the verbose window I see the commands:
"auto: on"
which probably presses the green "Auto" button.

and then lots of
"status"
commands which probably request the programming result.

But what strings does the Teensy loader return on the "status" request?

I tried to capture with a packet sniffer but it does not capture local host connections.
In the code of Koromix I cannot find answers to these questions.

It would be all so easy if teensy_reboot would return an exit code of 0 if it failed and an exit code of 1 if programming was successful!
In C / C++ this is the return value of the main() function or you call ExitProcess() directly: See MSDN


After establishing a connection to port 3149 I found out that all ascii commands are ignored if they do not end with a linefeed.

When the Teensy does not respond a programming request (because it was compiled with USB Type: No USB) the communication looks like this:


Sending 7 Bytes to Server (127.0.0.1):
'status\n'

Received:
'dir:E:\Hardware\Firmware\
file:Sketch.hex
readable:1
auto:1
online:0
online_count:0
offline_count:0
state:0
code_size:262144
EOT
'



And when the programming was successfull (after pressing the button on the board):

Sending 7 Bytes to Server (127.0.0.1):
'status\n'

Received:
'dir:E:\Hardware\Firmware\
file:Sketch.hex
readable:1
auto:1
online:0
online_count:1
offline_count:0
state:0
code_size:262144
EOT
'


So I deduce that online_count:1 means that the programming was successfull ?

What does all this stuff mean ?

state:0
readable:1
online:0
online_count:0
offline_count:0
 
Last edited:
Elmue, I have just found that you can accomplish what you desire using the command line Teensy loader (see PJRC github link) and a COM port open/close at 134 baud. You need to compile it using "make", and I noticed that the Makefile has some issues (on Windows 10) with all "=" appearing as "?=" so you need to do a find and replace all to sort this. Also you need to manually edit the windows CC line to be just "CC = gcc" and don't forget to un-comment the correct option at the top. So, once you have the command line Teensy loader as en exe, just run it using a command based on the example command given by PJRC on his website, then open the Teensy serial port at Baud 134 and close again, this initiates a reboot and the firmware is written! It works fine for me. I needed this because my custom Teensy 3.2 board is inaccessible!

So, to summarise:

Run the command-line Teensy loader with appropriate parameters (add the verbose option -v to see more of what's going on if you like). Ensure -w is used!
Open the COM port of the Teensy at 134 Baud then close again. Teensy will reboot
Loader will run and finish.

Done :)
 
Yes, PaulN82 is correct. If you want to ask Teensy to reboot, you should talk to it directly and set the baud rate to 134. That is, if it's programmed to be a serial port. If it's programmed with any of the non-Serial USB types, then you send it a HID feature request with 4 specific bytes (see the USB source in the core lib).

The localhost communication between Teensy Loader and teensy_reboot may change in future versions. It is *NOT* considered a public API which must be kept compatible or long-term "stable". Over the years it has changed several times. If you capture the communication, you may notice the very first data sent is the version number. This is done so teensy_reboot can know whether it is talking to.a version of Teensy Loader which is new enough. Indeed if you happen to run a very old Teensy Loader and then try running a recent teensy_reboot, it will detect this and refuse to do anything.

The command line version of Teensy Loader does have full source code published on github. Use that as your guide for how things work.

If you really want to use the localhost communication with the GUI Teensy Loader, you probably can figure out the details. I will even try to answer your questions. But first I want to be absolutely clear that this protocol *WILL* change in the future without any notice and without any regard for backwards compatibility. Since you're already complaining with words like "seems to me that PJRC is not willing to publish details about the Teensy tools", I can only imagine how disappointed and upset you may be when a future version of the software changes the protocol. The *only* part which you can confident will remain stable is the initial communication of the version number. Absolutely everything else about this protocol can and very likely will change in the future.

So if you still want to go down this ill-advised path, please ask some specific questions and I will try to answer in detail next week. Please try to ask your questions in a tone or style that shows your understanding that any software you write will very likely break when used with future versions of Teensy Loader.
 
Hello

Thanks for answering.
(However my question was from 2016.)

Paul:
What I want is to have a button in my application (written in C#) where any dummy user can click on to automatically upload a new firmware to a connected Teensy board.
Without further complications.
Just 100% automatic.

This is for you an "ill-advised path" ?

If you say that you *WILL* change the protocol in the future you WILL break that code.
So what is your recommendation, how to give my users the most simple way of 100% automated firmware upload when the protocol is undocumented and changing in the future?

What you are telling me, is that such a feature is impossible ?

I think that it is no problem to add new commands to the protocol in the future, if they become required by new Teensy boards.
But I don't see any reason why you should not maintain a downward compatibility with older commands.
 
What I want is to have a button in my application (written in C#) where any dummy user can click on to automatically upload a new firmware to a connected Teensy board.
Without further complications.
Just 100% automatic.

TeensySharp https://github.com/luni64/TeensySharp is a c# library which you can use to upload firmware to T3.1 - T4.0. You can also use it to identify connected Teensies, get notified on plugging in / out of Teensies, reboot them, find out their serial numbers and the COM Port they are connected to. So to say, a teensy swiss knife for C# programmers :)

In the example below we upload a firmware image to the first board we find.
Code:
USB_Device Teensy = Watcher.ConnectedDevices.FirstOrDefault();
SharpUploader.StartHalfKay(Teensy.Serialnumber);
int result = SharpUploader.Upload(FlashImage, Board, Teensy.Serialnumber, reboot: true);

Hope that helps
 
luni, The TeensySharp library is a huge help. Thank you. The only issue I've ran into so far is that it will only start the HalfKay bootloader for boards that are enumerated as a Serial device. This is an issue for any boards that don't appear as a Serial device. Such as one setup for RAW HID. I'm currently researching this and will post more info back here when I find the solution. If anyone knows the magik bytes to send to the USB device to start halfkay, that would be great.
 
The trick to getting Teensy into bootloader is sending the USB port to a unique baud rate - it is 134 bps. Looking in the USB code it monitors for that and then triggers control to the bootloader.

like this what you were looking for?:
Code:
\hardware\teensy\avr\cores\teensy3\usb_dev.c:
  606  			//serial_phex32(usb_cdc_line_coding[0]);
  607  			//serial_print("\n");
  608: 			if (usb_cdc_line_coding[0] == 134) usb_reboot_timer = 15;
 
I'm thinking that setting the baudrate to 134 only applies if the USB port shows up as a Serial Port. You can't really set a RAW HID usb port's baud rate. I think the code we are looking for would just be monitoring for some magic bytes to be sent to the Teensy. Paul mentioned it up in Post 6..
If it's programmed with any of the non-Serial USB types, then you send it a HID feature request with 4 specific bytes (see the USB source in the core lib).
I was looking for it in the tyTools code over at https://github.com/Koromix/tytools
 
Yes, TyTools does it as needed.

Following _reboot_Teensyduino_ in the sources will show the process:
Code:
C:\arduino-1.8.9t4\hardware\teensy\avr\cores\usb_disk\usb.c:
 1107  					usb_send_in();
 1108  					if (b1 == 0xA9 && b2 == 0x45 && b3 == 0xC2 && b4 == 0x6B)
 1109: 						_reboot_Teensyduino_();
 1110  					if (b1 == 0x8B && b2 == 0xC5 && b3 == 0x1D && b4 == 0x70)
 1111  						_restart_Teensyduino_();

C:\arduino-1.8.9t4\hardware\teensy\avr\cores\usb_flightsim\usb.c:
  589                                          usb_send_in();
  590  					if (b1 == 0xA9 && b2 == 0x45 && b3 == 0xC2 && b4 == 0x6B)
  591: 						_reboot_Teensyduino_();
  592  					if (b1 == 0x8B && b2 == 0xC5 && b3 == 0x1D && b4 == 0x70)
  593  						_restart_Teensyduino_();

C:\arduino-1.8.9t4\hardware\teensy\avr\cores\usb_hid\usb.c:
  944                                          usb_send_in();
  945  					if (b1 == 0xA9 && b2 == 0x45 && b3 == 0xC2 && b4 == 0x6B)
  946: 						_reboot_Teensyduino_();
  947  					if (b1 == 0x8B && b2 == 0xC5 && b3 == 0x1D && b4 == 0x70)
  948  						_restart_Teensyduino_();

C:\arduino-1.8.9t4\hardware\teensy\avr\cores\usb_midi\usb.c:
  620                                          usb_send_in();
  621  					if (b1 == 0xA9 && b2 == 0x45 && b3 == 0xC2 && b4 == 0x6B)
  622: 						_reboot_Teensyduino_();
  623  					if (b1 == 0x8B && b2 == 0xC5 && b3 == 0x1D && b4 == 0x70)
  624  						_restart_Teensyduino_();

C:\arduino-1.8.9t4\hardware\teensy\avr\cores\usb_rawhid\usb.c:
  596                                          usb_send_in();
  597  					if (b1 == 0xA9 && b2 == 0x45 && b3 == 0xC2 && b4 == 0x6B)
  598: 						_reboot_Teensyduino_();
  599  					if (b1 == 0x8B && b2 == 0xC5 && b3 == 0x1D && b4 == 0x70)
  600  						_restart_Teensyduino_();
 
Here is another reference to the Magic Bytes (feature report)... But sadly, noone ever mentions what it actually is.. Looks like this was from person who wrote tyTools (Koromix).
https://forum.pjrc.com/threads/29063-C-Library-for-Uploading-Firmware-from-User-Applications?p=77117&viewfull=1#post77117
Still searching..


EDIT:
Thank you defragster.. That's exactly what I was looking for.

And for anyone coming here in the future. The magic code is in the tyTools code here:
https://github.com/Koromix/tytools/blob/master/src/libty/class_teensy.c
Around Line 722

Code:
static int teensy_reboot(ty_board_interface *iface)
{
    static const unsigned int serial_magic = 134;
    static const unsigned char seremu_magic[] = {0, 0xA9, 0x45, 0xC2, 0x6B};
 
Last edited:
What you are telling me, is that such a feature is impossible ?

No, not impossible.

I'm saying the correct way is to identify the serial device (called COM port on Windows), open it, and set the baud rate to 134.

Or if Teensy is running in a non-serial mode, find the HID interface used to emulate serial and send it a HID feature request. Here's the code from usb_dev.c with the 4 magic bytes to put into that feature request. This also shows the 8 expected bytes of the setup packet which starts the control transfer.

Code:
#ifdef SEREMU_INTERFACE
                if (setup.word1 == 0x03000921 && setup.word2 == ((4<<16)|SEREMU_INTERFACE)
                  && buf[0] == 0xA9 && buf[1] == 0x45 && buf[2] == 0xC2 && buf[3] == 0x6B) {
                        usb_reboot_timer = 5;
                        endpoint0_transmit(NULL, 0);
                }
#endif


But I don't see any reason why you should not maintain a downward compatibility with older commands.

Right now, I also don't see any reason why backwards compatibility would not be maintained. But if any reason should come up, because this is not a public API, I would not hesitate to break backwards compatibility. The initial message with the version number was included from the start for exactly this purpose.

This private API isn't a big secret. It's ASCII text. The messages are simple and pretty easy to guess what they mean from their names. We don't do anything special (like digital signatures or other strong authentication) to prevent other programs from using it.

But nobody reading this thread should believe PJRC will necessarily maintain backwards compatibility on this private localhost communication.
 
On Teensy 4.0, the same 4 magic bytes are expected in the HID feature request. Here's the code from the usb.c used on Teensy 4.0.

Code:
#ifdef SEREMU_INTERFACE
        if (setup.word1 == 0x03000921 && setup.word2 == ((4<<16)|SEREMU_INTERFACE)
          && endpoint0_buffer[0] == 0xA9 && endpoint0_buffer[1] == 0x45
          && endpoint0_buffer[2] == 0xC2 && endpoint0_buffer[3] == 0x6B) {
                printf("seremu reboot request\n");
                USB1_USBINTR |= USB_USBINTR_SRE;
                usb_reboot_timer = 80; // TODO: 10 if only 12 Mbit/sec
        }
#endif
 
@ Gremlin, I'm aware of that and fixed it already for another project. I'll port it to TeensySharp in the next release.
@Paul: It would be perfect to have a byte at a fixed memory location to identify the board type from the Hex file. This would help third party downloaders preventing download of wrong hex files. Maybe an entry in the Linker script?
 
@Paul: It would be perfect to have a byte at a fixed memory location to identify the board type from the Hex file.

I just did a quick experiment and changed the linker script for the T-LC to use the '_teensy_model_identifier = 0x20' as FILL byte (instead of the usual 0xFF)
Code:
...
SECTIONS
{
   .text : {
		. = 0;
		KEEP(*(.vectors))
		*(.startup*)
		/* TODO: does linker detect startup overflow onto flashconfig? */
		. = 0x400;
		KEEP(*(.flashconfig*))
		*(.text*)
		*(.rodata*)
		. = ALIGN(4);
		KEEP(*(.init))
		. = ALIGN(4);
		__preinit_array_start = .;
		KEEP (*(.preinit_array))
		__preinit_array_end = .;
		__init_array_start = .;
		KEEP (*(SORT(.init_array.*)))
		KEEP (*(.init_array))
		__init_array_end = .;
	} > FLASH = 0x20      /* <<<<<<================== */
...

Generating the following HEX file (snippet)

Capture.PNG

For a FW downloader it would be very simple to identify this hex file as a T-LC file. This would of course work for the other boards correspondingly. I don't see any obvious disadvantage, a quick check showed that the downloaded file works normally.

Any chance to get something like this implemented?
 
Status
Not open for further replies.
Back
Top