更新 SJA1000_CAN.cs

修改缓冲区为队列
This commit is contained in:
2026-04-17 08:55:34 +08:00
parent 14e8fcb94b
commit dc5c201933

View File

@@ -1,5 +1,5 @@
// //
// SJA1000 CAN 控制器外设实现(简化版) // SJA1000 CAN 控制器外设实现(简化版,支持发送/接收队列,提高速率
// 仅支持 PeliCAN 模式的标准帧,不考虑 BasicCAN、扩展帧、错误处理、多帧、验收滤波和发送中断。 // 仅支持 PeliCAN 模式的标准帧,不考虑 BasicCAN、扩展帧、错误处理、多帧、验收滤波和发送中断。
// 寄存器地址映射基于 PeliCAN 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR, // 寄存器地址映射基于 PeliCAN 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR,
// 发送缓冲区(地址 16-26、RBSA 和 CDR。命令寄存器位2=RRB位3=CDO。 // 发送缓冲区(地址 16-26、RBSA 和 CDR。命令寄存器位2=RRB位3=CDO。
@@ -32,6 +32,8 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
txBuffer = new byte[11]; txBuffer = new byte[11];
rxBuffer = new byte[11]; rxBuffer = new byte[11];
txFrameQueue = new Queue<byte[]>(); // 新增:发送队列
rxFrameQueue = new Queue<byte[]>(); // 新增:接收队列
Reset(); Reset();
} }
@@ -54,6 +56,8 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
Array.Clear(txBuffer, 0, txBuffer.Length); Array.Clear(txBuffer, 0, txBuffer.Length);
Array.Clear(rxBuffer, 0, rxBuffer.Length); Array.Clear(rxBuffer, 0, rxBuffer.Length);
txFrameQueue.Clear(); // 清空发送队列
rxFrameQueue.Clear(); // 清空接收队列
UpdateInterrupts(); UpdateInterrupts();
@@ -183,9 +187,17 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
// 发送请求 // 发送请求
if (sr_tbs == 1) if (sr_tbs == 1)
{ {
sr_tbs = 0; // 锁定发送缓冲区 // 将当前 txBuffer 复制一份加入发送队列
/*** 测试 ***/ var frame = new byte[11];
GetTxBufferDataString(); Array.Copy(txBuffer, frame, 11);
lock (lockObject)
{
txFrameQueue.Enqueue(frame);
}
// 清空发送缓冲区,并立即释放 TBS允许 CPU 继续写入下一帧
Array.Clear(txBuffer, 0, txBuffer.Length);
sr_tbs = 1;
this.Log(LogLevel.Info, "Frame enqueued for transmission, queue size: {0}", txFrameQueue.Count);
} }
else else
{ {
@@ -194,10 +206,11 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
} }
if ((value & CMR_RRB) != 0) if ((value & CMR_RRB) != 0)
{ {
// 释放接收缓冲器 // 释放接收缓冲器:尝试从接收队列中加载下一帧
sr_rbs = 0; lock (lockObject)
UpdateIrFromRbs(); {
UpdateInterrupts(); LoadNextRxFrame();
}
this.Log(LogLevel.Info, "Receive buffer released"); this.Log(LogLevel.Info, "Receive buffer released");
} }
if ((value & CMR_CDO) != 0) if ((value & CMR_CDO) != 0)
@@ -299,15 +312,11 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
// ================ 公共方法与事件 ================ // ================ 公共方法与事件 ================
private void UpdateIrFromRbs() private void UpdateIrFromRbs()
{ {
if (sr_rbs == 1) if (sr_rbs == 1)
ir |= IR_RI; ir |= IR_RI;
else else
// ir &= (byte)~IR_RI;
ir = (byte)(ir & ~IR_RI); ir = (byte)(ir & ~IR_RI);
} }
@@ -330,81 +339,99 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
} }
private readonly object lockObject = new object(); // 用于线程安全的锁对象 private readonly object lockObject = new object(); // 用于线程安全的锁对象
/// <summary>
/// 获取发送队列中所有帧的字符串表示(每帧以空格分隔的十六进制字节,帧间用换行分隔)
/// 调用后清空发送队列。
/// </summary>
public string GetTxBufferDataString() public string GetTxBufferDataString()
{ {
if(sr_tbs ==1)
{
Console.WriteLine("sr_tbs=1");
return null;
}
lock (lockObject) lock (lockObject)
{ {
var sb = new StringBuilder(); if (txFrameQueue.Count == 0)
for (int i = 0; i < txBuffer.Length; i++)
{ {
if (i > 0) sb.Append(" "); Console.WriteLine("GetTxBufferDataString: no frames in TX queue");
sb.Append(txBuffer[i].ToString("X2")); return null;
} }
string result = sb.ToString(); var sb = new StringBuilder();
while (txFrameQueue.Count > 0)
{
var frame = txFrameQueue.Dequeue();
for (int i = 0; i < frame.Length; i++)
{
if (i > 0) sb.Append(" ");
sb.Append(frame[i].ToString("X2"));
}
sb.AppendLine(); // 帧间换行
}
string result = sb.ToString().TrimEnd();
Console.WriteLine("GetTxBufferDataString returning: " + result); Console.WriteLine("GetTxBufferDataString returning: " + result);
Array.Clear(txBuffer, 0, txBuffer.Length);
sr_tbs = 1;
return result; return result;
} }
} }
/// <summary>
/// 外部接口注入一帧接收数据11字节的十六进制字符串空格分隔
/// 可多次调用以注入多帧,帧将存入接收队列。
/// </summary>
public void SendRxBufferDataString(string frameString) public void SendRxBufferDataString(string frameString)
{ {
lock (lockObject) lock (lockObject)
{ {
if (string.IsNullOrWhiteSpace(frameString)) if (string.IsNullOrWhiteSpace(frameString))
{ {
Console.WriteLine("ReceiveFrame: empty string, ignored"); Console.WriteLine("SendRxBufferDataString: empty string, ignored");
return; return;
} }
if (sr_rbs==1)
{
Console.WriteLine("rxBuffer is full");
return;
}
Array.Clear(rxBuffer, 0, rxBuffer.Length);
string[] parts = frameString.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); string[] parts = frameString.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
int count = Math.Min(parts.Length, rxBuffer.Length); if (parts.Length != 11)
{
for (int i = 0; i < count; i++) Console.WriteLine($"SendRxBufferDataString: expected 11 bytes, got {parts.Length}, ignored");
return;
}
byte[] frame = new byte[11];
for (int i = 0; i < 11; i++)
{ {
string part = parts[i].Trim(); string part = parts[i].Trim();
if (byte.TryParse(part, System.Globalization.NumberStyles.HexNumber, if (!byte.TryParse(part, System.Globalization.NumberStyles.HexNumber,
System.Globalization.CultureInfo.InvariantCulture, out byte b)) System.Globalization.CultureInfo.InvariantCulture, out byte b))
{ {
rxBuffer[i] = b; Console.WriteLine($"SendRxBufferDataString: invalid hex byte '{part}' at index {i}, set to 0");
} b = 0;
else
{
Console.WriteLine($"ReceiveFrame: invalid hex byte '{part}' at index {i}, set to 0");
rxBuffer[i] = 0;
} }
frame[i] = b;
} }
rxFrameQueue.Enqueue(frame);
Console.WriteLine($"Frame enqueued to RX queue, size: {rxFrameQueue.Count}");
// 如果当前接收缓冲区空闲,立即加载第一帧
if (sr_rbs == 0)
{
LoadNextRxFrame();
}
}
}
// 从接收队列中加载下一帧到 rxBuffer并更新状态
private void LoadNextRxFrame()
{
if (rxFrameQueue.Count > 0)
{
var frame = rxFrameQueue.Dequeue();
Array.Copy(frame, rxBuffer, 11);
sr_rbs = 1; sr_rbs = 1;
UpdateIrFromRbs(); UpdateIrFromRbs();
UpdateInterrupts(); UpdateInterrupts();
Console.WriteLine("Loaded next RX frame into buffer, queue remaining: {0}", rxFrameQueue.Count);
// 打印 rxBuffer 内容 }
var sb = new StringBuilder(); else
sb.Append("RX Buffer after receive: "); {
for (int i = 0; i < rxBuffer.Length; i++) sr_rbs = 0;
{ UpdateIrFromRbs();
if (i > 0) sb.Append(" "); UpdateInterrupts();
sb.Append(rxBuffer[i].ToString("X2")); Console.WriteLine("RX queue empty, buffer cleared");
}
Console.WriteLine(sb.ToString());
Console.WriteLine($"Frame received from string: {frameString}");
} }
} }
// ================ 属性 ================ // ================ 属性 ================
public long Size => 0x80; // 地址范围 0-31 public long Size => 0x80; // 地址范围 0-31
@@ -474,7 +501,10 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
private byte ir; // 仅 bit0 有效 private byte ir; // 仅 bit0 有效
private readonly byte[] txBuffer; // 地址16-26 private readonly byte[] txBuffer; // 临时发送缓冲区(单帧)
private readonly byte[] rxBuffer; // 当前接收帧 private readonly byte[] rxBuffer; // 当前接收帧(单帧)
private readonly Queue<byte[]> txFrameQueue; // 发送队列
private readonly Queue<byte[]> rxFrameQueue; // 接收队列
} }
} }