Refactor kafka to pure Go (franz-go), fix DBC stubs, update Dockerfile
This commit is contained in:
27
pkg/can-go/internal/clock/clock.go
Normal file
27
pkg/can-go/internal/clock/clock.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Package clock provides primitives for mocking time.
|
||||
package clock
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Clock provides capabilities from the time standard library package.
|
||||
type Clock interface {
|
||||
// After waits for the duration to elapse and then sends the current time on the returned channel.
|
||||
After(duration time.Duration) <-chan time.Time
|
||||
|
||||
// NewTicker returns a new Ticker.
|
||||
NewTicker(d time.Duration) Ticker
|
||||
|
||||
// Now returns the current local time.
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
// Ticker wraps the time.Ticker class.
|
||||
type Ticker interface {
|
||||
// C returns the channel on which the ticks are delivered.
|
||||
C() <-chan time.Time
|
||||
|
||||
// Stop the Ticker.
|
||||
Stop()
|
||||
}
|
||||
34
pkg/can-go/internal/clock/system.go
Normal file
34
pkg/can-go/internal/clock/system.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package clock
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// System returns a Clock implementation that delegate to the time package.
|
||||
func System() Clock {
|
||||
return &systemClock{}
|
||||
}
|
||||
|
||||
type systemClock struct{}
|
||||
|
||||
var _ Clock = &systemClock{}
|
||||
|
||||
func (c systemClock) After(d time.Duration) <-chan time.Time {
|
||||
return time.After(d)
|
||||
}
|
||||
|
||||
func (c systemClock) NewTicker(d time.Duration) Ticker {
|
||||
return &systemTicker{Ticker: *time.NewTicker(d)}
|
||||
}
|
||||
|
||||
func (c systemClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
type systemTicker struct {
|
||||
time.Ticker
|
||||
}
|
||||
|
||||
func (t systemTicker) C() <-chan time.Time {
|
||||
return t.Ticker.C
|
||||
}
|
||||
529
pkg/can-go/internal/gen/mock/mockcanrunner/mocks.go
Normal file
529
pkg/can-go/internal/gen/mock/mockcanrunner/mocks.go
Normal file
@@ -0,0 +1,529 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/fiskerinc/cloud-services/pkg/can-go/pkg/canrunner (interfaces: Node,TransmittedMessage,ReceivedMessage,FrameTransmitter,FrameReceiver)
|
||||
|
||||
// Package mockcanrunner is a generated GoMock package.
|
||||
package mockcanrunner
|
||||
|
||||
import (
|
||||
context "context"
|
||||
can "github.com/fiskerinc/cloud-services/pkg/can-go"
|
||||
canrunner "github.com/fiskerinc/cloud-services/pkg/can-go/pkg/canrunner"
|
||||
descriptor "github.com/fiskerinc/cloud-services/pkg/can-go/pkg/descriptor"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
net "net"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
)
|
||||
|
||||
// MockNode is a mock of Node interface.
|
||||
type MockNode struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockNodeMockRecorder
|
||||
}
|
||||
|
||||
// MockNodeMockRecorder is the mock recorder for MockNode.
|
||||
type MockNodeMockRecorder struct {
|
||||
mock *MockNode
|
||||
}
|
||||
|
||||
// NewMockNode creates a new mock instance.
|
||||
func NewMockNode(ctrl *gomock.Controller) *MockNode {
|
||||
mock := &MockNode{ctrl: ctrl}
|
||||
mock.recorder = &MockNodeMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockNode) EXPECT() *MockNodeMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Connect mocks base method.
|
||||
func (m *MockNode) Connect() (net.Conn, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Connect")
|
||||
ret0, _ := ret[0].(net.Conn)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Connect indicates an expected call of Connect.
|
||||
func (mr *MockNodeMockRecorder) Connect() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Connect", reflect.TypeOf((*MockNode)(nil).Connect))
|
||||
}
|
||||
|
||||
// Descriptor mocks base method.
|
||||
func (m *MockNode) Descriptor() *descriptor.Node {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Descriptor")
|
||||
ret0, _ := ret[0].(*descriptor.Node)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Descriptor indicates an expected call of Descriptor.
|
||||
func (mr *MockNodeMockRecorder) Descriptor() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Descriptor", reflect.TypeOf((*MockNode)(nil).Descriptor))
|
||||
}
|
||||
|
||||
// Lock mocks base method.
|
||||
func (m *MockNode) Lock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Lock")
|
||||
}
|
||||
|
||||
// Lock indicates an expected call of Lock.
|
||||
func (mr *MockNodeMockRecorder) Lock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lock", reflect.TypeOf((*MockNode)(nil).Lock))
|
||||
}
|
||||
|
||||
// ReceivedMessage mocks base method.
|
||||
func (m *MockNode) ReceivedMessage(arg0 uint32) (canrunner.ReceivedMessage, bool) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ReceivedMessage", arg0)
|
||||
ret0, _ := ret[0].(canrunner.ReceivedMessage)
|
||||
ret1, _ := ret[1].(bool)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ReceivedMessage indicates an expected call of ReceivedMessage.
|
||||
func (mr *MockNodeMockRecorder) ReceivedMessage(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReceivedMessage", reflect.TypeOf((*MockNode)(nil).ReceivedMessage), arg0)
|
||||
}
|
||||
|
||||
// TransmittedMessages mocks base method.
|
||||
func (m *MockNode) TransmittedMessages() []canrunner.TransmittedMessage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "TransmittedMessages")
|
||||
ret0, _ := ret[0].([]canrunner.TransmittedMessage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// TransmittedMessages indicates an expected call of TransmittedMessages.
|
||||
func (mr *MockNodeMockRecorder) TransmittedMessages() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransmittedMessages", reflect.TypeOf((*MockNode)(nil).TransmittedMessages))
|
||||
}
|
||||
|
||||
// Unlock mocks base method.
|
||||
func (m *MockNode) Unlock() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Unlock")
|
||||
}
|
||||
|
||||
// Unlock indicates an expected call of Unlock.
|
||||
func (mr *MockNodeMockRecorder) Unlock() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockNode)(nil).Unlock))
|
||||
}
|
||||
|
||||
// MockTransmittedMessage is a mock of TransmittedMessage interface.
|
||||
type MockTransmittedMessage struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockTransmittedMessageMockRecorder
|
||||
}
|
||||
|
||||
// MockTransmittedMessageMockRecorder is the mock recorder for MockTransmittedMessage.
|
||||
type MockTransmittedMessageMockRecorder struct {
|
||||
mock *MockTransmittedMessage
|
||||
}
|
||||
|
||||
// NewMockTransmittedMessage creates a new mock instance.
|
||||
func NewMockTransmittedMessage(ctrl *gomock.Controller) *MockTransmittedMessage {
|
||||
mock := &MockTransmittedMessage{ctrl: ctrl}
|
||||
mock.recorder = &MockTransmittedMessageMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockTransmittedMessage) EXPECT() *MockTransmittedMessageMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// BeforeTransmitHook mocks base method.
|
||||
func (m *MockTransmittedMessage) BeforeTransmitHook() func(context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BeforeTransmitHook")
|
||||
ret0, _ := ret[0].(func(context.Context) error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BeforeTransmitHook indicates an expected call of BeforeTransmitHook.
|
||||
func (mr *MockTransmittedMessageMockRecorder) BeforeTransmitHook() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeTransmitHook", reflect.TypeOf((*MockTransmittedMessage)(nil).BeforeTransmitHook))
|
||||
}
|
||||
|
||||
// Descriptor mocks base method.
|
||||
func (m *MockTransmittedMessage) Descriptor() *descriptor.Message {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Descriptor")
|
||||
ret0, _ := ret[0].(*descriptor.Message)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Descriptor indicates an expected call of Descriptor.
|
||||
func (mr *MockTransmittedMessageMockRecorder) Descriptor() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Descriptor", reflect.TypeOf((*MockTransmittedMessage)(nil).Descriptor))
|
||||
}
|
||||
|
||||
// Frame mocks base method.
|
||||
func (m *MockTransmittedMessage) Frame() can.Frame {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Frame")
|
||||
ret0, _ := ret[0].(can.Frame)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Frame indicates an expected call of Frame.
|
||||
func (mr *MockTransmittedMessageMockRecorder) Frame() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Frame", reflect.TypeOf((*MockTransmittedMessage)(nil).Frame))
|
||||
}
|
||||
|
||||
// IsCyclicTransmissionEnabled mocks base method.
|
||||
func (m *MockTransmittedMessage) IsCyclicTransmissionEnabled() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IsCyclicTransmissionEnabled")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// IsCyclicTransmissionEnabled indicates an expected call of IsCyclicTransmissionEnabled.
|
||||
func (mr *MockTransmittedMessageMockRecorder) IsCyclicTransmissionEnabled() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsCyclicTransmissionEnabled", reflect.TypeOf((*MockTransmittedMessage)(nil).IsCyclicTransmissionEnabled))
|
||||
}
|
||||
|
||||
// MarshalFrame mocks base method.
|
||||
func (m *MockTransmittedMessage) MarshalFrame() (can.Frame, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MarshalFrame")
|
||||
ret0, _ := ret[0].(can.Frame)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// MarshalFrame indicates an expected call of MarshalFrame.
|
||||
func (mr *MockTransmittedMessageMockRecorder) MarshalFrame() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarshalFrame", reflect.TypeOf((*MockTransmittedMessage)(nil).MarshalFrame))
|
||||
}
|
||||
|
||||
// Reset mocks base method.
|
||||
func (m *MockTransmittedMessage) Reset() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Reset")
|
||||
}
|
||||
|
||||
// Reset indicates an expected call of Reset.
|
||||
func (mr *MockTransmittedMessageMockRecorder) Reset() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Reset", reflect.TypeOf((*MockTransmittedMessage)(nil).Reset))
|
||||
}
|
||||
|
||||
// SetTransmitTime mocks base method.
|
||||
func (m *MockTransmittedMessage) SetTransmitTime(arg0 time.Time) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetTransmitTime", arg0)
|
||||
}
|
||||
|
||||
// SetTransmitTime indicates an expected call of SetTransmitTime.
|
||||
func (mr *MockTransmittedMessageMockRecorder) SetTransmitTime(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTransmitTime", reflect.TypeOf((*MockTransmittedMessage)(nil).SetTransmitTime), arg0)
|
||||
}
|
||||
|
||||
// String mocks base method.
|
||||
func (m *MockTransmittedMessage) String() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "String")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// String indicates an expected call of String.
|
||||
func (mr *MockTransmittedMessageMockRecorder) String() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockTransmittedMessage)(nil).String))
|
||||
}
|
||||
|
||||
// TransmitEventChan mocks base method.
|
||||
func (m *MockTransmittedMessage) TransmitEventChan() <-chan struct{} {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "TransmitEventChan")
|
||||
ret0, _ := ret[0].(<-chan struct{})
|
||||
return ret0
|
||||
}
|
||||
|
||||
// TransmitEventChan indicates an expected call of TransmitEventChan.
|
||||
func (mr *MockTransmittedMessageMockRecorder) TransmitEventChan() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransmitEventChan", reflect.TypeOf((*MockTransmittedMessage)(nil).TransmitEventChan))
|
||||
}
|
||||
|
||||
// UnmarshalFrame mocks base method.
|
||||
func (m *MockTransmittedMessage) UnmarshalFrame(arg0 can.Frame) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UnmarshalFrame", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UnmarshalFrame indicates an expected call of UnmarshalFrame.
|
||||
func (mr *MockTransmittedMessageMockRecorder) UnmarshalFrame(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnmarshalFrame", reflect.TypeOf((*MockTransmittedMessage)(nil).UnmarshalFrame), arg0)
|
||||
}
|
||||
|
||||
// WakeUpChan mocks base method.
|
||||
func (m *MockTransmittedMessage) WakeUpChan() <-chan struct{} {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "WakeUpChan")
|
||||
ret0, _ := ret[0].(<-chan struct{})
|
||||
return ret0
|
||||
}
|
||||
|
||||
// WakeUpChan indicates an expected call of WakeUpChan.
|
||||
func (mr *MockTransmittedMessageMockRecorder) WakeUpChan() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WakeUpChan", reflect.TypeOf((*MockTransmittedMessage)(nil).WakeUpChan))
|
||||
}
|
||||
|
||||
// MockReceivedMessage is a mock of ReceivedMessage interface.
|
||||
type MockReceivedMessage struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockReceivedMessageMockRecorder
|
||||
}
|
||||
|
||||
// MockReceivedMessageMockRecorder is the mock recorder for MockReceivedMessage.
|
||||
type MockReceivedMessageMockRecorder struct {
|
||||
mock *MockReceivedMessage
|
||||
}
|
||||
|
||||
// NewMockReceivedMessage creates a new mock instance.
|
||||
func NewMockReceivedMessage(ctrl *gomock.Controller) *MockReceivedMessage {
|
||||
mock := &MockReceivedMessage{ctrl: ctrl}
|
||||
mock.recorder = &MockReceivedMessageMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockReceivedMessage) EXPECT() *MockReceivedMessageMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AfterReceiveHook mocks base method.
|
||||
func (m *MockReceivedMessage) AfterReceiveHook() func(context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AfterReceiveHook")
|
||||
ret0, _ := ret[0].(func(context.Context) error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AfterReceiveHook indicates an expected call of AfterReceiveHook.
|
||||
func (mr *MockReceivedMessageMockRecorder) AfterReceiveHook() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterReceiveHook", reflect.TypeOf((*MockReceivedMessage)(nil).AfterReceiveHook))
|
||||
}
|
||||
|
||||
// Descriptor mocks base method.
|
||||
func (m *MockReceivedMessage) Descriptor() *descriptor.Message {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Descriptor")
|
||||
ret0, _ := ret[0].(*descriptor.Message)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Descriptor indicates an expected call of Descriptor.
|
||||
func (mr *MockReceivedMessageMockRecorder) Descriptor() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Descriptor", reflect.TypeOf((*MockReceivedMessage)(nil).Descriptor))
|
||||
}
|
||||
|
||||
// Frame mocks base method.
|
||||
func (m *MockReceivedMessage) Frame() can.Frame {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Frame")
|
||||
ret0, _ := ret[0].(can.Frame)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Frame indicates an expected call of Frame.
|
||||
func (mr *MockReceivedMessageMockRecorder) Frame() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Frame", reflect.TypeOf((*MockReceivedMessage)(nil).Frame))
|
||||
}
|
||||
|
||||
// MarshalFrame mocks base method.
|
||||
func (m *MockReceivedMessage) MarshalFrame() (can.Frame, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MarshalFrame")
|
||||
ret0, _ := ret[0].(can.Frame)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// MarshalFrame indicates an expected call of MarshalFrame.
|
||||
func (mr *MockReceivedMessageMockRecorder) MarshalFrame() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarshalFrame", reflect.TypeOf((*MockReceivedMessage)(nil).MarshalFrame))
|
||||
}
|
||||
|
||||
// Reset mocks base method.
|
||||
func (m *MockReceivedMessage) Reset() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Reset")
|
||||
}
|
||||
|
||||
// Reset indicates an expected call of Reset.
|
||||
func (mr *MockReceivedMessageMockRecorder) Reset() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Reset", reflect.TypeOf((*MockReceivedMessage)(nil).Reset))
|
||||
}
|
||||
|
||||
// SetReceiveTime mocks base method.
|
||||
func (m *MockReceivedMessage) SetReceiveTime(arg0 time.Time) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetReceiveTime", arg0)
|
||||
}
|
||||
|
||||
// SetReceiveTime indicates an expected call of SetReceiveTime.
|
||||
func (mr *MockReceivedMessageMockRecorder) SetReceiveTime(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetReceiveTime", reflect.TypeOf((*MockReceivedMessage)(nil).SetReceiveTime), arg0)
|
||||
}
|
||||
|
||||
// String mocks base method.
|
||||
func (m *MockReceivedMessage) String() string {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "String")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// String indicates an expected call of String.
|
||||
func (mr *MockReceivedMessageMockRecorder) String() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockReceivedMessage)(nil).String))
|
||||
}
|
||||
|
||||
// UnmarshalFrame mocks base method.
|
||||
func (m *MockReceivedMessage) UnmarshalFrame(arg0 can.Frame) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UnmarshalFrame", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UnmarshalFrame indicates an expected call of UnmarshalFrame.
|
||||
func (mr *MockReceivedMessageMockRecorder) UnmarshalFrame(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnmarshalFrame", reflect.TypeOf((*MockReceivedMessage)(nil).UnmarshalFrame), arg0)
|
||||
}
|
||||
|
||||
// MockFrameTransmitter is a mock of FrameTransmitter interface.
|
||||
type MockFrameTransmitter struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockFrameTransmitterMockRecorder
|
||||
}
|
||||
|
||||
// MockFrameTransmitterMockRecorder is the mock recorder for MockFrameTransmitter.
|
||||
type MockFrameTransmitterMockRecorder struct {
|
||||
mock *MockFrameTransmitter
|
||||
}
|
||||
|
||||
// NewMockFrameTransmitter creates a new mock instance.
|
||||
func NewMockFrameTransmitter(ctrl *gomock.Controller) *MockFrameTransmitter {
|
||||
mock := &MockFrameTransmitter{ctrl: ctrl}
|
||||
mock.recorder = &MockFrameTransmitterMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockFrameTransmitter) EXPECT() *MockFrameTransmitterMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// TransmitFrame mocks base method.
|
||||
func (m *MockFrameTransmitter) TransmitFrame(arg0 context.Context, arg1 can.Frame) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "TransmitFrame", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// TransmitFrame indicates an expected call of TransmitFrame.
|
||||
func (mr *MockFrameTransmitterMockRecorder) TransmitFrame(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TransmitFrame", reflect.TypeOf((*MockFrameTransmitter)(nil).TransmitFrame), arg0, arg1)
|
||||
}
|
||||
|
||||
// MockFrameReceiver is a mock of FrameReceiver interface.
|
||||
type MockFrameReceiver struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockFrameReceiverMockRecorder
|
||||
}
|
||||
|
||||
// MockFrameReceiverMockRecorder is the mock recorder for MockFrameReceiver.
|
||||
type MockFrameReceiverMockRecorder struct {
|
||||
mock *MockFrameReceiver
|
||||
}
|
||||
|
||||
// NewMockFrameReceiver creates a new mock instance.
|
||||
func NewMockFrameReceiver(ctrl *gomock.Controller) *MockFrameReceiver {
|
||||
mock := &MockFrameReceiver{ctrl: ctrl}
|
||||
mock.recorder = &MockFrameReceiverMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockFrameReceiver) EXPECT() *MockFrameReceiverMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Err mocks base method.
|
||||
func (m *MockFrameReceiver) Err() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Err")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Err indicates an expected call of Err.
|
||||
func (mr *MockFrameReceiverMockRecorder) Err() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Err", reflect.TypeOf((*MockFrameReceiver)(nil).Err))
|
||||
}
|
||||
|
||||
// Frame mocks base method.
|
||||
func (m *MockFrameReceiver) Frame() can.Frame {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Frame")
|
||||
ret0, _ := ret[0].(can.Frame)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Frame indicates an expected call of Frame.
|
||||
func (mr *MockFrameReceiverMockRecorder) Frame() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Frame", reflect.TypeOf((*MockFrameReceiver)(nil).Frame))
|
||||
}
|
||||
|
||||
// Receive mocks base method.
|
||||
func (m *MockFrameReceiver) Receive() bool {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Receive")
|
||||
ret0, _ := ret[0].(bool)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Receive indicates an expected call of Receive.
|
||||
func (mr *MockFrameReceiverMockRecorder) Receive() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Receive", reflect.TypeOf((*MockFrameReceiver)(nil).Receive))
|
||||
}
|
||||
126
pkg/can-go/internal/gen/mock/mockclock/mocks.go
Normal file
126
pkg/can-go/internal/gen/mock/mockclock/mocks.go
Normal file
@@ -0,0 +1,126 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/fiskerinc/cloud-services/pkg/can-go/internal/clock (interfaces: Clock,Ticker)
|
||||
|
||||
// Package mockclock is a generated GoMock package.
|
||||
package mockclock
|
||||
|
||||
import (
|
||||
clock "github.com/fiskerinc/cloud-services/pkg/can-go/internal/clock"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
)
|
||||
|
||||
// MockClock is a mock of Clock interface.
|
||||
type MockClock struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockClockMockRecorder
|
||||
}
|
||||
|
||||
// MockClockMockRecorder is the mock recorder for MockClock.
|
||||
type MockClockMockRecorder struct {
|
||||
mock *MockClock
|
||||
}
|
||||
|
||||
// NewMockClock creates a new mock instance.
|
||||
func NewMockClock(ctrl *gomock.Controller) *MockClock {
|
||||
mock := &MockClock{ctrl: ctrl}
|
||||
mock.recorder = &MockClockMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockClock) EXPECT() *MockClockMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// After mocks base method.
|
||||
func (m *MockClock) After(arg0 time.Duration) <-chan time.Time {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "After", arg0)
|
||||
ret0, _ := ret[0].(<-chan time.Time)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// After indicates an expected call of After.
|
||||
func (mr *MockClockMockRecorder) After(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "After", reflect.TypeOf((*MockClock)(nil).After), arg0)
|
||||
}
|
||||
|
||||
// NewTicker mocks base method.
|
||||
func (m *MockClock) NewTicker(arg0 time.Duration) clock.Ticker {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NewTicker", arg0)
|
||||
ret0, _ := ret[0].(clock.Ticker)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// NewTicker indicates an expected call of NewTicker.
|
||||
func (mr *MockClockMockRecorder) NewTicker(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewTicker", reflect.TypeOf((*MockClock)(nil).NewTicker), arg0)
|
||||
}
|
||||
|
||||
// Now mocks base method.
|
||||
func (m *MockClock) Now() time.Time {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Now")
|
||||
ret0, _ := ret[0].(time.Time)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Now indicates an expected call of Now.
|
||||
func (mr *MockClockMockRecorder) Now() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Now", reflect.TypeOf((*MockClock)(nil).Now))
|
||||
}
|
||||
|
||||
// MockTicker is a mock of Ticker interface.
|
||||
type MockTicker struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockTickerMockRecorder
|
||||
}
|
||||
|
||||
// MockTickerMockRecorder is the mock recorder for MockTicker.
|
||||
type MockTickerMockRecorder struct {
|
||||
mock *MockTicker
|
||||
}
|
||||
|
||||
// NewMockTicker creates a new mock instance.
|
||||
func NewMockTicker(ctrl *gomock.Controller) *MockTicker {
|
||||
mock := &MockTicker{ctrl: ctrl}
|
||||
mock.recorder = &MockTickerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockTicker) EXPECT() *MockTickerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// C mocks base method.
|
||||
func (m *MockTicker) C() <-chan time.Time {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "C")
|
||||
ret0, _ := ret[0].(<-chan time.Time)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// C indicates an expected call of C.
|
||||
func (mr *MockTickerMockRecorder) C() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "C", reflect.TypeOf((*MockTicker)(nil).C))
|
||||
}
|
||||
|
||||
// Stop mocks base method.
|
||||
func (m *MockTicker) Stop() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Stop")
|
||||
}
|
||||
|
||||
// Stop indicates an expected call of Stop.
|
||||
func (mr *MockTickerMockRecorder) Stop() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockTicker)(nil).Stop))
|
||||
}
|
||||
120
pkg/can-go/internal/gen/mock/mocksocketcan/mocks.go
Normal file
120
pkg/can-go/internal/gen/mock/mocksocketcan/mocks.go
Normal file
@@ -0,0 +1,120 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: pkg/socketcan/fileconn.go
|
||||
|
||||
// Package mocksocketcan is a generated GoMock package.
|
||||
package mocksocketcan
|
||||
|
||||
import (
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
)
|
||||
|
||||
// Mockfile is a mock of file interface.
|
||||
type Mockfile struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockfileMockRecorder
|
||||
}
|
||||
|
||||
// MockfileMockRecorder is the mock recorder for Mockfile.
|
||||
type MockfileMockRecorder struct {
|
||||
mock *Mockfile
|
||||
}
|
||||
|
||||
// NewMockfile creates a new mock instance.
|
||||
func NewMockfile(ctrl *gomock.Controller) *Mockfile {
|
||||
mock := &Mockfile{ctrl: ctrl}
|
||||
mock.recorder = &MockfileMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *Mockfile) EXPECT() *MockfileMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Read mocks base method.
|
||||
func (m *Mockfile) Read(arg0 []byte) (int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Read", arg0)
|
||||
ret0, _ := ret[0].(int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Read indicates an expected call of Read.
|
||||
func (mr *MockfileMockRecorder) Read(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*Mockfile)(nil).Read), arg0)
|
||||
}
|
||||
|
||||
// Write mocks base method.
|
||||
func (m *Mockfile) Write(arg0 []byte) (int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Write", arg0)
|
||||
ret0, _ := ret[0].(int)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Write indicates an expected call of Write.
|
||||
func (mr *MockfileMockRecorder) Write(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*Mockfile)(nil).Write), arg0)
|
||||
}
|
||||
|
||||
// SetDeadline mocks base method.
|
||||
func (m *Mockfile) SetDeadline(arg0 time.Time) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetDeadline", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetDeadline indicates an expected call of SetDeadline.
|
||||
func (mr *MockfileMockRecorder) SetDeadline(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDeadline", reflect.TypeOf((*Mockfile)(nil).SetDeadline), arg0)
|
||||
}
|
||||
|
||||
// SetReadDeadline mocks base method.
|
||||
func (m *Mockfile) SetReadDeadline(arg0 time.Time) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetReadDeadline", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetReadDeadline indicates an expected call of SetReadDeadline.
|
||||
func (mr *MockfileMockRecorder) SetReadDeadline(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetReadDeadline", reflect.TypeOf((*Mockfile)(nil).SetReadDeadline), arg0)
|
||||
}
|
||||
|
||||
// SetWriteDeadline mocks base method.
|
||||
func (m *Mockfile) SetWriteDeadline(arg0 time.Time) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetWriteDeadline", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetWriteDeadline indicates an expected call of SetWriteDeadline.
|
||||
func (mr *MockfileMockRecorder) SetWriteDeadline(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetWriteDeadline", reflect.TypeOf((*Mockfile)(nil).SetWriteDeadline), arg0)
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *Mockfile) Close() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Close")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockfileMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*Mockfile)(nil).Close))
|
||||
}
|
||||
231
pkg/can-go/internal/generate/compile.go
Normal file
231
pkg/can-go/internal/generate/compile.go
Normal file
@@ -0,0 +1,231 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/dbc"
|
||||
"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/descriptor"
|
||||
)
|
||||
|
||||
type CompileResult struct {
|
||||
Hash string
|
||||
Database *descriptor.Database
|
||||
Warnings []error
|
||||
}
|
||||
|
||||
func Compile(sourceFile string, data []byte) (result *CompileResult, err error) {
|
||||
p := dbc.NewParser(sourceFile, data)
|
||||
if err := p.Parse(); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse DBC source file: %w", err)
|
||||
}
|
||||
defs := p.Defs()
|
||||
c := &compiler{
|
||||
db: &descriptor.Database{SourceFile: sourceFile, ECUs: make(map[string]bool)},
|
||||
defs: defs,
|
||||
}
|
||||
c.collectDescriptors()
|
||||
c.addMetadata()
|
||||
c.sortDescriptors()
|
||||
|
||||
hash := ComputeHash(data)
|
||||
return &CompileResult{Hash: hash, Database: c.db, Warnings: c.warnings}, nil
|
||||
}
|
||||
|
||||
type compileError struct {
|
||||
def dbc.Def
|
||||
reason string
|
||||
}
|
||||
|
||||
func (e *compileError) Error() string {
|
||||
return fmt.Sprintf("failed to compile: %v (%v)", e.reason, e.def)
|
||||
}
|
||||
|
||||
type compiler struct {
|
||||
db *descriptor.Database
|
||||
defs []dbc.Def
|
||||
warnings []error
|
||||
}
|
||||
|
||||
func (c *compiler) addWarning(warning error) {
|
||||
c.warnings = append(c.warnings, warning)
|
||||
}
|
||||
|
||||
func (c *compiler) collectDescriptors() {
|
||||
// find ECU names from messages
|
||||
re := regexp.MustCompile(`^[0-9A-Za-z]+`)
|
||||
|
||||
for _, def := range c.defs {
|
||||
switch def := def.(type) {
|
||||
case *dbc.VersionDef:
|
||||
c.db.Version = def.Version
|
||||
case *dbc.MessageDef:
|
||||
if def.MessageID == dbc.IndependentSignalsMessageID {
|
||||
continue // don't compile
|
||||
}
|
||||
|
||||
// add ECU names to set
|
||||
ecu := re.FindString(string(def.Name))
|
||||
if ecu != "" {
|
||||
c.db.ECUs[ecu] = true
|
||||
}
|
||||
|
||||
message := &descriptor.Message{
|
||||
Name: string(def.Name),
|
||||
ID: def.MessageID.ToCAN(),
|
||||
IsExtended: def.MessageID.IsExtended(),
|
||||
Length: uint16(def.Size),
|
||||
SenderNode: string(def.Transmitter),
|
||||
}
|
||||
for _, signalDef := range def.Signals {
|
||||
signal := &descriptor.Signal{
|
||||
Name: string(signalDef.Name),
|
||||
IsBigEndian: signalDef.IsBigEndian,
|
||||
IsSigned: signalDef.IsSigned,
|
||||
IsMultiplexer: signalDef.IsMultiplexerSwitch,
|
||||
IsMultiplexed: signalDef.IsMultiplexed,
|
||||
MultiplexerValue: uint(signalDef.MultiplexerSwitch),
|
||||
Start: uint16(signalDef.StartBit),
|
||||
Length: uint16(signalDef.Size),
|
||||
Scale: signalDef.Factor,
|
||||
Offset: signalDef.Offset,
|
||||
Min: signalDef.Minimum,
|
||||
Max: signalDef.Maximum,
|
||||
Unit: signalDef.Unit,
|
||||
}
|
||||
for _, receiver := range signalDef.Receivers {
|
||||
signal.ReceiverNodes = append(signal.ReceiverNodes, string(receiver))
|
||||
}
|
||||
message.Signals = append(message.Signals, signal)
|
||||
}
|
||||
c.db.Messages[message.ID] = message
|
||||
case *dbc.NodesDef:
|
||||
for _, node := range def.NodeNames {
|
||||
c.db.Nodes = append(c.db.Nodes, &descriptor.Node{Name: string(node)})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) addMetadata() {
|
||||
for _, def := range c.defs {
|
||||
switch def := def.(type) {
|
||||
case *dbc.CommentDef:
|
||||
switch def.ObjectType {
|
||||
case dbc.ObjectTypeMessage:
|
||||
if def.MessageID == dbc.IndependentSignalsMessageID {
|
||||
continue // don't compile
|
||||
}
|
||||
message, ok := c.db.Message(def.MessageID.ToCAN())
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared message"})
|
||||
continue
|
||||
}
|
||||
message.Description = def.Comment
|
||||
case dbc.ObjectTypeSignal:
|
||||
if def.MessageID == dbc.IndependentSignalsMessageID {
|
||||
continue // don't compile
|
||||
}
|
||||
signal, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName))
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared signal"})
|
||||
continue
|
||||
}
|
||||
signal.Description = def.Comment
|
||||
case dbc.ObjectTypeNetworkNode:
|
||||
node, ok := c.db.Node(string(def.NodeName))
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared node"})
|
||||
continue
|
||||
}
|
||||
node.Description = def.Comment
|
||||
}
|
||||
case *dbc.ValueDescriptionsDef:
|
||||
if def.MessageID == dbc.IndependentSignalsMessageID {
|
||||
continue // don't compile
|
||||
}
|
||||
if def.ObjectType != dbc.ObjectTypeSignal {
|
||||
continue // don't compile
|
||||
}
|
||||
signal, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName))
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared signal"})
|
||||
continue
|
||||
}
|
||||
for _, valueDescription := range def.ValueDescriptions {
|
||||
signal.ValueDescriptions = append(signal.ValueDescriptions, &descriptor.ValueDescription{
|
||||
Description: valueDescription.Description,
|
||||
Value: int(valueDescription.Value),
|
||||
})
|
||||
}
|
||||
case *dbc.AttributeValueForObjectDef:
|
||||
switch def.ObjectType {
|
||||
case dbc.ObjectTypeMessage:
|
||||
msg, ok := c.db.Message(def.MessageID.ToCAN())
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared message"})
|
||||
continue
|
||||
}
|
||||
switch def.AttributeName {
|
||||
case "GenMsgSendType":
|
||||
if err := msg.SendType.UnmarshalString(def.StringValue); err != nil {
|
||||
c.addWarning(&compileError{def: def, reason: err.Error()})
|
||||
continue
|
||||
}
|
||||
case "GenMsgCycleTime":
|
||||
msg.CycleTime = time.Duration(def.IntValue) * time.Millisecond
|
||||
case "GenMsgDelayTime":
|
||||
msg.DelayTime = time.Duration(def.IntValue) * time.Millisecond
|
||||
}
|
||||
case dbc.ObjectTypeSignal:
|
||||
sig, ok := c.db.Signal(def.MessageID.ToCAN(), string(def.SignalName))
|
||||
if !ok {
|
||||
c.addWarning(&compileError{def: def, reason: "no declared signal"})
|
||||
}
|
||||
if def.AttributeName == "GenSigStartValue" {
|
||||
sig.DefaultValue = int(def.IntValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) sortDescriptors() {
|
||||
// Sort nodes by name
|
||||
sort.Slice(c.db.Nodes, func(i, j int) bool {
|
||||
return c.db.Nodes[i].Name < c.db.Nodes[j].Name
|
||||
})
|
||||
// Sort messages by ID
|
||||
// sort.Slice(c.db.Messages, func(i, j int) bool {
|
||||
// return c.db.Messages[i].ID < c.db.Messages[j].ID
|
||||
// })
|
||||
for _, m := range c.db.Messages {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
m := m
|
||||
// Sort signals by start (and multiplexer value)
|
||||
sort.Slice(m.Signals, func(j, k int) bool {
|
||||
if m.Signals[j].MultiplexerValue < m.Signals[k].MultiplexerValue {
|
||||
return true
|
||||
}
|
||||
return m.Signals[j].Start < m.Signals[k].Start
|
||||
})
|
||||
// Sort value descriptions by value
|
||||
for _, s := range m.Signals {
|
||||
s := s
|
||||
sort.Slice(s.ValueDescriptions, func(k, l int) bool {
|
||||
return s.ValueDescriptions[k].Value < s.ValueDescriptions[l].Value
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ComputeHash(input []byte) string {
|
||||
h := sha256.New()
|
||||
h.Write(input)
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
306
pkg/can-go/internal/generate/compile_test.go
Normal file
306
pkg/can-go/internal/generate/compile_test.go
Normal file
@@ -0,0 +1,306 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/descriptor"
|
||||
examplecan "github.com/fiskerinc/cloud-services/pkg/can-go/testdata/gen/go/example"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestCompile_ExampleDBC(t *testing.T) {
|
||||
finish := runTestInDir(t, "../..")
|
||||
defer finish()
|
||||
const exampleDBCFile = "testdata/dbc/example/example.dbc"
|
||||
exampleDatabase := &descriptor.Database{
|
||||
SourceFile: exampleDBCFile,
|
||||
Version: "",
|
||||
Nodes: []*descriptor.Node{
|
||||
{
|
||||
Name: "DBG",
|
||||
},
|
||||
{
|
||||
Name: "DRIVER",
|
||||
Description: "The driver controller driving the car",
|
||||
},
|
||||
{
|
||||
Name: "IO",
|
||||
},
|
||||
{
|
||||
Name: "MOTOR",
|
||||
Description: "The motor controller of the car",
|
||||
},
|
||||
{
|
||||
Name: "SENSOR",
|
||||
Description: "The sensor controller of the car",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
exampleDatabase.Messages[1] = &descriptor.Message{
|
||||
ID: 1,
|
||||
Name: "EmptyMessage",
|
||||
SenderNode: "DBG",
|
||||
}
|
||||
|
||||
exampleDatabase.Messages[100] = &descriptor.Message{
|
||||
ID: 100,
|
||||
Name: "DriverHeartbeat",
|
||||
Length: 1,
|
||||
SenderNode: "DRIVER",
|
||||
Description: "Sync message used to synchronize the controllers",
|
||||
SendType: descriptor.SendTypeCyclic,
|
||||
CycleTime: time.Second,
|
||||
Signals: []*descriptor.Signal{
|
||||
{
|
||||
Name: "Command",
|
||||
Start: 0,
|
||||
Length: 8,
|
||||
Scale: 1,
|
||||
ReceiverNodes: []string{"SENSOR", "MOTOR"},
|
||||
ValueDescriptions: []*descriptor.ValueDescription{
|
||||
{Value: 0, Description: "None"},
|
||||
{Value: 1, Description: "Sync"},
|
||||
{Value: 2, Description: "Reboot"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
exampleDatabase.Messages[101] = &descriptor.Message{
|
||||
ID: 101,
|
||||
Name: "MotorCommand",
|
||||
Length: 1,
|
||||
SenderNode: "DRIVER",
|
||||
SendType: descriptor.SendTypeCyclic,
|
||||
CycleTime: 100 * time.Millisecond,
|
||||
Signals: []*descriptor.Signal{
|
||||
{
|
||||
Name: "Steer",
|
||||
Start: 0,
|
||||
Length: 4,
|
||||
IsSigned: true,
|
||||
Scale: 1,
|
||||
Offset: -5,
|
||||
Min: -5,
|
||||
Max: 5,
|
||||
ReceiverNodes: []string{"MOTOR"},
|
||||
},
|
||||
{
|
||||
Name: "Drive",
|
||||
Start: 4,
|
||||
Length: 4,
|
||||
Scale: 1,
|
||||
Max: 9,
|
||||
ReceiverNodes: []string{"MOTOR"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
exampleDatabase.Messages[200] = &descriptor.Message{
|
||||
ID: 200,
|
||||
Name: "SensorSonars",
|
||||
Length: 8,
|
||||
SenderNode: "SENSOR",
|
||||
SendType: descriptor.SendTypeCyclic,
|
||||
CycleTime: 100 * time.Millisecond,
|
||||
Signals: []*descriptor.Signal{
|
||||
{
|
||||
Name: "Mux",
|
||||
IsMultiplexer: true,
|
||||
Start: 0,
|
||||
Length: 4,
|
||||
Scale: 1,
|
||||
ReceiverNodes: []string{"DRIVER", "IO"},
|
||||
},
|
||||
{
|
||||
Name: "ErrCount",
|
||||
Start: 4,
|
||||
Length: 12,
|
||||
Scale: 1,
|
||||
ReceiverNodes: []string{"DRIVER", "IO"},
|
||||
},
|
||||
{
|
||||
Name: "Left",
|
||||
IsMultiplexed: true,
|
||||
MultiplexerValue: 0,
|
||||
Start: 16,
|
||||
Length: 12,
|
||||
Scale: 0.1,
|
||||
ReceiverNodes: []string{"DRIVER", "IO"},
|
||||
},
|
||||
{
|
||||
Name: "NoFiltLeft",
|
||||
IsMultiplexed: true,
|
||||
MultiplexerValue: 1,
|
||||
Start: 16,
|
||||
Length: 12,
|
||||
Scale: 0.1,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
},
|
||||
{
|
||||
Name: "Middle",
|
||||
IsMultiplexed: true,
|
||||
MultiplexerValue: 0,
|
||||
Start: 28,
|
||||
Length: 12,
|
||||
Scale: 0.1,
|
||||
ReceiverNodes: []string{"DRIVER", "IO"},
|
||||
},
|
||||
{
|
||||
Name: "NoFiltMiddle",
|
||||
IsMultiplexed: true,
|
||||
MultiplexerValue: 1,
|
||||
Start: 28,
|
||||
Length: 12,
|
||||
Scale: 0.1,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
},
|
||||
{
|
||||
Name: "Right",
|
||||
IsMultiplexed: true,
|
||||
MultiplexerValue: 0,
|
||||
Start: 40,
|
||||
Length: 12,
|
||||
Scale: 0.1,
|
||||
ReceiverNodes: []string{"DRIVER", "IO"},
|
||||
},
|
||||
{
|
||||
Name: "NoFiltRight",
|
||||
IsMultiplexed: true,
|
||||
MultiplexerValue: 1,
|
||||
Start: 40,
|
||||
Length: 12,
|
||||
Scale: 0.1,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
},
|
||||
{
|
||||
Name: "Rear",
|
||||
IsMultiplexed: true,
|
||||
MultiplexerValue: 0,
|
||||
Start: 52,
|
||||
Length: 12,
|
||||
Scale: 0.1,
|
||||
ReceiverNodes: []string{"DRIVER", "IO"},
|
||||
},
|
||||
{
|
||||
Name: "NoFiltRear",
|
||||
IsMultiplexed: true,
|
||||
MultiplexerValue: 1,
|
||||
Start: 52,
|
||||
Length: 12,
|
||||
Scale: 0.1,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
exampleDatabase.Messages[400] = &descriptor.Message{
|
||||
ID: 400,
|
||||
Name: "MotorStatus",
|
||||
Length: 3,
|
||||
SenderNode: "MOTOR",
|
||||
SendType: descriptor.SendTypeCyclic,
|
||||
CycleTime: 100 * time.Millisecond,
|
||||
Signals: []*descriptor.Signal{
|
||||
{
|
||||
Name: "WheelError",
|
||||
Start: 0,
|
||||
Length: 1,
|
||||
Scale: 1,
|
||||
ReceiverNodes: []string{"DRIVER", "IO"},
|
||||
},
|
||||
{
|
||||
Name: "SpeedKph",
|
||||
Start: 8,
|
||||
Length: 16,
|
||||
Scale: 0.001,
|
||||
Unit: "km/h",
|
||||
ReceiverNodes: []string{"DRIVER", "IO"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
exampleDatabase.Messages[500] = &descriptor.Message{
|
||||
ID: 500,
|
||||
Name: "IODebug",
|
||||
Length: 6,
|
||||
SenderNode: "IO",
|
||||
SendType: descriptor.SendTypeEvent,
|
||||
Signals: []*descriptor.Signal{
|
||||
{
|
||||
Name: "TestUnsigned",
|
||||
Start: 0,
|
||||
Length: 8,
|
||||
Scale: 1,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
},
|
||||
{
|
||||
Name: "TestEnum",
|
||||
Start: 8,
|
||||
Length: 6,
|
||||
Scale: 1,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
DefaultValue: int(examplecan.IODebug_TestEnum_Two),
|
||||
ValueDescriptions: []*descriptor.ValueDescription{
|
||||
{Value: 1, Description: "One"},
|
||||
{Value: 2, Description: "Two"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestSigned",
|
||||
Start: 16,
|
||||
Length: 8,
|
||||
IsSigned: true,
|
||||
Scale: 1,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
},
|
||||
{
|
||||
Name: "TestFloat",
|
||||
Start: 24,
|
||||
Length: 8,
|
||||
Scale: 0.5,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
},
|
||||
{
|
||||
Name: "TestBoolEnum",
|
||||
Start: 32,
|
||||
Length: 1,
|
||||
Scale: 1,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
ValueDescriptions: []*descriptor.ValueDescription{
|
||||
{Value: 0, Description: "Zero"},
|
||||
{Value: 1, Description: "One"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestScaledEnum",
|
||||
Start: 40,
|
||||
Length: 2,
|
||||
Scale: 2,
|
||||
Min: 0,
|
||||
Max: 6,
|
||||
ReceiverNodes: []string{"DBG"},
|
||||
ValueDescriptions: []*descriptor.ValueDescription{
|
||||
{Value: 0, Description: "Zero"},
|
||||
{Value: 1, Description: "Two"},
|
||||
{Value: 2, Description: "Four"},
|
||||
{Value: 3, Description: "Six"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
input, err := ioutil.ReadFile(exampleDBCFile)
|
||||
assert.NilError(t, err)
|
||||
result, err := Compile(exampleDBCFile, input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(result.Warnings) > 0 {
|
||||
t.Fatal(result.Warnings)
|
||||
}
|
||||
assert.DeepEqual(t, exampleDatabase, result.Database)
|
||||
}
|
||||
338
pkg/can-go/internal/generate/example_test.go
Normal file
338
pkg/can-go/internal/generate/example_test.go
Normal file
@@ -0,0 +1,338 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
can "github.com/fiskerinc/cloud-services/pkg/can-go"
|
||||
"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/generated"
|
||||
"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/socketcan"
|
||||
examplecan "github.com/fiskerinc/cloud-services/pkg/can-go/testdata/gen/go/example"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestExampleDatabase_MarshalUnmarshal(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
m can.Message
|
||||
f can.Frame
|
||||
}{
|
||||
{
|
||||
name: "IODebug",
|
||||
m: examplecan.NewIODebug().
|
||||
SetTestUnsigned(5).
|
||||
SetTestEnum(examplecan.IODebug_TestEnum_Two).
|
||||
SetTestSigned(-42).
|
||||
SetTestFloat(61.5).
|
||||
SetTestBoolEnum(examplecan.IODebug_TestBoolEnum_One).
|
||||
SetRawTestScaledEnum(examplecan.IODebug_TestScaledEnum_Four),
|
||||
f: can.Frame{
|
||||
ID: 500,
|
||||
Length: 6,
|
||||
Data: can.Data{5, 2, 214, 123, 1, 2},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "MotorStatus1",
|
||||
m: examplecan.NewMotorStatus().
|
||||
SetSpeedKph(0.423).
|
||||
SetWheelError(true),
|
||||
f: can.Frame{
|
||||
ID: 400,
|
||||
Length: 3,
|
||||
Data: can.Data{0x1, 0xa7, 0x1},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "MotorStatus2",
|
||||
m: examplecan.NewMotorStatus().
|
||||
SetSpeedKph(12),
|
||||
f: can.Frame{
|
||||
ID: 400,
|
||||
Length: 3,
|
||||
Data: can.Data{0x00, 0xe0, 0x2e},
|
||||
},
|
||||
},
|
||||
} {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
f, err := tt.m.MarshalFrame()
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, tt.f, f)
|
||||
// allocate new message of same type as tt.m
|
||||
msg := reflect.New(reflect.ValueOf(tt.m).Elem().Type()).Interface().(generated.Message)
|
||||
assert.NilError(t, msg.UnmarshalFrame(f))
|
||||
assert.Assert(t, reflect.DeepEqual(tt.m, msg))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExampleDatabase_UnmarshalFrame_Error(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
f can.Frame
|
||||
m generated.Message
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "wrong ID",
|
||||
f: can.Frame{ID: 11, Length: 8},
|
||||
m: examplecan.NewSensorSonars(),
|
||||
err: "unmarshal SensorSonars: expects ID 200 (got 00B#0000000000000000 with ID 11)",
|
||||
},
|
||||
{
|
||||
name: "wrong length",
|
||||
f: can.Frame{ID: 200, Length: 4},
|
||||
m: examplecan.NewSensorSonars(),
|
||||
err: "unmarshal SensorSonars: expects length 8 (got 0C8#00000000 with length 4)",
|
||||
},
|
||||
{
|
||||
name: "remote frame",
|
||||
f: can.Frame{ID: 200, Length: 8, IsRemote: true},
|
||||
m: examplecan.NewSensorSonars(),
|
||||
err: "unmarshal SensorSonars: expects non-remote frame (got remote frame 0C8#R8)",
|
||||
},
|
||||
{
|
||||
name: "extended ID",
|
||||
f: can.Frame{ID: 200, Length: 8, IsExtended: true},
|
||||
m: examplecan.NewSensorSonars(),
|
||||
err: "unmarshal SensorSonars: expects standard ID (got 000000C8#0000000000000000 with extended ID)",
|
||||
},
|
||||
} {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.err, tt.m.UnmarshalFrame(tt.f).Error())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExampleDatabase_TestEnum_String(t *testing.T) {
|
||||
assert.Equal(t, "One", examplecan.IODebug_TestEnum_One.String())
|
||||
assert.Equal(t, "Two", examplecan.IODebug_TestEnum_Two.String())
|
||||
assert.Equal(t, "IODebug_TestEnum(3)", examplecan.IODebug_TestEnum(3).String())
|
||||
}
|
||||
|
||||
func TestExampleDatabase_Message_String(t *testing.T) {
|
||||
const expected = "{WheelError: true, SpeedKph: 42km/h}"
|
||||
msg := examplecan.NewMotorStatus().
|
||||
SetSpeedKph(42).
|
||||
SetWheelError(true)
|
||||
assert.Equal(t, expected, msg.String())
|
||||
assert.Equal(t, expected, fmt.Sprintf("%v", msg))
|
||||
}
|
||||
|
||||
func TestExampleDatabase_OutOfBoundsValue(t *testing.T) {
|
||||
const expected = examplecan.IODebug_TestEnum(63)
|
||||
actual := examplecan.NewIODebug().SetTestEnum(255).TestEnum()
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestExampleDatabase_MultiplexedSignals(t *testing.T) {
|
||||
// Given a message with multiplexed signals
|
||||
msg := examplecan.NewSensorSonars().
|
||||
SetErrCount(1).
|
||||
SetMux(1).
|
||||
SetLeft(20).
|
||||
SetMiddle(30).
|
||||
SetRight(40).
|
||||
SetRear(50).
|
||||
SetNoFiltLeft(60).
|
||||
SetNoFiltMiddle(70).
|
||||
SetNoFiltRight(80).
|
||||
SetNoFiltRear(90)
|
||||
for _, tt := range []struct {
|
||||
expectedMux uint8
|
||||
expectedErrCount uint16
|
||||
expectedLeft float64
|
||||
expectedMiddle float64
|
||||
expectedRight float64
|
||||
expectedRear float64
|
||||
expectedNoFiltLeft float64
|
||||
expectedNoFiltMiddle float64
|
||||
expectedNoFiltRight float64
|
||||
expectedNoFiltRear float64
|
||||
}{
|
||||
{
|
||||
expectedMux: 0,
|
||||
expectedErrCount: 1,
|
||||
expectedLeft: 20,
|
||||
expectedMiddle: 30,
|
||||
expectedRight: 40,
|
||||
expectedRear: 50,
|
||||
expectedNoFiltLeft: 0,
|
||||
expectedNoFiltMiddle: 0,
|
||||
expectedNoFiltRight: 0,
|
||||
expectedNoFiltRear: 0,
|
||||
},
|
||||
{
|
||||
expectedMux: 1,
|
||||
expectedErrCount: 1,
|
||||
expectedLeft: 0,
|
||||
expectedMiddle: 0,
|
||||
expectedRight: 0,
|
||||
expectedRear: 0,
|
||||
expectedNoFiltLeft: 60,
|
||||
expectedNoFiltMiddle: 70,
|
||||
expectedNoFiltRight: 80,
|
||||
expectedNoFiltRear: 90,
|
||||
},
|
||||
} {
|
||||
tt := tt
|
||||
t.Run(fmt.Sprintf("mux=%v", tt.expectedMux), func(t *testing.T) {
|
||||
unmarshal1 := examplecan.NewSensorSonars()
|
||||
// When the multiplexer signal is 0 and we marshal the message
|
||||
// to a CAN frame
|
||||
msg.SetMux(tt.expectedMux)
|
||||
f1, err := msg.MarshalFrame()
|
||||
assert.NilError(t, err)
|
||||
// When we unmarshal the CAN frame back to a message
|
||||
assert.NilError(t, unmarshal1.UnmarshalFrame(f1))
|
||||
// Then only the multiplexed signals with multiplexer value 0
|
||||
// should be unmarshaled
|
||||
assert.Equal(t, tt.expectedMux, unmarshal1.Mux(), "Mux")
|
||||
assert.Equal(t, tt.expectedErrCount, unmarshal1.ErrCount(), "ErrCount")
|
||||
assert.Equal(t, tt.expectedLeft, unmarshal1.Left(), "Left")
|
||||
assert.Equal(t, tt.expectedMiddle, unmarshal1.Middle(), "Middle")
|
||||
assert.Equal(t, tt.expectedRight, unmarshal1.Right(), "Right")
|
||||
assert.Equal(t, tt.expectedRear, unmarshal1.Rear(), "Rear")
|
||||
assert.Equal(t, tt.expectedNoFiltLeft, unmarshal1.NoFiltLeft(), "NoFiltLeft")
|
||||
assert.Equal(t, tt.expectedNoFiltMiddle, unmarshal1.NoFiltMiddle(), "NoFiltMiddle")
|
||||
assert.Equal(t, tt.expectedNoFiltRight, unmarshal1.NoFiltRight(), "NoFiltRight")
|
||||
assert.Equal(t, tt.expectedNoFiltRear, unmarshal1.NoFiltRear(), "NoFiltRear")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExampleDatabase_CopyFrom(t *testing.T) {
|
||||
// Given: an original message
|
||||
from := examplecan.NewIODebug().
|
||||
SetRawTestScaledEnum(examplecan.IODebug_TestScaledEnum_Four).
|
||||
SetTestBoolEnum(true).
|
||||
SetTestFloat(0.1).
|
||||
SetTestSigned(-10).
|
||||
SetTestUnsigned(10)
|
||||
// When: another message copies from the original message
|
||||
to := examplecan.NewIODebug().CopyFrom(from)
|
||||
// Then:
|
||||
// all fields should be equal...
|
||||
assert.Equal(t, from.String(), to.String())
|
||||
assert.Equal(t, from.TestScaledEnum(), to.TestScaledEnum())
|
||||
assert.Equal(t, from.TestBoolEnum(), to.TestBoolEnum())
|
||||
assert.Equal(t, from.TestFloat(), to.TestFloat())
|
||||
assert.Equal(t, from.TestSigned(), to.TestSigned())
|
||||
assert.Equal(t, from.TestUnsigned(), to.TestUnsigned())
|
||||
// ...and changes to the original should not affect the new message
|
||||
from.SetTestUnsigned(100)
|
||||
assert.Equal(t, uint8(10), to.TestUnsigned())
|
||||
}
|
||||
|
||||
func TestExample_Nodes(t *testing.T) {
|
||||
const testTimeout = 2 * time.Second
|
||||
requireVCAN0(t)
|
||||
// given a DRIVER node and a MOTOR node
|
||||
motor := examplecan.NewMOTOR("can", "vcan0")
|
||||
driver := examplecan.NewDRIVER("can", "vcan0")
|
||||
// when starting them
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
g.Go(func() error {
|
||||
return motor.Run(ctx)
|
||||
})
|
||||
g.Go(func() error {
|
||||
return driver.Run(ctx)
|
||||
})
|
||||
// and the MOTOR node is configured to send a speed report
|
||||
const expectedSpeedKph = 42
|
||||
motor.Lock()
|
||||
motor.Tx().MotorStatus().SetSpeedKph(expectedSpeedKph)
|
||||
motor.Tx().MotorStatus().SetCyclicTransmissionEnabled(true)
|
||||
motor.Unlock()
|
||||
// and the DRIVER node is configured to send a steering command
|
||||
const expectedSteer = -4
|
||||
driver.Lock()
|
||||
driver.Tx().MotorCommand().SetSteer(expectedSteer)
|
||||
driver.Tx().MotorCommand().SetCyclicTransmissionEnabled(true)
|
||||
driver.Unlock()
|
||||
// and the MOTOR node is listening for the steering command
|
||||
expectedSteerReceivedChan := make(chan struct{})
|
||||
motor.Lock()
|
||||
motor.Rx().MotorCommand().SetAfterReceiveHook(func(context.Context) error {
|
||||
motor.Lock()
|
||||
if motor.Rx().MotorCommand().Steer() == expectedSteer {
|
||||
close(expectedSteerReceivedChan)
|
||||
motor.Rx().MotorCommand().SetAfterReceiveHook(func(context.Context) error { return nil })
|
||||
}
|
||||
motor.Unlock()
|
||||
return nil
|
||||
})
|
||||
motor.Unlock()
|
||||
// and the DRIVER node is listening for the speed report
|
||||
expectedSpeedReceivedChan := make(chan struct{})
|
||||
driver.Lock()
|
||||
driver.Rx().MotorStatus().SetAfterReceiveHook(func(context.Context) error {
|
||||
driver.Lock()
|
||||
if driver.Rx().MotorStatus().SpeedKph() == expectedSpeedKph {
|
||||
close(expectedSpeedReceivedChan)
|
||||
driver.Rx().MotorStatus().SetAfterReceiveHook(func(context.Context) error { return nil })
|
||||
}
|
||||
driver.Unlock()
|
||||
return nil
|
||||
})
|
||||
driver.Unlock()
|
||||
// then the steer command transmitted by DRIVER should be received by MOTOR
|
||||
select {
|
||||
case <-expectedSteerReceivedChan:
|
||||
case <-ctx.Done():
|
||||
t.Fatalf("expected steer not received: %v", expectedSteer)
|
||||
}
|
||||
// and the speed report transmitted by MOTOR should be received by DRIVER
|
||||
select {
|
||||
case <-expectedSpeedReceivedChan:
|
||||
case <-ctx.Done():
|
||||
t.Fatalf("expected speed not received: %v", expectedSpeedKph)
|
||||
}
|
||||
cancel()
|
||||
assert.NilError(t, g.Wait())
|
||||
}
|
||||
|
||||
func TestExample_Node_NoEmptyMessages(t *testing.T) {
|
||||
const testTimeout = 2 * time.Second
|
||||
requireVCAN0(t)
|
||||
// given a DRIVER node and a MOTOR node
|
||||
motor := examplecan.NewMOTOR("can", "vcan0")
|
||||
// when starting them
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
|
||||
handler := func(ctx context.Context) error {
|
||||
motor.Lock()
|
||||
motor.Tx().MotorStatus().SetSpeedKph(100).SetWheelError(true)
|
||||
motor.Unlock()
|
||||
return nil
|
||||
}
|
||||
motor.Tx().MotorStatus().SetBeforeTransmitHook(handler)
|
||||
motor.Tx().MotorStatus().SetCyclicTransmissionEnabled(true)
|
||||
c, err := socketcan.Dial("can", "vcan0")
|
||||
r := socketcan.NewReceiver(c)
|
||||
assert.NilError(t, err)
|
||||
g := errgroup.Group{}
|
||||
g.Go(func() error {
|
||||
return motor.Run(ctx)
|
||||
})
|
||||
assert.Assert(t, r.Receive())
|
||||
assert.Equal(t, examplecan.NewMotorStatus().SetSpeedKph(100).SetWheelError(true).Frame(), r.Frame())
|
||||
cancel()
|
||||
assert.NilError(t, g.Wait())
|
||||
}
|
||||
|
||||
func requireVCAN0(t *testing.T) {
|
||||
t.Helper()
|
||||
if _, err := net.InterfaceByName("vcan0"); err != nil {
|
||||
t.Skip("interface vcan0 does not exist")
|
||||
}
|
||||
}
|
||||
976
pkg/can-go/internal/generate/file.go
Normal file
976
pkg/can-go/internal/generate/file.go
Normal file
@@ -0,0 +1,976 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"go/types"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/descriptor"
|
||||
"github.com/shurcooL/go-goon"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
buf bytes.Buffer
|
||||
err error
|
||||
}
|
||||
|
||||
func NewFile() *File {
|
||||
f := &File{}
|
||||
f.buf.Grow(1e5) // 100K
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *File) Write(p []byte) (int, error) {
|
||||
if f.err != nil {
|
||||
return 0, f.err
|
||||
}
|
||||
n, err := f.buf.Write(p)
|
||||
f.err = err
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (f *File) P(v ...interface{}) {
|
||||
for _, x := range v {
|
||||
_, _ = fmt.Fprint(f, x)
|
||||
}
|
||||
_, _ = fmt.Fprintln(f)
|
||||
}
|
||||
|
||||
func (f *File) Dump(v interface{}) {
|
||||
_, _ = goon.Fdump(f, v)
|
||||
}
|
||||
|
||||
func (f *File) Content() ([]byte, error) {
|
||||
if f.err != nil {
|
||||
return nil, fmt.Errorf("file content: %w", f.err)
|
||||
}
|
||||
formatted, err := format.Source(f.buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("file content: %s: %w", f.buf.String(), err)
|
||||
}
|
||||
return formatted, nil
|
||||
}
|
||||
|
||||
func Database(h string, d *descriptor.Database) ([]byte, error) {
|
||||
f := NewFile()
|
||||
Package(f, d)
|
||||
Imports(f)
|
||||
Version(f, h, d.Version)
|
||||
ListECUs(f, d)
|
||||
|
||||
for _, m := range d.Messages {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
MessageType(f, m)
|
||||
for _, s := range m.Signals {
|
||||
if hasCustomType(s) {
|
||||
SignalCustomType(f, m, s)
|
||||
}
|
||||
}
|
||||
MarshalFrame(f, m)
|
||||
UnmarshalFrame(f, m)
|
||||
}
|
||||
if hasSendType(d) { // only code-generate nodes for schemas with send types specified
|
||||
for _, n := range d.Nodes {
|
||||
Node(f, d, n)
|
||||
}
|
||||
}
|
||||
Descriptors(f, d)
|
||||
return f.Content()
|
||||
}
|
||||
|
||||
func Package(f *File, d *descriptor.Database) {
|
||||
packageName := strings.TrimSuffix(path.Base(d.SourceFile), path.Ext(d.SourceFile)) + "can"
|
||||
f.P("// Package ", packageName, " provides primitives for encoding and decoding ", d.Name(), " CAN messages.")
|
||||
f.P("//")
|
||||
f.P("// Source: ", d.SourceFile)
|
||||
f.P("package ", packageName)
|
||||
f.P()
|
||||
}
|
||||
|
||||
func Imports(f *File) {
|
||||
f.P("import (")
|
||||
f.P(`"context"`)
|
||||
f.P(`"fmt"`)
|
||||
f.P(`"net"`)
|
||||
f.P(`"net/http"`)
|
||||
f.P(`"sync"`)
|
||||
f.P(`"time"`)
|
||||
f.P()
|
||||
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go"`)
|
||||
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/socketcan"`)
|
||||
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/candebug"`)
|
||||
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/canrunner"`)
|
||||
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/descriptor"`)
|
||||
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/generated"`)
|
||||
f.P(`"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/cantext"`)
|
||||
f.P(")")
|
||||
f.P()
|
||||
// we could use goimports for this, but it significantly slows down code generation
|
||||
f.P("// prevent unused imports")
|
||||
f.P("var (")
|
||||
f.P("_ = context.Background")
|
||||
f.P("_ = fmt.Print")
|
||||
f.P("_ = net.Dial")
|
||||
f.P("_ = http.Error")
|
||||
f.P("_ = sync.Mutex{}")
|
||||
f.P("_ = time.Now")
|
||||
f.P("_ = socketcan.Dial")
|
||||
f.P("_ = candebug.ServeMessagesHTTP")
|
||||
f.P("_ = canrunner.Run")
|
||||
f.P(")")
|
||||
f.P()
|
||||
f.P("// Generated code. DO NOT EDIT.")
|
||||
}
|
||||
|
||||
func Version(f *File, h string, v string) {
|
||||
f.P()
|
||||
f.P("// Hash used as versioning control for DBC")
|
||||
f.P(`const Hash string = "`, h, `"`)
|
||||
f.P("// Version is the version listed in the DBC")
|
||||
f.P(`const Version string = "`, v, `"`)
|
||||
f.P()
|
||||
}
|
||||
|
||||
func ListECUs(f *File, d *descriptor.Database) {
|
||||
f.P()
|
||||
f.P("// ECUs parsed from DBC")
|
||||
|
||||
ecuList := "var ECUs = []string{"
|
||||
i := 0
|
||||
for ecu := range d.ECUs {
|
||||
ecuList += fmt.Sprintf(`"%s"`, ecu)
|
||||
i++
|
||||
if i != len(d.ECUs) {
|
||||
ecuList += ", "
|
||||
}
|
||||
}
|
||||
ecuList += "}"
|
||||
f.P(ecuList)
|
||||
f.P()
|
||||
}
|
||||
|
||||
func SignalCustomType(f *File, m *descriptor.Message, s *descriptor.Signal) {
|
||||
f.P("// ", signalType(m, s), " models the ", s.Name, " signal of the ", m.Name, " message.")
|
||||
f.P("type ", signalType(m, s), " ", signalPrimitiveType(s))
|
||||
f.P()
|
||||
|
||||
// dtaylor@fiskerinc.com EDIT
|
||||
|
||||
// f.P("// Value descriptions for the ", s.Name, " signal of the ", m.Name, " message.")
|
||||
// f.P("const (")
|
||||
// for _, vd := range s.ValueDescriptions {
|
||||
// switch {
|
||||
// case s.Length == 1 && vd.Value == 1:
|
||||
// f.P(signalType(m, s), "_", vd.Description, " ", signalType(m, s), " = true")
|
||||
// case s.Length == 1 && vd.Value == 0:
|
||||
// f.P(signalType(m, s), "_", vd.Description, " ", signalType(m, s), " = false")
|
||||
// default:
|
||||
// f.P(signalType(m, s), "_", vd.Description, " ", signalType(m, s), " = ", vd.Value)
|
||||
// }
|
||||
// }
|
||||
// f.P(")")
|
||||
// f.P()
|
||||
|
||||
f.P("func (v ", signalType(m, s), ") String() string {")
|
||||
if s.Length == 1 {
|
||||
f.P("switch bool(v) {")
|
||||
for _, vd := range s.ValueDescriptions {
|
||||
if vd.Value == 1 {
|
||||
f.P("case true:")
|
||||
} else {
|
||||
f.P("case false:")
|
||||
}
|
||||
f.P(`return "`, vd.Description, `"`)
|
||||
}
|
||||
f.P("}")
|
||||
f.P(`return fmt.Sprintf("`, signalType(m, s), `(%t)", v)`)
|
||||
} else {
|
||||
f.P("switch v {")
|
||||
for _, vd := range s.ValueDescriptions {
|
||||
f.P("case ", vd.Value, ":")
|
||||
f.P(`return "`, vd.Description, `"`)
|
||||
}
|
||||
f.P("default:")
|
||||
f.P(`return fmt.Sprintf("`, signalType(m, s), `(%d)", v)`)
|
||||
f.P("}")
|
||||
}
|
||||
f.P("}")
|
||||
}
|
||||
|
||||
func MessageType(f *File, m *descriptor.Message) {
|
||||
f.P("// ", messageReaderInterface(m), " provides read access to a ", m.Name, " message.")
|
||||
f.P("type ", messageReaderInterface(m), " interface {")
|
||||
for _, s := range m.Signals {
|
||||
if hasPhysicalRepresentation(s) {
|
||||
f.P("// ", s.Name, " returns the physical value of the ", s.Name, " signal.")
|
||||
f.P(s.Name, "() float64")
|
||||
if len(s.ValueDescriptions) > 0 {
|
||||
f.P()
|
||||
f.P("// ", s.Name, " returns the raw (encoded) value of the ", s.Name, " signal.")
|
||||
f.P("Raw", s.Name, "() ", signalType(m, s))
|
||||
}
|
||||
} else {
|
||||
f.P("// ", s.Name, " returns the value of the ", s.Name, " signal.")
|
||||
f.P(s.Name, "()", signalType(m, s))
|
||||
}
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("// ", messageWriterInterface(m), " provides write access to a ", m.Name, " message.")
|
||||
f.P("type ", messageWriterInterface(m), " interface {")
|
||||
f.P("// CopyFrom copies all values from ", messageReaderInterface(m), ".")
|
||||
f.P("CopyFrom(", messageReaderInterface(m), ") *", messageStruct(m))
|
||||
for _, s := range m.Signals {
|
||||
if hasPhysicalRepresentation(s) {
|
||||
f.P("// Set", s.Name, " sets the physical value of the ", s.Name, " signal.")
|
||||
f.P("Set", s.Name, "(float64) *", messageStruct(m))
|
||||
if len(s.ValueDescriptions) > 0 {
|
||||
f.P()
|
||||
f.P("// SetRaw", s.Name, " sets the raw (encoded) value of the ", s.Name, " signal.")
|
||||
f.P("SetRaw", s.Name, "(", signalType(m, s), ") *", messageStruct(m))
|
||||
}
|
||||
} else {
|
||||
f.P("// Set", s.Name, " sets the value of the ", s.Name, " signal.")
|
||||
f.P("Set", s.Name, "(", signalType(m, s), ") *", messageStruct(m))
|
||||
}
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("type ", messageStruct(m), " struct {")
|
||||
for _, s := range m.Signals {
|
||||
f.P(signalField(s), " ", signalType(m, s))
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func New", messageStruct(m), "() *", messageStruct(m), " {")
|
||||
f.P("m := &", messageStruct(m), "{}")
|
||||
f.P("m.Reset()")
|
||||
f.P("return m")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", messageStruct(m), ") Reset() {")
|
||||
for _, s := range m.Signals {
|
||||
switch {
|
||||
case s.Length == 1 && s.DefaultValue == 1:
|
||||
f.P("m.", signalField(s), " = true")
|
||||
case s.Length == 1:
|
||||
f.P("m.", signalField(s), " = false")
|
||||
default:
|
||||
f.P("m.", signalField(s), " = ", s.DefaultValue)
|
||||
}
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", messageStruct(m), ") CopyFrom(o ", messageReaderInterface(m), ") *", messageStruct(m), "{")
|
||||
for _, s := range m.Signals {
|
||||
if hasPhysicalRepresentation(s) {
|
||||
f.P("m.Set", s.Name, "(o.", s.Name, "())")
|
||||
} else {
|
||||
f.P("m.", signalField(s), " = o.", s.Name, "()")
|
||||
}
|
||||
}
|
||||
f.P("return m")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("// Descriptor returns the ", m.Name, " descriptor.")
|
||||
f.P("func (m *", messageStruct(m), ") Descriptor() *descriptor.Message {")
|
||||
f.P("return ", messageDescriptor(m), ".Message")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("// String returns a compact string representation of the message.")
|
||||
f.P("func(m *", messageStruct(m), ") String() string {")
|
||||
f.P("return cantext.MessageString(m)")
|
||||
f.P("}")
|
||||
f.P()
|
||||
for _, s := range m.Signals {
|
||||
if !hasPhysicalRepresentation(s) {
|
||||
f.P("func (m *", messageStruct(m), ") ", s.Name, "() ", signalType(m, s), " {")
|
||||
f.P("return m.", signalField(s))
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", messageStruct(m), ") Set", s.Name, "(v ", signalType(m, s), ") *", messageStruct(m), " {")
|
||||
if s.Length == 1 {
|
||||
f.P("m.", signalField(s), " = v")
|
||||
} else {
|
||||
f.P(
|
||||
"m.", signalField(s), " = ", signalType(m, s), "(",
|
||||
signalDescriptor(m, s), ".SaturatedCast", signalSuperType(s), "(",
|
||||
signalPrimitiveSuperType(s), "(v)))",
|
||||
)
|
||||
}
|
||||
f.P("return m")
|
||||
f.P("}")
|
||||
f.P()
|
||||
continue
|
||||
}
|
||||
f.P("func (m *", messageStruct(m), ") ", s.Name, "() float64 {")
|
||||
f.P("return ", signalDescriptor(m, s), ".ToPhysical(float64(m.", signalField(s), "))")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", messageStruct(m), ") Set", s.Name, "(v float64) *", messageStruct(m), " {")
|
||||
f.P("m.", signalField(s), " = ", signalType(m, s), "(", signalDescriptor(m, s), ".FromPhysical(v))")
|
||||
f.P("return m")
|
||||
f.P("}")
|
||||
f.P()
|
||||
if len(s.ValueDescriptions) > 0 {
|
||||
f.P("func (m *", messageStruct(m), ") Raw", s.Name, "() ", signalType(m, s), " {")
|
||||
f.P("return m.", signalField(s))
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", messageStruct(m), ") SetRaw", s.Name, "(v ", signalType(m, s), ") *", messageStruct(m), "{")
|
||||
f.P(
|
||||
"m.", signalField(s), " = ", signalType(m, s), "(",
|
||||
signalDescriptor(m, s), ".SaturatedCast", signalSuperType(s), "(",
|
||||
signalPrimitiveSuperType(s), "(v)))",
|
||||
)
|
||||
f.P("return m")
|
||||
f.P("}")
|
||||
f.P()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Descriptors(f *File, d *descriptor.Database) {
|
||||
f.P("// Nodes returns the ", d.Name(), " node descriptors.")
|
||||
f.P("func Nodes() *NodesDescriptor {")
|
||||
f.P("return nd")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("// NodesDescriptor contains all ", d.Name(), " node descriptors.")
|
||||
f.P("type NodesDescriptor struct{")
|
||||
for _, n := range d.Nodes {
|
||||
f.P(n.Name, " *descriptor.Node")
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("// Messages returns the ", d.Name(), " message descriptors.")
|
||||
f.P("func Messages() *MessagesDescriptor {")
|
||||
f.P("return md")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("// MessagesDescriptor contains all ", d.Name(), " message descriptors.")
|
||||
f.P("type MessagesDescriptor struct{")
|
||||
for _, m := range d.Messages {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
f.P(m.Name, " *", m.Name, "Descriptor")
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("// UnmarshalFrame unmarshals the provided ", d.Name(), " CAN frame.")
|
||||
f.P("func (md *MessagesDescriptor) UnmarshalFrame(f can.Frame) (generated.Message, error) {")
|
||||
f.P("switch f.ID {")
|
||||
for _, m := range d.Messages {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
f.P("case md.", m.Name, ".ID:")
|
||||
f.P("var msg ", messageStruct(m))
|
||||
f.P("if err := msg.UnmarshalFrame(f); err != nil {")
|
||||
f.P(`return nil, fmt.Errorf("unmarshal `, d.Name(), ` frame: %w", err)`)
|
||||
f.P("}")
|
||||
f.P("return &msg, nil")
|
||||
}
|
||||
f.P("default:")
|
||||
f.P(`return nil, fmt.Errorf("unmarshal `, d.Name(), ` frame: ID not in database: %d", f.ID)`)
|
||||
f.P("}")
|
||||
f.P("}")
|
||||
f.P()
|
||||
for _, m := range d.Messages {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
f.P("type ", m.Name, "Descriptor struct{")
|
||||
f.P("*descriptor.Message")
|
||||
for _, s := range m.Signals {
|
||||
f.P(s.Name, " *descriptor.Signal")
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
}
|
||||
f.P("// Database returns the ", d.Name(), " database descriptor.")
|
||||
f.P("func (md *MessagesDescriptor) Database() *descriptor.Database {")
|
||||
f.P("return d")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("var nd = &NodesDescriptor{")
|
||||
for ni, n := range d.Nodes {
|
||||
f.P(n.Name, ": d.Nodes[", ni, "],")
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("var md = &MessagesDescriptor{")
|
||||
for mi, m := range d.Messages {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
f.P(m.Name, ": &", m.Name, "Descriptor{")
|
||||
f.P("Message: d.Messages[", mi, "],")
|
||||
for si, s := range m.Signals {
|
||||
f.P(s.Name, ": d.Messages[", mi, "].Signals[", si, "],")
|
||||
}
|
||||
f.P("},")
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("var d = ")
|
||||
f.Dump(d)
|
||||
f.P()
|
||||
}
|
||||
|
||||
func MarshalFrame(f *File, m *descriptor.Message) {
|
||||
f.P("// Frame returns a CAN frame representing the message.")
|
||||
f.P("func (m *", messageStruct(m), ") Frame() can.Frame {")
|
||||
f.P("md := ", messageDescriptor(m))
|
||||
f.P("f := can.Frame{ID: md.ID, IsExtended: md.IsExtended, Length: md.Length}")
|
||||
for _, s := range m.Signals {
|
||||
if s.IsMultiplexed {
|
||||
continue
|
||||
}
|
||||
f.P(
|
||||
"md.", s.Name, ".Marshal", signalSuperType(s),
|
||||
"(&f.Data, ", signalPrimitiveSuperType(s), "(m.", signalField(s), "))",
|
||||
)
|
||||
}
|
||||
if mux, ok := m.MultiplexerSignal(); ok {
|
||||
for _, s := range m.Signals {
|
||||
if !s.IsMultiplexed {
|
||||
continue
|
||||
}
|
||||
f.P("if m.", signalField(mux), " == ", s.MultiplexerValue, " {")
|
||||
f.P(
|
||||
"md.", s.Name, ".Marshal", signalSuperType(s), "(&f.Data, ", signalPrimitiveSuperType(s),
|
||||
"(m.", signalField(s), "))",
|
||||
)
|
||||
f.P("}")
|
||||
}
|
||||
}
|
||||
f.P("return f")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("// MarshalFrame encodes the message as a CAN frame.")
|
||||
f.P("func (m *", messageStruct(m), ") MarshalFrame() (can.Frame, error) {")
|
||||
f.P("return m.Frame(), nil")
|
||||
f.P("}")
|
||||
f.P()
|
||||
}
|
||||
|
||||
func UnmarshalFrame(f *File, m *descriptor.Message) {
|
||||
f.P("// UnmarshalFrame decodes the message from a CAN frame.")
|
||||
f.P("func (m *", messageStruct(m), ") UnmarshalFrame(f can.Frame) error {")
|
||||
f.P("md := ", messageDescriptor(m))
|
||||
// generate frame checks
|
||||
id := func(isExtended bool) string {
|
||||
if isExtended {
|
||||
return "extended ID"
|
||||
}
|
||||
return "standard ID"
|
||||
}
|
||||
f.P("switch {")
|
||||
f.P("case f.ID != md.ID:")
|
||||
f.P(`return fmt.Errorf(`)
|
||||
f.P(`"unmarshal `, m.Name, `: expects ID `, m.ID, ` (got %s with ID %d)", f.String(), f.ID,`)
|
||||
f.P(`)`)
|
||||
f.P("case f.Length != md.Length:")
|
||||
f.P(`return fmt.Errorf(`)
|
||||
f.P(`"unmarshal `, m.Name, `: expects length `, m.Length, ` (got %s with length %d)", f.String(), f.Length,`)
|
||||
f.P(`)`)
|
||||
f.P("case f.IsRemote:")
|
||||
f.P(`return fmt.Errorf(`)
|
||||
f.P(`"unmarshal `, m.Name, `: expects non-remote frame (got remote frame %s)", f.String(),`)
|
||||
f.P(`)`)
|
||||
f.P("case f.IsExtended != md.IsExtended:")
|
||||
f.P(`return fmt.Errorf(`)
|
||||
f.P(`"unmarshal `, m.Name, `: expects `, id(m.IsExtended), ` (got %s with `, id(!m.IsExtended), `)", f.String(),`)
|
||||
f.P(`)`)
|
||||
f.P("}")
|
||||
if len(m.Signals) == 0 {
|
||||
f.P("return nil")
|
||||
f.P("}")
|
||||
return
|
||||
}
|
||||
// generate non-multiplexed signal unmarshaling
|
||||
for _, s := range m.Signals {
|
||||
if s.IsMultiplexed {
|
||||
continue
|
||||
}
|
||||
f.P("m.", signalField(s), " = ", signalType(m, s), "(md.", s.Name, ".Unmarshal", signalSuperType(s), "(f.Data))")
|
||||
}
|
||||
// generate multiplexed signal unmarshaling
|
||||
if mux, ok := m.MultiplexerSignal(); ok {
|
||||
for _, s := range m.Signals {
|
||||
if !s.IsMultiplexed {
|
||||
continue
|
||||
}
|
||||
f.P("if m.", signalField(mux), " == ", s.MultiplexerValue, " {")
|
||||
f.P("m.", signalField(s), " = ", signalType(m, s), "(md.", s.Name, ".Unmarshal", signalSuperType(s), "(f.Data))")
|
||||
f.P("}")
|
||||
}
|
||||
}
|
||||
f.P("return nil")
|
||||
f.P("}")
|
||||
f.P()
|
||||
}
|
||||
|
||||
func Node(f *File, d *descriptor.Database, n *descriptor.Node) {
|
||||
rxMessages := collectRxMessages(d, n)
|
||||
txMessages := collectTxMessages(d, n)
|
||||
f.P("type ", nodeInterface(n), " interface {")
|
||||
f.P("sync.Locker")
|
||||
f.P("Tx() ", txGroupInterface(n))
|
||||
f.P("Rx() ", rxGroupInterface(n))
|
||||
f.P("Run(ctx context.Context) error")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("type ", rxGroupInterface(n), " interface {")
|
||||
f.P("http.Handler // for debugging")
|
||||
for _, m := range rxMessages {
|
||||
f.P(m.Name, "() ", rxMessageInterface(n, m))
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("type ", txGroupInterface(n), " interface {")
|
||||
f.P("http.Handler // for debugging")
|
||||
for _, m := range txMessages {
|
||||
f.P(m.Name, "() ", txMessageInterface(n, m))
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
for _, m := range rxMessages {
|
||||
f.P("type ", rxMessageInterface(n, m), " interface {")
|
||||
f.P(messageReaderInterface(m))
|
||||
f.P("ReceiveTime() time.Time")
|
||||
f.P("SetAfterReceiveHook(h func(context.Context) error)")
|
||||
f.P("}")
|
||||
f.P()
|
||||
}
|
||||
for _, m := range txMessages {
|
||||
f.P("type ", txMessageInterface(n, m), " interface {")
|
||||
f.P(messageReaderInterface(m))
|
||||
f.P(messageWriterInterface(m))
|
||||
f.P("TransmitTime() time.Time")
|
||||
f.P("Transmit(ctx context.Context) error")
|
||||
f.P("SetBeforeTransmitHook(h func(context.Context) error)")
|
||||
if m.SendType == descriptor.SendTypeCyclic {
|
||||
f.P("// SetCyclicTransmissionEnabled enables/disables cyclic transmission.")
|
||||
f.P("SetCyclicTransmissionEnabled(bool)")
|
||||
f.P("// IsCyclicTransmissionEnabled returns whether cyclic transmission is enabled/disabled.")
|
||||
f.P("IsCyclicTransmissionEnabled() bool")
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
}
|
||||
f.P("type ", nodeStruct(n), " struct {")
|
||||
f.P("sync.Mutex // protects all node state")
|
||||
f.P("network string")
|
||||
f.P("address string")
|
||||
f.P("rx ", rxGroupStruct(n))
|
||||
f.P("tx ", txGroupStruct(n))
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("var _ ", nodeInterface(n), " = &", nodeStruct(n), "{}")
|
||||
f.P("var _ canrunner.Node = &", nodeStruct(n), "{}")
|
||||
f.P()
|
||||
f.P("func New", nodeInterface(n), "(network, address string) ", nodeInterface(n), " {")
|
||||
f.P("n := &", nodeStruct(n), "{network: network, address: address}")
|
||||
f.P("n.rx.parentMutex = &n.Mutex")
|
||||
f.P("n.tx.parentMutex = &n.Mutex")
|
||||
for _, m := range rxMessages {
|
||||
f.P("n.rx.", messageField(m), ".init()")
|
||||
f.P("n.rx.", messageField(m), ".Reset()")
|
||||
}
|
||||
for _, m := range txMessages {
|
||||
f.P("n.tx.", messageField(m), ".init()")
|
||||
f.P("n.tx.", messageField(m), ".Reset()")
|
||||
}
|
||||
f.P("return n")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (n *", nodeStruct(n), ") Run(ctx context.Context) error {")
|
||||
f.P("return canrunner.Run(ctx, n)")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (n *", nodeStruct(n), ") Rx() ", rxGroupInterface(n), " {")
|
||||
f.P("return &n.rx")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (n *", nodeStruct(n), ") Tx() ", txGroupInterface(n), " {")
|
||||
f.P("return &n.tx")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("type ", rxGroupStruct(n), " struct {")
|
||||
f.P("parentMutex *sync.Mutex")
|
||||
for _, m := range rxMessages {
|
||||
f.P(messageField(m), " ", rxMessageStruct(n, m))
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("var _ ", rxGroupInterface(n), " = &", rxGroupStruct(n), "{}")
|
||||
f.P()
|
||||
f.P("func (rx *", rxGroupStruct(n), ") ServeHTTP(w http.ResponseWriter, r *http.Request) {")
|
||||
f.P("rx.parentMutex.Lock()")
|
||||
f.P("defer rx.parentMutex.Unlock()")
|
||||
f.P("candebug.ServeMessagesHTTP(w, r, []generated.Message{")
|
||||
for _, m := range rxMessages {
|
||||
f.P("&rx.", messageField(m), ",")
|
||||
}
|
||||
f.P("})")
|
||||
f.P("}")
|
||||
f.P()
|
||||
for _, m := range rxMessages {
|
||||
f.P("func (rx *", rxGroupStruct(n), ") ", m.Name, "() ", rxMessageInterface(n, m), " {")
|
||||
f.P("return &rx.", messageField(m))
|
||||
f.P("}")
|
||||
f.P()
|
||||
}
|
||||
f.P()
|
||||
f.P("type ", txGroupStruct(n), " struct {")
|
||||
f.P("parentMutex *sync.Mutex")
|
||||
for _, m := range txMessages {
|
||||
f.P(messageField(m), " ", txMessageStruct(n, m))
|
||||
}
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("var _ ", txGroupInterface(n), " = &", txGroupStruct(n), "{}")
|
||||
f.P()
|
||||
f.P("func (tx *", txGroupStruct(n), ") ServeHTTP(w http.ResponseWriter, r *http.Request) {")
|
||||
f.P("tx.parentMutex.Lock()")
|
||||
f.P("defer tx.parentMutex.Unlock()")
|
||||
f.P("candebug.ServeMessagesHTTP(w, r, []generated.Message{")
|
||||
for _, m := range txMessages {
|
||||
f.P("&tx.", messageField(m), ",")
|
||||
}
|
||||
f.P("})")
|
||||
f.P("}")
|
||||
f.P()
|
||||
for _, m := range txMessages {
|
||||
f.P("func (tx *", txGroupStruct(n), ") ", m.Name, "() ", txMessageInterface(n, m), " {")
|
||||
f.P("return &tx.", messageField(m))
|
||||
f.P("}")
|
||||
f.P()
|
||||
}
|
||||
f.P()
|
||||
f.P("func (n *", nodeStruct(n), ") Descriptor() *descriptor.Node {")
|
||||
f.P("return ", nodeDescriptor(n))
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (n *", nodeStruct(n), ") Connect() (net.Conn, error) {")
|
||||
f.P("return socketcan.Dial(n.network, n.address)")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (n *", nodeStruct(n), ") ReceivedMessage(id uint32) (canrunner.ReceivedMessage, bool) {")
|
||||
f.P("switch id {")
|
||||
for _, m := range rxMessages {
|
||||
f.P("case ", m.ID, ":")
|
||||
f.P("return &n.rx.", messageField(m), ", true")
|
||||
}
|
||||
f.P("default:")
|
||||
f.P("return nil, false")
|
||||
f.P("}")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (n *", nodeStruct(n), ") TransmittedMessages() []canrunner.TransmittedMessage {")
|
||||
f.P("return []canrunner.TransmittedMessage{")
|
||||
for _, m := range txMessages {
|
||||
f.P("&n.tx.", messageField(m), ",")
|
||||
}
|
||||
f.P("}")
|
||||
f.P("}")
|
||||
f.P()
|
||||
for _, m := range rxMessages {
|
||||
f.P("type ", rxMessageStruct(n, m), " struct {")
|
||||
f.P(messageStruct(m))
|
||||
f.P("receiveTime time.Time")
|
||||
f.P("afterReceiveHook func(context.Context) error")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", rxMessageStruct(n, m), ") init() {")
|
||||
f.P("m.afterReceiveHook = func(context.Context) error { return nil }")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", rxMessageStruct(n, m), ") SetAfterReceiveHook(h func(context.Context) error) {")
|
||||
f.P("m.afterReceiveHook = h")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", rxMessageStruct(n, m), ") AfterReceiveHook() func(context.Context) error {")
|
||||
f.P("return m.afterReceiveHook")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", rxMessageStruct(n, m), ") ReceiveTime() time.Time {")
|
||||
f.P("return m.receiveTime")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", rxMessageStruct(n, m), ") SetReceiveTime(t time.Time) {")
|
||||
f.P("m.receiveTime = t")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("var _ canrunner.ReceivedMessage = &", rxMessageStruct(n, m), "{}")
|
||||
f.P()
|
||||
}
|
||||
for _, m := range txMessages {
|
||||
f.P("type ", txMessageStruct(n, m), " struct {")
|
||||
f.P(messageStruct(m))
|
||||
f.P("transmitTime time.Time")
|
||||
f.P("beforeTransmitHook func(context.Context) error")
|
||||
f.P("isCyclicEnabled bool")
|
||||
f.P("wakeUpChan chan struct{}")
|
||||
f.P("transmitEventChan chan struct{}")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("var _ ", txMessageInterface(n, m), " = &", txMessageStruct(n, m), "{}")
|
||||
f.P("var _ canrunner.TransmittedMessage = &", txMessageStruct(n, m), "{}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") init() {")
|
||||
f.P("m.beforeTransmitHook = func(context.Context) error { return nil }")
|
||||
f.P("m.wakeUpChan = make(chan struct{}, 1)")
|
||||
f.P("m.transmitEventChan = make(chan struct{})")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") SetBeforeTransmitHook(h func(context.Context) error) {")
|
||||
f.P("m.beforeTransmitHook = h")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") BeforeTransmitHook() func(context.Context) error {")
|
||||
f.P("return m.beforeTransmitHook")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") TransmitTime() time.Time {")
|
||||
f.P("return m.transmitTime")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") SetTransmitTime(t time.Time) {")
|
||||
f.P("m.transmitTime = t")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") IsCyclicTransmissionEnabled() bool {")
|
||||
f.P("return m.isCyclicEnabled")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") SetCyclicTransmissionEnabled(b bool) {")
|
||||
f.P("m.isCyclicEnabled = b")
|
||||
f.P("select {")
|
||||
f.P("case m.wakeUpChan <-struct{}{}:")
|
||||
f.P("default:")
|
||||
f.P("}")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") WakeUpChan() <-chan struct{} {")
|
||||
f.P("return m.wakeUpChan")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") Transmit(ctx context.Context) error {")
|
||||
f.P("select {")
|
||||
f.P("case m.transmitEventChan <- struct{}{}:")
|
||||
f.P("return nil")
|
||||
f.P("case <-ctx.Done():")
|
||||
f.P(`return fmt.Errorf("event-triggered transmit of `, m.Name, `: %w", ctx.Err())`)
|
||||
f.P("}")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("func (m *", txMessageStruct(n, m), ") TransmitEventChan() <-chan struct{} {")
|
||||
f.P("return m.transmitEventChan")
|
||||
f.P("}")
|
||||
f.P()
|
||||
f.P("var _ canrunner.TransmittedMessage = &", txMessageStruct(n, m), "{}")
|
||||
f.P()
|
||||
}
|
||||
}
|
||||
|
||||
func txGroupInterface(n *descriptor.Node) string {
|
||||
return n.Name + "_Tx"
|
||||
}
|
||||
|
||||
func txGroupStruct(n *descriptor.Node) string {
|
||||
return "xxx_" + n.Name + "_Tx"
|
||||
}
|
||||
|
||||
func rxGroupInterface(n *descriptor.Node) string {
|
||||
return n.Name + "_Rx"
|
||||
}
|
||||
|
||||
func rxGroupStruct(n *descriptor.Node) string {
|
||||
return "xxx_" + n.Name + "_Rx"
|
||||
}
|
||||
|
||||
func rxMessageInterface(n *descriptor.Node, m *descriptor.Message) string {
|
||||
return n.Name + "_Rx_" + m.Name
|
||||
}
|
||||
|
||||
func rxMessageStruct(n *descriptor.Node, m *descriptor.Message) string {
|
||||
return "xxx_" + n.Name + "_Rx_" + m.Name
|
||||
}
|
||||
|
||||
func txMessageInterface(n *descriptor.Node, m *descriptor.Message) string {
|
||||
return n.Name + "_Tx_" + m.Name
|
||||
}
|
||||
|
||||
func txMessageStruct(n *descriptor.Node, m *descriptor.Message) string {
|
||||
return "xxx_" + n.Name + "_Tx_" + m.Name
|
||||
}
|
||||
|
||||
func collectTxMessages(d *descriptor.Database, n *descriptor.Node) []*descriptor.Message {
|
||||
tx := make([]*descriptor.Message, 0, len(d.Messages))
|
||||
for _, m := range d.Messages {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if m.SenderNode == n.Name && m.SendType != descriptor.SendTypeNone {
|
||||
tx = append(tx, m)
|
||||
}
|
||||
}
|
||||
return tx
|
||||
}
|
||||
|
||||
func collectRxMessages(d *descriptor.Database, n *descriptor.Node) []*descriptor.Message {
|
||||
rx := make([]*descriptor.Message, 0, len(d.Messages))
|
||||
Loop:
|
||||
for _, m := range d.Messages {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, s := range m.Signals {
|
||||
for _, node := range s.ReceiverNodes {
|
||||
if node != n.Name {
|
||||
continue
|
||||
}
|
||||
rx = append(rx, m)
|
||||
continue Loop
|
||||
}
|
||||
}
|
||||
}
|
||||
return rx
|
||||
}
|
||||
|
||||
func hasPhysicalRepresentation(s *descriptor.Signal) bool {
|
||||
hasScale := s.Scale != 0 && s.Scale != 1
|
||||
hasOffset := s.Offset != 0
|
||||
hasRange := s.Min != 0 || s.Max != 0
|
||||
var hasConstrainedRange bool
|
||||
if s.IsSigned {
|
||||
hasConstrainedRange = s.Min > float64(s.MinSigned()) || s.Max < float64(s.MaxSigned())
|
||||
} else {
|
||||
hasConstrainedRange = s.Min > 0 || s.Max < float64(s.MaxUnsigned())
|
||||
}
|
||||
return hasScale || hasOffset || hasRange && hasConstrainedRange
|
||||
}
|
||||
|
||||
func hasCustomType(s *descriptor.Signal) bool {
|
||||
return len(s.ValueDescriptions) > 0
|
||||
}
|
||||
|
||||
func hasSendType(d *descriptor.Database) bool {
|
||||
for _, m := range d.Messages {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if m.SendType != descriptor.SendTypeNone {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func signalType(m *descriptor.Message, s *descriptor.Signal) string {
|
||||
if hasCustomType(s) {
|
||||
return m.Name + "_" + s.Name
|
||||
}
|
||||
return signalPrimitiveType(s).String()
|
||||
}
|
||||
|
||||
func signalPrimitiveType(s *descriptor.Signal) types.Type {
|
||||
var t types.BasicKind
|
||||
switch {
|
||||
case s.Length == 1:
|
||||
t = types.Bool
|
||||
case s.Length <= 8 && s.IsSigned:
|
||||
t = types.Int8
|
||||
case s.Length <= 8:
|
||||
t = types.Uint8
|
||||
case s.Length <= 16 && s.IsSigned:
|
||||
t = types.Int16
|
||||
case s.Length <= 16:
|
||||
t = types.Uint16
|
||||
case s.Length <= 32 && s.IsSigned:
|
||||
t = types.Int32
|
||||
case s.Length <= 32:
|
||||
t = types.Uint32
|
||||
case s.Length <= 64 && s.IsSigned:
|
||||
t = types.Int64
|
||||
default:
|
||||
t = types.Uint64
|
||||
}
|
||||
return types.Typ[t]
|
||||
}
|
||||
|
||||
func signalPrimitiveSuperType(s *descriptor.Signal) types.Type {
|
||||
var t types.BasicKind
|
||||
switch {
|
||||
case s.Length == 1:
|
||||
t = types.Bool
|
||||
case s.IsSigned:
|
||||
t = types.Int64
|
||||
default:
|
||||
t = types.Uint64
|
||||
}
|
||||
return types.Typ[t]
|
||||
}
|
||||
|
||||
func signalSuperType(s *descriptor.Signal) string {
|
||||
switch {
|
||||
case s.Length == 1:
|
||||
return "Bool"
|
||||
case s.IsSigned:
|
||||
return "Signed"
|
||||
default:
|
||||
return "Unsigned"
|
||||
}
|
||||
}
|
||||
|
||||
func nodeInterface(n *descriptor.Node) string {
|
||||
return n.Name
|
||||
}
|
||||
|
||||
func nodeStruct(n *descriptor.Node) string {
|
||||
return "xxx_" + n.Name
|
||||
}
|
||||
|
||||
func messageStruct(m *descriptor.Message) string {
|
||||
return m.Name
|
||||
}
|
||||
|
||||
func messageReaderInterface(m *descriptor.Message) string {
|
||||
return m.Name + "Reader"
|
||||
}
|
||||
|
||||
func messageWriterInterface(m *descriptor.Message) string {
|
||||
return m.Name + "Writer"
|
||||
}
|
||||
|
||||
func messageField(m *descriptor.Message) string {
|
||||
return "xxx_" + m.Name
|
||||
}
|
||||
|
||||
func signalField(s *descriptor.Signal) string {
|
||||
return "xxx_" + s.Name
|
||||
}
|
||||
|
||||
func nodeDescriptor(n *descriptor.Node) string {
|
||||
return "Nodes()." + n.Name
|
||||
}
|
||||
|
||||
func messageDescriptor(m *descriptor.Message) string {
|
||||
return "Messages()." + m.Name
|
||||
}
|
||||
|
||||
func signalDescriptor(m *descriptor.Message, s *descriptor.Signal) string {
|
||||
return messageDescriptor(m) + "." + s.Name
|
||||
}
|
||||
18
pkg/can-go/internal/generate/file_test.go
Normal file
18
pkg/can-go/internal/generate/file_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func runTestInDir(t *testing.T, dir string) func() {
|
||||
// change working directory to project root
|
||||
wd, err := os.Getwd()
|
||||
assert.NilError(t, err)
|
||||
assert.NilError(t, os.Chdir(dir))
|
||||
return func() {
|
||||
assert.NilError(t, os.Chdir(wd))
|
||||
}
|
||||
}
|
||||
17
pkg/can-go/internal/identifiers/case.go
Normal file
17
pkg/can-go/internal/identifiers/case.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package identifiers
|
||||
|
||||
import "unicode"
|
||||
|
||||
func IsCamelCase(s string) bool {
|
||||
i := 0
|
||||
for _, r := range s {
|
||||
if unicode.IsDigit(r) {
|
||||
continue
|
||||
}
|
||||
if i == 0 && !unicode.IsUpper(r) || !IsAlphaChar(r) && !IsNumChar(r) {
|
||||
return false
|
||||
}
|
||||
i++
|
||||
}
|
||||
return true
|
||||
}
|
||||
18
pkg/can-go/internal/identifiers/case_test.go
Normal file
18
pkg/can-go/internal/identifiers/case_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package identifiers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestIsCamelCase(t *testing.T) {
|
||||
assert.Assert(t, IsCamelCase("SOC"))
|
||||
assert.Assert(t, IsCamelCase("Camel"))
|
||||
assert.Assert(t, IsCamelCase("CamelCase"))
|
||||
assert.Assert(t, IsCamelCase("111CamelCaseNr"))
|
||||
assert.Assert(t, !IsCamelCase("camelCase"))
|
||||
assert.Assert(t, !IsCamelCase("snake_case"))
|
||||
assert.Assert(t, !IsCamelCase("kebab-case"))
|
||||
assert.Assert(t, !IsCamelCase("111camelCaseNr"))
|
||||
}
|
||||
9
pkg/can-go/internal/identifiers/char.go
Normal file
9
pkg/can-go/internal/identifiers/char.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package identifiers
|
||||
|
||||
func IsAlphaChar(r rune) bool {
|
||||
return ('A' <= r && r <= 'Z') || ('a' <= r && r <= 'z')
|
||||
}
|
||||
|
||||
func IsNumChar(r rune) bool {
|
||||
return '0' <= r && r <= '9'
|
||||
}
|
||||
23
pkg/can-go/internal/identifiers/char_test.go
Normal file
23
pkg/can-go/internal/identifiers/char_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package identifiers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestIsAlphaChar(t *testing.T) {
|
||||
assert.Assert(t, IsAlphaChar('b'))
|
||||
assert.Assert(t, IsAlphaChar('C'))
|
||||
assert.Assert(t, !IsAlphaChar('Ö'))
|
||||
assert.Assert(t, !IsAlphaChar('_'))
|
||||
}
|
||||
|
||||
func TestIsNumChar(t *testing.T) {
|
||||
assert.Assert(t, IsNumChar('0'))
|
||||
assert.Assert(t, IsNumChar('1'))
|
||||
assert.Assert(t, IsNumChar('2'))
|
||||
assert.Assert(t, IsNumChar('9'))
|
||||
assert.Assert(t, !IsNumChar('/'))
|
||||
assert.Assert(t, !IsNumChar('a'))
|
||||
}
|
||||
50
pkg/can-go/internal/reinterpret/reinterpret.go
Normal file
50
pkg/can-go/internal/reinterpret/reinterpret.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// Package reinterpret provides primitives for reinterpreting arbitrary-length values as signed or unsigned.
|
||||
package reinterpret
|
||||
|
||||
// AsSigned reinterprets the provided unsigned value as a signed value.
|
||||
func AsSigned(unsigned uint64, bits uint8) int64 {
|
||||
switch bits {
|
||||
case 8:
|
||||
return int64(int8(uint8(unsigned)))
|
||||
case 16:
|
||||
return int64(int16(uint16(unsigned)))
|
||||
case 32:
|
||||
return int64(int32(uint32(unsigned)))
|
||||
case 64:
|
||||
return int64(unsigned)
|
||||
default:
|
||||
// calculate bit mask for sign bit
|
||||
signBitMask := uint64(1 << (bits - 1))
|
||||
// check if sign bit is set
|
||||
isNegative := unsigned&signBitMask > 0
|
||||
if !isNegative {
|
||||
// sign bit not set means we can reinterpret the value as-is
|
||||
return int64(unsigned)
|
||||
}
|
||||
// calculate bit mask for extracting value bits (all bits except the sign bit)
|
||||
valueBitMask := signBitMask - 1
|
||||
// calculate two's complement of the value bits
|
||||
value := ((^unsigned) & valueBitMask) + 1
|
||||
// result is the negative value of the two's complement
|
||||
return -1 * int64(value)
|
||||
}
|
||||
}
|
||||
|
||||
// AsUnsigned reinterprets the provided signed value as an unsigned value.
|
||||
func AsUnsigned(signed int64, bits uint8) uint64 {
|
||||
switch bits {
|
||||
case 8:
|
||||
return uint64(uint8(int8(signed)))
|
||||
case 16:
|
||||
return uint64(uint16(int16(signed)))
|
||||
case 32:
|
||||
return uint64(uint32(int32(signed)))
|
||||
case 64:
|
||||
return uint64(signed)
|
||||
default:
|
||||
// calculate bit mask for extracting relevant bits
|
||||
valueBitMask := uint64(1<<bits) - 1
|
||||
// extract relevant bits
|
||||
return uint64(signed) & valueBitMask
|
||||
}
|
||||
}
|
||||
68
pkg/can-go/internal/reinterpret/reinterpret_test.go
Normal file
68
pkg/can-go/internal/reinterpret/reinterpret_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package reinterpret
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestReinterpretSign(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
unsigned uint64
|
||||
length uint8
|
||||
signed int64
|
||||
}{
|
||||
// -1, byte aligned
|
||||
{unsigned: 0xf, length: 4, signed: -1},
|
||||
{unsigned: 0xff, length: 8, signed: -1},
|
||||
{unsigned: 0xfff, length: 12, signed: -1},
|
||||
{unsigned: 0xffff, length: 16, signed: -1},
|
||||
{unsigned: 0xfffff, length: 20, signed: -1},
|
||||
{unsigned: 0xffffff, length: 24, signed: -1},
|
||||
{unsigned: 0xfffffff, length: 28, signed: -1},
|
||||
{unsigned: 0xffffffff, length: 32, signed: -1},
|
||||
{unsigned: 0xfffffffff, length: 36, signed: -1},
|
||||
{unsigned: 0xffffffffff, length: 40, signed: -1},
|
||||
{unsigned: 0xfffffffffff, length: 44, signed: -1},
|
||||
{unsigned: 0xffffffffffff, length: 48, signed: -1},
|
||||
{unsigned: 0xfffffffffffff, length: 52, signed: -1},
|
||||
{unsigned: 0xffffffffffffff, length: 56, signed: -1},
|
||||
{unsigned: 0xfffffffffffffff, length: 60, signed: -1},
|
||||
{unsigned: 0xffffffffffffffff, length: 64, signed: -1},
|
||||
// 3 bits
|
||||
{unsigned: 0x0, length: 3, signed: 0},
|
||||
{unsigned: 0x1, length: 3, signed: 1},
|
||||
{unsigned: 0x2, length: 3, signed: 2},
|
||||
{unsigned: 0x3, length: 3, signed: 3},
|
||||
{unsigned: 0x4, length: 3, signed: -4},
|
||||
{unsigned: 0x5, length: 3, signed: -3},
|
||||
{unsigned: 0x6, length: 3, signed: -2},
|
||||
{unsigned: 0x7, length: 3, signed: -1},
|
||||
// 4 bits
|
||||
{unsigned: 0x0, length: 4, signed: 0},
|
||||
{unsigned: 0x1, length: 4, signed: 1},
|
||||
{unsigned: 0x2, length: 4, signed: 2},
|
||||
{unsigned: 0x3, length: 4, signed: 3},
|
||||
{unsigned: 0x4, length: 4, signed: 4},
|
||||
{unsigned: 0x5, length: 4, signed: 5},
|
||||
{unsigned: 0x6, length: 4, signed: 6},
|
||||
{unsigned: 0x7, length: 4, signed: 7},
|
||||
{unsigned: 0x8, length: 4, signed: -8},
|
||||
{unsigned: 0x9, length: 4, signed: -7},
|
||||
{unsigned: 0xa, length: 4, signed: -6},
|
||||
{unsigned: 0xb, length: 4, signed: -5},
|
||||
{unsigned: 0xc, length: 4, signed: -4},
|
||||
{unsigned: 0xd, length: 4, signed: -3},
|
||||
{unsigned: 0xe, length: 4, signed: -2},
|
||||
{unsigned: 0xf, length: 4, signed: -1},
|
||||
} {
|
||||
tt := tt
|
||||
t.Run(fmt.Sprintf("%+v", tt), func(t *testing.T) {
|
||||
assert.Equal(t, tt.signed, AsSigned(tt.unsigned, tt.length))
|
||||
assert.Equal(t, tt.unsigned, AsUnsigned(tt.signed, tt.length))
|
||||
assert.Equal(t, tt.signed, AsSigned(AsUnsigned(tt.signed, tt.length), tt.length))
|
||||
assert.Equal(t, tt.unsigned, AsUnsigned(AsSigned(tt.unsigned, tt.length), tt.length))
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user