DataStreamerConnect/ArduinoUploader/ArduinoProgrammer.cs

188 строки
7.3 KiB
C#

/*
Copyright(c) Microsoft Corp. All rights reserved.
The MIT License(MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using IntelHexFormatReader;
using IntelHexFormatReader.Model;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Windows.Foundation;
namespace UploaderComponent
{
public sealed class ArduinoProgrammer
{
private ArduinoData arduinoData;
Arduino arduino;
public ArduinoProgrammer(Arduino a, ArduinoData ad)
{
arduino = a;
arduinoData = ad;
}
public IAsyncAction Program(String fileName, int memorySize)
{
Debug.WriteLine("Load hex file");
HexFileReader reader = new HexFileReader(fileName, memorySize);
Debug.WriteLine("Load hex file: Done");
Debug.WriteLine("Parse hex file: Start");
MemoryBlock memoryRepresentation = reader.Parse();
Debug.WriteLine("Parse hex file: Done");
return ProgramInternal(memoryRepresentation).AsAsyncAction();
}
internal async Task ProgramInternal(MemoryBlock memoryBlockContents)
{
Debug.WriteLine("ProgramInternal");
if (!arduino.IsConnected)
{
Debug.WriteLine("Arduino is not connected????");
throw new Exception("Arduino is not connected");
}
// Reset the device
Debug.WriteLine("Reset device");
arduino.ResetDevice();
// Reopen the device
Debug.WriteLine("Reopen device");
await arduino.Connect();
await Task.Delay(250);
// setup connection with the arduino
Debug.WriteLine("Establish bootlooder sync");
arduino.EstablishSync();
arduino.EstablishSync();
// Check device signature
//Debug.WriteLine("Validate device signature");
//good = await arduino.CheckSignature();
//Debug.WriteLine("signature validated");
Debug.WriteLine("Initialize device");
arduino.InitializeDevice();
Debug.WriteLine("Device initialized");
Debug.WriteLine("Enable programming mode");
EnableProgrammingMode();
Debug.WriteLine("Enable programming mode Done");
Debug.WriteLine("Programming device...");
ProgramDevice(memoryBlockContents);
Debug.WriteLine("Device programmed.");
Debug.WriteLine("Leave programming mode");
LeaveProgrammingMode();
Debug.WriteLine("Leave programming mode");
}
internal void EnableProgrammingMode()
{
arduino.SendWithSyncRetry(new EnableProgrammingModeRequest());
var nextByte = arduino.ReceiveNext();
if (nextByte == Constants.RespStkOk) return;
if (nextByte == Constants.RespStkNodevice || nextByte == Constants.RespStkFailed)
throw new ArduinoUploaderException("Unable to enable programming mode on the device!");
}
internal void LeaveProgrammingMode()
{
arduino.SendWithSyncRetry(new LeaveProgrammingModeRequest());
var nextByte = arduino.ReceiveNext();
if (nextByte == Constants.RespStkOk) return;
if (nextByte == Constants.RespStkNodevice || nextByte == Constants.RespStkFailed)
throw new ArduinoUploaderException("Unable to leave programming mode on the device!");
}
internal void ProgramDevice(MemoryBlock memoryBlock, IProgress<double> progress = null)
{
int sizeToWrite = memoryBlock.HighestModifiedOffset + 1;
var flashMem = arduino.Mcu.Flash;
int pageSize = flashMem.PageSize;
Debug.WriteLine($"Preparing to write {sizeToWrite} bytes...");
Debug.WriteLine($"Flash page size: {pageSize}.");
int offset;
for (offset = 0; offset < sizeToWrite; offset += pageSize)
{
progress?.Report((double)offset / (sizeToWrite * 2));
var needsWrite = false;
for (var i = offset; i < offset + pageSize; i++)
{
if (!memoryBlock.Cells[i].Modified) continue;
needsWrite = true;
break;
}
if (needsWrite)
{
var bytesToCopy = memoryBlock.Cells.Skip(offset).Take(pageSize).Select(x => x.Value).ToArray();
Debug.WriteLine($"Writing page at offset {offset}.");
LoadAddress(flashMem, offset);
ExecuteWritePage(flashMem, offset, bytesToCopy);
}
else
{
Debug.WriteLine("Skip writing page...");
}
}
Debug.WriteLine($"{sizeToWrite} bytes written to flash memory!");
}
internal void LoadAddress(IMemory memory, int addr)
{
Debug.WriteLine($"Sending load address request: {addr}.");
addr = addr >> 1;
arduino.SendWithSyncRetry(new LoadAddressRequest(addr));
var result = arduino.ReceiveNext();
if (result != Constants.RespStkOk)
throw new ArduinoUploaderException($"LoadAddress failed with result {result}!");
}
internal void ExecuteWritePage(IMemory memory, int offset, byte[] bytes)
{
arduino.SendWithSyncRetry(new ExecuteProgramPageRequest(memory, bytes));
var nextByte = arduino.ReceiveNext();
if (nextByte == Constants.RespStkOk) return;
throw new ArduinoUploaderException($"Write at offset {offset} failed!");
}
internal byte[] ExecuteReadPage(IMemory memory)
{
int pageSize = memory.PageSize;
arduino.SendWithSyncRetry(new ExecuteReadPageRequest(memory.Type, pageSize));
var bytes = arduino.ReceiveNext((uint)pageSize);
if (bytes == null)
throw new ArduinoUploaderException("Execute read page failed!");
var nextByte = arduino.ReceiveNext();
if (nextByte == Constants.RespStkOk) return bytes;
throw new ArduinoUploaderException("Execute read page failed!");
}
}
}