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