From dc5c20193392d83fc236662625af772c1cc3fb44 Mon Sep 17 00:00:00 2001 From: yaomingjun Date: Fri, 17 Apr 2026 08:55:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20SJA1000=5FCAN.cs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改缓冲区为队列 --- SJA1000_CAN.cs | 990 +++++++++++++++++++++++++------------------------ 1 file changed, 510 insertions(+), 480 deletions(-) diff --git a/SJA1000_CAN.cs b/SJA1000_CAN.cs index 150a4fd..4d7d699 100644 --- a/SJA1000_CAN.cs +++ b/SJA1000_CAN.cs @@ -1,480 +1,510 @@ -// -// SJA1000 CAN 控制器外设实现(简化版) -// 仅支持 PeliCAN 模式的标准帧,不考虑 BasicCAN、扩展帧、错误处理、多帧、验收滤波和发送中断。 -// 寄存器地址映射基于 PeliCAN 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR, -// 发送缓冲区(地址 16-26)、RBSA 和 CDR。命令寄存器位2=RRB,位3=CDO。 -// 接收为单帧,无 FIFO,无数据溢出处理。 -// 所有寄存器可随时读写,无复位模式限制。 -// -// author: Generated based on UART16550 template -// - -using System; -using System.Text; -using System.Collections.Generic; -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 -{ - /// - /// 简化版 SJA1000 CAN 控制器(PeliCAN 模式,仅标准帧) - /// - public class SJA1000_CAN : IDoubleWordPeripheral, IBytePeripheral, IKnownSize - { - public SJA1000_CAN(IMachine machine) - { - this.machine = machine; - IRQ = new GPIO(); - - txBuffer = new byte[11]; - rxBuffer = new byte[11]; - - Reset(); - } - - public void Reset() - { - mod = 0; - ier = 0; - btr0 = 0; - btr1 = 0; - ocr = 0; - rxerr = 0; - txerr = 0; - rbsa = 0; - cdr = 0; - - sr_tbs = 1; // 发送缓冲区初始为空闲 - sr_rbs = 0; // 接收缓冲区初始为空 - ir = 0; - - Array.Clear(txBuffer, 0, txBuffer.Length); - Array.Clear(rxBuffer, 0, rxBuffer.Length); - - UpdateInterrupts(); - - this.Log(LogLevel.Info, "SJA1000 CAN controller reset (simplified)"); - } - - // ================ IBusPeripheral 接口实现 ================ - - public uint ReadDoubleWord(long offset) - { - return ReadByte(offset); - } - - public void WriteDoubleWord(long offset, uint value) - { - WriteByte(offset, (byte)value); - } - - public byte ReadByte(long offset) - { - byte value = 0; - switch ((Registers)offset) - { - case Registers.MOD: - value = mod; - this.Log(LogLevel.Info, "Read MOD: 0x{0:X2}", value); - break; - - case Registers.CMR: - // 命令寄存器只写,读返回0 - this.Log(LogLevel.Info, "Read CMR (always 0)"); - value = 0; - break; - - case Registers.SR: - value = (byte)((sr_tbs << 2) | sr_rbs); // BS 恒为0 - 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 后清零,但需要根据当前 RBS 重新评估 RI(电平触发) - ir = 0; - UpdateIrFromRbs(); - UpdateInterrupts(); - this.Log(LogLevel.Info, "Read IR: 0x{0:X2}, cleared", value); - break; - - case Registers.IER: - value = ier; - 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; - - // 发送/接收缓冲区地址 16-26 - 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); - if (sr_rbs == 1) - { - // 接收缓冲区有数据时,读返回接收帧的内容 - value = rxBuffer[bufIndex/4]; - this.Log(LogLevel.Info, "Read RX buffer[{0}]: 0x{1:X2}", bufIndex/4, value); - } - else - { - //否则返回发送缓冲区的内容(通常无意义) - value = txBuffer[bufIndex/4]; - this.Log(LogLevel.Info, "Read TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value); - - } - break; - - default: - // 未实现的寄存器返回0 - this.Log(LogLevel.Info, "Read from unimplemented offset 0x{0:X}", offset); - value = 0; - break; - } - return value; - } - - public void WriteByte(long offset, byte value) - { - switch ((Registers)offset) - { - case Registers.MOD: - mod = value; - this.Log(LogLevel.Info, "Write MOD: 0x{0:X2}", value); - break; - - case Registers.CMR: - // 命令寄存器只写,处理命令 - this.Log(LogLevel.Info, "Write CMR: 0x{0:X2}", value); - if ((value & CMR_TR) != 0) - { - // 发送请求 - if (sr_tbs == 1) - { - sr_tbs = 0; // 锁定发送缓冲区 - /*** 测试 ***/ - GetTxBufferDataString(); - } - else - { - this.Log(LogLevel.Warning, "Send request while TBS=0 ignored"); - } - } - if ((value & CMR_RRB) != 0) - { - // 释放接收缓冲器 - sr_rbs = 0; - UpdateIrFromRbs(); - UpdateInterrupts(); - this.Log(LogLevel.Info, "Receive buffer released"); - } - if ((value & CMR_CDO) != 0) - { - // 清除数据溢出(无操作) - this.Log(LogLevel.Info, "Clear data overflow (no effect)"); - } - break; - - case Registers.SR: - if (sr_tbs == 1) - { - sr_tbs = 0; - } - else - { - sr_tbs = 1; - } - if (sr_rbs == 1) - { - sr_rbs = 0; - } - else - { - sr_rbs = 1; - } - break; - case Registers.IR: - // 只读,忽略写 - this.Log(LogLevel.Warning, "Attempted write to read-only IR"); - break; - - case Registers.IER: - ier = (byte)(value & 0x01); // 只使用 bit0 (RIE) - UpdateIrFromRbs(); - UpdateInterrupts(); - this.Log(LogLevel.Info, "Write IER: 0x{0:X2}", ier); - break; - - case Registers.BTR0: - btr0 = value; - this.Log(LogLevel.Info, "Write BTR0: 0x{0:X2}", value); - break; - case Registers.BTR1: - btr1 = value; - this.Log(LogLevel.Info, "Write BTR1: 0x{0:X2}", value); - break; - case Registers.OCR: - ocr = value; - this.Log(LogLevel.Info, "Write OCR: 0x{0:X2}", value); - break; - case Registers.RXERR: - rxerr = value; - this.Log(LogLevel.Info, "Write RXERR: 0x{0:X2}", value); - break; - case Registers.TXERR: - txerr = value; - this.Log(LogLevel.Info, "Write TXERR: 0x{0:X2}", value); - break; - case Registers.RBSA: - rbsa = value; - this.Log(LogLevel.Info, "Write RBSA: 0x{0:X2}", value); - break; - case Registers.CDR: - cdr = value; - 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); - if (sr_tbs == 1) - { - txBuffer[bufIndex/4] = value; - this.Log(LogLevel.Info, "Write TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value); - } - else - { - this.Log(LogLevel.Warning, "Write to TX buffer while TBS=0 ignored"); - } - break; - - default: - // 未实现的寄存器忽略写 - this.Log(LogLevel.Info, "Write to unimplemented offset 0x{0:X} = 0x{1:X2}", offset, value); - break; - } - } - - // ================ 公共方法与事件 ================ - - - - - private void UpdateIrFromRbs() - { - if (sr_rbs == 1) - ir |= IR_RI; - else - // ir &= (byte)~IR_RI; - ir = (byte)(ir & ~IR_RI); - } - - private void UpdateInterrupts() - { - bool interrupt = ((ir & IR_RI) != 0) && ((ier & IER_RIE) != 0); - IRQ.Set(interrupt); - if (interrupt) - { - machine.ScheduleAction(TimeInterval.FromMicroseconds(1), _ => - { - IRQ.Set(false); - }); - this.Log(LogLevel.Info, "Interrupt asserted (RI)"); - } - else - { - this.Log(LogLevel.Info, "Interrupt deasserted"); - } - } - private readonly object lockObject = new object(); // 用于线程安全的锁对象 - - 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 (i > 0) sb.Append(" "); - sb.Append(txBuffer[i].ToString("X2")); - } - string result = sb.ToString(); - Console.WriteLine("GetTxBufferDataString returning: " + result); - Array.Clear(txBuffer, 0, txBuffer.Length); - sr_tbs = 1; - return result; - } - } - - public void SendRxBufferDataString(string frameString) - { - lock (lockObject) - { - - - if (string.IsNullOrWhiteSpace(frameString)) - { - Console.WriteLine("ReceiveFrame: 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++) - { - string part = parts[i].Trim(); - 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; - } - } - - 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}"); - } - } - // ================ 属性 ================ - - public long Size => 0x80; // 地址范围 0-31 - - public GPIO IRQ { get; } - - // ================ 寄存器枚举 ================ - - private enum Registers : long - { - MOD = 0x00, - CMR = 0x04, - SR = 0x08, - IR = 0x0C, - IER = 0x10, - BTR0 = 0x18, - BTR1 = 0x1C, - OCR = 0x20, - RXERR = 0x38, // 14 - TXERR = 0x3C, // 15 - TX_FRAME_INFO = 0x40, // 16 - 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, - TX_DATA8 = 0x68, // 26 - RBSA = 0x78, // 30 - CDR = 0x7C, // 31 - - } - - // ================ 常量位定义 ================ - - private const byte CMR_TR = 0x01; // 发送请求 (bit0) - private const byte CMR_RRB = 0x04; // 释放接收缓冲器 (bit2) - private const byte CMR_CDO = 0x08; // 清除数据溢出 (bit3) - - private const byte SR_BS = 0x80; // 总线状态 (bit7) - 本模拟中恒0 - private const byte SR_TBS = 0x04; // 发送缓冲器状态 (bit2) - private const byte SR_RBS = 0x01; // 接收缓冲器状态 (bit0) - - private const byte IR_RI = 0x01; // 接收中断 (bit0) - - private const byte IER_RIE = 0x01; // 接收中断使能 (bit0) - - // ================ 私有字段 ================ - - 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; - - // 状态位 - private byte sr_tbs; // 1=空闲 - private byte sr_rbs; // 1=有数据 - - private byte ir; // 仅 bit0 有效 - - private readonly byte[] txBuffer; // 地址16-26 - private readonly byte[] rxBuffer; // 当前接收帧 - } -} +// +// SJA1000 CAN 控制器外设实现(简化版,支持发送/接收队列,提高速率) +// 仅支持 PeliCAN 模式的标准帧,不考虑 BasicCAN、扩展帧、错误处理、多帧、验收滤波和发送中断。 +// 寄存器地址映射基于 PeliCAN 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR, +// 发送缓冲区(地址 16-26)、RBSA 和 CDR。命令寄存器位2=RRB,位3=CDO。 +// 接收为单帧,无 FIFO,无数据溢出处理。 +// 所有寄存器可随时读写,无复位模式限制。 +// +// author: Generated based on UART16550 template +// + +using System; +using System.Text; +using System.Collections.Generic; +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 +{ + /// + /// 简化版 SJA1000 CAN 控制器(PeliCAN 模式,仅标准帧) + /// + public class SJA1000_CAN : IDoubleWordPeripheral, IBytePeripheral, IKnownSize + { + public SJA1000_CAN(IMachine machine) + { + this.machine = machine; + IRQ = new GPIO(); + + txBuffer = new byte[11]; + rxBuffer = new byte[11]; + txFrameQueue = new Queue(); // 新增:发送队列 + rxFrameQueue = new Queue(); // 新增:接收队列 + + Reset(); + } + + public void Reset() + { + mod = 0; + ier = 0; + btr0 = 0; + btr1 = 0; + ocr = 0; + rxerr = 0; + txerr = 0; + rbsa = 0; + cdr = 0; + + sr_tbs = 1; // 发送缓冲区初始为空闲 + sr_rbs = 0; // 接收缓冲区初始为空 + ir = 0; + + Array.Clear(txBuffer, 0, txBuffer.Length); + Array.Clear(rxBuffer, 0, rxBuffer.Length); + txFrameQueue.Clear(); // 清空发送队列 + rxFrameQueue.Clear(); // 清空接收队列 + + UpdateInterrupts(); + + this.Log(LogLevel.Info, "SJA1000 CAN controller reset (simplified)"); + } + + // ================ IBusPeripheral 接口实现 ================ + + public uint ReadDoubleWord(long offset) + { + return ReadByte(offset); + } + + public void WriteDoubleWord(long offset, uint value) + { + WriteByte(offset, (byte)value); + } + + public byte ReadByte(long offset) + { + byte value = 0; + switch ((Registers)offset) + { + case Registers.MOD: + value = mod; + this.Log(LogLevel.Info, "Read MOD: 0x{0:X2}", value); + break; + + case Registers.CMR: + // 命令寄存器只写,读返回0 + this.Log(LogLevel.Info, "Read CMR (always 0)"); + value = 0; + break; + + case Registers.SR: + value = (byte)((sr_tbs << 2) | sr_rbs); // BS 恒为0 + 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 后清零,但需要根据当前 RBS 重新评估 RI(电平触发) + ir = 0; + UpdateIrFromRbs(); + UpdateInterrupts(); + this.Log(LogLevel.Info, "Read IR: 0x{0:X2}, cleared", value); + break; + + case Registers.IER: + value = ier; + 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; + + // 发送/接收缓冲区地址 16-26 + 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); + if (sr_rbs == 1) + { + // 接收缓冲区有数据时,读返回接收帧的内容 + value = rxBuffer[bufIndex/4]; + this.Log(LogLevel.Info, "Read RX buffer[{0}]: 0x{1:X2}", bufIndex/4, value); + } + else + { + //否则返回发送缓冲区的内容(通常无意义) + value = txBuffer[bufIndex/4]; + this.Log(LogLevel.Info, "Read TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value); + + } + break; + + default: + // 未实现的寄存器返回0 + this.Log(LogLevel.Info, "Read from unimplemented offset 0x{0:X}", offset); + value = 0; + break; + } + return value; + } + + public void WriteByte(long offset, byte value) + { + switch ((Registers)offset) + { + case Registers.MOD: + mod = value; + this.Log(LogLevel.Info, "Write MOD: 0x{0:X2}", value); + break; + + case Registers.CMR: + // 命令寄存器只写,处理命令 + this.Log(LogLevel.Info, "Write CMR: 0x{0:X2}", value); + if ((value & CMR_TR) != 0) + { + // 发送请求 + if (sr_tbs == 1) + { + // 将当前 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 + { + this.Log(LogLevel.Warning, "Send request while TBS=0 ignored"); + } + } + if ((value & CMR_RRB) != 0) + { + // 释放接收缓冲器:尝试从接收队列中加载下一帧 + lock (lockObject) + { + LoadNextRxFrame(); + } + this.Log(LogLevel.Info, "Receive buffer released"); + } + if ((value & CMR_CDO) != 0) + { + // 清除数据溢出(无操作) + this.Log(LogLevel.Info, "Clear data overflow (no effect)"); + } + break; + + case Registers.SR: + if (sr_tbs == 1) + { + sr_tbs = 0; + } + else + { + sr_tbs = 1; + } + if (sr_rbs == 1) + { + sr_rbs = 0; + } + else + { + sr_rbs = 1; + } + break; + case Registers.IR: + // 只读,忽略写 + this.Log(LogLevel.Warning, "Attempted write to read-only IR"); + break; + + case Registers.IER: + ier = (byte)(value & 0x01); // 只使用 bit0 (RIE) + UpdateIrFromRbs(); + UpdateInterrupts(); + this.Log(LogLevel.Info, "Write IER: 0x{0:X2}", ier); + break; + + case Registers.BTR0: + btr0 = value; + this.Log(LogLevel.Info, "Write BTR0: 0x{0:X2}", value); + break; + case Registers.BTR1: + btr1 = value; + this.Log(LogLevel.Info, "Write BTR1: 0x{0:X2}", value); + break; + case Registers.OCR: + ocr = value; + this.Log(LogLevel.Info, "Write OCR: 0x{0:X2}", value); + break; + case Registers.RXERR: + rxerr = value; + this.Log(LogLevel.Info, "Write RXERR: 0x{0:X2}", value); + break; + case Registers.TXERR: + txerr = value; + this.Log(LogLevel.Info, "Write TXERR: 0x{0:X2}", value); + break; + case Registers.RBSA: + rbsa = value; + this.Log(LogLevel.Info, "Write RBSA: 0x{0:X2}", value); + break; + case Registers.CDR: + cdr = value; + 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); + if (sr_tbs == 1) + { + txBuffer[bufIndex/4] = value; + this.Log(LogLevel.Info, "Write TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value); + } + else + { + this.Log(LogLevel.Warning, "Write to TX buffer while TBS=0 ignored"); + } + break; + + default: + // 未实现的寄存器忽略写 + this.Log(LogLevel.Info, "Write to unimplemented offset 0x{0:X} = 0x{1:X2}", offset, value); + break; + } + } + + // ================ 公共方法与事件 ================ + + private void UpdateIrFromRbs() + { + if (sr_rbs == 1) + ir |= IR_RI; + else + ir = (byte)(ir & ~IR_RI); + } + + private void UpdateInterrupts() + { + bool interrupt = ((ir & IR_RI) != 0) && ((ier & IER_RIE) != 0); + IRQ.Set(interrupt); + if (interrupt) + { + machine.ScheduleAction(TimeInterval.FromMicroseconds(1), _ => + { + IRQ.Set(false); + }); + this.Log(LogLevel.Info, "Interrupt asserted (RI)"); + } + else + { + this.Log(LogLevel.Info, "Interrupt deasserted"); + } + } + private readonly object lockObject = new object(); // 用于线程安全的锁对象 + + /// + /// 获取发送队列中所有帧的字符串表示(每帧以空格分隔的十六进制字节,帧间用换行分隔) + /// 调用后清空发送队列。 + /// + public string GetTxBufferDataString() + { + lock (lockObject) + { + if (txFrameQueue.Count == 0) + { + Console.WriteLine("GetTxBufferDataString: no frames in TX queue"); + return null; + } + 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); + return result; + } + } + + /// + /// 外部接口注入一帧接收数据(11字节的十六进制字符串,空格分隔) + /// 可多次调用以注入多帧,帧将存入接收队列。 + /// + public void SendRxBufferDataString(string frameString) + { + lock (lockObject) + { + if (string.IsNullOrWhiteSpace(frameString)) + { + Console.WriteLine("SendRxBufferDataString: empty string, ignored"); + return; + } + string[] parts = frameString.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + 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, + System.Globalization.CultureInfo.InvariantCulture, out byte b)) + { + 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(); + 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 + + public GPIO IRQ { get; } + + // ================ 寄存器枚举 ================ + + private enum Registers : long + { + MOD = 0x00, + CMR = 0x04, + SR = 0x08, + IR = 0x0C, + IER = 0x10, + BTR0 = 0x18, + BTR1 = 0x1C, + OCR = 0x20, + RXERR = 0x38, // 14 + TXERR = 0x3C, // 15 + TX_FRAME_INFO = 0x40, // 16 + 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, + TX_DATA8 = 0x68, // 26 + RBSA = 0x78, // 30 + CDR = 0x7C, // 31 + + } + + // ================ 常量位定义 ================ + + private const byte CMR_TR = 0x01; // 发送请求 (bit0) + private const byte CMR_RRB = 0x04; // 释放接收缓冲器 (bit2) + private const byte CMR_CDO = 0x08; // 清除数据溢出 (bit3) + + private const byte SR_BS = 0x80; // 总线状态 (bit7) - 本模拟中恒0 + private const byte SR_TBS = 0x04; // 发送缓冲器状态 (bit2) + private const byte SR_RBS = 0x01; // 接收缓冲器状态 (bit0) + + private const byte IR_RI = 0x01; // 接收中断 (bit0) + + private const byte IER_RIE = 0x01; // 接收中断使能 (bit0) + + // ================ 私有字段 ================ + + 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; + + // 状态位 + private byte sr_tbs; // 1=空闲 + private byte sr_rbs; // 1=有数据 + + private byte ir; // 仅 bit0 有效 + + private readonly byte[] txBuffer; // 临时发送缓冲区(单帧) + private readonly byte[] rxBuffer; // 当前接收帧(单帧) + + private readonly Queue txFrameQueue; // 发送队列 + private readonly Queue rxFrameQueue; // 接收队列 + } +} \ No newline at end of file