parent
fedccf327f
commit
790b1e62e0
@ -0,0 +1,37 @@ |
||||
using BusCommPracticeConsoleApp.Models; |
||||
|
||||
namespace BusCommPracticeConsoleApp.CANs |
||||
{ |
||||
public class CANBus |
||||
{ |
||||
private readonly List<CANNode> _nodes = new List<CANNode>(); |
||||
private CanFrame _currentFrame = null; |
||||
|
||||
public void AddNode(CANNode node) |
||||
{ |
||||
_nodes.Add(node); |
||||
node.ConnectToBus(this); |
||||
} |
||||
|
||||
public void SendFrame(CANNode sender, CanFrame frame) |
||||
{ |
||||
if (_currentFrame != null && frame.ID >= _currentFrame.ID) |
||||
{ |
||||
Console.WriteLine("Already higher priority frame is used."); |
||||
return; |
||||
} |
||||
|
||||
_currentFrame = frame; |
||||
Console.WriteLine($"{sender.Name} node send the frame{Environment.NewLine}{frame}"); |
||||
} |
||||
|
||||
public void CompleteTransmission() |
||||
{ |
||||
if (_currentFrame == null) |
||||
return; |
||||
|
||||
Console.WriteLine($"Send 0x{_currentFrame.ID.ToString("X8")} frame complete."); |
||||
_currentFrame = null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,35 @@ |
||||
namespace BusCommPracticeConsoleApp.CANs |
||||
{ |
||||
public class CANNode |
||||
{ |
||||
public string Name { get; set; } |
||||
private CANBus _bus; |
||||
|
||||
public CANNode(string name) |
||||
{ |
||||
Name = name; |
||||
} |
||||
|
||||
public void ConnectToBus(CANBus bus) |
||||
{ |
||||
_bus = bus; |
||||
} |
||||
|
||||
public void SendMessage(uint id, byte[] data) |
||||
{ |
||||
var frame = new CanFrame(id, false, data); |
||||
_bus.SendFrame(this, frame); |
||||
} |
||||
|
||||
public void ReceiveFrame(CanFrame frame) |
||||
{ |
||||
if (frame.CRC != frame.CRC) |
||||
Console.WriteLine("<{Name}> node CRC check error!"); |
||||
} |
||||
|
||||
public void AcknowledgeFrame() |
||||
{ |
||||
Console.WriteLine($"<{Name}> node acknowledged."); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,65 @@ |
||||
using System.Text; |
||||
|
||||
namespace BusCommPracticeConsoleApp.CANs |
||||
{ |
||||
public class CanFrame |
||||
{ |
||||
// Field Define |
||||
public bool SOF { get; set; } = true; // Start of Frame (1bit) |
||||
public uint ID { get; set; } // Identifier (29bits) |
||||
public bool RTR { get; set; } // Remote Transmittion Request (1bit) |
||||
public byte DLC { get; set; } // Data Length Code (4bit, 0~8) |
||||
public byte[] Data { get; set; } // Data Field (0~8 bytes) |
||||
public ushort CRC { get; set; } // Cyclic Redundancy Check (15bits) |
||||
public bool ACK { get; set; } // Acknowledge (1bit) |
||||
public byte EOF { get; set; } // End of Frame (7bits, all 1) |
||||
|
||||
public CanFrame(uint id, bool rtr, byte[] data) |
||||
{ |
||||
if (id > 0x1FFFFFFF) // 29bits check |
||||
throw new ArgumentException("The id cannot larger than 29bits."); |
||||
|
||||
if (data.Length > 8) |
||||
throw new ArgumentException("The data length cannot larger than 8bytes."); |
||||
|
||||
ID = id; |
||||
RTR = rtr; |
||||
DLC = (byte)data.Length; |
||||
Data = data; |
||||
CRC = CalculateCRC(); |
||||
ACK = false; |
||||
} |
||||
|
||||
private ushort CalculateCRC() |
||||
{ |
||||
uint crc = ID; |
||||
crc += RTR ? 1u : 0u; |
||||
crc += DLC; |
||||
foreach (var c in Data) |
||||
crc += c; |
||||
|
||||
return (ushort)(crc & 0x7FFF); // 15bits masking |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
StringBuilder sb = new StringBuilder(); |
||||
sb.AppendLine("=== CAN 2.0B Frame ==="); |
||||
sb.AppendLine($"SOF: {SOF}"); |
||||
sb.AppendLine($"ID: 0x{ID:X8}"); |
||||
sb.AppendLine($"RTR: {RTR}"); |
||||
sb.AppendLine($"DLC: {DLC}"); |
||||
sb.Append("Data: "); |
||||
for (int i = 0; i < DLC; i++) |
||||
{ |
||||
sb.Append($"0x{Data[i]:X2} "); |
||||
} |
||||
sb.AppendLine(); |
||||
sb.AppendLine($"CRC: 0x{CRC:X4}"); |
||||
sb.AppendLine($"ACK: {ACK}"); |
||||
sb.AppendLine($"EOF: 0b{Convert.ToString(EOF, 2).PadLeft(7, '0')}"); |
||||
sb.AppendLine("======================"); |
||||
return sb.ToString(); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue