更新 SJA1000_CAN.cs
修改缓冲区为队列
This commit is contained in:
134
SJA1000_CAN.cs
134
SJA1000_CAN.cs
@@ -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)
|
||||
{
|
||||
if (txFrameQueue.Count == 0)
|
||||
{
|
||||
Console.WriteLine("GetTxBufferDataString: no frames in TX queue");
|
||||
return null;
|
||||
}
|
||||
var sb = new StringBuilder();
|
||||
for (int i = 0; i < txBuffer.Length; i++)
|
||||
while (txFrameQueue.Count > 0)
|
||||
{
|
||||
var frame = txFrameQueue.Dequeue();
|
||||
for (int i = 0; i < frame.Length; i++)
|
||||
{
|
||||
if (i > 0) sb.Append(" ");
|
||||
sb.Append(txBuffer[i].ToString("X2"));
|
||||
sb.Append(frame[i].ToString("X2"));
|
||||
}
|
||||
string result = sb.ToString();
|
||||
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;
|
||||
Console.WriteLine($"SendRxBufferDataString: invalid hex byte '{part}' at index {i}, set to 0");
|
||||
b = 0;
|
||||
}
|
||||
else
|
||||
frame[i] = b;
|
||||
}
|
||||
rxFrameQueue.Enqueue(frame);
|
||||
Console.WriteLine($"Frame enqueued to RX queue, size: {rxFrameQueue.Count}");
|
||||
|
||||
// 如果当前接收缓冲区空闲,立即加载第一帧
|
||||
if (sr_rbs == 0)
|
||||
{
|
||||
Console.WriteLine($"ReceiveFrame: invalid hex byte '{part}' at index {i}, set to 0");
|
||||
rxBuffer[i] = 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++)
|
||||
Console.WriteLine("Loaded next RX frame into buffer, queue remaining: {0}", rxFrameQueue.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i > 0) sb.Append(" ");
|
||||
sb.Append(rxBuffer[i].ToString("X2"));
|
||||
sr_rbs = 0;
|
||||
UpdateIrFromRbs();
|
||||
UpdateInterrupts();
|
||||
Console.WriteLine("RX queue empty, buffer cleared");
|
||||
}
|
||||
}
|
||||
Console.WriteLine(sb.ToString());
|
||||
|
||||
Console.WriteLine($"Frame received from string: {frameString}");
|
||||
}
|
||||
}
|
||||
// ================ 属性 ================
|
||||
|
||||
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; // 接收队列
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user