更新 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 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR,
// 发送缓冲区(地址 16-26、RBSA 和 CDR。命令寄存器位2=RRB位3=CDO。
@@ -32,6 +32,8 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
txBuffer = new byte[11];
rxBuffer = new byte[11];
txFrameQueue = new Queue<byte[]>(); // 新增:发送队列
rxFrameQueue = new Queue<byte[]>(); // 新增:接收队列
Reset();
}
@@ -54,6 +56,8 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
Array.Clear(txBuffer, 0, txBuffer.Length);
Array.Clear(rxBuffer, 0, rxBuffer.Length);
txFrameQueue.Clear(); // 清空发送队列
rxFrameQueue.Clear(); // 清空接收队列
UpdateInterrupts();
@@ -183,9 +187,17 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
// 发送请求
if (sr_tbs == 1)
{
sr_tbs = 0; // 锁定发送缓冲区
/*** 测试 ***/
GetTxBufferDataString();
// 将当前 txBuffer 复制一份加入发送队列
var frame = new byte[11];
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
{
@@ -194,10 +206,11 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
}
if ((value & CMR_RRB) != 0)
{
// 释放接收缓冲器
sr_rbs = 0;
UpdateIrFromRbs();
UpdateInterrupts();
// 释放接收缓冲器:尝试从接收队列中加载下一帧
lock (lockObject)
{
LoadNextRxFrame();
}
this.Log(LogLevel.Info, "Receive buffer released");
}
if ((value & CMR_CDO) != 0)
@@ -299,15 +312,11 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
// ================ 公共方法与事件 ================
private void UpdateIrFromRbs()
{
if (sr_rbs == 1)
ir |= IR_RI;
else
// ir &= (byte)~IR_RI;
ir = (byte)(ir & ~IR_RI);
}
@@ -330,81 +339,99 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
}
private readonly object lockObject = new object(); // 用于线程安全的锁对象
/// <summary>
/// 获取发送队列中所有帧的字符串表示(每帧以空格分隔的十六进制字节,帧间用换行分隔)
/// 调用后清空发送队列。
/// </summary>
public string GetTxBufferDataString()
{
if(sr_tbs ==1)
{
Console.WriteLine("sr_tbs=1");
return null;
}
lock (lockObject)
{
var sb = new StringBuilder();
for (int i = 0; i < txBuffer.Length; i++)
if (txFrameQueue.Count == 0)
{
if (i > 0) sb.Append(" ");
sb.Append(txBuffer[i].ToString("X2"));
Console.WriteLine("GetTxBufferDataString: no frames in TX queue");
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);
Array.Clear(txBuffer, 0, txBuffer.Length);
sr_tbs = 1;
return result;
}
}
/// <summary>
/// 外部接口注入一帧接收数据11字节的十六进制字符串空格分隔
/// 可多次调用以注入多帧,帧将存入接收队列。
/// </summary>
public void SendRxBufferDataString(string frameString)
{
lock (lockObject)
{
if (string.IsNullOrWhiteSpace(frameString))
{
Console.WriteLine("ReceiveFrame: empty string, ignored");
Console.WriteLine("SendRxBufferDataString: empty string, ignored");
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);
int count = Math.Min(parts.Length, rxBuffer.Length);
for (int i = 0; i < count; i++)
if (parts.Length != 11)
{
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();
if (byte.TryParse(part, System.Globalization.NumberStyles.HexNumber,
if (!byte.TryParse(part, System.Globalization.NumberStyles.HexNumber,
System.Globalization.CultureInfo.InvariantCulture, out byte b))
{
rxBuffer[i] = b;
}
else
{
Console.WriteLine($"ReceiveFrame: invalid hex byte '{part}' at index {i}, set to 0");
rxBuffer[i] = 0;
Console.WriteLine($"SendRxBufferDataString: invalid hex byte '{part}' at index {i}, set to 0");
b = 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;
UpdateIrFromRbs();
UpdateInterrupts();
// 打印 rxBuffer 内容
var sb = new StringBuilder();
sb.Append("RX Buffer after receive: ");
for (int i = 0; i < rxBuffer.Length; i++)
{
if (i > 0) sb.Append(" ");
sb.Append(rxBuffer[i].ToString("X2"));
}
Console.WriteLine(sb.ToString());
Console.WriteLine($"Frame received from string: {frameString}");
Console.WriteLine("Loaded next RX frame into buffer, queue remaining: {0}", rxFrameQueue.Count);
}
else
{
sr_rbs = 0;
UpdateIrFromRbs();
UpdateInterrupts();
Console.WriteLine("RX queue empty, buffer cleared");
}
}
// ================ 属性 ================
public long Size => 0x80; // 地址范围 0-31
@@ -474,7 +501,10 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
private byte ir; // 仅 bit0 有效
private readonly byte[] txBuffer; // 地址16-26
private readonly byte[] rxBuffer; // 当前接收帧
private readonly byte[] txBuffer; // 临时发送缓冲区(单帧)
private readonly byte[] rxBuffer; // 当前接收帧(单帧)
private readonly Queue<byte[]> txFrameQueue; // 发送队列
private readonly Queue<byte[]> rxFrameQueue; // 接收队列
}
}