Current section
Files
Jump to
Current section
Files
src/cangaroo/types.gleam
//// Type definitions for cangaroo.
////
//// This module defines the core types used throughout cangaroo for
//// representing CAN sockets, clients, frames, and filters. The main types
//// you'll interact with are:
////
//// - `CanClient`: The primary handle for interacting with a CAN interface
//// - `CanFrame`: Represents a CAN frame with an ID and data payload
//// - `CanFilter`: Defines filtering criteria for receiving certain frames
import gleam/dynamic
import gleam/erlang/process
/// An opaque type representing a CAN socket connection.
///
/// This type wraps the underlying Excansock process and is managed internally
/// by `CanClient`. You typically don't interact with `CanSocket` directly,
/// use `CanClient` and the functions in the main `cangaroo` module instead.
pub opaque type CanSocket {
CanSocket(pid: process.Pid)
}
/// An opaque type representing an active CAN client connection.
///
/// A `CanClient` is the primary handle for interacting with a CAN interface.
/// It encapsulates:
/// - The underlying CAN socket connection
/// - An OTP actor that handles incoming frames
/// - A subject for receiving CAN frames in your application
///
/// Create a client using `cangaroo.start_link()` and close it with
/// `cangaroo.close()` when you're done.
///
/// To receive incoming CAN frames, use the `messages()` function to get the subject,
/// then select on it with `gleam/erlang/process` selectors.
pub opaque type CanClient {
CanClient(
socket: CanSocket,
subject: process.Subject(CanFrame),
actor_subject: process.Subject(ActorMessage),
)
}
/// Represents a CAN frame with an identifier and data payload.
///
/// A CAN frame is the basic unit of communication on a CAN bus. Each frame
/// contains:
/// - `id`: The CAN identifier, either 11-bit (standard) or 29-bit (extended)
/// - `data`: The payload as a `BitArray`, up to 8 bytes for standard CAN
/// - `extended`: `True` for 29-bit extended IDs, `False` for 11-bit standard IDs
pub type CanFrame {
CanFrame(id: Int, data: BitArray, extended: Bool)
}
/// Defines a filter for receiving certain CAN frames.
///
/// Filters control which CAN frames are delivered to your application.
/// Each filter has three components:
/// - `id`: The CAN identifier to match against
/// - `mask`: A bitmask that determines which bits of the ID must match
/// - `extended`: `True` to filter extended frames, `False` for standard frames
///
/// A frame passes the filter if: `(frame_id & mask) == (filter_id & mask)`
pub type CanFilter {
CanFilter(id: Int, mask: Int, extended: Bool)
}
/// Internal message type used by the CAN client actor.
///
/// These messages are handled internally by cangaroo and are
/// not typically used directly by application code.
///
/// - `RawCanData`: Contains raw CAN frame data received from the bus (standard frames)
/// - `RawExtendedCanData`: Contains raw CAN frame data for extended frames (29-bit ID)
/// - `Shutdown`: Signals the actor to close the socket and stop
/// - `ExcansockDown`: The underlying Excansock GenServer process has exited
pub type ActorMessage {
RawCanData(frame_data: dynamic.Dynamic)
RawExtendedCanData(frame_data: dynamic.Dynamic)
Shutdown
ExcansockDown(reason: process.ExitReason)
}
pub fn messages(client: CanClient) -> process.Subject(CanFrame) {
client.subject
}
@internal
pub fn new_socket(pid: process.Pid) -> CanSocket {
CanSocket(pid)
}
@internal
pub fn socket_pid(socket: CanSocket) -> process.Pid {
socket.pid
}
@internal
pub fn new_client(
socket: CanSocket,
subject: process.Subject(CanFrame),
actor_subject: process.Subject(ActorMessage),
) -> CanClient {
CanClient(socket:, subject:, actor_subject:)
}
@internal
pub fn client_socket(client: CanClient) -> CanSocket {
client.socket
}
@internal
pub fn client_actor_subject(client: CanClient) -> process.Subject(ActorMessage) {
client.actor_subject
}