Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions src/SocketCANSharp/CanFrameFast.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#region License
/*
BSD 3-Clause License

Copyright (c) 2025, Brill Power
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

#if NET8_0_OR_GREATER
using System;
using System.Runtime.InteropServices;

namespace SocketCANSharp
{
/// <summary>
/// Represents a CAN frame (classical or FD) that exists only on the stack.
/// </summary>
public readonly ref struct CanFrameFast
{
private readonly Span<byte> _buffer;
private readonly Span<uint> _bufferAsUint;

/// <summary>
/// Construct a new CanFrameFast instance with the supplied buffer.
/// </summary>
public CanFrameFast(ref Span<byte> buffer)
{
if (buffer.Length != 16 && buffer.Length != 72)
{
throw new ArgumentException("Supplied buffer is too small.");
}
_buffer = buffer;
_bufferAsUint = MemoryMarshal.Cast<byte, uint>(buffer);
}

/// <summary>
/// Gets a reference to the 11 or 29-bit CAN ID.
/// </summary>
public ref uint CanId
{
get { return ref _bufferAsUint[0]; }
}

/// <summary>
/// Frame length in bytes.
/// </summary>
public ref byte Length
{
get { return ref _buffer[4]; }
}

/// <summary>
/// CAN FD specific flags for ESI, BRS, etc.
/// </summary>
public CanFdFlags Flags
{
get { return (CanFdFlags)_buffer[5]; }
set { _buffer[5] = (byte)value; }
}

/// <summary>
/// CAN frame payload.
/// </summary>
public Span<byte> Data => _buffer.Slice(8);

/// <summary>
/// Gets the total size of this CAN frame (either 16 or 72 bytes).
/// </summary>
public int Size => _buffer.Length;

/// <summary>
/// Indexes into the payload of this CAN frame.
/// </summary>
public ref byte this[int index]
{
get { return ref _buffer[8 + index]; }
}

internal Span<byte> Buffer => _buffer;
}
}
#endif // NET8_0_OR_GREATER
48 changes: 36 additions & 12 deletions src/SocketCANSharp/LibcNativeMethods.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#region License
/*
/*
BSD 3-Clause License

Copyright (c) 2021, Derek Will
Expand Down Expand Up @@ -28,7 +28,7 @@ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

Expand Down Expand Up @@ -89,7 +89,7 @@ public static class LibcNativeMethods
public static extern int Ioctl(SafeFileDescriptorHandle socketHandle, int request, [In][Out] IfreqMtu ifreq);

/// <summary>
/// Used to obtain a timeval struct with the receive timestamp of the last packet passed to the user.
/// Used to obtain a timeval struct with the receive timestamp of the last packet passed to the user.
/// </summary>
/// <param name="socketHandle">Socket Handle Wrapper Instance</param>
/// <param name="request">Request Code</param>
Expand Down Expand Up @@ -147,7 +147,19 @@ public static class LibcNativeMethods
/// <returns>0 on success, -1 on error</returns>
[DllImport("libc", EntryPoint="connect", SetLastError=true)]
public static extern int Connect(SafeFileDescriptorHandle socketHandle, SockAddrCanJ1939 addr, int addrSize);


#if NET8_0_OR_GREATER
/// <summary>
/// Write the contents of a byte buffer to the socket.
/// </summary>
/// <param name="socketHandle">Socket Handle Wrappper Instance</param>
/// <param name="frame">Reference to a buffer to write</param>
/// <param name="frameSize">Size of the buffer in bytes</param>
/// <returns>The number of bytes written on success, -1 on error</returns>
[DllImport("libc", EntryPoint = "write", SetLastError = true)]
internal static extern int Write(SafeFileDescriptorHandle socketHandle, ref byte frame, int frameSize);
#endif // NET8_0_OR_GREATER

/// <summary>
/// Write the CanFrame to the socket.
/// </summary>
Expand Down Expand Up @@ -288,6 +300,18 @@ public static class LibcNativeMethods
[DllImport("libc", EntryPoint="write", SetLastError=true)]
public static extern int Write(SafeFileDescriptorHandle socketHandle, byte[] data, int dataSize);

#if NET8_0_OR_GREATER
/// <summary>
/// Read into a byte buffer from the socket.
/// </summary>
/// <param name="socketHandle">Socket Handle Wrapper Instance</param>
/// <param name="frame">A reference to a byte buffer to populate</param>
/// <param name="frameSize">Size of byte buffer</param>
/// <returns>The number of bytes read on success, -1 on error</returns>
[DllImport("libc", EntryPoint = "read", SetLastError = true)]
internal static extern int Read(SafeFileDescriptorHandle socketHandle, ref byte frame, int frameSize);
#endif // NET8_0_OR_GREATER

/// <summary>
/// Read a CanFrame from the socket.
/// </summary>
Expand Down Expand Up @@ -337,7 +361,7 @@ public static class LibcNativeMethods
/// <returns>The number of bytes read on success, -1 on error</returns>
[DllImport("libc", EntryPoint="read", SetLastError=true)]
public static extern int Read(SafeFileDescriptorHandle socketHandle, [Out] BcmGenericMessage message, int msgSize);

/// <summary>
/// Read a BcmGenericMessage from the socket. Variant for 32-bit.
/// </summary>
Expand Down Expand Up @@ -715,7 +739,7 @@ public static class LibcNativeMethods
/// <returns>0 or 1 on success depending on option name and value, -1 on error</returns>
[DllImport("libc", EntryPoint="setsockopt", SetLastError=true)]
public static extern int SetSockOpt(SafeFileDescriptorHandle socketHandle, SocketLevel socketLevel, J1939SocketOptions optionName, ref int optionValue, int optionValueSize);

/// <summary>
/// Get the socket option specified by the option name and socket level to the provided option value for the supplied socket.
/// </summary>
Expand Down Expand Up @@ -751,7 +775,7 @@ public static class LibcNativeMethods
/// <returns>0 on success, -1 on error</returns>
[DllImport("libc", EntryPoint="getsockopt", SetLastError=true)]
public static extern int GetSockOpt(SafeFileDescriptorHandle socketHandle, SocketLevel socketLevel, J1939SocketOptions optionName, [In, Out] J1939Filter[] filters, ref int optionValueSize);

/// <summary>
/// Set the socket option specified by the option name and socket level to the provided option value for the supplied socket.
/// </summary>
Expand All @@ -775,7 +799,7 @@ public static class LibcNativeMethods
/// <returns>0 on success, -1 on error</returns>
[DllImport("libc", EntryPoint = "getsockopt", SetLastError = true)]
public static extern int GetSockOpt(SafeFileDescriptorHandle socketHandle, SocketLevel socketLevel, int optionName, IntPtr optionValue, ref int optionValueSize);

/// <summary>
/// Set the socket option specified by the option name and socket level to the provided option value for the supplied socket.
/// </summary>
Expand Down Expand Up @@ -817,12 +841,12 @@ public static class LibcNativeMethods
/// <summary>
/// Opens an epoll file descriptor.
/// </summary>
/// <param name="size">The size argument is ignored since Linux 2.6.8, but must be greater than zero for backwards compatibility.
/// <param name="size">The size argument is ignored since Linux 2.6.8, but must be greater than zero for backwards compatibility.
/// Originally, this argument was intended as a hint to the kernel as to the number of file descriptors that the caller expected to add to the epoll instance.</param>
/// <returns>On success, returns a valid file descriptor handle. On failure, returns an invalid file descriptor handle.</returns>
[DllImport("libc", EntryPoint="epoll_create", SetLastError=true)]
public static extern SafeFileDescriptorHandle EpollCreate(int size);

/// <summary>
/// Control interface used to add, modify, and delete entries from the interest list of an epoll file descriptor.
/// </summary>
Expand All @@ -833,7 +857,7 @@ public static class LibcNativeMethods
/// <returns>0 on success, -1 on error</returns>
[DllImport("libc", EntryPoint="epoll_ctl", SetLastError=true)]
public static extern int EpollControl(SafeFileDescriptorHandle epfd, EpollOperation op, SafeFileDescriptorHandle fd, ref EpollEvent evnt);

/// <summary>
/// Waits for an I/O event on an epoll file descriptor.
/// </summary>
Expand Down Expand Up @@ -902,7 +926,7 @@ public static class LibcNativeMethods
/// <returns>The number of bytes received on success, -1 on error</returns>
[DllImport("libc", EntryPoint="recvmsg", SetLastError=true)]
public static extern int RecvMsg(SafeFileDescriptorHandle socketHandle, ref MessageHeader canMessage, MessageFlags flags);

/// <summary>
/// Retrieves the index of the network interface corresponding to the specified name.
/// </summary>
Expand Down
Loading