diff --git a/server.test/CommonTest.cs b/server.test/CommonTest.cs index 782a428..5d6061f 100644 --- a/server.test/CommonTest.cs +++ b/server.test/CommonTest.cs @@ -1,3 +1,4 @@ +using System.Buffers.Binary; using Common; namespace server.test; @@ -45,4 +46,16 @@ public class CommonTest Assert.Equal(Number.ToBit(0xAA, 3).Value, true); Assert.Equal(Number.ToBit(0xAA, 2).Value, false); } + + [Fact] + public void ReverseBits() + { + Assert.Equal(BinaryPrimitives.ReverseEndianness((byte)0xA0), (byte)0x50); + + var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 }; + var bytes = new byte[4]; + for (int i = 0; i < 4; i++) + bytes[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Assert.Equal(bytesSrc, new byte[] { 0xD5, 0x00, 0x00, 0x80 }); + } } diff --git a/server.test/UDPServerTest.cs b/server.test/UDPServerTest.cs index 5cde6f3..5ec27ce 100644 --- a/server.test/UDPServerTest.cs +++ b/server.test/UDPServerTest.cs @@ -92,7 +92,7 @@ public class UDPServerTest Assert.True(ret.HasValue); var data = ret.Value; Assert.Equal(address, data.Address); - Assert.Equal(number, Number.BytesToNumber(data.Data)); + Assert.Equal(number, Number.BytesToUInt32(data.Data).Value); } } @@ -112,7 +112,7 @@ public class UDPServerTest Assert.True(ret.IsSuccessful); var data = ret.Value; Assert.True(data.IsSuccessful); - Assert.Equal(number, Number.BytesToNumber(data.ToBytes())); + Assert.Equal(number, Number.BytesToUInt32(data.ToBytes()).Value); } } @@ -132,7 +132,7 @@ public class UDPServerTest Assert.True(ret.IsSuccessful); var data = ret.Value; Assert.True(data.IsSuccessful); - Assert.Equal(number, Number.BytesToNumber(data.ToBytes())); + Assert.Equal(number, Number.BytesToUInt32(data.ToBytes()).Value); } } } diff --git a/server/src/RemoteUpdate.cs b/server/src/RemoteUpdate.cs index 727f72b..72ba3c0 100644 --- a/server/src/RemoteUpdate.cs +++ b/server/src/RemoteUpdate.cs @@ -1,22 +1,24 @@ +using System.Buffers.Binary; using System.Net; using DotNext; namespace RemoteUpdate; static class RemoteUpdateClientAddr { + public const UInt32 Base = 0x20_00_00_00; /// /// ADDR: 0X00: 写Flash-读写地址——控制位
/// [31:16]: wr_sector_num
/// [15: 0]: {flash_wr_en,-,-,-, start_wr_sector}
///
- public const UInt32 WriteCtrl = 0x00; + public const UInt32 WriteCtrl = Base + 0x00; /// /// ADDR: 0X01: 写Flash-只写地址——FIFO入口
/// [31:0]: 写比特流数据入口
///
- public const UInt32 WriteFIFO = 0x01; + public const UInt32 WriteFIFO = Base + 0x01; /// /// ADDR: 0X02: 写Flash-只读地址——标志位
@@ -25,14 +27,14 @@ static class RemoteUpdateClientAddr /// [15: 8]: {-, -, -, -, -, -, -, flash_wr_done}
/// [ 7: 0]: {-, -, -, -, -, -, -, flash_clear_done}
///
- public const UInt32 WriteSign = 0x02; + public const UInt32 WriteSign = Base + 0x02; /// /// ADDR: 0X03: 读Flash-读写地址——控制位1
/// [31:16]: rd_sector_num
/// [15: 0]: {flash_rd_en,-,-,-, start_rd_sub_sector}
///
- public const UInt32 ReadCtrl1 = 0x03; + public const UInt32 ReadCtrl1 = Base + 0x03; /// /// ADDR: 0X04: 读Flash-读写地址——控制位2
@@ -41,19 +43,19 @@ static class RemoteUpdateClientAddr /// [15: 8]: {-, -, -, -, -, -, -, crc_check_en}
/// [ 7: 0]: {-, -, -, -, -, -, -, bitstream_up2cpu_en}
///
- public const UInt32 ReadCtrl2 = 0x04; + public const UInt32 ReadCtrl2 = Base + 0x04; /// /// ADDR: 0X05: 读Flash-只读地址——FIFO出口
/// [31:0]: 读比特流数据出口
///
- public const UInt32 ReadFIFO = 0x05; + public const UInt32 ReadFIFO = Base + 0x05; /// /// ADDR: 0X06: 读Flash-只读地址——CRC校验值
/// [31:0]: CRC校验值 bs_readback_crc
///
- public const UInt32 ReadCRC = 0x06; + public const UInt32 ReadCRC = Base + 0x06; /// /// ADDR: 0X07: 读Flash-只读地址——标志位
@@ -62,29 +64,27 @@ static class RemoteUpdateClientAddr /// [15: 8]: {-, -, -, -, -, -, -, flash_rd_done}
/// [ 7: 0]: {-, -, -, -, -, -, -, bs_readback_crc_valid}
///
- public const UInt32 ReadSign = 0x07; + public const UInt32 ReadSign = Base + 0x07; /// /// ADDR: 0X08: 热启动开关-读写地址——控制位
/// [31: 8]: hotreset_addr
/// [ 7: 0]: {-, -, -, -, -, -, -, hotreset_en}
///
- public const UInt32 HotResetCtrl = 0x08; + public const UInt32 HotResetCtrl = Base + 0x08; /// /// ADDR: 0X09: 只读地址 版本号
/// [31: 0]: FPGA_VERSION[31:0]
///
- public const UInt32 Version = 0x09; + public const UInt32 Version = Base + 0x09; } static class FlashAddr { - public static readonly UInt32[] Switch = { 0x0000, 0x2000, 0x4000 }; - public static readonly UInt32[] Jump = { 0x1000, 0x3000, 0x5000 }; - public static readonly UInt32[] User = { 0x406000, 0x806000, 0xC06000 }; - - public const UInt32 Golden = 0x6000; + public static readonly UInt32[] Switch = { 0xFFFF, 0x0000, 0x2000, 0x4000 }; + public static readonly UInt32[] Jump = { 0xFFFF, 0x1000, 0x3000, 0x5000 }; + public static readonly UInt32[] Bitstream = { 0x006000, 0x406000, 0x806000, 0xC06000 }; } @@ -131,7 +131,7 @@ public class RemoteUpdateClient /// [TODO:parameter] /// [TODO:parameter] /// [TODO:return] - public async ValueTask> WriteFlash(UInt32 flashAddr, int writeSectorNum, byte[] bytesData) + private async ValueTask> WriteFlash(UInt32 flashAddr, int writeSectorNum, byte[] bytesData) { // Assert if (writeSectorNum <= 0 || writeSectorNum >= FLASH_SECTOR_LENGTH) @@ -178,19 +178,19 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> EnableBitstream(int bitstreamNum) + private async ValueTask> EnableBitstream(int bitstreamNum) { // Assert if (bitstreamNum <= 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 1 ~ 3 for EnableBitstream, but given {bitstreamNum}", nameof(bitstreamNum))); var bytesData = new byte[FLASH_SECTOR_LENGTH]; Array.Fill(bytesData, 0xFF); - bytesData[FLASH_SECTOR_LENGTH - 1] = 0x01; - bytesData[FLASH_SECTOR_LENGTH - 2] = 0x33; - bytesData[FLASH_SECTOR_LENGTH - 3] = 0x2D; - bytesData[FLASH_SECTOR_LENGTH - 4] = 0x94; + bytesData[FLASH_SECTOR_LENGTH - 4] = 0x80; // 0b10000000 + bytesData[FLASH_SECTOR_LENGTH - 3] = 0xCC; // 0b11001100 + bytesData[FLASH_SECTOR_LENGTH - 2] = 0xB4; // 0b10110100 + bytesData[FLASH_SECTOR_LENGTH - 1] = 0x29; // 0b00101001 var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData); if (!ret.IsSuccessful) return new(ret.Error); @@ -202,12 +202,12 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> DisableBitstream(int bitstreamNum) + private async ValueTask> DisableBitstream(int bitstreamNum) { // Assert if (bitstreamNum <= 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 1 ~ 3 for DisableBitstream, but given {bitstreamNum}", nameof(bitstreamNum))); var bytesData = new byte[FLASH_SECTOR_LENGTH]; Array.Fill(bytesData, 0xFF); @@ -223,28 +223,68 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> WriteJumpCmd(int bitstreamNum) + private async ValueTask> WriteJumpCmd(int bitstreamNum) { // Assert if (bitstreamNum <= 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 1 ~ 3 for WriteJumpCmd, but given {bitstreamNum}", nameof(bitstreamNum))); // Init data var bytesData = new byte[FLASH_SECTOR_LENGTH]; for (int i = 0; i < FLASH_SECTOR_LENGTH; i += 4) - bytesData[i] = 0xA0; + bytesData[i] = BinaryPrimitives.ReverseEndianness((byte)0xA0); - Buffer.BlockCopy(new byte[] { 0xAB, 0x00, 0x00, 0x01 }, 0, bytesData, 0x04, 4); - Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x0B }, 0, bytesData, 0x08, 4); - Buffer.BlockCopy(new byte[] { 0xAB, 0xC0, 0x00, 0x01 }, 0, bytesData, 0x34, 4); - Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x00 }, 0, bytesData, 0x38, 4); - Buffer.BlockCopy(new byte[] { 0xAC, 0x00, 0x00, 0x01 }, 0, bytesData, 0x3C, 4); - Buffer.BlockCopy(Common.Number.NumberToBytes(FlashAddr.User[bitstreamNum], 4).Value, 0, bytesData, 0x40, 4); - Buffer.BlockCopy(new byte[] { 0xA8, 0x80, 0x00, 0x01 }, 0, bytesData, 0x44, 4); - Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x0F }, 0, bytesData, 0x48, 4); + { + var bytesSrc = new byte[] { 0xAB, 0x00, 0x00, 0x01 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x04, 4); + } + { + var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0B }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x08, 4); + } + { + var bytesSrc = new byte[] { 0xAB, 0xC0, 0x00, 0x01 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x34, 4); + } + { + var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x00 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x38, 4); + } + { + var bytesSrc = new byte[] { 0xAC, 0x00, 0x00, 0x01 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x3C, 4); + } + { + var bytesSrc = Common.Number.NumberToBytes(FlashAddr.Bitstream[bitstreamNum], 4).Value; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x40, 4); + } + { + var bytesSrc = new byte[] { 0xA8, 0x80, 0x00, 0x01 }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x44, 4); + } + { + var bytesSrc = new byte[] { 0x00, 0x00, 0x00, 0x0F }; + for (int i = 0; i < 4; i++) + bytesSrc[i] = BinaryPrimitives.ReverseEndianness(bytesSrc[i]); + Buffer.BlockCopy(bytesSrc, 0, bytesData, 0x48, 4); + } - var ret = await WriteFlash(FlashAddr.Switch[bitstreamNum], 1, bytesData); + var ret = await WriteFlash(FlashAddr.Jump[bitstreamNum], 1, bytesData); if (!ret.IsSuccessful) return new(ret.Error); return ret.Value; } @@ -254,14 +294,14 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> InitRemoteUpdate(int bitstreamNum) + private async ValueTask> InitRemoteUpdate(int bitstreamNum) { // Assert - if (bitstreamNum <= 0 || bitstreamNum > 3) + if (bitstreamNum < 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 0 ~ 3 for InitRemoteUpdate, but given {bitstreamNum}", nameof(bitstreamNum))); - for (int i = 0; i < 3; i++) + for (int i = 1; i <= 3; i++) { { var ret = (i == bitstreamNum) ? await EnableBitstream(i) : await DisableBitstream(i); @@ -284,9 +324,10 @@ public class RemoteUpdateClient /// [TODO:description] /// /// [TODO:parameter] + /// [TODO:parameter] /// [TODO:parameter] /// [TODO:return] - public async ValueTask> CheckBitstreamCRC(int bitstreamNum, UInt32 checkSum) + private async ValueTask> CheckBitstreamCRC(int bitstreamNum, int bitstreamLen, UInt32 checkSum) { { var ret = await UDPClientPool.WriteAddr(this.ep, RemoteUpdateClientAddr.ReadCtrl2, 0x00_00_00_00, this.timeout); @@ -297,7 +338,8 @@ public class RemoteUpdateClient { var ret = await UDPClientPool.WriteAddr( this.ep, RemoteUpdateClientAddr.ReadCtrl1, - Convert.ToUInt32((1024 << 16) | (1 << 15) | Convert.ToInt32(FlashAddr.User[bitstreamNum] / 4096)), this.timeout); + Convert.ToUInt32((bitstreamLen << 16) | (1 << 15) | Convert.ToInt32(FlashAddr.Bitstream[bitstreamNum] / 4096)), + this.timeout); if (!ret.IsSuccessful) return new(ret.Error); if (!ret.Value) return new(new Exception("Write read control 1 failed")); } @@ -334,16 +376,16 @@ public class RemoteUpdateClient /// /// [TODO:parameter] /// [TODO:return] - public async ValueTask> HotRest(int bitstreamNum) + private async ValueTask> HotRest(int bitstreamNum) { // Assert - if (bitstreamNum <= 0 || bitstreamNum > 3) + if (bitstreamNum < 0 || bitstreamNum > 3) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"Bitsteam num should be 0 ~ 3 for HotRest, but given {bitstreamNum}", nameof(bitstreamNum))); var ret = await UDPClientPool.WriteAddr( this.ep, RemoteUpdateClientAddr.HotResetCtrl, - ((FlashAddr.User[bitstreamNum] << 8) | 1), this.timeout); + ((FlashAddr.Bitstream[bitstreamNum] << 8) | 1), this.timeout); if (!ret.IsSuccessful) return new(ret.Error); return ret.Value; } @@ -356,10 +398,13 @@ public class RemoteUpdateClient /// [TODO:return] public async ValueTask> UpdateBitstream(int bitstreamNum, byte[] bytesData) { - // Assert - if (bitstreamNum <= 0 || bitstreamNum > 3) + if (bytesData.Length % (4 * 1024) != 0) return new(new ArgumentException( - $"Bitsteam num should be 1 ~ 3, but given {bitstreamNum}", nameof(bitstreamNum))); + $"The length of data should be divided by 4096, bug given {bytesData.Length}", nameof(bytesData))); + var bitstreamBlockNum = bytesData.Length / (4 * 1024); + + await MsgBus.UDPServer.ClearUDPData(this.address); + logger.Trace("Clear udp data finished"); { var ret = await InitRemoteUpdate(bitstreamNum); @@ -368,15 +413,57 @@ public class RemoteUpdateClient } { - var ret = await WriteFlash(FlashAddr.User[bitstreamNum], 1024, bytesData); + var ret = await WriteFlash(FlashAddr.Bitstream[bitstreamNum], bitstreamBlockNum, bytesData); if (!ret.IsSuccessful) return new(ret.Error); if (!ret.Value) return new(new Exception("Write bitstream failed")); } + { + var crc = Honoo.IO.Hashing.Crc.Create(Honoo.IO.Hashing.CrcName.CRC32_MPEG_2); + var checkSum = crc.ComputeFinal(bytesData); + var ret = await CheckBitstreamCRC(bitstreamNum, bitstreamBlockNum, checkSum.ToUInt32()); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) logger.Warn("CRC32 not correct!"); + else logger.Info("CRC32 calibration passed"); + } + { var ret = await HotRest(bitstreamNum); if (!ret.IsSuccessful) return new(ret.Error); return ret.Value; } } + + /// + /// [TODO:description] + /// + /// [TODO:parameter] + /// [TODO:return] + public async ValueTask> HotResetBitstream(int bitstreamNum) + { + await MsgBus.UDPServer.ClearUDPData(this.address); + logger.Trace("Clear udp data finished"); + + { + var ret = await InitRemoteUpdate(bitstreamNum); + if (!ret.IsSuccessful) return new(ret.Error); + if (!ret.Value) return new(new Exception("Init remote update failed")); + } + + { + var ret = await HotRest(bitstreamNum); + if (!ret.IsSuccessful) return new(ret.Error); + return ret.Value; + } + } + + public async ValueTask> UploadBitstreams( + int enableBitstreamNum, + byte[]? goldenBitream, + byte[]? bitstream1, + byte[]? bitstream2, + byte[]? bitstream3) + { + return true; + } }