2023-04-22 07:48:04 +00:00
|
|
|
// Package can provides generic CAN interfaces and types.
|
|
|
|
//
|
|
|
|
// It has a generic can Frame (packet), as well as a filter type.
|
|
|
|
// we also define standard interfaces for objects that can accept
|
|
|
|
// can frames. We can use this pattern to easily extend the capabiltiies of the program
|
|
|
|
// by writing "adapters" to various devices/formats (xbee, sqlite, network socket, socketcan)
|
2023-05-08 06:28:36 +00:00
|
|
|
package gotelem
|
2023-04-15 15:03:35 +00:00
|
|
|
|
2023-05-09 15:25:29 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2023-04-22 07:48:04 +00:00
|
|
|
// Frame represents a protocol-agnostic CAN frame. The Id can be standard or extended,
|
|
|
|
// but if it is extended, the Kind should be EFF.
|
2023-04-15 15:03:35 +00:00
|
|
|
type Frame struct {
|
2023-04-16 07:46:41 +00:00
|
|
|
Id uint32
|
|
|
|
Data []byte
|
2023-04-15 15:03:35 +00:00
|
|
|
Kind Kind
|
|
|
|
}
|
|
|
|
|
2023-05-20 19:53:49 +00:00
|
|
|
//go:generate msgp
|
2023-05-03 15:38:37 +00:00
|
|
|
type CANFrame interface {
|
|
|
|
Id() uint32
|
|
|
|
Data() []byte
|
|
|
|
Type() Kind
|
|
|
|
}
|
|
|
|
|
2023-04-15 15:03:35 +00:00
|
|
|
//go:generate stringer -output=frame_kind.go -type Kind
|
2023-04-22 07:48:04 +00:00
|
|
|
|
|
|
|
// Kind is the type of the can Frame
|
2023-04-15 15:03:35 +00:00
|
|
|
type Kind uint8
|
|
|
|
|
|
|
|
const (
|
2023-05-09 15:25:29 +00:00
|
|
|
CanSFFFrame Kind = iota // Standard ID Frame
|
|
|
|
CanEFFFrame // Extended ID Frame
|
|
|
|
CanRTRFrame // Remote Transmission Request Frame
|
|
|
|
CanErrFrame // Error Frame
|
2023-04-15 15:03:35 +00:00
|
|
|
)
|
|
|
|
|
2023-04-22 07:48:04 +00:00
|
|
|
// CanFilter is a basic filter for masking out data. It has an Inverted flag
|
|
|
|
// which indicates opposite behavior (reject all packets that match Id and Mask).
|
|
|
|
// The filter matches when (packet.Id & filter.Mask) == filter.Id
|
2023-04-16 07:46:41 +00:00
|
|
|
type CanFilter struct {
|
|
|
|
Id uint32
|
|
|
|
Mask uint32
|
|
|
|
Inverted bool
|
|
|
|
}
|
2023-04-15 15:03:35 +00:00
|
|
|
|
2023-04-22 07:48:04 +00:00
|
|
|
// CanSink is an object that can accept Frames to transmit.
|
2023-04-15 15:03:35 +00:00
|
|
|
type CanSink interface {
|
2023-04-16 07:46:41 +00:00
|
|
|
Send(*Frame) error
|
2023-04-15 15:03:35 +00:00
|
|
|
}
|
|
|
|
|
2023-04-22 07:48:04 +00:00
|
|
|
// CanSource is an object that can receive Frames.
|
2023-04-15 15:03:35 +00:00
|
|
|
type CanSource interface {
|
2023-04-15 20:41:51 +00:00
|
|
|
Recv() (*Frame, error)
|
2023-04-15 15:03:35 +00:00
|
|
|
}
|
2023-04-20 20:26:29 +00:00
|
|
|
|
2023-04-22 07:48:04 +00:00
|
|
|
// CanTransciever is an object that can both send and receive Frames.
|
2023-04-20 20:26:29 +00:00
|
|
|
type CanTransciever interface {
|
|
|
|
CanSink
|
|
|
|
CanSource
|
|
|
|
}
|
2023-05-09 15:25:29 +00:00
|
|
|
|
|
|
|
// CanWriter
|
|
|
|
type CanWriter struct {
|
|
|
|
output *os.File
|
|
|
|
}
|
|
|
|
|
|
|
|
// send writes the frame to the file.
|
|
|
|
func (cw *CanWriter) Send(f *Frame) error {
|
|
|
|
ts := time.Now().Unix()
|
|
|
|
|
2023-05-14 21:19:57 +00:00
|
|
|
_, err := fmt.Fprintf(cw.output, "%d %X %X\n", ts, f.Id, f.Data)
|
2023-05-09 15:25:29 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cw *CanWriter) Close() error {
|
|
|
|
return cw.output.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
func OpenCanWriter(name string) (*CanWriter, error) {
|
|
|
|
f, err := os.Create(name)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cw := &CanWriter{
|
|
|
|
output: f,
|
|
|
|
}
|
|
|
|
return cw, nil
|
|
|
|
}
|