void SendFirmwareBlock(byte[] data, int length) { int i = 0; int part = 0; byte[] crc16; Console.WriteLine("sending block 0x{0:X02} 0x{1:X04} 0x{2:X04}", LastBinBlock + CurrentUpdateFiles[CurrentUpdateFileIndex].blockOffset, LastBinBlock * CurrentUpdateFiles[CurrentUpdateFileIndex].blockSize, length); for (i = 0; i < length; i += 8) { //build Message Id containing current part number LastSentFrame = new CANMessage(BuildCANId(CANMaerklinCommand.Bootloader, 0x0300) + (byte)part, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00 }); part++; Array.Copy(data, i, LastSentFrame.Data, 0, 8); serialCAN.SendCAN(LastSentFrame); } LastSentFrame = new CANMessage(BuildCANId(CANMaerklinCommand.Bootloader, CS2AddressHash), new byte[] { 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00 }); Array.Copy(CurrentDeviceId.HexStringToByteArray(), 0, LastSentFrame.Data, 0, 4); Crc16Ccitt crc16Ccitt = new Crc16Ccitt(InitialCrcValue.NonZero1); crc16 = crc16Ccitt.ComputeChecksumBytes(data.Take(length).ToArray()).ToBigEndian(); LastSentFrame.Data[5] = crc16[0]; LastSentFrame.Data[6] = crc16[1]; Console.WriteLine("block checksum 0x{0}", crc16.ByteArrayToHexString()); serialCAN.SendCAN(LastSentFrame); }
private void SerialCAN_CANMessageReceived(object sender, CANMessageReceivedEventArgs e) { int requestedBlockIndex; if (UpdateRunning) { switch ((CANMaerklinCommand)(e.CANMessage.Id & 0xFFFF0000UL)) { case (CANMaerklinCommand.Ping): Console.WriteLine("received CAN Ping {0}\n", e.CANMessage); if (CurrentDeviceHash == (e.CANMessage.Id & 0x00FFFF)) { if (!FileUpdateRunning) { //Ping received from update device so we expect the File update has been completed Console.WriteLine("UPDATE COMPLETE"); UpdateCompletedAutoResetEvent.Set(); UpdateRunning = false; } } break; case (CANMaerklinCommand.PingRsp): Console.WriteLine("received CAN Ping answer from Device {0}\n", (DeviceType)(e.CANMessage.Data[0])); if ((e.CANMessage.Data.Length == 8) && (e.CANMessage.Data[0] == (byte)DeviceType)) { string deviceVersion = string.Format("{0}.{1}", e.CANMessage.Data[4], e.CANMessage.Data[5]); switch ((DeviceType)e.CANMessage.Data[0]) { case DeviceType.GB2: Console.WriteLine("found Gleisbox with ID 0x{0} Version {1}\n", CurrentDeviceId, deviceVersion); CurrentDeviceId = GetDeviceIdFromCanMessage(e.CANMessage); CurrentDeviceHash = e.CANMessage.Id & 0x00FFFF; PingReceived = true; break; case DeviceType.MS2: Console.WriteLine("found MS2 with ID 0x{0} Version {1}\n", CurrentDeviceId, deviceVersion); CurrentDeviceId = GetDeviceIdFromCanMessage(e.CANMessage); CurrentDeviceHash = e.CANMessage.Id & 0x00FFFF; PingReceived = true; break; } if (IsFirmwareUpdate) { StartFirmwareUpdateProcedure(deviceVersion); } else { StartConfigFileSend(); } } break; case CANMaerklinCommand.BootloaderRsp: //Firmware update process if (PingReceived) { if (e.CANMessage.Data.Length == 8 && GetDeviceIdFromCanMessage(e.CANMessage) == CurrentDeviceId && ((e.CANMessage.Data[7] == 0x10) || (e.CANMessage.Data[7] == 0x32))) { Console.WriteLine("Send initial block id"); SendInitialBlockId(e.CANMessage); } else { /* first data block */ if (LastSentFrame == null || e.CANMessage.Data.ByteArrayEquals(LastSentFrame.Data) && LastBinBlock == TotalBlocksToSend) { Console.WriteLine("Send first data block"); SendFirmwareBlock(DataBytesToSendWithPadding.Skip(LastBinBlock * (int)CurrentUpdateFiles[CurrentUpdateFileIndex].blockSize).ToArray(), DataBytesToSendWithPadding.Length - TotalBlocksToSend * (int)CurrentUpdateFiles[CurrentUpdateFileIndex].blockSize); LastBinBlock--; } else { //there seems to be different NACK types : 0xF1 and 0xF2 if (CheckFrameNack != null && e.CANMessage.Data.Length >= 5 && CheckFrameNack.Data.Length >= 5 && e.CANMessage.Id == CheckFrameNack.Id && e.CANMessage.Data.Take(4).ToArray().ByteArrayEquals(CheckFrameNack.Data.Take(4).ToArray()) && (e.CANMessage.Data[4] == 0xF1 || e.CANMessage.Data[4] == 0xF2) ) { Console.WriteLine("Aiiee got NACK. Aborting"); UpdateCompletedAutoResetEvent.Set(); UpdateRunning = false; } //MS2 may use 0x0000 as hash -> compare CheckFrameBlockId full 8 bytes if (CheckFrameBlockId != null && e.CANMessage.Data.ByteArrayEquals(CheckFrameBlockId.Data)) { SendFirmwareBlock(DataBytesToSendWithPadding.Skip(LastBinBlock * (int)CurrentUpdateFiles[CurrentUpdateFileIndex].blockSize).ToArray(), (int)CurrentUpdateFiles[CurrentUpdateFileIndex].blockSize); //firmware flashing has to be sent in reversed order LastBinBlock--; } //MS2 may use 0x0000 as hash -> compare CheckFrame full 8 bytes if (CheckFrame != null && e.CANMessage.Data.Length == CheckFrame.Data.Length && e.CANMessage.Data.Take(5).ToArray().ByteArrayEquals(CheckFrame.Data.Take(5).ToArray())) { if ((LastBinBlock >= 0)) { SendNextBlockId((byte)(LastBinBlock + CurrentUpdateFiles[CurrentUpdateFileIndex].blockOffset)); } else { if (DeviceType == DeviceType.MS2) { Console.WriteLine("Reboot MS2 - be patient..."); //end of update LastSentFrame = new CANMessage(BuildCANId(CANMaerklinCommand.Bootloader, CS2AddressHash), new byte[] { 0x00, 0x00, 0x00, 0x00, 0xf5 }); Array.Copy(CurrentDeviceId.HexStringToByteArray(), 0, LastSentFrame.Data, 0, 4); serialCAN.SendCAN(LastSentFrame); Thread.Sleep(1000); //soft reset LastSentFrame = new CANMessage(BuildCANId(CANMaerklinCommand.Bootloader, CS2AddressHash), new byte[] { 0x00, 0x00, 0x00, 0x00, 0x11 }); Array.Copy(CurrentDeviceId.HexStringToByteArray(), 0, LastSentFrame.Data, 0, 4); serialCAN.SendCAN(LastSentFrame); Thread.Sleep(13000); //Start updating MS2 files StartConfigFileSend(); } else { Console.WriteLine("UPDATE COMPLETE"); UpdateCompletedAutoResetEvent.Set(); UpdateRunning = false; } } } } } } break; case CANMaerklinCommand.ConfigDataQuery: //Send/Update CONFIG DATA if (e.CANMessage.Data.ByteArrayToHexString() == "6666666666666666") { if (RequestedConfigNameData.EndsWith("ver")) { if (AckconfigFileRequestFrame != null) { serialCAN.SendCAN(AckconfigFileRequestFrame); } //Send config data LastBinBlock = 0; PrepareCS2FileVersionInfoToSend(CurrentUpdateFiles[CurrentUpdateFileIndex]); byte[] fileSizeBytes = BitConverter.GetBytes(FileLength).ToBigEndian(); Array.Copy(fileSizeBytes, LastSentFrame.Data, 4); Crc16Ccitt crc16Ccitt = new Crc16Ccitt(InitialCrcValue.NonZero1); LastSentFrame.Id = BuildCANId(CANMaerklinCommand.ConfigDataStream, e.CANMessage.Id & 0x00FFFF); var crc16 = crc16Ccitt.ComputeChecksumBytes(DataBytesToSendWithPadding).ToBigEndian(); LastSentFrame.Data[4] = crc16[0]; LastSentFrame.Data[5] = crc16[1]; Console.WriteLine("block checksum 0x{0}", crc16.ByteArrayToHexString()); serialCAN.SendCAN(LastSentFrame); //send all data for (int i = 0; i < DataBytesToSendWithPadding.Length; i += 8) { LastSentFrame.Data = new byte[8]; Array.Copy(DataBytesToSendWithPadding, i, LastSentFrame.Data, 0, 8); serialCAN.SendCAN(LastSentFrame); } Console.WriteLine("Data sent."); } } else if (e.CANMessage.Data.ByteArrayToHexString().Substring(6) == "0000000000" && int.TryParse(Encoding.ASCII.GetString(e.CANMessage.Data).Trim('\0'), out requestedBlockIndex)) { FileUpdateRunning = true; if (!string.IsNullOrEmpty(RequestedConfigNameData)) { Console.WriteLine("Request file {0} block {1}", RequestedConfigNameData, requestedBlockIndex); byte[] bytesToSend = DataBytesToSendWithPadding.Skip(requestedBlockIndex * CurrentUpdateFiles[CurrentUpdateFileIndex].blockSize).Take(CurrentUpdateFiles[CurrentUpdateFileIndex].blockSize).ToArray(); //check if requested block is last block if (DataBytesToSendWithPadding.Length / CurrentUpdateFiles[CurrentUpdateFileIndex].blockSize == requestedBlockIndex) { FileUpdateRunning = false; } byte[] fileSizeBytes = BitConverter.GetBytes(bytesToSend.Length).ToBigEndian(); //Prepare messages for later sending (FFFFFF... message) AckconfigFileRequestFrame = e.CANMessage.Clone(); AckconfigFileRequestFrame.Id = BuildCANId(CANMaerklinCommand.ConfigDataQueryRsp, CS2AddressHash); serialCAN.SendCAN(AckconfigFileRequestFrame); Array.Copy(fileSizeBytes, LastSentFrame.Data, 4); Crc16Ccitt crc16Ccitt = new Crc16Ccitt(InitialCrcValue.NonZero1); LastSentFrame.Id = BuildCANId(CANMaerklinCommand.ConfigDataStream, e.CANMessage.Id & 0x00FFFF); var crc16 = crc16Ccitt.ComputeChecksumBytes(bytesToSend).ToBigEndian(); LastSentFrame.Data[4] = crc16[0]; LastSentFrame.Data[5] = crc16[1]; Console.WriteLine("block checksum 0x{0}", crc16.ByteArrayToHexString()); Thread.Sleep(100); serialCAN.SendCAN(LastSentFrame); //send block LastSentFrame.Id = BuildCANId(CANMaerklinCommand.ConfigDataStream, e.CANMessage.Id & 0x00FFFF); for (int i = 0; i < bytesToSend.Length; i += 8) { LastSentFrame.Data = new byte[8]; Array.Copy(bytesToSend, i, LastSentFrame.Data, 0, 8); serialCAN.SendCAN(LastSentFrame); } } } else { RequestedConfigNameData = Encoding.ASCII.GetString(e.CANMessage.Data).Trim('\0'); CurrentUpdateFileIndex = Array.FindIndex(ms2_update_data, x => x.versionName == RequestedConfigNameData); if (Array.Exists(ms2_update_data, x => x.versionName == RequestedConfigNameData)) { //CS2 version string request Console.WriteLine("Request .CS2 fileinfo {0}", RequestedConfigNameData); CurrentUpdateFileIndex = Array.FindIndex(ms2_update_data, x => x.versionName == RequestedConfigNameData); LastSentFrame = new CANMessage(BuildCANId(CANMaerklinCommand.ConfigDataStream, CS2AddressHash), new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); //Prepare messages for later sending (FFFFFF... message) AckconfigFileRequestFrame = e.CANMessage.Clone(); AckconfigFileRequestFrame.Id = BuildCANId(CANMaerklinCommand.ConfigDataQueryRsp, CS2AddressHash); } else if (Array.Exists(ms2_update_data, x => x.name == RequestedConfigNameData)) { //File data request Console.WriteLine("Request file {0}", RequestedConfigNameData); CurrentUpdateFileIndex = Array.FindIndex(ms2_update_data, x => x.name == RequestedConfigNameData); ReadFirmwareFile(CurrentUpdateFiles[CurrentUpdateFileIndex], false); LastSentFrame = new CANMessage(BuildCANId(CANMaerklinCommand.ConfigDataStream, CS2AddressHash), new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); AckconfigFileRequestFrame = e.CANMessage.Clone(); AckconfigFileRequestFrame.Id = BuildCANId(CANMaerklinCommand.ConfigDataStreamRsp, CS2AddressHash); } else { Console.WriteLine("Couldn't find requested file {0}", RequestedConfigNameData); } } break; default: break; } } }