C# Linux使用CAN通讯
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
public class CanSocket
{
private const int PF_CAN = 29;
private const int SOCK_RAW = 3;
private const int CAN_RAW = 1;
private const int SIOCGIFINDEX = 0x8933;
private const int SOL_SOCKET = 1;
private const int SO_RCVTIMEO = 20;
private int _fd = -1;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CanFrame
{
public uint can_id;
public byte can_dlc;
private byte __pad;
private byte __res0;
private byte __res1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] data;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct Ifreq
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string ifr_name;
public int ifr_ifindex;
}
[StructLayout(LayoutKind.Sequential)]
private struct SockAddrCan
{
public int can_family;
public int can_ifindex;
public uint can_skt_err_mask;
}
[DllImport("libc", SetLastError = true)]
private static extern int socket(int domain, int type, int protocol);
[DllImport("libc", SetLastError = true)]
private static extern int ioctl(int fd, int request, ref Ifreq ifr);
[DllImport("libc", SetLastError = true)]
private static extern int bind(int fd, ref SockAddrCan addr, int addrlen);
[DllImport("libc", SetLastError = true)]
private static extern int write(int fd, ref CanFrame frame, int count);
[DllImport("libc", SetLastError = true)]
private static extern int read(int fd, ref CanFrame frame, int count);
[DllImport("libc", SetLastError = true)]
private static extern int close(int fd);
public bool Open(string canInterface = "can0", int bitrate = 500000)
{
try
{
ExecuteShell($"ip link set {canInterface} down");
ExecuteShell($"ip link set {canInterface} type can bitrate {bitrate}");
ExecuteShell($"ip link set {canInterface} up");
_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (_fd < 0) return false;
Ifreq ifr = default;
ifr.ifr_name = canInterface;
if (ioctl(_fd, SIOCGIFINDEX, ref ifr) < 0)
{
close(_fd);
_fd = -1;
return false;
}
SockAddrCan addr = default;
addr.can_family = PF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(_fd, ref addr, Marshal.SizeOf<SockAddrCan>()) < 0)
{
close(_fd);
_fd = -1;
return false;
}
return true;
}
catch
{
if (_fd >= 0) { close(_fd); _fd = -1; }
return false;
}
}
public bool Send(uint canId, byte[] data)
{
if (_fd < 0 || data == null || data.Length > 8)
return false;
try
{
CanFrame frame = default;
frame.can_id = canId | 0x80000000;
frame.can_dlc = (byte)data.Length;
frame.data = new byte[8];
Array.Copy(data, frame.data, data.Length);
return write(_fd, ref frame, Marshal.SizeOf(frame)) > 0;
}
catch
{
return false;
}
}
public bool Receive(out uint canId, out byte[] data, int timeoutMs = 100)
{
canId = 0;
data = Array.Empty<byte>();
if (_fd < 0) return false;
try
{
CanFrame frame = default;
int ret = read(_fd, ref frame, Marshal.SizeOf(frame));
if (ret <= 0)
{
Thread.Sleep(10);
return false;
}
canId = frame.can_id & 0x1FFFFFFF;
data = new byte[frame.can_dlc];
Array.Copy(frame.data, data, frame.can_dlc);
return true;
}
catch
{
return false;
}
}
public void Close()
{
if (_fd >= 0)
{
close(_fd);
_fd = -1;
}
}
private void ExecuteShell(string cmd)
{
try
{
using var proc = Process.Start(new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = $"-c \"{cmd}\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
});
proc.WaitForExit();
}
catch { }
}
}
调用
var can = new CanSocket(); if (!can.Open("can0",250000)) { Console.WriteLine("CAN 打开失败"); return; } Console.WriteLine("CAN 已打开"); // 接收线程 new Thread(() => { while (true) { if (can.Receive(out var id, out var bytes)) { Console.WriteLine($"Recv ID={id:X} {BitConverter.ToString(bytes)}"); } Thread.Sleep(10); } }).Start(); // 发送线程 new Thread(() => { while (true) { can.Send(0x180256F4, new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }); Thread.Sleep(1000); } }).Start(); Console.ReadLine(); can.Close();
浙公网安备 33010602011771号