dotnet 核心中的 SocketCAN

SocketCAN in dotnet core

我正在为 Linux 上的设备编写软件,它应该可以与 CAN 接口一起使用。理想情况下,我希望在不连接来自 c ++ 的第三方库的情况下使用该接口。可能吗?

您需要查看 SocketCAN 库,它是 Linux 的一部分。 您还可以使用 candump 和 cansend 来帮助您开发,也可以查看 candump.c and cansend.c 源文件以获取灵感。

我看到有一个 dotnet 标签,如果你想在 dotnet 中使用 CAN,我建议你写一个小的 C 库来处理 CAN 的东西。然后将其编组到 dotnet,一旦您可以访问 dotnet,您就可以将内容包装在 类 中并创建您需要的任何抽象。

我使用本机函数解决了这个问题。这里示例绑定套接字,可以使用本地函数 write( or aio_write) 和 read 读写消息。 CanPublisher in UDSim 例如

const int Siocgifindex = 0x8933;
private const int PfCan = 29;
private const int SockRaw = 3;
private const int CanRaw = 1;
private const int CanMtu = 16;

[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 mtu);
[DllImport("libc", SetLastError = true)]
private static extern int bind(int fd, ref SockaddrCan addr, int addrlen);


[StructLayout(LayoutKind.Sequential)]
struct SockaddrCan
{
    public ushort can_family;
    public int can_ifindex;
    public uint rx_id;
    public uint tx_id;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct Ifreq
{
    public Ifreq(string ifr_name)
    {
        this.ifr_name = ifr_name;
        this.ifr_ifindex = 0; // ifru_ivalue
        this.ifru_mtu = 0;
    }

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
    public string ifr_name;
    public int ifr_ifindex;
    public uint ifru_mtu;
}

var addr = new SockaddrCan();
var s = socket(PfCan, SockRaw, CanRaw);
var ifr = new Ifreq("vcan0");
var ret = ioctl(s, Siocgifindex, ref ifr);
addr.can_ifindex = ifr.ifr_ifindex;
addr.can_family = PfCan;
ret = bind(s, ref addr, Marshal.SizeOf(addr));

我已经为 SocketCAN 编写了一个名为 SocketCAN# (SocketCANSharp) 的 .NET 托管包装器库:https://github.com/derek-will/SocketCANSharp

SocketCAN# 允许在 Linux.

上的 .NET 应用程序中使用原始 CAN、ISO-TP、广播管理器和 J1939 套接字

一些示例代码:

IEnumerable<CanNetworkInterface> collection = CanNetworkInterface.GetAllInterfaces(true);

var iface = collection.FirstOrDefault(i =>  i.Name.Equals("vcan0"));

using (var rawCanSocket = new RawCanSocket())
{
    rawCanSocket.Bind(iface);
    int bytesWritten = rawCanSocket.Write(
        new CanFrame(0x123, new byte[] { 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }));
}

库下面使用 P/Invoke 调用本机 libc 函数并在托管代码和非托管代码之间来回编组各种类型。