mirror of https://github.com/duggerd/KFDtool.git
339 lines
12 KiB
C#
339 lines
12 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.ComponentModel;
|
|||
|
using System.IO;
|
|||
|
using System.Linq;
|
|||
|
using System.Text;
|
|||
|
using System.Threading;
|
|||
|
using System.Threading.Tasks;
|
|||
|
|
|||
|
namespace KFDtool.BSL430
|
|||
|
{
|
|||
|
/*
|
|||
|
* THE BSL430 AND HIDLIBRARY PROJECTS NEED TO BE REPLACED
|
|||
|
*
|
|||
|
* FOR SOME REASON ANYTHING BUT THE SHIPPING VERSION OF HIDLIBRARY
|
|||
|
* DOES NOT WORK, AND THERE ARE MODIFICATIONS TO HIDLIBRARY NOT IN
|
|||
|
* THE PROJECT MASTER ON GITHUB
|
|||
|
*
|
|||
|
* THE HIDLIBRARY VS PROJECT IS TAKEN FROM THE DECOMPILED HIDLIBRARY
|
|||
|
* BIN IN THE ORIGINAL BSL430 PROJECT AS THERE IS ONLY A X86 BIN
|
|||
|
*
|
|||
|
* IT "WORKS" BUT IT NEEDS TO BE REPLACED
|
|||
|
*/
|
|||
|
|
|||
|
/*
|
|||
|
* The firmware updater expects a device to connect with VID/PID 0x2407/0x0200.
|
|||
|
* Once this device is connected, the updater updates the firmware using custom code and
|
|||
|
* HIDusb library (HIDInterface).
|
|||
|
*/
|
|||
|
public class FirmwareUpdater
|
|||
|
{
|
|||
|
public const int DISCONNECTED = 0;
|
|||
|
public const int CONNECTED = 1;
|
|||
|
public const int SENDINGDATA = 2;
|
|||
|
public const int CANCELED = 3;
|
|||
|
public const int COMPLETE = 4;
|
|||
|
|
|||
|
// Used for Firmware Upgrade only
|
|||
|
private HIDusb usbBSL = new HIDusb(0x2047, 0x0200);
|
|||
|
private BackgroundWorker firmwareUpgradeWorker;
|
|||
|
|
|||
|
// Event Handlers
|
|||
|
public event EventHandler StatusChanged;
|
|||
|
public event EventHandler ConnectionChanged;
|
|||
|
public event EventHandler ProgressUpdated;
|
|||
|
|
|||
|
// PROPERTIES
|
|||
|
private int status = DISCONNECTED;
|
|||
|
public int Status
|
|||
|
{
|
|||
|
get { return status; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (status != value)
|
|||
|
{
|
|||
|
status = value;
|
|||
|
OnStatusChanged(new EventArgs());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
public bool Connected
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (usbBSL != null && usbBSL.IsConnected)
|
|||
|
return true;
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private double percentage;
|
|||
|
public double Percentage
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return percentage;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
if (value < 0) percentage = 0.0;
|
|||
|
else if (value > 1.0) percentage = 1.0;
|
|||
|
else percentage = value;
|
|||
|
|
|||
|
// Notify an update on the progress
|
|||
|
OnProgressUpdated(new EventArgs());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public string FirmwareBinary { get; set; }
|
|||
|
|
|||
|
public string RamBslBinary { get; set; }
|
|||
|
|
|||
|
private bool AutoStartUpdate;
|
|||
|
|
|||
|
public FirmwareUpdater(string firmwareStr, string ramBslStr, bool autoStartUpdate)
|
|||
|
{
|
|||
|
// Save the firmware string
|
|||
|
FirmwareBinary = firmwareStr;
|
|||
|
|
|||
|
// Save the RAM BSL string
|
|||
|
RamBslBinary = ramBslStr;
|
|||
|
|
|||
|
AutoStartUpdate = autoStartUpdate;
|
|||
|
|
|||
|
// Status is initially DISCONNECTED
|
|||
|
Status = DISCONNECTED;
|
|||
|
|
|||
|
// Attach a function to the worker's DoWork and other events
|
|||
|
firmwareUpgradeWorker = new BackgroundWorker();
|
|||
|
firmwareUpgradeWorker.DoWork += firmwareUpgradeWorker_DoWork;
|
|||
|
firmwareUpgradeWorker.RunWorkerCompleted += firmwareUpgradeWorker_RunWorkerCompleted;
|
|||
|
|
|||
|
// Attach events to USB connection
|
|||
|
usbBSL.Connected += OnUSBConnected;
|
|||
|
usbBSL.Disconnected += OnUSBDisconnected;
|
|||
|
|
|||
|
// The device is expected to be DISCONNECTED
|
|||
|
// But in case it is already connected, run the update already
|
|||
|
if (usbBSL.IsConnected)
|
|||
|
{
|
|||
|
// Generate event notifying status change
|
|||
|
Status = CONNECTED;
|
|||
|
|
|||
|
if (autoStartUpdate)
|
|||
|
startFirmwareUpdate();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Reads a text file containing the code to be uploaded.
|
|||
|
/// Returns a new FirmwareUpdater instance for the given code.
|
|||
|
/// </summary>
|
|||
|
/// <param name="firmwarePath"></param>
|
|||
|
/// <param name="ramBslPath"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public static FirmwareUpdater FromTextHexFile(string firmwarePath, string ramBslPath)
|
|||
|
{
|
|||
|
string fwStr = File.ReadAllText(firmwarePath);
|
|||
|
string bslStr = File.ReadAllText(ramBslPath);
|
|||
|
return new FirmwareUpdater(fwStr, bslStr, true);
|
|||
|
}
|
|||
|
|
|||
|
// To be called at the end of the firmware update by the UI
|
|||
|
public void ResetConnectionStatus()
|
|||
|
{
|
|||
|
if (usbBSL.IsConnected)
|
|||
|
Status = CONNECTED;
|
|||
|
else
|
|||
|
Status = DISCONNECTED;
|
|||
|
}
|
|||
|
|
|||
|
public void startFirmwareUpdate()
|
|||
|
{
|
|||
|
// The connection was detected.
|
|||
|
// De-register connection event. If the UI needs to re-attempt firmware update,
|
|||
|
// if will call a new instance of FirmwareUpdater.
|
|||
|
usbBSL.Connected -= OnUSBConnected;
|
|||
|
|
|||
|
// Since this function can be called twice, verify that
|
|||
|
// the background worker is not alredy running. And then run it.
|
|||
|
if (!firmwareUpgradeWorker.IsBusy)
|
|||
|
firmwareUpgradeWorker.RunWorkerAsync();
|
|||
|
}
|
|||
|
|
|||
|
// Firmware Update Background Work
|
|||
|
private void firmwareUpgradeWorker_DoWork(object sender, DoWorkEventArgs e)
|
|||
|
{
|
|||
|
Percentage = 0;
|
|||
|
|
|||
|
// Load and parse the binary source for RAM_BSL to be loaded in RAM, and the actual firmware code
|
|||
|
BinaryTextFileParser ram_bsl = new BinaryTextFileParser(RamBslBinary);
|
|||
|
BinaryTextFileParser firmware = new BinaryTextFileParser(FirmwareBinary);
|
|||
|
|
|||
|
// append bor to firmware
|
|||
|
firmware.sections.Add(new CodeSection());
|
|||
|
firmware.sections.Last().StartAddress = 0x0120;
|
|||
|
firmware.sections.Last().AppendBinaryCode(new byte[] { 0xA5, 0x06 });
|
|||
|
|
|||
|
// Clear the incomming messages from device
|
|||
|
while (usbBSL.readNext() != null) ;
|
|||
|
|
|||
|
// 1. PASSWORD
|
|||
|
// Provide the empty password: will trigger a mass erase !!
|
|||
|
byte[] password = new byte[32];
|
|||
|
for (int i = 0; i < password.Length; i++) password[i] = 0xFF;
|
|||
|
byte[] cmd = BSLCoreCommandParser.RXPassword(password);
|
|||
|
|
|||
|
int msg;
|
|||
|
do
|
|||
|
{
|
|||
|
usbBSL.write(cmd);
|
|||
|
|
|||
|
while (usbBSL.PacketsIn.Count() == 0) Thread.Sleep(100);
|
|||
|
Thread.Sleep(200);
|
|||
|
|
|||
|
// Read the incoming data
|
|||
|
msg = BSLCoreCommandParser.readMessage(usbBSL.readNext());
|
|||
|
|
|||
|
} while (msg != BSLCoreCommandParser.MSG_SUCCESSFULL);
|
|||
|
|
|||
|
// 2. LOAD RAM-BSL to RAM
|
|||
|
List<byte[]> cmds = BSLCoreCommandParser.listOfRxDataBlock(ram_bsl.sections, 62, true);
|
|||
|
foreach (byte[] command in cmds)
|
|||
|
{
|
|||
|
// The commands are RXDataBlockFast, with no response from the device
|
|||
|
usbBSL.write(command);
|
|||
|
}
|
|||
|
// Wait for all packets to be sent (not really necessary)
|
|||
|
while (usbBSL.PacketsOut.Count > 0) Thread.Sleep(100);
|
|||
|
|
|||
|
// 3. START EXECUTING RAM BSL
|
|||
|
// At this point, USB connection may be lost and reconnected immediately after
|
|||
|
// TODO: test and check no wrong event is triggered
|
|||
|
usbBSL.Disconnected -= OnUSBDisconnected;
|
|||
|
|
|||
|
cmd = BSLCoreCommandParser.LoadPC(0x2504);
|
|||
|
usbBSL.write(cmd);
|
|||
|
// Wait for all packets to be sent
|
|||
|
while (usbBSL.PacketsOut.Count > 0) Thread.Sleep(100);
|
|||
|
Thread.Sleep(500);
|
|||
|
|
|||
|
// HID should reset automatically
|
|||
|
usbBSL.Close();
|
|||
|
usbBSL = new HIDusb(0x2047, 0x0200);
|
|||
|
while (!usbBSL.IsConnected) Thread.Sleep(100);
|
|||
|
|
|||
|
// 4. UPLOAD NEW FIRMWARE
|
|||
|
Status = SENDINGDATA;
|
|||
|
|
|||
|
usbBSL.Disconnected += OnUSBDisconnected;
|
|||
|
// Send a mass erase, in case the password was correct
|
|||
|
usbBSL.write(BSLCoreCommandParser.MassErase());
|
|||
|
while (usbBSL.PacketsOut.Count > 0) Thread.Sleep(20);
|
|||
|
|
|||
|
// Send the firmware data
|
|||
|
int nbCmdsSent = 0;
|
|||
|
cmds = BSLCoreCommandParser.listOfRxDataBlock(firmware.sections, 62, false);
|
|||
|
foreach (byte[] command in cmds)
|
|||
|
{
|
|||
|
bool commandSucceeded;
|
|||
|
do
|
|||
|
{
|
|||
|
commandSucceeded = true;
|
|||
|
|
|||
|
// The commands are RXDataBlock with response from the device
|
|||
|
usbBSL.write(command);
|
|||
|
|
|||
|
// Estimate percentage of advance
|
|||
|
Percentage = (double)nbCmdsSent / (double)cmds.Count;
|
|||
|
|
|||
|
// Expect a feedback after each write command. Long, but secure execution.
|
|||
|
while (usbBSL.PacketsOut.Count > 0 && commandSucceeded)
|
|||
|
{
|
|||
|
if (usbBSL.PacketsOut[0] == null)
|
|||
|
{
|
|||
|
usbBSL.PacketsOut.RemoveAt(0);
|
|||
|
commandSucceeded = false;
|
|||
|
}
|
|||
|
System.Threading.Thread.Sleep(1);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Read the feedback
|
|||
|
while (usbBSL.PacketsIn.Count > 0)
|
|||
|
{
|
|||
|
if (BSLCoreCommandParser.readMessage(usbBSL.PacketsIn[0]) != BSLCoreCommandParser.MSG_SUCCESSFULL)
|
|||
|
{
|
|||
|
commandSucceeded = false;
|
|||
|
}
|
|||
|
usbBSL.PacketsIn.RemoveAt(0);
|
|||
|
}
|
|||
|
} while (!commandSucceeded);
|
|||
|
|
|||
|
nbCmdsSent++;
|
|||
|
}
|
|||
|
|
|||
|
Status = COMPLETE;
|
|||
|
usbBSL.Disconnected -= OnUSBDisconnected;
|
|||
|
|
|||
|
// Program was uploaded. Need now to reset
|
|||
|
int resetAddress = firmware.ResetAddress();
|
|||
|
cmd = BSLCoreCommandParser.LoadPC(resetAddress);
|
|||
|
usbBSL.write(cmd);
|
|||
|
while (usbBSL.PacketsOut.Count > 0) Thread.Sleep(100);
|
|||
|
|
|||
|
// TODO: manage the threads and event of the USB HID
|
|||
|
// Re-connecting generates issues
|
|||
|
}
|
|||
|
private void firmwareUpgradeWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|||
|
{
|
|||
|
Percentage = 0.0;
|
|||
|
}
|
|||
|
|
|||
|
// EXTERNAL EVENTS
|
|||
|
private void OnUSBConnected(object sender, EventArgs e)
|
|||
|
{
|
|||
|
// Generate event notifying status change
|
|||
|
Status = CONNECTED;
|
|||
|
OnConnectionChanged(new EventArgs());
|
|||
|
|
|||
|
// Trigger the update on connection event
|
|||
|
if (AutoStartUpdate)
|
|||
|
startFirmwareUpdate();
|
|||
|
}
|
|||
|
private void OnUSBDisconnected(object sender, EventArgs e)
|
|||
|
{
|
|||
|
// If this event is fired, the device was disconnected BEFORE the end
|
|||
|
// of the firmware update. Fire an error.
|
|||
|
Status = CANCELED;
|
|||
|
OnConnectionChanged(new EventArgs());
|
|||
|
|
|||
|
// De-register event. If the GUI wants to try the update again, it will
|
|||
|
// call a new instance of updater
|
|||
|
usbBSL.Disconnected -= OnUSBDisconnected;
|
|||
|
}
|
|||
|
|
|||
|
// INTERNAL EVENTS
|
|||
|
private void OnStatusChanged(EventArgs e)
|
|||
|
{
|
|||
|
EventHandler handler = StatusChanged;
|
|||
|
if (handler != null)
|
|||
|
handler(this, e);
|
|||
|
}
|
|||
|
private void OnConnectionChanged(EventArgs e)
|
|||
|
{
|
|||
|
EventHandler handler = ConnectionChanged;
|
|||
|
if (handler != null)
|
|||
|
handler(this, e);
|
|||
|
}
|
|||
|
private void OnProgressUpdated(EventArgs e)
|
|||
|
{
|
|||
|
EventHandler handler = ProgressUpdated;
|
|||
|
if (handler != null)
|
|||
|
handler(this, e);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|