Files
simulation_Peripheral/SJA1000_CAN.cs

654 lines
25 KiB
C#
Raw Normal View History

//
2026-06-15 17:11:35 +08:00
// SJA1000 CAN 控制器外设实现(简化版,支持接收队列,可配置长度)
// 仅支持 PeliCAN 模式的标准帧,不考虑 BasicCAN、扩展帧、错误处理、多帧、验收滤波和发送中断。
// 寄存器地址映射基于 PeliCAN 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR,
// 发送缓冲区(地址 16-26、RBSA 和 CDR。命令寄存器位2=RRB位3=CDO。
// 所有寄存器可随时读写,无复位模式限制。
//
2026-06-15 17:11:35 +08:00
// 接收队列长度可通过修改静态字段 MaxRxQueueSize 调整。
2026-05-25 15:33:24 +08:00
// 接收队列满时,外部注入的新帧被丢弃。
//
2026-06-15 17:11:35 +08:00
// 发送采用立即发送模式(无波特率延迟),每帧发送完成后触发 FrameTransmitted 事件并转发到 TCP 客户端。
// TCP Server 为静态共享实例,监听端口 10000将发送的帧数据转发给所有连接的客户端。
2026-05-25 15:33:24 +08:00
// 日志开关EnableVerboseLog = false 可关闭所有日志输出。
2026-06-15 17:11:35 +08:00
// 实现了 IDisposable 接口TCP 服务器由所有实例共享,仅当最后一个实例销毁时停止服务器。
//
using System;
using System.Text;
using System.Collections.Generic;
2026-06-15 17:11:35 +08:00
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
2026-06-15 17:11:35 +08:00
/// 简化版 SJA1000 CAN 控制器PeliCAN 模式仅标准帧立即发送TCP 转发)
/// </summary>
2026-06-15 17:11:35 +08:00
public class SJA1000_CAN : IDoubleWordPeripheral, IBytePeripheral, IKnownSize, IDisposable
{
2026-05-25 15:33:24 +08:00
// 日志开关(设置为 false 可屏蔽所有日志)
public static bool EnableVerboseLog = false;
2026-06-15 17:11:35 +08:00
// 接收队列长度配置(可修改)
2026-05-25 15:33:24 +08:00
public static int MaxRxQueueSize = 64; // 接收队列最大帧数
2026-06-15 17:11:35 +08:00
// 发送事件:当一帧数据被发送时触发
public event Action<byte[]> FrameTransmitted;
// ================ 静态 TCP Server 共享资源 ================
private static TcpListener sharedTcpListener;
private static readonly List<NetworkStream> sharedTcpClients = new List<NetworkStream>();
private static readonly object sharedTcpLock = new object();
private static CancellationTokenSource sharedTcpCts;
private static Task sharedTcpServerTask;
private static int sharedTcpRefCount = 0; // 引用计数
private bool disposed = false;
public SJA1000_CAN(IMachine machine)
{
this.machine = machine;
IRQ = new GPIO();
txBuffer = new byte[11];
rxBuffer = new byte[11];
2026-06-15 17:11:35 +08:00
rxFrameQueue = new Queue<byte[]>();
// 启动共享 TCP Server增加引用计数
StartSharedTcpServer();
Reset();
}
public void Reset()
{
mod = 0;
ier = 0;
btr0 = 0;
btr1 = 0;
ocr = 0;
rxerr = 0;
txerr = 0;
rbsa = 0;
cdr = 0;
2026-06-15 17:11:35 +08:00
sr_tbs = 1; // 发送缓冲区始终空闲(立即发送模式)
sr_rbs = 0; // 接收缓冲区初始为空
ir = 0;
Array.Clear(txBuffer, 0, txBuffer.Length);
Array.Clear(rxBuffer, 0, rxBuffer.Length);
2026-05-25 15:33:24 +08:00
rxFrameQueue.Clear();
2026-06-15 17:11:35 +08:00
lastInterruptState = false;
UpdateInterrupts();
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog)
2026-06-15 17:11:35 +08:00
this.Log(LogLevel.Info, $"SJA1000 CAN controller reset (rxQueueMax={MaxRxQueueSize})");
}
// ================ 共享 TCP Server 管理 ================
private void StartSharedTcpServer()
{
lock (sharedTcpLock)
{
sharedTcpRefCount++;
if (sharedTcpRefCount > 1)
{
if (EnableVerboseLog)
Console.WriteLine("TCP Server already running, using existing instance.");
return;
}
// 确保之前的已停止(安全)
StopSharedTcpServerInternal();
sharedTcpCts = new CancellationTokenSource();
sharedTcpServerTask = Task.Run(() => TcpServerLoop(sharedTcpCts.Token), sharedTcpCts.Token);
if (EnableVerboseLog)
Console.WriteLine("TCP Server started on port 10000 (shared)");
}
}
2026-06-15 17:11:35 +08:00
private void StopSharedTcpServer()
{
lock (sharedTcpLock)
{
if (sharedTcpRefCount > 0)
sharedTcpRefCount--;
if (sharedTcpRefCount > 0)
{
if (EnableVerboseLog)
Console.WriteLine("TCP Server still in use, not stopping.");
return;
}
StopSharedTcpServerInternal();
}
}
2026-06-15 17:11:35 +08:00
private static void StopSharedTcpServerInternal()
{
2026-06-15 17:11:35 +08:00
if (sharedTcpCts != null)
{
sharedTcpCts.Cancel();
try { sharedTcpServerTask?.Wait(1000); } catch { }
sharedTcpCts.Dispose();
sharedTcpCts = null;
sharedTcpServerTask = null;
}
if (sharedTcpListener != null)
{
try { sharedTcpListener.Stop(); } catch { }
sharedTcpListener = null;
}
lock (sharedTcpLock)
{
foreach (var s in sharedTcpClients)
s?.Close();
sharedTcpClients.Clear();
}
if (EnableVerboseLog)
Console.WriteLine("TCP Server stopped.");
}
private static void TcpServerLoop(CancellationToken token)
{
try
{
sharedTcpListener = new TcpListener(IPAddress.Any, 10000);
sharedTcpListener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sharedTcpListener.Start();
while (!token.IsCancellationRequested)
{
var clientTask = sharedTcpListener.AcceptTcpClientAsync();
clientTask.Wait(token);
if (clientTask.IsCompleted && !token.IsCancellationRequested)
{
var client = clientTask.Result;
var stream = client.GetStream();
lock (sharedTcpLock)
{
sharedTcpClients.Add(stream);
}
if (EnableVerboseLog)
Console.WriteLine($"TCP client connected from {client.Client.RemoteEndPoint}");
}
}
}
catch (OperationCanceledException) { }
catch (Exception ex)
{
if (EnableVerboseLog)
Console.WriteLine($"TCP Server error: {ex.Message}");
}
finally
{
sharedTcpListener?.Stop();
lock (sharedTcpLock)
{
foreach (var s in sharedTcpClients)
s?.Close();
sharedTcpClients.Clear();
}
}
}
2026-06-15 17:11:35 +08:00
private void BroadcastFrame(byte[] frame)
{
2026-06-15 17:11:35 +08:00
if (frame == null || frame.Length != 11) return;
lock (sharedTcpLock)
{
var clients = sharedTcpClients.ToArray();
foreach (var stream in clients)
{
try
{
stream.Write(frame, 0, frame.Length);
stream.Flush();
}
catch (Exception ex)
{
if (EnableVerboseLog)
Console.WriteLine($"Failed to send frame to client: {ex.Message}");
sharedTcpClients.Remove(stream);
stream.Close();
}
}
}
}
2026-06-15 17:11:35 +08:00
// ================ IBusPeripheral 接口实现(完全不变) ================
public uint ReadDoubleWord(long offset) => ReadByte(offset);
public void WriteDoubleWord(long offset, uint value) => WriteByte(offset, (byte)value);
public byte ReadByte(long offset)
{
byte value = 0;
2026-05-25 15:33:24 +08:00
lock (lockObject)
{
2026-05-25 15:33:24 +08:00
switch ((Registers)offset)
{
case Registers.MOD:
value = mod;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read MOD: 0x{0:X2}", value);
break;
case Registers.CMR:
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read CMR (always 0)");
value = 0;
break;
case Registers.SR:
2026-06-15 17:11:35 +08:00
value = (byte)((sr_tbs << 2) | sr_rbs);
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read SR: TBS={0}, RBS={1} -> 0x{2:X2}", sr_tbs, sr_rbs, value);
break;
case Registers.IR:
value = ir;
ir = 0;
UpdateIrFromRbs();
lastInterruptState = false;
UpdateInterrupts();
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read IR: 0x{0:X2}, cleared", value);
break;
case Registers.IER:
value = ier;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read IER: 0x{0:X2}", value);
break;
case Registers.BTR0:
value = btr0;
break;
case Registers.BTR1:
value = btr1;
break;
case Registers.OCR:
value = ocr;
break;
case Registers.RXERR:
value = rxerr;
break;
case Registers.TXERR:
value = txerr;
break;
case Registers.RBSA:
value = rbsa;
break;
case Registers.CDR:
value = cdr;
break;
case Registers.TX_FRAME_INFO:
case Registers.TX_ID1:
case Registers.TX_ID2:
case Registers.TX_DATA1:
case Registers.TX_DATA2:
case Registers.TX_DATA3:
case Registers.TX_DATA4:
case Registers.TX_DATA5:
case Registers.TX_DATA6:
case Registers.TX_DATA7:
case Registers.TX_DATA8:
int bufIndex = (int)(offset - (long)Registers.TX_FRAME_INFO) / 4;
if (sr_rbs == 1)
{
value = rxBuffer[bufIndex];
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read RX buffer[{0}]: 0x{1:X2}", bufIndex, value);
}
else
{
value = txBuffer[bufIndex];
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read TX buffer[{0}]: 0x{1:X2}", bufIndex, value);
}
break;
2026-05-25 15:33:24 +08:00
default:
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read from unimplemented offset 0x{0:X}", offset);
value = 0;
break;
}
}
return value;
}
public void WriteByte(long offset, byte value)
{
2026-05-25 15:33:24 +08:00
lock (lockObject)
{
2026-05-25 15:33:24 +08:00
switch ((Registers)offset)
{
case Registers.MOD:
mod = value;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write MOD: 0x{0:X2}", value);
break;
case Registers.CMR:
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write CMR: 0x{0:X2}", value);
if ((value & CMR_TR) != 0)
{
2026-06-15 17:11:35 +08:00
// 发送请求(立即发送模式)
2026-05-25 15:33:24 +08:00
if (sr_tbs == 1)
{
2026-06-15 17:11:35 +08:00
// 复制当前帧
byte[] frame = new byte[11];
Array.Copy(txBuffer, frame, 11);
// 清空发送缓冲区(准备下一帧)
Array.Clear(txBuffer, 0, txBuffer.Length);
// 立即发送帧数据
FrameTransmitted?.Invoke(frame);
BroadcastFrame(frame);
// 保持发送缓冲区空闲(始终允许写入)
sr_tbs = 1;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Frame transmitted immediately");
2026-05-25 15:33:24 +08:00
}
else
{
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog) this.Log(LogLevel.Warning, "Send request while TBS=0 ignored");
}
}
2026-05-25 15:33:24 +08:00
if ((value & CMR_RRB) != 0)
{
2026-06-15 17:11:35 +08:00
// 释放接收缓冲器
sr_rbs = 0;
UpdateIrFromRbs();
UpdateInterrupts();
2026-05-25 15:33:24 +08:00
LoadNextRxFrame();
2026-06-15 17:11:35 +08:00
UpdateInterrupts();
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog) this.Log(LogLevel.Info, "Receive buffer released");
}
2026-05-25 15:33:24 +08:00
if ((value & CMR_CDO) != 0)
{
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog) this.Log(LogLevel.Info, "Clear data overflow (no effect)");
}
2026-05-25 15:33:24 +08:00
break;
case Registers.SR:
if (EnableVerboseLog) this.Log(LogLevel.Warning, "Attempted write to read-only SR");
break;
case Registers.IR:
if (EnableVerboseLog) this.Log(LogLevel.Warning, "Attempted write to read-only IR");
break;
case Registers.IER:
ier = (byte)(value & 0x01);
UpdateIrFromRbs();
UpdateInterrupts();
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write IER: 0x{0:X2}", ier);
break;
case Registers.BTR0:
btr0 = value;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write BTR0: 0x{0:X2}", value);
break;
case Registers.BTR1:
btr1 = value;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write BTR1: 0x{0:X2}", value);
break;
case Registers.OCR:
ocr = value;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write OCR: 0x{0:X2}", value);
break;
case Registers.RXERR:
rxerr = value;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write RXERR: 0x{0:X2}", value);
break;
case Registers.TXERR:
txerr = value;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write TXERR: 0x{0:X2}", value);
break;
case Registers.RBSA:
rbsa = value;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write RBSA: 0x{0:X2}", value);
break;
case Registers.CDR:
cdr = value;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write CDR: 0x{0:X2}", value);
break;
case Registers.TX_FRAME_INFO:
case Registers.TX_ID1:
case Registers.TX_ID2:
case Registers.TX_DATA1:
case Registers.TX_DATA2:
case Registers.TX_DATA3:
case Registers.TX_DATA4:
case Registers.TX_DATA5:
case Registers.TX_DATA6:
case Registers.TX_DATA7:
case Registers.TX_DATA8:
int bufIndex = (int)(offset - (long)Registers.TX_FRAME_INFO) / 4;
if (sr_tbs == 1)
{
txBuffer[bufIndex] = value;
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write TX buffer[{0}]: 0x{1:X2}", bufIndex, value);
}
else
{
if (EnableVerboseLog) this.Log(LogLevel.Warning, "Write to TX buffer while TBS=0 ignored");
}
break;
2026-05-25 15:33:24 +08:00
default:
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write to unimplemented offset 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
}
2026-06-15 17:11:35 +08:00
// ================ 接收与中断管理 ================
private void UpdateIrFromRbs()
{
if (sr_rbs == 1)
ir |= IR_RI;
else
2026-05-25 15:33:24 +08:00
ir = (byte)(ir & ~IR_RI);
}
private void UpdateInterrupts()
{
2026-05-25 15:33:24 +08:00
bool currentInterrupt = ((ir & IR_RI) != 0) && ((ier & IER_RIE) != 0);
if (currentInterrupt && !lastInterruptState)
{
2026-05-25 15:33:24 +08:00
IRQ.Set(true);
2026-06-15 17:11:35 +08:00
machine.ScheduleAction(TimeInterval.FromMicroseconds(1), _ => IRQ.Set(false));
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog) this.Log(LogLevel.Info, "Interrupt pulse generated (RI)");
}
lastInterruptState = currentInterrupt;
}
2026-05-25 15:33:24 +08:00
private readonly object lockObject = new object();
2026-06-15 17:11:35 +08:00
private bool lastInterruptState;
/// <summary>
2026-06-15 17:11:35 +08:00
/// 获取接收队列中所有帧的字符串表示(每帧以空格分隔的十六进制字节,帧间用换行分隔)
/// 注意:此方法仅用于调试,会影响接收队列。
/// </summary>
2026-06-15 17:11:35 +08:00
public string GetRxBufferDataString()
{
lock (lockObject)
{
2026-06-15 17:11:35 +08:00
if (rxFrameQueue.Count == 0)
{
2026-06-15 17:11:35 +08:00
if (EnableVerboseLog) Console.WriteLine("GetRxBufferDataString: no frames in RX queue");
return null;
}
var sb = new StringBuilder();
2026-06-15 17:11:35 +08:00
while (rxFrameQueue.Count > 0)
{
2026-06-15 17:11:35 +08:00
var frame = rxFrameQueue.Dequeue();
for (int i = 0; i < frame.Length; i++)
{
if (i > 0) sb.Append(" ");
sb.Append(frame[i].ToString("X2"));
}
2026-05-25 15:33:24 +08:00
sb.AppendLine();
}
string result = sb.ToString().TrimEnd();
2026-06-15 17:11:35 +08:00
if (EnableVerboseLog) Console.WriteLine("GetRxBufferDataString returning: " + result);
return result;
}
}
2026-05-25 15:33:24 +08:00
/// <summary>
2026-06-15 17:11:35 +08:00
/// 外部接口注入一帧接收数据(可变长度的十六进制字符串,空格分隔)
/// 可多次调用以注入多帧,帧将存入接收队列。
2026-05-25 15:33:24 +08:00
/// 若接收队列已满,则新帧被丢弃。
2026-06-15 17:11:35 +08:00
/// 输入字符串长度可变0~11 字节),不足 11 字节时自动补零,超出 11 字节时截断并警告。
/// </summary>
public void SendRxBufferDataString(string frameString)
{
lock (lockObject)
{
if (string.IsNullOrWhiteSpace(frameString))
{
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog) Console.WriteLine("SendRxBufferDataString: empty string, ignored");
return;
}
string[] parts = frameString.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
2026-06-15 17:11:35 +08:00
int length = parts.Length;
if (length > 11)
{
2026-06-15 17:11:35 +08:00
if (EnableVerboseLog) Console.WriteLine($"SendRxBufferDataString: input has {length} bytes, truncating to 11");
length = 11;
}
2026-06-15 17:11:35 +08:00
byte[] frame = new byte[11];
2026-06-15 17:11:35 +08:00
for (int i = 0; i < length; i++)
{
string part = parts[i].Trim();
if (!byte.TryParse(part, System.Globalization.NumberStyles.HexNumber,
System.Globalization.CultureInfo.InvariantCulture, out byte b))
{
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog) Console.WriteLine($"SendRxBufferDataString: invalid hex byte '{part}' at index {i}, set to 0");
b = 0;
}
frame[i] = b;
}
2026-05-25 15:33:24 +08:00
if (rxFrameQueue.Count >= MaxRxQueueSize)
{
2026-06-15 17:11:35 +08:00
if (EnableVerboseLog) Console.WriteLine($"SendRxBufferDataString: RX queue full, frame dropped");
2026-05-25 15:33:24 +08:00
return;
}
rxFrameQueue.Enqueue(frame);
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog) Console.WriteLine($"Frame enqueued to RX queue, size: {rxFrameQueue.Count}");
if (sr_rbs == 0)
{
LoadNextRxFrame();
2026-06-15 17:11:35 +08:00
UpdateInterrupts();
}
}
}
private void LoadNextRxFrame()
{
if (rxFrameQueue.Count > 0)
{
var frame = rxFrameQueue.Dequeue();
Array.Copy(frame, rxBuffer, 11);
sr_rbs = 1;
UpdateIrFromRbs();
2026-06-15 17:11:35 +08:00
if (EnableVerboseLog) Console.WriteLine("Loaded next RX frame, remaining: {0}", rxFrameQueue.Count);
}
else
{
sr_rbs = 0;
UpdateIrFromRbs();
2026-05-25 15:33:24 +08:00
if (EnableVerboseLog) Console.WriteLine("RX queue empty, buffer cleared");
}
}
2026-06-15 17:11:35 +08:00
// ================ IDisposable 实现 ================
public void Dispose()
{
if (!disposed)
{
StopSharedTcpServer(); // 减少引用计数,可能停止服务器
disposed = true;
}
GC.SuppressFinalize(this);
}
~SJA1000_CAN()
{
Dispose();
}
// ================ 属性 ================
2026-05-25 15:33:24 +08:00
public long Size => 0x80;
public GPIO IRQ { get; }
// ================ 寄存器枚举 ================
private enum Registers : long
{
MOD = 0x00,
CMR = 0x04,
2026-05-25 15:33:24 +08:00
SR = 0x08,
IR = 0x0C,
IER = 0x10,
BTR0 = 0x18,
BTR1 = 0x1C,
2026-05-25 15:33:24 +08:00
OCR = 0x20,
RXERR = 0x38,
TXERR = 0x3C,
TX_FRAME_INFO = 0x40,
TX_ID1 = 0x44,
TX_ID2 = 0x48,
TX_DATA1 = 0x4C,
TX_DATA2 = 0x50,
TX_DATA3 = 0x54,
TX_DATA4 = 0x58,
TX_DATA5 = 0x5C,
TX_DATA6 = 0x60,
TX_DATA7 = 0x64,
2026-05-25 15:33:24 +08:00
TX_DATA8 = 0x68,
RBSA = 0x78,
CDR = 0x7C,
}
// ================ 常量位定义 ================
2026-05-25 15:33:24 +08:00
private const byte CMR_TR = 0x01;
private const byte CMR_RRB = 0x04;
private const byte CMR_CDO = 0x08;
2026-05-25 15:33:24 +08:00
private const byte SR_TBS = 0x04;
private const byte SR_RBS = 0x01;
2026-05-25 15:33:24 +08:00
private const byte IR_RI = 0x01;
private const byte IER_RIE = 0x01;
// ================ 私有字段 ================
private readonly IMachine machine;
private byte mod;
private byte ier;
private byte btr0, btr1;
private byte ocr;
private byte rxerr, txerr;
private byte rbsa;
private byte cdr;
2026-05-25 15:33:24 +08:00
private byte sr_tbs;
private byte sr_rbs;
private byte ir;
2026-05-25 15:33:24 +08:00
private readonly byte[] txBuffer;
private readonly byte[] rxBuffer;
2026-06-15 17:11:35 +08:00
private readonly Queue<byte[]> rxFrameQueue; // 仅接收队列
}
}