feat: 完成jpeg后端
This commit is contained in:
@@ -12,7 +12,7 @@ static class HdmiInAddr
|
||||
public const UInt32 HdmiIn_READFIFO = BASE + 0x1;
|
||||
}
|
||||
|
||||
class HdmiIn
|
||||
public class HdmiIn
|
||||
{
|
||||
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
|
||||
@@ -7,14 +7,28 @@ namespace Peripherals.JpegClient;
|
||||
static class JpegAddr
|
||||
{
|
||||
const UInt32 BASE = 0x0000_0000;
|
||||
public const UInt32 ENABLE = BASE + 0x0;
|
||||
public const UInt32 FRAME_NUM = BASE + 0x1;
|
||||
public const UInt32 FRAME_INFO = BASE + 0x2;
|
||||
public const UInt32 FRAME_SAMPLE_RATE = BASE + 0x3;
|
||||
public const UInt32 FRAME_DATA_MAX_POINTER = BASE + 0x4;
|
||||
|
||||
public const UInt32 DDR_FRAME_DATA_ADDR = 0x0000_0000;
|
||||
public const UInt32 DDR_FRAME_DATA_MAX_ADDR = 0x8000_0000;
|
||||
public const UInt32 CAPTURE_RD_CTRL = BASE + 0x0;
|
||||
public const UInt32 CAPTURE_WR_CTRL = BASE + 0x1;
|
||||
|
||||
public const UInt32 START_WR_ADDR0 = BASE + 0x2;
|
||||
public const UInt32 END_WR_ADDR0 = BASE + 0x3;
|
||||
public const UInt32 START_WR_ADDR1 = BASE + 0x4;
|
||||
public const UInt32 END_WR_ADDR1 = BASE + 0x5;
|
||||
public const UInt32 START_RD_ADDR0 = BASE + 0x6;
|
||||
public const UInt32 END_RD_ADDR0 = BASE + 0x7;
|
||||
|
||||
public const UInt32 HDMI_NOT_READY = BASE + 0x8;
|
||||
public const UInt32 HDMI_HEIGHT_WIDTH = BASE + 0x9;
|
||||
|
||||
public const UInt32 JPEG_HEIGHT_WIDTH = BASE + 0xA;
|
||||
public const UInt32 JPEG_ADD_NEED_FRAME_NUM = BASE + 0xB;
|
||||
public const UInt32 JPEG_FRAME_SAVE_NUM = BASE + 0xC;
|
||||
public const UInt32 JPEG_FIFO_FRAME_INFO = BASE + 0xD;
|
||||
|
||||
public const UInt32 ADDR_HDMI_WD_START = 0x4000_0000;
|
||||
public const UInt32 ADDR_JPEG_START = 0x8000_0000;
|
||||
public const UInt32 ADDR_JPEG_END = 0xA000_0000;
|
||||
}
|
||||
|
||||
public class JpegInfo
|
||||
@@ -79,39 +93,248 @@ public class Jpeg
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public async ValueTask<Result<bool>> Init(bool enable = true)
|
||||
{
|
||||
{
|
||||
var ret = await CheckHdmiIsReady();
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to check HDMI ready: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error("HDMI not ready");
|
||||
return new(false);
|
||||
}
|
||||
}
|
||||
|
||||
int width = -1, height = -1;
|
||||
{
|
||||
var ret = await GetHdmiResolution();
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get HDMI resolution: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
(width, height) = ret.Value;
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await ConnectJpeg2Hdmi(width, height);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to connect JPEG to HDMI: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error("Failed to connect JPEG to HDMI");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (enable)
|
||||
return await SetEnable(true);
|
||||
else return true;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> SetEnable(bool enable)
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.ENABLE, Convert.ToUInt32(enable), this.timeout);
|
||||
if (enable)
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddrSeq(
|
||||
this.ep,
|
||||
this.taskID,
|
||||
[JpegAddr.CAPTURE_RD_CTRL, JpegAddr.CAPTURE_WR_CTRL],
|
||||
[0b11, 0b01],
|
||||
this.timeout
|
||||
);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set JPEG enable: {ret.Error}");
|
||||
return false;
|
||||
}
|
||||
return ret.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddrSeq(
|
||||
this.ep,
|
||||
this.taskID,
|
||||
[JpegAddr.CAPTURE_RD_CTRL, JpegAddr.CAPTURE_WR_CTRL],
|
||||
[0b00, 0b00],
|
||||
this.timeout
|
||||
);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set JPEG disable: {ret.Error}");
|
||||
return false;
|
||||
}
|
||||
return ret.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<Result<bool>> CheckHdmiIsReady()
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddrWithWait(
|
||||
this.ep, this.taskID, JpegAddr.HDMI_NOT_READY, 0b01, 0b01, 100, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set JPEG enable: {ret.Error}");
|
||||
return false;
|
||||
logger.Error($"Failed to check HDMI status: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
return ret.Value;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> SetSampleRate(uint rate)
|
||||
public async ValueTask<Result<(int, int)>> GetHdmiResolution()
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.FRAME_SAMPLE_RATE, rate, this.timeout);
|
||||
var ret = await UDPClientPool.ReadAddr(
|
||||
this.ep, this.taskID, JpegAddr.HDMI_HEIGHT_WIDTH, 0, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set JPEG sample rate: {ret.Error}");
|
||||
return false;
|
||||
logger.Error($"Failed to get HDMI resolution: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
return ret.Value;
|
||||
|
||||
var data = ret.Value.Options.Data;
|
||||
if (data == null || data.Length != 4)
|
||||
{
|
||||
logger.Error($"Invalid HDMI resolution data length: {data?.Length ?? 0}");
|
||||
return new(new Exception("Invalid HDMI resolution data length"));
|
||||
}
|
||||
|
||||
var width = data[0] | (data[1] << 8);
|
||||
var height = data[2] | (data[3] << 8);
|
||||
return new((width, height));
|
||||
}
|
||||
|
||||
public async ValueTask<bool> SetSampleRate(JpegSampleRate rate)
|
||||
public async ValueTask<Result<bool>> ConnectJpeg2Hdmi(int width, int height)
|
||||
{
|
||||
return await SetSampleRate((uint)rate);
|
||||
if (width <= 0 || height <= 0)
|
||||
{
|
||||
logger.Error($"Invalid HDMI resolution: {width}x{height}");
|
||||
return new(new ArgumentException("Invalid HDMI resolution"));
|
||||
}
|
||||
|
||||
var frameSize = (UInt32)(width * height / 4);
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.START_WR_ADDR0, JpegAddr.ADDR_HDMI_WD_START, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set HDMI output start address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set HDMI output start address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.END_WR_ADDR0,
|
||||
JpegAddr.ADDR_HDMI_WD_START + frameSize, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set HDMI output end address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set HDMI output address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.START_RD_ADDR0, JpegAddr.ADDR_HDMI_WD_START, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg input start address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg input address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.END_RD_ADDR0,
|
||||
JpegAddr.ADDR_HDMI_WD_START + frameSize, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg input end address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg input end address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.START_WR_ADDR1, JpegAddr.ADDR_JPEG_START, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg output start address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg output start address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.END_WR_ADDR1, JpegAddr.ADDR_JPEG_END, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg output end address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg output end address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// public async ValueTask<bool> SetSampleRate(uint rate)
|
||||
// {
|
||||
// var ret = await UDPClientPool.WriteAddr(
|
||||
// this.ep, this.taskID, JpegAddr.FRAME_SAMPLE_RATE, rate, this.timeout);
|
||||
// if (!ret.IsSuccessful)
|
||||
// {
|
||||
// logger.Error($"Failed to set JPEG sample rate: {ret.Error}");
|
||||
// return false;
|
||||
// }
|
||||
// return ret.Value;
|
||||
// }
|
||||
|
||||
// public async ValueTask<bool> SetSampleRate(JpegSampleRate rate)
|
||||
// {
|
||||
// return await SetSampleRate((uint)rate);
|
||||
// }
|
||||
|
||||
public async ValueTask<uint> GetFrameNumber()
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddrByte(
|
||||
this.ep, this.taskID, JpegAddr.FRAME_NUM, this.timeout);
|
||||
this.ep, this.taskID, JpegAddr.JPEG_FRAME_SAVE_NUM, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get JPEG frame number: {ret.Error}");
|
||||
@@ -122,7 +345,7 @@ public class Jpeg
|
||||
|
||||
public async ValueTask<Optional<List<JpegInfo>>> GetFrameInfo(int num)
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, JpegAddr.FRAME_INFO, num, this.timeout);
|
||||
var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, JpegAddr.JPEG_FIFO_FRAME_INFO, num, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get JPEG frame info: {ret.Error}");
|
||||
@@ -150,10 +373,10 @@ public class Jpeg
|
||||
return new(infos);
|
||||
}
|
||||
|
||||
public async ValueTask<bool> UpdatePointer(uint cnt)
|
||||
public async ValueTask<bool> AddFrameNum2Process(uint cnt)
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.FRAME_DATA_MAX_POINTER, cnt, this.timeout);
|
||||
this.ep, this.taskID, JpegAddr.JPEG_ADD_NEED_FRAME_NUM, cnt, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to update pointer: {ret.Error}");
|
||||
@@ -171,13 +394,16 @@ public class Jpeg
|
||||
}
|
||||
MsgBus.UDPServer.ClearUDPData(this.ep.Address.ToString(), this.ep.Port);
|
||||
|
||||
var firstReadLength = (int)(Math.Min(length, JpegAddr.DDR_FRAME_DATA_MAX_ADDR - offset));
|
||||
var firstReadLength = (int)(Math.Min(
|
||||
length,
|
||||
JpegAddr.ADDR_JPEG_END - JpegAddr.ADDR_JPEG_START - offset
|
||||
));
|
||||
var secondReadLength = (int)(length - firstReadLength);
|
||||
var dataBytes = new byte[length];
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddr4Bytes(
|
||||
this.ep, this.taskID, JpegAddr.DDR_FRAME_DATA_ADDR + offset, firstReadLength, this.timeout);
|
||||
this.ep, this.taskID, JpegAddr.ADDR_JPEG_START + offset, firstReadLength, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get JPEG frame data: {ret.Error}");
|
||||
@@ -194,7 +420,7 @@ public class Jpeg
|
||||
if (secondReadLength > 0)
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddr4Bytes(
|
||||
this.ep, this.taskID, JpegAddr.DDR_FRAME_DATA_ADDR, secondReadLength, this.timeout);
|
||||
this.ep, this.taskID, JpegAddr.ADDR_JPEG_START, secondReadLength, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get JPEG frame data: {ret.Error}");
|
||||
@@ -239,7 +465,7 @@ public class Jpeg
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UpdatePointer((uint)sizes.Length);
|
||||
var ret = await AddFrameNum2Process((uint)sizes.Length);
|
||||
if (!ret) logger.Error($"Failed to update pointer");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user