From ddb712a9bb690235625e2799606564ff99be17d8 Mon Sep 17 00:00:00 2001 From: qrp73 <46676744+qrp73@users.noreply.github.com> Date: Tue, 23 Jul 2024 01:39:47 +0300 Subject: [PATCH] fix bootloader packets structure; add beacon for bootloader 5.00.01 --- AssemblyInfo.cs | 4 +-- CommandHelper.cs | 46 ++++++++++++++++++------ Packets/Packet.cs | 4 ++- Packets/PacketFlashBeaconAck.cs | 58 ++++++++++++++++++++++++------ Packets/PacketFlashWriteAck.cs | 57 +++++++++++++++++------------ Packets/PacketFlashWriteReq.cs | 63 +++++++++++++++++---------------- Program.cs | 29 ++++++++------- 7 files changed, 170 insertions(+), 91 deletions(-) diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs index d87274c..8d87d1b 100644 --- a/AssemblyInfo.cs +++ b/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.5.2.0")] -[assembly: AssemblyFileVersion("1.5.2.0")] +[assembly: AssemblyVersion("1.6.0.0")] +[assembly: AssemblyFileVersion("1.6.0.0")] diff --git a/CommandHelper.cs b/CommandHelper.cs index 8ae67b0..42466aa 100644 --- a/CommandHelper.cs +++ b/CommandHelper.cs @@ -236,13 +236,21 @@ public static bool WriteFlashUnpacked(Device device, string version, string file return CommandHelper.WriteFlash(device, version, data); } + private static uint GenerateId() + { + var random = new Random(); + return (uint)random.Next(1, int.MaxValue); + } + public static bool WriteFlash(Device device, string version, byte[] data) { if (data.Length > 0x10000) throw new ArgumentOutOfRangeException("data.Length"); - var offsetFinal = (ushort)data.Length; - if ((offsetFinal & 0xff) != 0) - offsetFinal = (ushort)((offsetFinal + 0x100) & 0xff00); + const int chunkSize = 0x100; + var chunkCount = (ushort)(data.Length / chunkSize); + if ((data.Length % chunkSize) != 0) + chunkCount++; + var offsetFinal = chunkCount * chunkSize; if (offsetFinal > FirmwareConstraints.MaxFlashAddr + 1) throw new InvalidOperationException( string.Format( @@ -250,7 +258,7 @@ public static bool WriteFlash(Device device, string version, byte[] data) data.Length, offsetFinal)); - Console.WriteLine("Write FLASH size=0x{0:x4}, offsetFinal=0x{1:x4}", data.Length, offsetFinal); + Console.WriteLine("Write FLASH size=0x{0:x4}", data.Length); Console.WriteLine("Waiting for bootloader beacon..."); var packet = device.Recv(); var pktBeacon = packet as PacketFlashBeaconAck; @@ -260,6 +268,11 @@ public static bool WriteFlash(Device device, string version, byte[] data) return false; } Console.WriteLine(" Bootloader: {0}", pktBeacon.Version); + if (pktBeacon.HdrId != PacketFlashBeaconAck.ID) + { + Logger.Error("Sorry, this bootloader is not supported yet"); + return false; + } var pktVersion = version != null ? new PacketFlashVersionReq(version) : new PacketFlashVersionReq(); @@ -274,20 +287,28 @@ public static bool WriteFlash(Device device, string version, byte[] data) } Console.WriteLine(" Bootloader: {0}", pktBeacon.Version); - return ProcessAddressSpace(0x0000, data.Length, 0x100, FirmwareConstraints.MinFlashAddr, FirmwareConstraints.MaxFlashAddr, MaxFlashBlock, + var seqId = GenerateId(); + + return ProcessAddressSpace(0x0000, data.Length, chunkSize, FirmwareConstraints.MinFlashAddr, FirmwareConstraints.MaxFlashAddr, MaxFlashBlock, (absOffset, blockOffset, blockLength) => { Console.Write(" Write {0:x4}...{1:x4}: ", absOffset, absOffset + blockLength); var subData = new byte[blockLength]; Array.Copy(data, blockOffset, subData, 0, subData.Length); - device.Send(new PacketFlashWriteReq((ushort)absOffset, offsetFinal, subData)); + var chunkNumber = (ushort)(absOffset / chunkSize); + device.Send(new PacketFlashWriteReq(chunkNumber, chunkCount, subData, seqId)); //Packet packet; - for (; ; ) + for (var counter=0; ; counter++) { packet = device.Recv(); if (packet is PacketFlashBeaconAck) Console.Write("[beacon]"); else break; + if (counter > 10) + { + Logger.Error("No response"); + return false; + } } var wrpacket = packet as PacketFlashWriteAck; if (wrpacket == null) @@ -295,14 +316,19 @@ public static bool WriteFlash(Device device, string version, byte[] data) Logger.Error("Unexpected response {0}", packet); return false; } - if (wrpacket.Offset != absOffset) + if (wrpacket.Result != 0) + { + Logger.Error("Write failed with error code {0}", wrpacket.Result); + return false; + } + if (wrpacket.ChunkNumber != chunkNumber) { - Logger.Warn("Unexpected offset in response {0}", packet); + Logger.Warn("Unexpected ChunkNumber in response {0}", packet); return false; } //if (wrpacket.Id != id) //{ - // Logger.Warn("Unexpected response Id (0x{0:x8}!=0x{1:x8})", wrpacket.Id, id); + // Logger.Warn("Unexpected response Id (0x{0:x8}!=0x{1:x8})", wrpacket.SequenceId, id); //} Console.WriteLine("OK"); return true; diff --git a/Packets/Packet.cs b/Packets/Packet.cs index 821275d..41f427b 100644 --- a/Packets/Packet.cs +++ b/Packets/Packet.cs @@ -88,7 +88,9 @@ public static Packet Deserialize(byte[] data) case PacketFlashVersionReq.ID: return new PacketFlashVersionReq(data); case PacketFlashWriteAck.ID: return new PacketFlashWriteAck(data); case PacketFlashWriteReq.ID: return new PacketFlashWriteReq(data); - + // bootloader 5.00.01 + case PacketFlashBeaconAck.ID2: return new PacketFlashBeaconAck(data); + // firmware case PacketHelloAck.ID: return new PacketHelloAck(data); case PacketHelloReq.ID: return new PacketHelloReq(data); diff --git a/Packets/PacketFlashBeaconAck.cs b/Packets/PacketFlashBeaconAck.cs index b643c0c..e4077be 100644 --- a/Packets/PacketFlashBeaconAck.cs +++ b/Packets/PacketFlashBeaconAck.cs @@ -22,14 +22,19 @@ You should have received a copy of the GNU General Public License namespace K5TOOL.Packets { + // bootloader 2: + // can be 20 bytes or 36 bytes + // for 20 bytes there is no version + // public class PacketFlashBeaconAck : Packet { public const ushort ID = 0x0518; + public const ushort ID2 = 0x057a; public PacketFlashBeaconAck(byte[] rawData) : base(rawData) { - if (base.HdrId != ID) + if (base.HdrId != ID && base.HdrId != ID2) throw new InvalidOperationException(); if (base.HdrSize < 18 || base.HdrSize > 50) { @@ -46,17 +51,40 @@ public PacketFlashBeaconAck(byte[] rawData) } } + // bootloader 2.00.06 + // 18 05 20 00 // 01 02 02 0B 0C 53 46 34 52 59 FF 08 8C 00 32 00 // 32 2E 30 30 2E 30 36 00 34 0A 00 00 00 00 00 20 - public PacketFlashBeaconAck() - : this(new byte[] { - 0x18,0x05,0x20,0x00,0x01,0x02,0x02,0x0b,0x0c,0x53,0x46,0x34,0x52,0x59,0xff,0x08, - 0x8c,0x00,0x32,0x00,0x32,0x2e,0x30,0x30,0x2e,0x30,0x36,0x00,0x34,0x0a,0x00,0x00, - 0x00,0x00,0x00,0x20 }) + // bootloader 5.00.01 + // 7a 05 20 00 + // 01 02 02 06 1c 53 50 4a 37 47 ff 10 93 00 89 00 + // 35 2e 30 30 2e 30 31 00 28 0c 00 00 00 00 00 20 + public PacketFlashBeaconAck(bool isBL5=false) + : this(isBL5 ? + Utils.FromHex("7a052000010202061c53504a3747ff1093008900352e30302e303100280c000000000020") : + Utils.FromHex("180520000102020b0c5346345259ff088c003200322e30302e303600340a000000000020")) { } - // TODO: what means first 16 bytes? + // These keys are used to encrypt data for packet id=0x0516 (CMD_NVR_PUT) + // It happens during AgencyId activation, it get 4 letter and encrypt it to 104 bytes + public uint K0 + { + get { return (uint)(_rawData[4] | (_rawData[5] << 8) | (_rawData[6] << 16) | (_rawData[7] << 24)); } + } + public uint K1 + { + get { return (uint)(_rawData[8] | (_rawData[9] << 8) | (_rawData[10] << 16) | (_rawData[11] << 24)); } + } + public uint K2 + { + get { return (uint)(_rawData[12] | (_rawData[13] << 8) | (_rawData[14] << 16) | (_rawData[15] << 24)); } + } + public uint K3 + { + get { return (uint)(_rawData[16] | (_rawData[17] << 8) | (_rawData[18] << 16) | (_rawData[19] << 24)); } + } + public string Version { @@ -79,14 +107,22 @@ public override string ToString() { return string.Format( "{0} {{\n" + - " HdrSize={1}\n" + - " Version=\"{2}\"\n"+ - " Data={3}\n" + + " HdrId=0x{1:x4}\n" + + " HdrSize={2}\n" + + " Version=\"{3}\"\n"+ + " K0=0x{4:x8}\n" + + " K1=0x{5:x8}\n" + + " K2=0x{6:x8}\n" + + " K3=0x{7:x8}\n" + "}}", this.GetType().Name, + HdrId, HdrSize, Version, - Utils.ToHex(_rawData.Skip(4).Take(0x10))); + K0, + K1, + K2, + K3); } } } diff --git a/Packets/PacketFlashWriteAck.cs b/Packets/PacketFlashWriteAck.cs index 23d6c26..7794c4d 100644 --- a/Packets/PacketFlashWriteAck.cs +++ b/Packets/PacketFlashWriteAck.cs @@ -19,7 +19,9 @@ You should have received a copy of the GNU General Public License using System; namespace K5TOOL.Packets { - // ?? 1a050800 8a8d9f1d 0000 0000 + // OK: 1a0508008a8d9f1d00000000 + // bad id: 1a0508000000000000000100 + // bad ver: 1a0508000000000000000100 public class PacketFlashWriteAck : Packet { public const ushort ID = 0x051a; @@ -35,12 +37,12 @@ public PacketFlashWriteAck(byte[] rawData) } } - public PacketFlashWriteAck(ushort offset, uint id = 0x1d9f8d8a) - : this(MakePacketBuffer(id, offset, 0x0000)) + public PacketFlashWriteAck(ushort chunkNumber, uint sequenceId = 0x1d9f8d8a) + : this(MakePacketBuffer(sequenceId, chunkNumber, 0x0000)) { } - private static byte[] MakePacketBuffer(uint id, ushort offset, ushort padding) + private static byte[] MakePacketBuffer(uint sequenceId, ushort chunkNumber, ushort padding) { var hdrSize = 8; var buf = new byte[12]; @@ -48,30 +50,37 @@ private static byte[] MakePacketBuffer(uint id, ushort offset, ushort padding) buf[1] = 0x05; buf[2] = (byte)hdrSize; buf[3] = (byte)(hdrSize >> 8); - buf[4] = (byte)id; - buf[5] = (byte)(id >> 8); - buf[6] = (byte)(id >> 16); - buf[7] = (byte)(id >> 24); - buf[8] = (byte)(offset >> 8); - buf[9] = (byte)offset; - buf[10] = (byte)(padding >> 8); - buf[11] = (byte)padding; + buf[4] = (byte)sequenceId; + buf[5] = (byte)(sequenceId >> 8); + buf[6] = (byte)(sequenceId >> 16); + buf[7] = (byte)(sequenceId >> 24); + buf[8] = (byte)chunkNumber; + buf[9] = (byte)(chunkNumber >> 8); + buf[10] = (byte)padding; + buf[11] = (byte)(padding >> 8); return buf; } - public uint Id + public uint SequenceId { get { return (uint)(_rawData[4] | (_rawData[5] << 8) | (_rawData[6] << 16) | (_rawData[7] << 24)); } } - public ushort Offset + public ushort ChunkNumber { - get { return (ushort)((_rawData[8] << 8) | _rawData[9]); } + get { return (ushort)(_rawData[8] | (_rawData[9] << 8)); } } - public ushort Padding + // 0=OK + // 1=Error + public byte Result { - get { return (ushort)((_rawData[10] << 8) | _rawData[11]); } + get { return _rawData[10]; } + } + // What is this? + public byte V0 + { + get { return _rawData[11]; } } public override string ToString() @@ -79,15 +88,17 @@ public override string ToString() return string.Format( "{0} {{\n" + " HdrSize={1}\n" + - " Id=0x{2:x8}\n" + - " Offset=0x{3:x4}\n" + - " Padding=0x{4:x4}\n" + + " SequenceId=0x{2:x8}\n" + + " ChunkNumber=0x{3:x4}\n" + + " Result={4}\n" + + " V0={5}\n" + "}}", this.GetType().Name, HdrSize, - Id, - Offset, - Padding); + SequenceId, + ChunkNumber, + Result, + V0); } } } diff --git a/Packets/PacketFlashWriteReq.cs b/Packets/PacketFlashWriteReq.cs index 16ef1b6..ad1a89c 100644 --- a/Packets/PacketFlashWriteReq.cs +++ b/Packets/PacketFlashWriteReq.cs @@ -38,26 +38,30 @@ public PacketFlashWriteReq(byte[] rawData) } } - public PacketFlashWriteReq(ushort offset, ushort offsetFinal, byte[] data, uint id=0x1d9f8d8a) - : base(MakePacketBuffer(id, offset, offsetFinal, data, 0x0000)) + public PacketFlashWriteReq(ushort chunkNumber, ushort chunkCount, byte[] data) + : this(chunkNumber, chunkCount, data, 0x1d9f8d8a) { - if (offsetFinal < offset+0x100) - throw new ArgumentOutOfRangeException("offsetFinal"); - if (offset + 0x100 > FirmwareConstraints.MaxFlashAddr+1 || offsetFinal > FirmwareConstraints.MaxFlashAddr+1) + } + + public PacketFlashWriteReq(ushort chunkNumber, ushort chunkCount, byte[] data, uint id/*=0x1d9f8d8a*/) + : base(MakePacketBuffer(id, chunkNumber, chunkCount, data, 0x0000)) + { + if (chunkNumber > chunkCount) + throw new ArgumentOutOfRangeException("chunkNumber"); + if (chunkCount > FirmwareConstraints.MaxFlashAddr + 1) throw new InvalidOperationException( string.Format( - "DANGEROUS FLASH ADDRESS WRITE! offset=0x{0:x4}, offsetFinal=0x{1:x4}", - offset + 0x100, - offsetFinal)); + "chunkCount={0:x4}!", + chunkCount)); } // 0x19, 0x5, 0xc, 0x1, 0x8a, 0x8d, 0x9f, 0x1d, address_msb, address_lsb, address_final_msb, address_final_lsb, length_msb, length_lsb, 0x0, 0x0, ...data - private static byte[] MakePacketBuffer(uint id, ushort offset, ushort offsetFinal, byte[] data, ushort padding) + private static byte[] MakePacketBuffer(uint id, ushort chunkNumber, ushort chunkCount, byte[] data, ushort padding) { if (data.Length > 0x100) throw new ArgumentOutOfRangeException("data"); - if ((offsetFinal & 0x00ff) != 0) - throw new ArgumentOutOfRangeException("offsetFinal"); + if ((chunkCount & 0xff00) != 0) + throw new ArgumentOutOfRangeException("chunkCount>0x100 is not tested yet"); var length = data.Length; var buf = new byte[16 + 0x100]; var hdrSize = buf.Length - 4; @@ -71,34 +75,31 @@ private static byte[] MakePacketBuffer(uint id, ushort offset, ushort offsetFina buf[5] = (byte)(id >> 8); // 0x8d buf[6] = (byte)(id >> 16); // 0x9f buf[7] = (byte)(id >> 24); // 0x1d - buf[8] = (byte)(offset >> 8); // why reverse? - buf[9] = (byte)offset; - buf[10] = (byte)(offsetFinal >> 8); // why reverse? - buf[11] = (byte)offsetFinal; // always 0x00? - buf[12] = (byte)length; // wtf??? - buf[13] = (byte)(length >> 8); // wtf??? + buf[8] = (byte)chunkNumber; + buf[9] = (byte)(chunkNumber >> 8); + buf[10] = (byte)chunkCount; + buf[11] = (byte)(chunkCount >> 8); + buf[12] = (byte)length; + buf[13] = (byte)(length >> 8); buf[14] = (byte)padding; // 0x00 buf[15] = (byte)(padding >> 8); // 0x00 Array.Copy(data, 0, buf, 16, data.Length); return buf; } - // ??? random id don't works! - // 0x1d9f8d8a - public uint Id + public uint SequenceId { get { return (uint)(_rawData[4] | (_rawData[5] << 8) | (_rawData[6] << 16) | (_rawData[7] << 24)); } } - public ushort Offset + public ushort ChunkNumber { - get { return (ushort)(_rawData[9] | (_rawData[8] << 8)); } + get { return (ushort)(_rawData[8] | (_rawData[9] << 8)); } } - // expected last write per session 0xe600 - public ushort OffsetFinal + public ushort ChunkCount { - get { return (ushort)(_rawData[11] | (_rawData[10] << 8)); } + get { return (ushort)(_rawData[10] | (_rawData[11] << 8)); } } public ushort Size @@ -126,18 +127,18 @@ public override string ToString() return string.Format( "{0} {{\n" + " HdrSize={1}\n" + - " Id=0x{2:x8}\n" + - " Offset=0x{3:x4}\n" + - " OffsetFinal=0x{4:x4}\n" + + " SequenceId=0x{2:x8}\n" + + " ChunkNumber=0x{3:x4}\n" + + " ChunkCount=0x{4:x4}\n" + " Size=0x{5:x2}\n" + " Padding=0x{6:x4}\n" + " Data={7}\n" + "}}", this.GetType().Name, HdrSize, - Id, - Offset, - OffsetFinal, + SequenceId, + ChunkNumber, + ChunkCount, Size, Padding, Utils.ToHex(Data)); diff --git a/Program.cs b/Program.cs index b4a7052..b4075af 100644 --- a/Program.cs +++ b/Program.cs @@ -393,10 +393,11 @@ private static int OnCommand_Simula(string name, string[] v) var isMute = false; byte[] fwdata = null; string fwvers = null; + var packetFlashBeacon = new PacketFlashBeaconAck(false); for (; ; ) { if (!isMute) - device.Send(new PacketFlashBeaconAck()); + device.Send(packetFlashBeacon); try { var packet = device.Recv(); @@ -406,34 +407,36 @@ private static int OnCommand_Simula(string name, string[] v) { fwvers = packetVer.Version; Console.WriteLine("flashVersion: {0}", packetVer.Version); - device.Send(new PacketFlashBeaconAck()); + continue; + //device.Send(packetFlashBeacon); } var packetWrite = packet as PacketFlashWriteReq; if (packetWrite != null) { - Console.WriteLine("flash offset=0x{0:x4}, size=0x{1:x4}, offsetFinal=0x{2:x4}", packetWrite.Offset, packetWrite.Size, packetWrite.OffsetFinal); + Console.WriteLine("flash chunkNumber=0x{0:x4}, size=0x{1:x4}, chunkCount=0x{2:x4}", packetWrite.ChunkNumber, packetWrite.Size, packetWrite.ChunkCount); if (fwdata == null) { - fwdata = new byte[packetWrite.OffsetFinal]; - if (packetWrite.Offset != 0) + fwdata = new byte[packetWrite.ChunkCount*0x100]; + if (packetWrite.ChunkNumber != 0) { - Console.WriteLine("WARN: started from offset=0x{0:x4}", packetWrite.Offset); + Console.WriteLine("WARN: started from chunkNumber=0x{0:x4}", packetWrite.ChunkNumber); } } - else if (fwdata.Length != packetWrite.OffsetFinal) + else if (fwdata.Length != packetWrite.ChunkCount*0x100) { - Console.WriteLine("WARN: offsetFinal unexpectedly changed 0x{0:x4} => 0x{1:x4}", fwdata.Length, packetWrite.OffsetFinal); - if (fwdata.Length < packetWrite.OffsetFinal) + Console.WriteLine("WARN: chunkCount unexpectedly changed 0x{0:x4} => 0x{1:x4}", fwdata.Length/0x100, packetWrite.ChunkCount); + var expectedSize = packetWrite.ChunkCount * 0x100; + if (fwdata.Length < expectedSize) { - var buf = new byte[packetWrite.OffsetFinal]; + var buf = new byte[expectedSize]; Array.Copy(fwdata, buf, fwdata.Length); } } //Array.Copy(packetWrite.Data, 0, fwdata, packetWrite.Offset, packetWrite.Size); - Array.Copy(packetWrite.RawData, 16, fwdata, packetWrite.Offset, packetWrite.HdrSize - 12); + Array.Copy(packetWrite.RawData, 16, fwdata, packetWrite.ChunkNumber*0x100, packetWrite.HdrSize - 12); // detect flashing complete event - if (((packetWrite.Offset+0x100)&0xff00) == packetWrite.OffsetFinal) + if (packetWrite.ChunkNumber == packetWrite.ChunkCount-1) { var shrink = 0x100 - packetWrite.Size; //var shrink = 0; @@ -446,7 +449,7 @@ private static int OnCommand_Simula(string name, string[] v) fwdata = null; } - device.Send(new PacketFlashWriteAck(packetWrite.Offset, packetWrite.Id)); + device.Send(new PacketFlashWriteAck(packetWrite.ChunkNumber, packetWrite.SequenceId)); } isMute = true; }