private async void ReadTcrtBtn_Click(object sender, EventArgs e) { if (_tapecartInfo == null) { return; } if (_readActive) { _readActive = false; // stop return; } // 2 mbyte tcrt file byte[] tcrtImage = new byte[0x200000 + 216]; // select tcrt file to write SaveFileDialog saveFileDialog = new SaveFileDialog(); try { saveFileDialog.Filter = "TCRT files|*.tcrt"; saveFileDialog.Title = "Select a TCRT file"; if (saveFileDialog.ShowDialog() != DialogResult.OK) { return; } // test if we can write this file File.WriteAllBytes(saveFileDialog.FileName, tcrtImage); File.Delete(saveFileDialog.FileName); } catch (Exception) { _logging.Warn(MODUL_NAME, "ReadTcrtBtn_Click", $"Error opening tcrt file for write '{Path.GetFileName(saveFileDialog.FileName)}'"); TcrtInfoTb.Text = $"Error opening TCRT file for write"; return; } TcrtFilenameTb.Text = saveFileDialog.FileName; string logFilename = Path.GetFileName(saveFileDialog.FileName); _logging.Info(MODUL_NAME, "ReadTcrtBtn_Click", $"Read file, Filename='{logFilename}' {_arduinoComm.CurrentParameter}"); // fill header with 0xFF ByteArray.Fill(tcrtImage, Tapecart.HEADER_SIZE, 0xFF, Tapecart.MAX_FLASH_SIZE); ByteArray.WriteASCIIString(tcrtImage, 0, Tapecart.TAPECART_SIGNATURE); ByteArray.WriteUInt16(tcrtImage, Tapecart.OFFSET_VERSION, Tapecart.VERSION); // we can not determine the real tcrt size, so we assume maximum flash size ByteArray.WriteInt32(tcrtImage, Tapecart.OFFSET_FLASHSIZE, Tapecart.MAX_FLASH_SIZE); // handle loader if (INCL_LOADER_IN_TCRT) { tcrtImage[Tapecart.OFFSET_FLAGS] = 0x01; byte[] loader = _arduinoComm.ReadLoader(); if (loader == null || loader.Length != Tapecart.LOADER_LENGTH) { _logging.Warn(MODUL_NAME, "ReadTcrtBtn_Click", $"Error reading loader"); TcrtInfoTb.Text = $"Error reading loader"; return; } Buffer.BlockCopy(loader, 0, tcrtImage, Tapecart.OFFSET_LOADER, Tapecart.LOADER_LENGTH); } else { tcrtImage[Tapecart.OFFSET_FLAGS] = 0x00; // filling with 0x00 is not really neccessary but makes the TCRT file equal if you compare it to existing files ByteArray.Fill(tcrtImage, Tapecart.OFFSET_LOADER, 0x00, Tapecart.LOADER_LENGTH); } // read loader info int loaderOffset; int loaderLength; int loaderCallAddr; string filename; if (!_arduinoComm.ReadLoadInfo(out loaderOffset, out loaderLength, out loaderCallAddr, out filename)) { _logging.Warn(MODUL_NAME, "ReadTcrtBtn_Click", $"Error reading loader info"); TcrtInfoTb.Text = $"Error reading loader info"; return; } ByteArray.WriteUInt16(tcrtImage, Tapecart.OFFSET_LOADER_OFFSET, (UInt16)loaderOffset); ByteArray.WriteUInt16(tcrtImage, Tapecart.OFFSET_LOADER_LENGTH, (UInt16)loaderLength); ByteArray.WriteUInt16(tcrtImage, Tapecart.OFFSET_LOADER_CALLADDR, (UInt16)loaderCallAddr); ByteArray.WriteASCIIString(tcrtImage, Tapecart.OFFSET_LOADER_NAME, filename, 0x20); int tcrtSize = Tapecart.MAX_FLASH_SIZE; TcrtInfoTb.Text = $"Loader info={loaderOffset:X4}h,{loaderLength:X4}h,{loaderCallAddr:X4}h,{filename.Trim()}"; _logging.Info(MODUL_NAME, "ReadTcrtBtn_Click", $"Loader info={loaderOffset:X4}h,{loaderLength:X4}h,{loaderCallAddr:X4}h,{filename.Trim()}"); // read flash data string btnText = ReadTcrtBtn.Text; ReadTcrtBtn.Text = "Cancel read"; WriteTcrtBtn.Enabled = false; ReadWritePb.Minimum = 0; ReadWritePb.Maximum = 100; ReadWritePb.Step = 1; ReadWritePb.Value = 0; _readActive = true; _readWriteCanceled = false; SetButtonStatus(); await Task.Run(() => { int flashOffset = 0; Crc32 calcCrc = new Crc32(); Stopwatch sw = new Stopwatch(); sw.Start(); while (flashOffset < tcrtSize) { if (!_readActive) { // cancel _readWriteCanceled = true; // <- must be set before invoke !!! UpdateReadWriteStatus("Read canceled", Color.Red); _logging.Info(MODUL_NAME, "ReadTcrtBtn_Click", $"Read canceled at {flashOffset:X6}"); UpdateReadWriteBar(0); return; } byte[] page = _arduinoComm.ReadFlashPage(flashOffset); if (page == null) { UpdateReadWriteStatus($"Error at offset={flashOffset:X6}", Color.Red); _readWriteCanceled = true; return; } calcCrc.Update(page, 0, Tapecart.BLOCK_SIZE); Buffer.BlockCopy(page, 0, tcrtImage, flashOffset + Tapecart.HEADER_SIZE, Tapecart.BLOCK_SIZE); flashOffset += Tapecart.BLOCK_SIZE; if (flashOffset % 0x1000 == 0) { if (flashOffset == 0x1000) { Helper.ControlInvokeRequired(BrowserInfoTb, () => { BrowserInfoTb.Text = TapecartBrowser.GetInfo(tcrtImage, Tapecart.HEADER_SIZE); }); } UpdateReadWriteStatus($"Reading: Offset={flashOffset:X6}h Time={Minutes(sw.ElapsedMilliseconds)}"); UpdateReadWriteBar(flashOffset * 100 / tcrtSize); } } if (ChecksumCb.Checked) { _logging.Info(MODUL_NAME, "ReadTcrtBtn_Click", "Checksum test..."); UpdateReadWriteStatus($"Checksum-Test..."); UInt32 crc; Stopwatch sw2 = new Stopwatch(); sw2.Start(); _arduinoComm.Crc32Flash(0, (int)tcrtSize, out crc); Debug.WriteLine($"crc-time={Minutes(sw2.ElapsedMilliseconds)}"); if (crc != calcCrc.Crc) { Debug.WriteLine($"checksum error calc={calcCrc.Crc:X8} flash={crc:X8}"); _logging.Warn(MODUL_NAME, "ReadTcrtBtn_Click", $"checksum error calc={calcCrc.Crc:X8} flash={crc:X8}"); UpdateReadWriteStatus($"Checksum error", Color.Red); return; } else { _logging.Info(MODUL_NAME, "ReadTcrtBtn_Click", $"checksum ok {crc:X8}"); } } _logging.Info(MODUL_NAME, "ReadTcrtBtn_Click", $"Read finished: Offset={flashOffset:X6}h Time={Minutes(sw.ElapsedMilliseconds)}"); UpdateReadWriteStatus($"Read finished: Offset={flashOffset:X6}h Time={Minutes(sw.ElapsedMilliseconds)}", Color.Green); UpdateReadWriteBar(100); }); if (!_readWriteCanceled) { // write tcrt file, should write without error because we tested it before try { File.WriteAllBytes(saveFileDialog.FileName, tcrtImage); } catch (Exception ex) { _logging.Warn(MODUL_NAME, "ReadTcrtBtn_Click", $"Error writing tcrt file '{logFilename}'"); TcrtInfoTb.Text = $"Error writing TCRT file"; } } _readActive = false; _readWriteCanceled = true; ReadTcrtBtn.Text = btnText; SetButtonStatus(); }
private async void WriteTcrtBtn_Click(object sender, EventArgs e) { if (_tapecartInfo == null) { return; } if (_writeActive) { _writeActive = false; // stop return; } // load tcrt file OpenFileDialog openFileDialog = new OpenFileDialog(); byte[] tcrtImage; try { openFileDialog.Filter = "TCRT files|*.tcrt"; openFileDialog.Title = "Select a TCRT file"; if (openFileDialog.ShowDialog() != DialogResult.OK) { return; } tcrtImage = File.ReadAllBytes(openFileDialog.FileName); } catch (Exception ex) { _logging.Warn(MODUL_NAME, "WriteTcrtBtn_Click", $"Error reading '{Path.GetFileName(openFileDialog.FileName)}'"); return; } TcrtFilenameTb.Text = openFileDialog.FileName; string logFilename = Path.GetFileName(openFileDialog.FileName); _logging.Info(MODUL_NAME, "WriteTcrtBtn_Click", $"Write file: Filename='{logFilename}' {_arduinoComm.CurrentParameter}"); // check tcrt header if (ByteArray.ReadAsciiString(tcrtImage, 0x00, 16) != Tapecart.TAPECART_SIGNATURE) { _logging.Warn(MODUL_NAME, "WriteTcrtBtn_Click", $"Invalid TCRT signature, tcrt file='{logFilename}'"); TcrtInfoTb.Text = "Invalid TCRT header"; return; } int tcrtVersion = BitConverter.ToUInt16(tcrtImage, Tapecart.OFFSET_VERSION); if (tcrtVersion != 1) { _logging.Warn(MODUL_NAME, "WriteTcrtBtn_Click", $"Invalid TCRT version, tcrt file='{logFilename}'"); TcrtInfoTb.Text = $"Invalid TCRT version {tcrtVersion}"; return; } int tcrtSize = (int)BitConverter.ToUInt32(tcrtImage, Tapecart.OFFSET_FLASHSIZE); if (tcrtSize > _tapecartInfo.TotalSize || tcrtSize < 0x1000) { _logging.Warn(MODUL_NAME, "WriteTcrtBtn_Click", $"TCRT size exceeds cartridge size, tcrt file='{logFilename}'"); TcrtInfoTb.Text = $"Invalid TCRT size {tcrtSize / 1024:X}h kB"; return; } BrowserInfoTb.Text = TapecartBrowser.GetInfo(tcrtImage, Tapecart.HEADER_SIZE); // write loader byte[] loader; int flags = tcrtImage[Tapecart.OFFSET_FLAGS]; if ((flags & 0x01) == 0) { // loader not present, use standard loader _logging.Info(MODUL_NAME, "WriteTcrtBtn_Click", $"TCRT file has no loader, using standard loader"); loader = Helper.GetEmbeddedRessource("TapecartFlasher.Resources.tapecart_loader.bin"); } else { // use loader from tcrt image _logging.Info(MODUL_NAME, "WriteTcrtBtn_Click", $"Using TCRT file loader"); loader = new byte[Tapecart.LOADER_LENGTH]; Buffer.BlockCopy(tcrtImage, Tapecart.OFFSET_LOADER, loader, 0, Tapecart.LOADER_LENGTH); } byte[] installedLoader = _arduinoComm.ReadLoader(); if (!ByteArray.CompareBytes(loader, 0, installedLoader, 0, Tapecart.LOADER_LENGTH)) { // installed loader is different, write loader if (!_arduinoComm.WriteLoader(loader)) { _logging.Warn(MODUL_NAME, "WriteTcrtBtn_Click", $"Error writing loader, tcrt file='{logFilename}'"); TcrtInfoTb.Text = $"Error writing loader"; return; } } else { _logging.Info(MODUL_NAME, "WriteTcrtBtn_Click", $"Identical loader is already installed"); } // write loadinfo int loaderOffset = BitConverter.ToUInt16(tcrtImage, Tapecart.OFFSET_LOADER_OFFSET); int loaderLength = BitConverter.ToUInt16(tcrtImage, Tapecart.OFFSET_LOADER_LENGTH); int loaderCalladdr = BitConverter.ToUInt16(tcrtImage, Tapecart.OFFSET_LOADER_CALLADDR); string filename = ByteArray.ReadAsciiString(tcrtImage, Tapecart.OFFSET_LOADER_NAME, Tapecart.LOADER_NAME_LENGTH); if (!_arduinoComm.WriteLoadInfo(loaderOffset, loaderLength, loaderCalladdr, filename)) { _logging.Warn(MODUL_NAME, "WriteTcrtBtn_Click", $"Error writing loader info, tcrt file='{logFilename}'"); TcrtInfoTb.Text = $"Error writing loader info"; return; } TcrtInfoTb.Text = $"Size={tcrtSize:X6}h Loader info={loaderOffset:X4}h,{loaderLength:X4}h,{loaderCalladdr:X4}h,{filename.Trim()}"; // write flash data string btnText = WriteTcrtBtn.Text; WriteTcrtBtn.Text = "Cancel write"; ReadTcrtBtn.Enabled = false; ReadWritePb.Minimum = 0; ReadWritePb.Maximum = 100; ReadWritePb.Step = 1; ReadWritePb.Value = 0; _writeActive = true; _readWriteCanceled = false; SetButtonStatus(); await Task.Run(() => { int flashOffset = 0; Crc32 calcCrc = new Crc32(); Stopwatch sw = new Stopwatch(); sw.Start(); while (flashOffset < tcrtSize) { if (!_writeActive) { // cancel _readWriteCanceled = true; // <- must be set before invoke !!! UpdateReadWriteStatus("Write canceled", Color.Red); _logging.Warn(MODUL_NAME, "WriteTcrtBtn_Click", $"Write canceled at {flashOffset:X6}"); UpdateReadWriteBar(0); return; } if (flashOffset % Tapecart.ERASE_SIZE == 0) { _arduinoComm.EraseFlashBlock(flashOffset); } if (!_arduinoComm.WriteFlashPage(tcrtImage, flashOffset + Tapecart.HEADER_SIZE, flashOffset)) { UpdateReadWriteStatus($"Error at offset={flashOffset:X6}", Color.Red); _logging.Warn(MODUL_NAME, "WriteTcrtBtn_Click", $"Error at offset={flashOffset:X6}"); _readWriteCanceled = true; return; } calcCrc.Update(tcrtImage, flashOffset + Tapecart.HEADER_SIZE, Tapecart.BLOCK_SIZE); flashOffset += Tapecart.BLOCK_SIZE; if (flashOffset % 0x1000 == 0) { UpdateReadWriteBar((int)(flashOffset * 100 / tcrtSize)); UpdateReadWriteStatus($"Writing: Offset={flashOffset:X6}h Time={Minutes(sw.ElapsedMilliseconds)}"); } } if (ChecksumCb.Checked) { _logging.Info(MODUL_NAME, "WriteTcrtBtn_Click", "Checksum test..."); UpdateReadWriteStatus($"Checksum-Test..."); UInt32 crc; Stopwatch sw2 = new Stopwatch(); sw2.Start(); _arduinoComm.Crc32Flash(0, (int)tcrtSize, out crc); Debug.WriteLine($"crc-time={Minutes(sw2.ElapsedMilliseconds)}"); if (crc != calcCrc.Crc) { Debug.WriteLine($"checksum error calc={calcCrc.Crc:X8} flash={crc:X8}"); _logging.Warn(MODUL_NAME, "WriteTcrtBtn_Click", $"checksum error calc={calcCrc.Crc:X8} flash={crc:X8}"); UpdateReadWriteStatus($"Checksum error", Color.Red); return; } else { _logging.Info(MODUL_NAME, "WriteTcrtBtn_Click", $"checksum ok {crc:X8}"); } } _logging.Info(MODUL_NAME, "WriteTcrtBtn_Click", $"Write finished: Offset={flashOffset:X6}h Time={Minutes(sw.ElapsedMilliseconds)}"); UpdateReadWriteStatus($"Write finished: Offset={flashOffset:X6}h Time={Minutes(sw.ElapsedMilliseconds)}", Color.Green); UpdateReadWriteBar(100); }); _readWriteCanceled = true; _writeActive = false; WriteTcrtBtn.Text = btnText; SetButtonStatus(); }