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();

 

posted @ 2026-06-03 14:06  妖言惑众'  阅读(5)  评论(0)    收藏  举报