C# Library for Uploading Firmware from User Applications

luni

Well-known member
Hello all,

I'm currently working on a commercial project which will include a Teensy 3.1. As discussed a few times in the forum for many applications it is desirable to upload new firmware from within windows applications. I therefore wrote a little easy to use C# library which handles uploads to Teensy boards. For the protocol I used the algorithms from the Teensy_Loader_CLI. Communication with the board is done via Mike O'Brians HIDLibrary (https://github.com/mikeobrien/HidLibrary). The lib is published it at GitHub (https://github.com/luni64/TeensySharp, VS2013 Solution).

The usage is quite simple. Below you find some pseudo code showing the idea. A working test app is included in the repo
Code:
var Board = PJRC_Board.Teensy_31;  // all boards implemented but only Teensy 3.1 tested so far           
var FlashImage = SharpUploader.GetEmptyFlashImage(Board);  //Get an empty flash image with the correct size and all bytes cleared (i.e. set to 0xFF)    

// Open the hex file, parse it and write the result into the image file
var HexStream = File.OpenText(testfile);
SharpHexParser.ParseStream(HexStream, FlashImage);    

// Upload the image to the board and reboot
int result = SharpUploader.Upload(FlashImage, Board, reboot: true);

The Lib works nicely for T3.1. I don't have other Teensies so I couldn't test it for those boards. Any feedback, test results and improvement suggestions welcome

Have fun
Lutz
 
Last edited:
I updated the TeensySharp library with a class to find all Teensies on the USB tree of a windows system. This class can be used in your Windows applications to provide a list of all currently connected Teensies (USB Serial) together with their Serialnumbers and the Port Names (COMXY). Windows has a habit of changing those Com Port Numbers from time to time which can be quite confusing for the average user.
With the libaray you can open the SerialPort without having the user to know or select the Port Number from a list or whatever. You can even attach an eventhandler which will notify you if somebody connected / disconnected a Teensy board. Effectively this will allow for a fully transparent autoconnect feature in your applications (You can automatically open the ComPort when a user plugs in your Teensy Device)

Documentation, source code and examples can be found on GitHub. https://github.com/luni64/TeensySharp


Questions:
  1. To upload firmware I still have to start HalfKay by pressing the program button. Pauls GUI Loader can do this automagically, I didn't find any documentation on how to achieve this. Any pointers?
  2. If Teensy is running the USB Serial protocoll it reports a nice (unique?) serial number in the DeviceID. This comes in handy if you have more than one board connected. HalfKay does not seem to report this number, at least I didn't find it. This would be a very nice feature. (e.g. In a production system I want to be sure that my users download the firmware to the correct device which can be difficult if I have more than one Teensy running)

Lutz
 
You can reboot a board in serial mode by setting the baudrate to 134. The procedure is obviously different if your board runs in HID (such as Raw HID), then it involves sending a magic feature report :)

HalfKay reports the serial number, but with a few caveats:
- it's hexadecimal (e.g. 000116FF)
- since Teensyduino 1.19 (IIRC) the running serial number is multiplied by ten to work around a bug in the OSX serial driver (so 000116FF in HalfKay == 714230 when running)

So to match the running serial number, you just have to convert the number from hexadecimal and multiply it by ten unless it's equal or superior to 10000000. I send you to the core commit related to this: https://github.com/PaulStoffregen/cores/commit/4d8a62cf65624d2dc1d861748a9bb2e90aaf194d

I believe you can get the serial number from a HID handle with HidD_GetSerialNumberString().
 
Thanks for the information Koromix, that helps a lot. I will try the HalfKay serial number parsing this evening.
I assume in order to reboot I have to set the baudrate to 136 on the teensy firmware? If so, I still don't understand how the TeensyLoader is able to start HalfKay regardless what firmware is running...
 
Nono, you do it on the computer using SetCommState() on the device HANDLE, which you get by opening the COM port. I don't know much about the .NET framework and if it provides anything to manage serial ports, but here is some (untested) C/Win32 code to do it (without error management).

Code:
DCB dcb;
DWORD previous_rate;

dcb.DCBlength = sizeof(dcb);

/* Get this HANDLE with CreateFile("COMx") */
GetCommState(handle, &dcb);
previous_rate = dcb.BaudRate;

dcb.BaudRate = 134;
SetCommState(handle, &dcb);

/* Restore the previous baudrate, to make sure Windows does not try to apply this setting on
    a future device/Teensy (and reboot it again) */
dcb.BaudRate = previous_rate;
SetCommState(handle, &dcb);
 
Great, that works perfectly. In .net it is as simple as

Code:
...
var Com = new SerialPort("COM14"); 
Com.Open();

int OldBaudRate = Com.BaudRate; 
Com.BaudRate = 134;
Com.BaudRate = OldBaudRate;
...
Thanks a lot
 
I never bricked a Teensy with it and I never got any complaints.
The library uses the algorithms from Pauls CLI uploader. I'm quite sure that technically you can not brick a Teensy by downloading firmware but of course I can not guarantee anything.
 
you cant “brick” a teensy unless you intentionally try to erase the flash boot sector or short the wiring, ir apply too much voltage to any pin...
 
Pauls CLI uploader.
Is the code for that uploader available somewhere?

