Skip to content

Commit

Permalink
turned ascii into txt
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewI26 committed Dec 29, 2024
1 parent 5b0bb19 commit fc51ba6
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 150 deletions.
21 changes: 13 additions & 8 deletions canlink/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ canlink

`canlink` contains utilities for managing CAN traffic for the duration of a HIL test.

BusManager and Tracer
BusManager
---------------
`BusManager` is a centralized node responsible for orchestrating all interactions with a CAN bus.
It acts as a message broker supporting the transmission of bus traffic to registered handlers and receiving incoming messages from these handlers to write to the bus.

Tracer
---------------
`Tracer` writes traffic on a CAN bus into trace files.
Currently supported formats are Json and Ascii.
Tracer takes in a struct that must implement the `Converter` interface.
A `Converter` must have a method `GetFileExtension`to return the proper file extension and `FrameToString`to convert a frame to a string. Currently implemented converters support `Jsonl` (https://jsonlines.org/) and `Text` for basic text logging.

__NOTE: If seeking to trace traffic into an unsupported format, implement a converter for that specific format.__


### Usage
Expand All @@ -27,26 +32,26 @@ A logger, and pointer to a socketcan connection are passed as arguments.
// Create a network connection for vcan0
conn, err := socketcan.DialContext(context.Background(), "can", "vcan0")
if err != nil {
return
return
}

manager := canlink.NewBusManager(logger, &conn)
}
```

2) Create an instance of Tracer with the `NewTracer()` function.
A can interface, trace directory and logger must be provided as arguments.
The trace directory must be a folder within the current directory with the same name as the argument provided.
A can interface, logger, and converter must be provided as arguments.
A timeout and a file name are optional parameters. If no file name is provided, a name will be generated using the current time and date. The tracer will timeout after 30 minutes by default. The trace file will be created in the same directory.
Functional options are available of type `TracerOption` if required.

```go
func main() {
tracer := canlink.NewTracer(
"vcan0",
"traces",
logger,
canlink.WithBusName("veh"),
canlink.WithConverter(canlink.NewAscii()),
canlink.Text{}
canlink.WithTimeout(1*time.Second)
canlink.WithFileName("trace_sample")
)
}
```
Expand Down
18 changes: 5 additions & 13 deletions canlink/ascii.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,15 @@ import (
"go.uber.org/zap"
)

// Ascii object provides utilities for writing frames to trace files in ascii format
type Ascii struct {
fileExtention string
}

func NewAscii() *Ascii {
return &Ascii{
fileExtention: ".asc",
}
}
// Text object provides utilities for writing frames to trace files in text format
type Text struct {}

func (a *Ascii) GetFileExtention() string {
return a.fileExtention
func (a *Text) GetFileExtension() string {
return "txt"
}

// FrameToString converts a timestamped frame into a string, for file writing
func (a *Ascii) FrameToString(l *zap.Logger, timestampedFrame *TimestampedFrame) string {
func (a *Text) FrameToString(l *zap.Logger, timestampedFrame *TimestampedFrame) string {
var builder strings.Builder

write := func(s string) {
Expand Down
4 changes: 2 additions & 2 deletions canlink/convertors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
)

// Converter provides functionality for converting timestamped frames into strings for file writing.
// Each supported trace file type must impliment Converter.
// Each supported trace file type must implement Converter.
type Converter interface {
GetFileExtention() string
GetFileExtension() string
FrameToString(*zap.Logger, *TimestampedFrame) string
}
26 changes: 10 additions & 16 deletions canlink/json.go → canlink/jsonl.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,28 @@ import (
"go.uber.org/zap"
)

// Json object provides utilities for writing frames to trace files in json format
type Json struct {
fileExtention string
}

func NewJson() *Json {
return &Json{
fileExtention: ".jsonl",
}
}
// Jsonl object provides utilities for writing frames to trace files in jsonl format.
// See https://jsonlines.org/ to view Jsonl documentation.
type Jsonl struct {}

func (a *Json) GetFileExtention() string {
return a.fileExtention
// GetFileExtension returns the file extension
func (a *Jsonl) GetFileExtension() string {
return "jsonl"
}

// FrameToString converts a timestamped frame into a string, for file writing
func (a *Json) FrameToString(l *zap.Logger, timestampedFrame *TimestampedFrame) string {
jsonObject := map[string]interface{}{
func (a *Jsonl) FrameToString(l *zap.Logger, timestampedFrame *TimestampedFrame) string {
jsonlObject := map[string]interface{}{
"time": timestampedFrame.Time.Format(_messageTimeFormat),
"id": strconv.FormatUint(uint64(timestampedFrame.Frame.ID), _decimal),
"frameLength": strconv.FormatUint(uint64(timestampedFrame.Frame.Length), _decimal),
"bytes": timestampedFrame.Frame.Data,
}

jsonData, err := json.Marshal(jsonObject)
jsonlData, err := json.Marshal(jsonlObject)
if err != nil {
l.Error(err.Error())
}

return string(jsonData)
return string(jsonlData)
}
86 changes: 38 additions & 48 deletions canlink/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/macformula/hil/utils"
"github.com/pkg/errors"
"path/filepath"

"go.uber.org/zap"
)
Expand All @@ -17,6 +16,8 @@ const (
_frameBufferLength = 10
_loggerName = "can_tracer"

_defaultFileName = "" // if no file name is provided, file name will be generated when trace file is created

_decimal = 10

_messageTimeFormat = "15:04:05.0000"
Expand All @@ -30,32 +31,31 @@ type TracerOption func(*Tracer)
// Tracer listens on a CAN bus and records all traffic
type Tracer struct {
l *zap.Logger
frameCh chan TimestampedFrame // This channel will be provided by the bus manager
frameCh chan TimestampedFrame // This channel will be created by the bus manager
err *utils.ResettableError

traceDir string
converter Converter
traceFile *os.File
fileName string

canInterface string
timeout time.Duration
busName string
}

// NewTracer returns a new Tracer
func NewTracer(
canInterface string,
traceDir string,
l *zap.Logger,
converter Converter,
opts ...TracerOption) *Tracer {

tracer := &Tracer{
l: l.Named(_loggerName),
err: utils.NewResettaleError(),
timeout: _defaultTimeout,
canInterface: canInterface,
traceDir: traceDir,
busName: canInterface,
fileName: _defaultFileName,
converter: converter,
}

for _, o := range opts {
Expand All @@ -72,24 +72,10 @@ func WithTimeout(timeout time.Duration) TracerOption {
}
}

// WithBusName sets the name of the bus for the Tracer
func WithBusName(name string) TracerOption {
return func(t *Tracer) {
t.busName = name
}
}

// WithFrameChannel sets frame channel for incoming frames
func WithFrameCh(frameCh chan TimestampedFrame) TracerOption {
// WithFileName sets the file name
func WithFileName(fileName string) TracerOption {
return func(t *Tracer) {
t.frameCh = frameCh
}
}

// WithConverter sets the converter
func WithConverter(converter Converter) TracerOption {
return func(t *Tracer) {
t.converter = converter
t.fileName = fileName
}
}

Expand All @@ -116,17 +102,30 @@ func (t *Tracer) Error() error {

// Handle listens to the frames in the broadcastChan and writes them to a file
func (t *Tracer) Handle(broadcastChan chan TimestampedFrame, transmitChan chan TimestampedFrame) error {
file, err := createEmptyTraceFile(t.traceDir, t.busName, t.converter.GetFileExtention())
if t.fileName == _defaultFileName {
dateStr := time.Now().Format(_filenameDateFormat)
timeStr := time.Now().Format(_filenameTimeFormat)
t.fileName = fmt.Sprintf(
"%s_%s.%s",
dateStr,
timeStr,
t.converter.GetFileExtension(),
)
} else {
t.fileName = fmt.Sprintf(
"%s.%s",
t.fileName,
t.converter.GetFileExtension(),
)
}

file, err := t.createEmptyTraceFile()
t.traceFile = file

if err != nil {
t.l.Info("cannot create trace file")
return errors.Wrap(err, "creating trace file")
}

if err != nil {
return errors.Wrap(err, "close trace file")
}

timeout := time.After(t.timeout)

func() error {
Expand All @@ -136,7 +135,7 @@ func (t *Tracer) Handle(broadcastChan chan TimestampedFrame, transmitChan chan T
t.l.Info("maximum trace time reached")
return nil
case receivedFrame := <-broadcastChan:
t.l.Info("frame recieved")
t.l.Info("frame received")
line := t.converter.FrameToString(t.l, &receivedFrame)

_, err := t.traceFile.WriteString(line + "\n")
Expand All @@ -156,25 +155,16 @@ func (t *Tracer) Name() string {
return "Tracer"
}

// createEmptyTraceFile creates an *os.File given information
func createEmptyTraceFile(dir string, busName string, fileSuffix string) (*os.File, error) {
dateStr := time.Now().Format(_filenameDateFormat)
timeStr := time.Now().Format(_filenameTimeFormat)

fileName := fmt.Sprintf(
"%s_%s_%s.%s",
busName,
dateStr,
timeStr,
fileSuffix,
)

filePath := filepath.Join(dir, fileName)
func (t *Tracer) GetFileName() string {
return t.fileName
}

file, err := os.Create(filePath)
// createEmptyTraceFile generates empty trace file given a file name
func (t *Tracer) createEmptyTraceFile() (*os.File, error) {
file, err := os.Create(t.fileName)
if err != nil {
return nil, errors.Wrap(err, "create file")
return nil, errors.Wrap(err, "create trace file")
}

return file, nil
}
}
Binary file removed cmd/busmanager/busmanager
Binary file not shown.
Binary file removed cmd/tracetest/main
Binary file not shown.
Loading

0 comments on commit fc51ba6

Please sign in to comment.