2020-01-26 18:57:32 +00:00
|
|
|
package part
|
|
|
|
|
|
|
|
import (
|
2020-02-02 22:42:43 +00:00
|
|
|
"fmt"
|
2020-01-26 18:57:32 +00:00
|
|
|
"github.com/cyrilix/robocar-base/service"
|
|
|
|
"github.com/cyrilix/robocar-protobuf/go/events"
|
|
|
|
mqtt "github.com/eclipse/paho.mqtt.golang"
|
2021-10-12 20:08:07 +00:00
|
|
|
"go.uber.org/zap"
|
2022-01-03 16:01:34 +00:00
|
|
|
"google.golang.org/protobuf/proto"
|
2020-01-26 18:57:32 +00:00
|
|
|
"sync"
|
2020-02-02 22:42:43 +00:00
|
|
|
"time"
|
2020-01-26 18:57:32 +00:00
|
|
|
)
|
|
|
|
|
2023-01-25 18:21:20 +00:00
|
|
|
func NewRecorder(client mqtt.Client, recordTopic, cameraTopic, rcSteeringTopic, tfSteeringTopic, driveModeTopic,
|
|
|
|
switchRecordTopic string) *Recorder {
|
2020-01-26 18:57:32 +00:00
|
|
|
return &Recorder{
|
2020-02-02 22:42:43 +00:00
|
|
|
client: client,
|
|
|
|
recordTopic: recordTopic,
|
|
|
|
cameraTopic: cameraTopic,
|
2023-01-25 18:21:20 +00:00
|
|
|
rcSteeringTopic: rcSteeringTopic,
|
|
|
|
tfSteeringTopic: tfSteeringTopic,
|
|
|
|
driveModeTopic: driveModeTopic,
|
2020-01-26 18:57:32 +00:00
|
|
|
switchRecordTopic: switchRecordTopic,
|
2020-02-02 22:42:43 +00:00
|
|
|
enabled: false,
|
|
|
|
idGenerator: NewDateBasedGenerator(),
|
|
|
|
recordSet: "",
|
|
|
|
cancel: make(chan interface{}),
|
2020-01-26 18:57:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type Recorder struct {
|
2023-01-25 18:21:20 +00:00
|
|
|
client mqtt.Client
|
|
|
|
recordTopic string
|
|
|
|
cameraTopic, switchRecordTopic string
|
2020-01-26 18:57:32 +00:00
|
|
|
|
2023-01-25 18:21:20 +00:00
|
|
|
driveModeTopic, rcSteeringTopic, tfSteeringTopic string
|
|
|
|
|
|
|
|
muRcSteeringMsg sync.Mutex
|
|
|
|
currentRcSteering *events.SteeringMessage
|
|
|
|
|
|
|
|
muTfSteeringMsg sync.Mutex
|
|
|
|
currentTfSteering *events.SteeringMessage
|
|
|
|
|
|
|
|
muDriveModeMsg sync.Mutex
|
|
|
|
currentDriveMode *events.DriveModeMessage
|
2020-01-26 18:57:32 +00:00
|
|
|
|
|
|
|
muEnabled sync.RWMutex
|
|
|
|
enabled bool
|
|
|
|
|
2020-02-02 22:42:43 +00:00
|
|
|
idGenerator IdGenerator
|
|
|
|
recordSet string
|
|
|
|
|
2020-01-26 18:57:32 +00:00
|
|
|
cancel chan interface {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Recorder) Start() error {
|
|
|
|
registerCallBacks(r)
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-r.cancel:
|
2021-10-12 20:08:07 +00:00
|
|
|
zap.S().Info("Stop service")
|
2020-01-26 18:57:32 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Recorder) Stop() {
|
|
|
|
close(r.cancel)
|
2023-01-25 18:21:20 +00:00
|
|
|
service.StopService("record", r.client, r.cameraTopic, r.rcSteeringTopic, r.tfSteeringTopic, r.driveModeTopic)
|
2020-01-26 18:57:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Recorder) onSwitchRecord(_ mqtt.Client, message mqtt.Message) {
|
|
|
|
var msg events.SwitchRecordMessage
|
|
|
|
err := proto.Unmarshal(message.Payload(), &msg)
|
|
|
|
if err != nil {
|
2021-10-12 20:08:07 +00:00
|
|
|
zap.S().Errorf("unable to unmarshal protobuf %T: %v", msg, err)
|
2020-01-26 18:57:32 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
r.muEnabled.Lock()
|
|
|
|
defer r.muEnabled.Unlock()
|
2020-02-02 22:42:43 +00:00
|
|
|
|
2021-02-22 17:35:15 +00:00
|
|
|
if !r.enabled && msg.GetEnabled() {
|
2020-02-02 22:42:43 +00:00
|
|
|
r.recordSet = r.idGenerator.Next()
|
|
|
|
}
|
|
|
|
|
2020-01-26 18:57:32 +00:00
|
|
|
r.enabled = msg.GetEnabled()
|
|
|
|
}
|
|
|
|
|
2023-01-25 18:21:20 +00:00
|
|
|
func (r *Recorder) onRcSteering(_ mqtt.Client, message mqtt.Message) {
|
|
|
|
var msg events.SteeringMessage
|
|
|
|
err := proto.Unmarshal(message.Payload(), &msg)
|
|
|
|
if err != nil {
|
|
|
|
zap.S().Errorf("unable to unmarshal protobuf %T: %v", msg, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
r.muRcSteeringMsg.Lock()
|
|
|
|
defer r.muRcSteeringMsg.Unlock()
|
|
|
|
r.currentRcSteering = &msg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Recorder) onTfSteering(_ mqtt.Client, message mqtt.Message) {
|
2020-01-26 18:57:32 +00:00
|
|
|
var msg events.SteeringMessage
|
|
|
|
err := proto.Unmarshal(message.Payload(), &msg)
|
|
|
|
if err != nil {
|
2021-10-12 20:08:07 +00:00
|
|
|
zap.S().Errorf("unable to unmarshal protobuf %T: %v", msg, err)
|
2020-01-26 18:57:32 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-01-25 18:21:20 +00:00
|
|
|
r.muTfSteeringMsg.Lock()
|
|
|
|
defer r.muTfSteeringMsg.Unlock()
|
|
|
|
r.currentTfSteering = &msg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Recorder) onDriveMode(_ mqtt.Client, message mqtt.Message) {
|
|
|
|
var msg events.DriveModeMessage
|
|
|
|
err := proto.Unmarshal(message.Payload(), &msg)
|
|
|
|
if err != nil {
|
|
|
|
zap.S().Errorf("unable to unmarshal protobuf %T: %v", msg, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
r.muDriveModeMsg.Lock()
|
|
|
|
defer r.muDriveModeMsg.Unlock()
|
|
|
|
r.currentDriveMode = &msg
|
2020-01-26 18:57:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Recorder) onFrame(_ mqtt.Client, message mqtt.Message) {
|
|
|
|
if !r.Enabled() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var msg events.FrameMessage
|
|
|
|
err := proto.Unmarshal(message.Payload(), &msg)
|
|
|
|
if err != nil {
|
2021-10-12 20:08:07 +00:00
|
|
|
zap.S().Errorf("unable to unmarshal protobuf FrameMessage: %v", err)
|
2020-01-26 18:57:32 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
steering := r.CurrentSteering()
|
|
|
|
if steering == nil {
|
2021-10-12 20:08:07 +00:00
|
|
|
zap.S().Warnf("no current steeringMsg, skip frameMsg %v", msg.GetId().Id)
|
2020-01-26 18:57:32 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-01-25 18:21:20 +00:00
|
|
|
autopilot := r.CurrentAutopilotSteering()
|
|
|
|
if autopilot == nil {
|
|
|
|
zap.S().Warnf("no current autopilot steeringMsg")
|
|
|
|
}
|
|
|
|
|
|
|
|
driveMode := r.CurrentDriveMode()
|
|
|
|
if driveMode == nil {
|
|
|
|
zap.S().Warnf("no current driveModeMsg")
|
|
|
|
}
|
|
|
|
|
2020-01-26 18:57:32 +00:00
|
|
|
record := events.RecordMessage{
|
2023-01-25 18:21:20 +00:00
|
|
|
Frame: &msg,
|
|
|
|
Steering: steering,
|
|
|
|
AutopilotSteering: autopilot,
|
|
|
|
DriveMode: driveMode,
|
|
|
|
RecordSet: r.recordSet,
|
2020-01-26 18:57:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
payload, err := proto.Marshal(&record)
|
|
|
|
if err != nil {
|
2021-10-12 20:08:07 +00:00
|
|
|
zap.S().Errorf("unable to marshal message %v: %v", record, err)
|
2020-01-26 18:57:32 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
publish(r.client, r.recordTopic, &payload)
|
|
|
|
}
|
|
|
|
|
|
|
|
var publish = func(client mqtt.Client, topic string, payload *[]byte) {
|
|
|
|
client.Publish(topic, 0, false, *payload)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Recorder) CurrentSteering() *events.SteeringMessage {
|
2023-01-25 18:21:20 +00:00
|
|
|
r.muRcSteeringMsg.Lock()
|
|
|
|
defer r.muRcSteeringMsg.Unlock()
|
|
|
|
steering := r.currentRcSteering
|
|
|
|
return steering
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Recorder) CurrentAutopilotSteering() *events.SteeringMessage {
|
|
|
|
r.muTfSteeringMsg.Lock()
|
|
|
|
defer r.muTfSteeringMsg.Unlock()
|
|
|
|
steering := r.currentTfSteering
|
2020-01-26 18:57:32 +00:00
|
|
|
return steering
|
|
|
|
}
|
|
|
|
|
2023-01-25 18:21:20 +00:00
|
|
|
func (r *Recorder) CurrentDriveMode() *events.DriveModeMessage {
|
|
|
|
r.muDriveModeMsg.Lock()
|
|
|
|
defer r.muDriveModeMsg.Unlock()
|
|
|
|
driveMode := r.currentDriveMode
|
|
|
|
return driveMode
|
|
|
|
}
|
|
|
|
|
2020-01-26 18:57:32 +00:00
|
|
|
func (r *Recorder) Enabled() bool {
|
|
|
|
r.muEnabled.RLock()
|
|
|
|
defer r.muEnabled.RUnlock()
|
|
|
|
return r.enabled
|
|
|
|
}
|
|
|
|
|
|
|
|
var registerCallBacks = func(r *Recorder) {
|
|
|
|
err := service.RegisterCallback(r.client, r.cameraTopic, r.onFrame)
|
|
|
|
if err != nil {
|
2022-01-02 15:49:04 +00:00
|
|
|
zap.S().Panicf("unable to register callback to %v:%v", r.cameraTopic, err)
|
2020-01-26 18:57:32 +00:00
|
|
|
}
|
|
|
|
|
2023-01-25 18:21:20 +00:00
|
|
|
err = service.RegisterCallback(r.client, r.rcSteeringTopic, r.onRcSteering)
|
|
|
|
if err != nil {
|
|
|
|
zap.S().Panicf("unable to register callback to %v:%v", r.rcSteeringTopic, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = service.RegisterCallback(r.client, r.tfSteeringTopic, r.onTfSteering)
|
|
|
|
if err != nil {
|
|
|
|
zap.S().Panicf("unable to register callback to %v:%v", r.tfSteeringTopic, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = service.RegisterCallback(r.client, r.driveModeTopic, r.onDriveMode)
|
2020-01-26 18:57:32 +00:00
|
|
|
if err != nil {
|
2023-01-25 18:21:20 +00:00
|
|
|
zap.S().Panicf("unable to register callback to %v:%v", r.driveModeTopic, err)
|
2020-01-26 18:57:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = service.RegisterCallback(r.client, r.switchRecordTopic, r.onSwitchRecord)
|
|
|
|
if err != nil {
|
2022-01-02 15:49:04 +00:00
|
|
|
zap.S().Panicf("unable to register callback to %v:%v", r.switchRecordTopic, err)
|
2020-01-26 18:57:32 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-02 22:42:43 +00:00
|
|
|
|
|
|
|
type IdGenerator interface {
|
|
|
|
Next() string
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewDateBasedGenerator() *DateBasedGenerator {
|
|
|
|
return &DateBasedGenerator{
|
|
|
|
muCpt: sync.Mutex{},
|
|
|
|
cpt: 0,
|
2022-01-02 15:32:00 +00:00
|
|
|
idTemplate: "%s_%d",
|
|
|
|
start: time.Now().Format("2006-01-02T15-04"),
|
2020-02-02 22:42:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type DateBasedGenerator struct {
|
|
|
|
muCpt sync.Mutex
|
|
|
|
cpt int
|
|
|
|
idTemplate string
|
|
|
|
start string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *DateBasedGenerator) Next() string {
|
|
|
|
d.muCpt.Lock()
|
|
|
|
defer d.muCpt.Unlock()
|
|
|
|
d.cpt += 1
|
|
|
|
return fmt.Sprintf(d.idTemplate, d.start, d.cpt)
|
|
|
|
}
|