I was just looking at TeensySharp source code and could not find a Teensy 3.2 value in PJRC_Board. I guess I should just use Teensy_31 since both 3.1 and 3.2 boards are compatible right?
 
So I just gave it a try and TeensyWatcher could not find my board as it's not matching any of the expected product IDs.
My product ID is 0x0476 but that very much depends how you configured it.
For Teensy 3.2 I've noted the the following product IDs for instance:
const int KProductIdTeensy32KeyboardMouseJoystick = 0x0482;
const int KProductIdTeensy32RawHid = 0x0486;
const int KProductIdTeensy32AllTheThings = 0x0476;

The TeensyWatcher code is expecting either:
const uint serPid = 0x483;
const uint halfKayPid = 0x478;

Is this a limitation of the uploader or an issue with TeensyWatcher implementation?
 
The TeensyWatcher code is expecting either:
const uint serPid = 0x483;
const uint halfKayPid = 0x478;

Is this a limitation of the uploader or an issue with TeensyWatcher implementation?

This is not a principle limitation. When I did TeensySharp / TeensyWatcher I only implemented it for Teensies in serial mode (0x483). Extending to the other modes is possible (and not really difficult) but since I didn't have a use case / request until now I never did it.
 
Hi Lutz,

I have taken the liberty to paste your answer to the TeensySharp in the Teensyduino 1.54 thread here and link to it:

TeensySharp was written some 6 years ago and has a rather small user base (<300 downloads at nuget). So, I have to admit that it was not very well maintained over the years. However, ~two years ago I spent some time to upgrade it to the then new multiple Serial ports which also required supporting the IAD descriptors. This upgraded version works but was never really finished and not much tested. It lives in the development branch of the repo. I recently got a request to support the new MicroMode versions so, I started to work on it again (at least whenever I find some time...). I would be glad if you could give it a try and identify open bugs.

First of all, thanks a lot that you are still working on this project at all!

Sometimes life could be so simple ;o)
Your TeensySharp is the main part of my project and I was absolutely thrilled with it until Teensyduino version 1.53 - everything ran perfectly. The desktop configuration program is intended for setting a Teensy audio visualizer and finds the used Teensy unerringly and reliably thanks to your software. Here are a few screenshots, so you know what it's all about: https://www.diylab.de/revox-a700-audio-visualizer-software-de/

I also used only one class from your project, the "TeensyWatcher" class and therefore used the "TeensyWatcher.cs" directly without including the whole package via NuGet.

This (old) class is clearly understandable for me.
Honestly, that's all it needs, your project should be called "C# library for finding Teensies on the USB tree" - who needs the rest?

So now you have completely turned the whole construct upside down and I have to understand what you are actually doing, I am quite frustrated at the moment.

Imagine if you had only implemented this simple function to identify a connected Teensy and provide the port and then provided a simple explanation that everyone understands, that would be interesting for a lot of users.

I have to take a step back and get used to the fact that everything is different with Teensyduino 1.54 now. Whether it is better, I do not like to judge.
I'm going to pull weeds first ;o)

Kind regards
DIYLAB (Bruno)
 
If you are only interested in the COM ports of the connected Teensies and don't need their serial number and don't want to upload firmware you can simply hack TeensyWatcher.cs:

From the point of view of the WMI database the IAD descriptor generates two logical devices one composite device containing the serial number and one Serial device containing the Port. The PNPClass of the first device is "USB" the PNPClass of the second device is "Ports". You can just ignore all devices with PNPClass != Ports and read out the COM port from the remaining devices via the "Caption" property:

Code:
 protected USB_Device MakeDevice(ManagementBaseObject mgmtObj)
 {
       var DeviceIdParts = ((string)mgmtObj["PNPDeviceID"]).Split("\\".ToArray());
       if (DeviceIdParts[0] != "USB") return null;

       int start = DeviceIdParts[1].IndexOf("PID_") + 4;
       uint pid = Convert.ToUInt32(DeviceIdParts[1].Substring(start, 4), 16);
       if (pid == serPid)
       {
// change from here on ..........................................
           string port = null;
           uint serNum = 0;
           //uint serNum = Convert.ToUInt32(DeviceIdParts[2]);
           
           if ((string)mgmtObj["PNPClass"] == "Ports")
           {
                port = (((string)mgmtObj["Caption"]).Split("()".ToArray()))[1];
           }
           else return null;
//.....

Remarks:

So now you have completely turned the whole construct upside down and I have to understand what you are actually doing, I am quite frustrated at the moment.
Actually this statement is quite rude. You copied out a class from a free library and now you complain that an updated version of this free library requires you to rethink? I don't want to comment on this further.

Imagine if you had only implemented this simple function to identify a connected Teensy and provide the port and then provided a simple explanation that everyone understands, that would be interesting for a lot of users.
Main use case of the library is to upload firmware from within a c# user application. The fact that you are only interested in a small part of it does not necessarily apply for other users. Anyway, it's open source, feel free to fork and improve it.
 
Actually this statement is quite rude.

Oh, if that's how it was taken, then I'm honestly sorry!
I wanted to say that I am unhappy about the state of my project per se and that is of course not exclusively related to TeensySharp. So sorry!
I appreciate what you are doing, of course.
 
Back
Top