BSL430.NET Library
------------------
BSL430.NET is Cross-Platform library serving as **MSP430 Toolchain**, to *Upload*, *Download* and *Erase* MCU memory, with communication based on generic UART converters like FT232 or Serial port. It uses BSL430.NET.FirmwareTools as aux library to help manage most common firmware formats like **Intel-HEX**, **TI-TXT**, **SREC** and **ELF**, with ability to *Convert*, *Combine*, *Create*, *Parse*, *Validate* and *Get BSL password*.

```
Note: This library is recommended to build as x86 or x64, rather than AnyCPU!
      It depends on unmanaged code, that needs to use correct pointer size.
```
- [Framework Support](#Framework-Support)
- [Communication](#Communication)
- [Device Set Up](#Device-Set-Up)
- [Code Samples](#Code-Samples)
  - [Scan Single Device Type](#Scan-Single-Device-Type)
    - [Scan FTDI](#Scan-FTDI)
    - [Scan libftdi](#Scan-libftdi)
    - [Scan USB](#Scan-USB)
    - [Scan Serial](#Scan-Serial-COM)
  - [Scan All Device Types](#Scan-All-Device-Types)
  - [Upload to MCU](#Upload-to-MCU)
    - [Simple](#Simple-Upload)
    - [Detailed](#Detailed-Upload)
  - [Download from MCU](#Download-from-MCU)
    - [Simple](#Simple-Download-from-MCU)
    - [Detailed](#Detailed-Download-from-MCU)
  - [Erase MCU](#Erase-MCU)
    - [Simple](#Simple-Erase-MCU)
    - [Detailed](#Detailed-Erase-MCU)

Framework Support
-----------------
- .NET Framework 4.6.1
- .NET Standard 2.0

Communication
-------------
Communication with MCU is handled by 4 different ways. **FTDI** (FT232) is Windows only approach and requires *FT2XX drivers* installed on target PC. Another approch is called **Libftdi** and this works on Windows and also Linux, because rather on  FT2XX original FTDI drivers it depends on open-sourced alternative libftdfi. Both ways use unmanaged libraries for low-level communication, those libraris are provided in folder *lib* or just integrated into Win GUI App. Another simple approch is  to use standard **Serial** port (COM) with RS232/UART converter, or the last one, **USB** with F5xx/F6xx USB enabled MCUs. These 2 ways use managed libraries so you dont need to worry about anything, plus they are also multiplatform. 

Unmanaged comm libs need to be put in right location, to let CLR correctly loads them, please follow .NET P/Invoke guidelines (usually in same folder as executable). 

Device Set Up
-------------
Device is then set up by three methods, first **MCU family** is chosen, this will determine BSL protocol and various stuff. Next **Baud Rate** is selected, proportionaly equal to transfer speed. Baud Rate setting is available only for modern 5xx/6xx MCUs but in some rare cases does not work like specified in official docs. Ultimately, the Invoke Method is chosen.

**Invoke Method** is crucial setting of the way how bootloader is turned on. It is a voltage sequence applied to certain MCU pins. It is required to connect *RST/TEST* pins to *DTR/RTS* according to **Wiring Diagram** and specific MCU family. These two signals forces MCU to start execute BSL bootloader code. In most cases, when MCU has Shared JTAG pins, *RST(MCU)* is connected to *DTR(PC)* and *TEST(MCU)* to *RTS(PC)*. In case of MCU has Dedicated JTAG pins, connect *RST(MCU)* to *DTR(PC)* and *TCK(MCU)* to *RTS(PC)*. When USB mode is used or when you want to handle this yourself, choose MANUAL.

**BSL password** is 16, 20 or 32 byte array and is required for Download (and Upload). Password is last 16-byte (F543x-non-A only) or 32-byte (others) of IVT (FFE0-FFFF), if newer 5xx/6xx MCU is used. If MCU from older series is used (1xx/2xx/4xx), password is exactly 20-byte long. But mostly it is 32-byte. Use Firmware Tools to get the correct BSL password and prevent problems (read below).

```
Warning: Old 1xx/2xx/4xx bootloader protocol handle Erase or incorrectly entered 
         password as complete memory wipe including Info A (with calibration data), 
         if LOCK A bit is not set! It is always better to use modern MCUs with 
         5xx/6xx BSL protocol, but if there is no oher way, be careful.
```
Code Samples
------------
### Scan Single Device Type
Scan for available devices, output of this method can be fed directly do Upload, Download or Erase methods as DefaultDevice. FTDI is intended to work only on Windows, libftdi, USB and Serial COM are cross-platform, but not always everything works as expected. It is important to use correct bitness of unmanaged libraries and also to have drivers installed for FTDI use. 

This scan is useful only when targeting single device type, output is Status class with error message/number and Devices list.
#### Scan (FTDI)
```csharp
public ScanResult<FTDI_Device> ScanFTDI()
{
    using (var dev = new BSL430NET(Mode.UART_FTD2XX))
    {
        var scan = dev.Scan<FTDI_Device>();

        Console.WriteLine(scan.Status);
        Console.WriteLine(scan.Devices);

        return scan;
    }
}
```
#### Scan (libftdi)
```csharp
public ScanResult<Libftdi_Device> ScanLibftdi()
{
    using (var dev = new BSL430NET(Mode.UART_libftdi))
    {
        var scan = dev.Scan<Libftdi_Device>();

        Console.WriteLine(scan.Status);
        Console.WriteLine(scan.Devices);

        return scan;
    }
}
```
#### Scan (USB)
```csharp
public ScanResult<USB_HID_Device> ScanUSB()
{
    using (var dev = new BSL430NET(Mode.USB_HID))
    {
        var scan = dev.Scan<USB_HID_Device>();

        Console.WriteLine(scan.Status);
        Console.WriteLine(scan.Devices);

        return scan;
    }
}
```
#### Scan (Serial COM)
```csharp
public ScanResult<Serial_Device> ScanSerial()
{
    using (var dev = new BSL430NET(Mode.UART_Serial))
    {
        var scan = dev.Scan<Serial_Device>();

        Console.WriteLine(scan.Status);
        Console.WriteLine(scan.Devices);

        return scan;
    }
}
```
### Scan All Device Types
This scan is the common scenario of first called method after start or clicked Scan button. There are 4 output  classes device specific, each with Status class with error message/number and Devices list.
```csharp
public ScanAllResult ScanAll()
{
    using (var dev = new BSL430NET())
    {
        var scan = dev.ScanAllEx();

        Console.WriteLine(scan.FtdiDevices.Status);
        Console.WriteLine(scan.LibftdiDevices.Status);
        Console.WriteLine(scan.UsbDevices.Status);
        Console.WriteLine(scan.SerialDevices.Status);

        Console.WriteLine(scan.FtdiDevices.Devices);
        Console.WriteLine(scan.LibftdiDevices.Devices);
        Console.WriteLine(scan.UsbDevices.Devices);
        Console.WriteLine(scan.SerialDevices.Devices);

        return scan;
    }
}
```
### Upload to MCU
Uploading code to micro is the most common way how use this library. This method needs to be called only with source FirmwarePath, in formats Intel-HEX, TI-TXT, SREC or ELF. Password, key to unlock bootloader, is here optional, because mostly you want dont know it and also doesnt care about that data, because they are being overwriten with new one. However there are two use cases, when good password matters. First, you already uploaded main firmware to your device and now you want to upload only Info A memory (user settings, constants..). In this case you dont want to Erase MCU first, so you need to supply valid BSL password. Secondly, read warning below:
```
Warning: Password is optional for Download, but if wrong password is entered, 
         MCU takes it as an attack and erase all memory, executing Mass Erase.
         If modern 5xx/6xx micro is used, code is just wiped, but if old
         1xx/2xx/4xx one is used and LOCK A bit is not set, also Info A mem
         is wiped, with factory calibration data. So please be careful.
```
#### Simple Upload
This example is intended as a copy-paste template for already experienced developers.
```csharp
public StatusEx UploadSimple(string FirmwarePath, Bsl430NetDevice Dev)
{ 
    using (var dev = new BSL430NET(Dev))
    {
        dev.ProgressChanged += new Bsl430NetEventHandler(delegate
            (object s, Bsl430NetEventArgs args) {
            Console.WriteLine($"{args.Progress} {args.Report}");
        });

        dev.SetBaudRate(BaudRate.BAUD_115200);
        dev.SetMCU(MCU.MSP430_F5xx);
        dev.SetInvokeMechanism(InvokeMechanism.SHARED_JTAG);

        StatusEx ret = dev.Upload(FirmwarePath);

        Console.WriteLine($"{ret}");
        return ret;
    }
}
```

#### Detailed Upload
In this example 1 firmware file is uploaded to 3 different MCUs at once. There are presented three approaches how to use this library, firstly with hardcoded device name, secondly with output of Scan methods, and lasty with Mode enum, which can serve different situations. Also Event Handling, Device settings and other various things are explained. This is only example, in real life there is usually no need for simultaneous upload by 3 different modes, so this is only for explanation purpose.
```csharp
public async void UploadDetailed()
{ 
    // Devices
    string HardcodedDevice = "FTDI1";                  // hardcoded device name
    var DeviceFromScan = new Bsl430NetDevice("USB2");  // device from Scan methods
    Mode GenericDevice = Mode.UART_Serial;             // not know device yet

    // Input data
    string FirmwarePath = @"firmware.hex";             // firmware file path

    // Dev1 and dev2 use DefaultDevice - default device is entered once into
    // constructor, and then doesnt need to be filled again; the usual way.
    // Dev3 use generic approach, that can be useful when target multiple MCUs
    using (var dev1 = new BSL430NET(HardcodedDevice))
    using (var dev2 = new BSL430NET(DeviceFromScan))
    using (var dev3 = new BSL430NET(GenericDevice))
    {
        // create simple event handler, prints progress (0-100) and report
        var BslEventHandler = new Bsl430NetEventHandler(delegate
            (object s, Bsl430NetEventArgs args) {
            Console.WriteLine($"{args.Progress} {args.Report}");
        });

        // assign same event handler for all devices
        dev1.ProgressChanged += BslEventHandler;
        dev2.ProgressChanged += BslEventHandler;
        dev3.ProgressChanged += BslEventHandler;

        // dev1 settings: fastest speed, F5xx MCU, stanard Invoke (TEST pin)
        Status stat1Baud = dev1.SetBaudRate(BaudRate.BAUD_115200);
        Status stat1Mcu = dev1.SetMCU(MCU.MSP430_F5xx);
        Status stat1Invoke = dev1.SetInvokeMechanism(InvokeMechanism.SHARED_JTAG);

        // dev2 settings: slowest speed, FR6xx MCU, dedicated JTAG pins (TCK pin)
        Status stat2Baud = dev2.SetBaudRate(BaudRate.BAUD_9600);
        Status stat2Mcu = dev2.SetMCU(MCU.MSP430_FR6xx);
        Status stat2Invoke = dev2.SetInvokeMechanism(InvokeMechanism.DEDICATED_JTAG);

        // dev3 settings: middle speed, old G2xx3 MCU -> old protocol ! read below
        Status stat3Baud = dev3.SetBaudRate(BaudRate.BAUD_38400);
        Status stat3Mcu = dev3.SetMCU(MCU.MSP430_G2xx3);
        Status stat3Invoke = dev3.SetInvokeMechanism(InvokeMechanism.SHARED_JTAG);

        // Run Upload of single firmware to 3 MCUs, BSL password is not needed,
        // as Mass Erase is executed first, clearing memory. Only beware when
        // 1xx/2xx/4xx old MCU is used, Mass Erase could wipe also Info A with 
        // calibration data. This is not case of modern 5xx/6xx MCUs, however
        // if you dont want to clear memory first, you must supply BSL password
        var result1 = Task.FromResult<StatusEx>(dev1.Upload(FirmwarePath));
        var result2 = Task.FromResult<StatusEx>(dev2.Upload(FirmwarePath));
        var result3 = await Task.FromResult<StatusEx>(dev3.Upload(FirmwarePath, "COM1"));
        
        // use overiden ToString method to output all important result data
        Console.WriteLine($"Dev1: {result1}\n\n");
        Console.WriteLine($"Dev2: {result2}\n\n");
        Console.WriteLine($"Dev3: {result3}");
    }
}
```
### Download from MCU
Downloading code from micro is useful only sometimes, like when solving a problem with some remote device. This method needs to be called with AddrStart, which is the address of the very first data node wanted, next DataSize is required, as this is the count of bytes downloaded starting from AddrStart. Password is key to unlock bootloader. Before call you need to set up device acording to specific situation, MCU family, Invoke Method and Baud Rate (already described). After calling data can be processed, so the Firmware Output Path is the location of created firmware made from downloaded data, formated in FwFormat specified. StatusEx is returned holding complete result info data.
```
Warning: Password is needed for Download. If wrong password is entered, MCU 
         takes it as an attack and erase all memory, executing Mass Erase.
         If modern 5xx/6xx micro is used, code is just wiped, but if old
         1xx/2xx/4xx one is used and LOCK A bit is not set, also Info A mem
         is wiped, with factory calibration data. So please be careful.
```
#### Simple Download
This example is intended as a copy-paste template for already experienced developers.
```csharp
public StatusEx DownloadSimple(string OutputPath, FwTools.FwFormat Format, 
                               Bsl430NetDevice Dev, byte[] Password,
                               int AddrStart, int DataSize)
{ 
    using (var dev = new BSL430NET(Dev))
    {
        dev.ProgressChanged += new Bsl430NetEventHandler(delegate
            (object s, Bsl430NetEventArgs args) {
            Console.WriteLine($"{args.Progress} {args.Report}");
        });

        dev.SetBaudRate(BaudRate.BAUD_115200);
        dev.SetMCU(MCU.MSP430_F5xx);
        dev.SetInvokeMechanism(InvokeMechanism.SHARED_JTAG);

        StatusEx ret = dev.Download(Password, AddrStart, DataSize, out List<byte> Data);
        string fw = FwTools.Create(Data, AddrStart, Format);

        using (StreamWriter wr = new StreamWriter(OutputPath)) {
            wr.Write(fw);
        }

        Console.WriteLine($"{ret}\n{fw}");
        return ret;
    }
}
```

#### Detailed Download
In this example 3 firmware files are download from 3 different MCUs at once. There are presented three approaches how to use this library, firstly with hardcoded device name, secondly with output of Scan methods, and lasty with Mode enum, which can serve different situations. Also Event Handling, Device settings and other various things are explained. This is only example, in real life there is usually no need for simultaneous download by 3 different modes, so this is only for explanation purpose.
```csharp
public async void DownloadDetailed()
{
    // Devices
    string HardcodedDevice = "FTDI1";                  // hardcoded device name
    var DeviceFromScan = new Bsl430NetDevice("USB2");  // device from Scan methods
    Mode GenericDevice = Mode.UART_Serial;             // not know device yet

    // Input data

    // Output firmware file paths
    string OutputPath1 = @"firmware1.hex";             // firmware output path 1
    string OutputPath2 = @"firmware2.txt";             // firmware output path 2
    string OutputPath3 = @"firmware3.s19";             // firmware output path 3

    // Output firmware file formats
    FwTools.FwFormat OutputFormat1 = FwTools.FwFormat.INTEL_HEX;  // Intel-HEX
    FwTools.FwFormat OutputFormat2 = FwTools.FwFormat.TI_TXT;     // TI-TXT 
    FwTools.FwFormat OutputFormat3 = FwTools.FwFormat.SREC;       // SREC

    // First address - from where to start
    int AddrStart1 = 0x8000;                           // start address 1 - 0x8000
    int AddrStart2 = 0x9999;                           // start address 2 - 0x9999
    int AddrStart3 = 0xAACC;                           // start address 3 - 0xAACC

    // Byte size - how many bytes to download
    int DataSize1 = 32768;                             // byte size 1 - 0x8000 hex
    int DataSize2 = 1000;                              // byte size 2 - 1000 dec
    int DataSize3 = 1;                                 // byte size 3 - single byte

    // BSL password, crucial parameter (read doc)
    byte[] Password1 = Enumerable.Repeat((byte)0xFF, 32).ToArray(); // standard 32 len
    byte[] Password2 = Enumerable.Repeat((byte)0xFF, 16).ToArray(); // F543x Non A only
    byte[] Password3 = Enumerable.Repeat((byte)0xFF, 20).ToArray(); // 20 byte old MCUs

    // Dev1 and dev2 use DefaultDevice - default device is entered once into
    // constructor, and then doesnt need to be filled again; the usual way.
    // Dev3 use generic approach, that can be useful when target multiple MCUs
    using (var dev1 = new BSL430NET(HardcodedDevice))
    using (var dev2 = new BSL430NET(DeviceFromScan))
    using (var dev3 = new BSL430NET(GenericDevice))
    {
        // create simple event handler, prints progress (0-100) and report
        var BslEventHandler = new Bsl430NetEventHandler(delegate
            (object s, Bsl430NetEventArgs args) {
            Console.WriteLine($"{args.Progress} {args.Report}");
        });

        // assign same event handler for all devices
        dev1.ProgressChanged += BslEventHandler;
        dev2.ProgressChanged += BslEventHandler;
        dev3.ProgressChanged += BslEventHandler;

        // dev1 settings: fastest speed, F6xx MCU, standard 32 byte password
        Status stat1Baud = dev1.SetBaudRate(BaudRate.BAUD_115200);
        Status stat1Mcu = dev1.SetMCU(MCU.MSP430_F6xx);
        Status stat1Invoke = dev1.SetInvokeMechanism(InvokeMechanism.DEDICATED_JTAG);

        // dev2 settings: slowest speed, F543x MCU Non A -> 16 byte password!
        Status stat2Baud = dev2.SetBaudRate(BaudRate.BAUD_9600);
        Status stat2Mcu = dev2.SetMCU(MCU.MSP430_F543x_NON_A);
        Status stat2Invoke = dev2.SetInvokeMechanism(InvokeMechanism.SHARED_JTAG);

        // dev3 settings: middle speed, old G2xx3 MCU -> 20 byte password, old protocol
        Status stat3Baud = dev3.SetBaudRate(BaudRate.BAUD_38400);
        Status stat3Mcu = dev3.SetMCU(MCU.MSP430_G2xx3);
        Status stat3Invoke = dev3.SetInvokeMechanism(InvokeMechanism.SHARED_JTAG);

        // Run Download of 3 firmwares to 3 MCUs, BSL password is required,
        // Beware when 1xx/2xx/4xx old MCU is used, incorrect password could 
        // wipe also Info A with calibration data. This is not case when 
        // LOCK A bit is set, preventing erase, or if modern 5xx/6xx MCUs used
        var result1 = Task.FromResult<StatusEx>(
            dev1.Download(Password1, AddrStart1, DataSize1, out List<byte> Data1));
        var result2 = Task.FromResult<StatusEx>(
            dev2.Download(Password2, AddrStart2, DataSize2, out List<byte> Data2));
        var result3 = await Task.FromResult<StatusEx>(
            dev3.Download(Password3, AddrStart3, DataSize3, out List<byte> Data3, "COM1"));

        // After download create firmare classes from raw data
        string fw1 = FwTools.Create(Data1, AddrStart1, OutputFormat1);
        string fw2 = FwTools.Create(Data2, AddrStart2, OutputFormat2);
        string fw3 = FwTools.Create(Data3, AddrStart3, OutputFormat3);

        // Finally write ready firmwares to disk
        using (StreamWriter wr1 = new StreamWriter(OutputPath1))
        using (StreamWriter wr2 = new StreamWriter(OutputPath2))
        using (StreamWriter wr3 = new StreamWriter(OutputPath3)) 
        {
            wr1.Write(fw1);
            wr2.Write(fw2);
            wr3.Write(fw3);
        }
        
        // use overiden ToString method to output all important result data
        Console.WriteLine($"Dev1: {result1}\n{fw1}\n\n");
        Console.WriteLine($"Dev2: {result2}\n{fw2}\n\n");
        Console.WriteLine($"Dev3: {result3}\n{fw3}");
    }
}
```

### Erase MCU
Erasing micro is also sometimes needed and doesnt require any input data, nor it cares about set Baud Rate value. Just call this method and quickly all memory is erased.
```
Warning: If old 1xx/2xx/4xx MCU is used and LOCK A bit is not set **DONT** do it!
         Info A memory will be erased as well, with factory calibration data.
         This will also happen when incorrect password entered, so be careful.
         Or just dont use old micros and buy a new better one :)
```
#### Simple Erase
This example is intended as a copy-paste template for already experienced developers.
```csharp
public StatusEx EraseSimple(Bsl430NetDevice Dev)
{ 
    using (var dev = new BSL430NET(Dev))
    {
        dev.ProgressChanged += new Bsl430NetEventHandler(delegate
            (object s, Bsl430NetEventArgs args) {
            Console.WriteLine($"{args.Progress} {args.Report}");
        });

        dev.SetBaudRate(BaudRate.BAUD_115200);
        dev.SetMCU(MCU.MSP430_F5xx);
        dev.SetInvokeMechanism(InvokeMechanism.SHARED_JTAG);

        StatusEx ret = dev.Erase();

        Console.WriteLine($"{ret}");
        return ret;
    }
}
```

#### Detailed Erase
In this example 3 MCUs are erased at once. There are presented three approaches how to use this library, firstly with hardcoded device name, secondly with output of Scan methods, and lasty with Mode enum, which can serve different situations. Also Event Handling and Device settings are explained. This is only example, in real life there is usually no need for simultaneous erase by 3 different modes, so this is only for explanation purpose.
```csharp
public async void EraseDetailed()
{
    // Devices
    string HardcodedDevice = "FTDI1";                  // hardcoded device name
    var DeviceFromScan = new Bsl430NetDevice("USB2");  // device from Scan methods
    Mode GenericDevice = Mode.UART_Serial;             // not know device yet

    // For Erase there is no need for input data

    // Dev1 and dev2 use DefaultDevice - default device is entered once into
    // constructor, and then doesnt need to be filled again; the usual way.
    // Dev3 use generic approach, that can be useful when target multiple MCUs
    using (var dev1 = new BSL430NET(HardcodedDevice))
    using (var dev2 = new BSL430NET(DeviceFromScan))
    using (var dev3 = new BSL430NET(GenericDevice))
    {
        // create simple event handler, prints progress (0-100) and report
        var BslEventHandler = new Bsl430NetEventHandler(delegate
            (object s, Bsl430NetEventArgs args) {
            Console.WriteLine($"{args.Progress} {args.Report}");
        });

        // assign same event handler for all devices
        dev1.ProgressChanged += BslEventHandler;
        dev2.ProgressChanged += BslEventHandler;
        dev3.ProgressChanged += BslEventHandler;

        // dev1 settings: F6xx MCU, dedicated JTAG pins (TCK pin)
        Status stat1Mcu = dev1.SetMCU(MCU.MSP430_F6xx);
        Status stat1Invoke = dev1.SetInvokeMechanism(InvokeMechanism.DEDICATED_JTAG);

        // dev2 settings: F5xx MCU, shared JTAG pins (TEST pin)
        Status stat2Mcu = dev2.SetMCU(MCU.MSP430_F5xx);
        Status stat2Invoke = dev2.SetInvokeMechanism(InvokeMechanism.SHARED_JTAG);

        // dev3 settings: old G2xx3 MCU - careful to not wipe Info A! set LOCK A bit
        Status stat3Mcu = dev3.SetMCU(MCU.MSP430_G2xx3);
        Status stat3Invoke = dev3.SetInvokeMechanism(InvokeMechanism.SHARED_JTAG);

        // Run Mass Erase of 3 MCUs - whole memory is wiped. Beware when 1xx/2xx/4xx 
        // old MCU is used and LOCK A is NOT set, Info A with calib data is wiped!
        var result1 = Task.FromResult<StatusEx>(dev1.Erase());
        var result2 = Task.FromResult<StatusEx>(dev2.Erase());
        var result3 = await Task.FromResult<StatusEx>(dev3.Erase("COM1"));
        
        // use overiden ToString method to output all important result data
        Console.WriteLine($"Dev1: {result1}\n\n");
        Console.WriteLine($"Dev2: {result2}\n\n");
        Console.WriteLine($"Dev3: {result3}");
    }
}
```
