Implements Gateway for car controls
This commit is contained in:
1 parent
b2ca7423ea
commit
843ada8357
6 files changed
+511
-78
No files matched your search
+29
-24
@@ -17,28 +17,31 @@ import (
|
||||
)
|
||||
|
||||
func New(publisher Publisher, addressSimulator string) *Gateway {
|
||||
log.Info("run camera camera")
|
||||
l := log.WithField("simulator", addressSimulator)
|
||||
l.Info("run camera from simulator")
|
||||
|
||||
return &Gateway{
|
||||
address: addressSimulator,
|
||||
publisher: publisher,
|
||||
address: addressSimulator,
|
||||
publisher: publisher,
|
||||
log: l,
|
||||
}
|
||||
}
|
||||
|
||||
/* Simulator interface to publish camera frames into mqtt topic */
|
||||
type Gateway struct {
|
||||
cancel chan interface{}
|
||||
cancel chan interface{}
|
||||
|
||||
address string
|
||||
conn io.ReadCloser
|
||||
|
||||
publisher Publisher
|
||||
log *log.Entry
|
||||
}
|
||||
|
||||
func (p *Gateway) Start() error {
|
||||
log.Info("connect to simulator")
|
||||
p.log.Info("connect to simulator")
|
||||
p.cancel = make(chan interface{})
|
||||
msgChan := make(chan *simulator.SimulatorMsg)
|
||||
msgChan := make(chan *simulator.TelemetryMsg)
|
||||
|
||||
go p.run(msgChan)
|
||||
|
||||
@@ -53,17 +56,17 @@ func (p *Gateway) Start() error {
|
||||
}
|
||||
|
||||
func (p *Gateway) Stop() {
|
||||
log.Info("close simulator gateway")
|
||||
p.log.Info("close simulator gateway")
|
||||
close(p.cancel)
|
||||
|
||||
if err := p.Close(); err != nil {
|
||||
log.Printf("unexpected error while simulator connection is closed: %v", err)
|
||||
p.log.Warnf("unexpected error while simulator connection is closed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Gateway) Close() error {
|
||||
if p.conn == nil {
|
||||
log.Warnln("no connection to close")
|
||||
p.log.Warn("no connection to close")
|
||||
return nil
|
||||
}
|
||||
if err := p.conn.Close(); err != nil {
|
||||
@@ -72,19 +75,21 @@ func (p *Gateway) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Gateway) run(msgChan chan<- *simulator.SimulatorMsg) {
|
||||
func (p *Gateway) run(msgChan chan<- *simulator.TelemetryMsg) {
|
||||
err := retry.Do(func() error {
|
||||
p.log.Info("connect to simulator")
|
||||
conn, err := connect(p.address)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to connect to simulator at %v", p.address)
|
||||
}
|
||||
p.conn = conn
|
||||
p.log.Info("connection success")
|
||||
return nil
|
||||
},
|
||||
retry.Delay(1*time.Second),
|
||||
)
|
||||
if err != nil {
|
||||
log.Panicf("unable to connect to simulator: %v", err)
|
||||
p.log.Panicf("unable to connect to simulator: %v", err)
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(p.conn)
|
||||
@@ -93,25 +98,25 @@ func (p *Gateway) run(msgChan chan<- *simulator.SimulatorMsg) {
|
||||
func() error { return p.listen(msgChan, reader) },
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("unable to connect to server: %v", err)
|
||||
p.log.Errorf("unable to connect to server: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Gateway) listen(msgChan chan<- *simulator.SimulatorMsg, reader *bufio.Reader) error {
|
||||
func (p *Gateway) listen(msgChan chan<- *simulator.TelemetryMsg, reader *bufio.Reader) error {
|
||||
for {
|
||||
rawLine, err := reader.ReadBytes('\n')
|
||||
if err == io.EOF {
|
||||
log.Info("Connection closed")
|
||||
p.log.Info("Connection closed")
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read response: %v", err)
|
||||
}
|
||||
|
||||
var msg simulator.SimulatorMsg
|
||||
var msg simulator.TelemetryMsg
|
||||
err = json.Unmarshal(rawLine, &msg)
|
||||
if err != nil {
|
||||
log.Errorf("unable to unmarshal simulator msg: %v", err)
|
||||
p.log.Errorf("unable to unmarshal simulator msg: %v", err)
|
||||
}
|
||||
if "telemetry" != msg.MsgType {
|
||||
continue
|
||||
@@ -120,7 +125,7 @@ func (p *Gateway) listen(msgChan chan<- *simulator.SimulatorMsg, reader *bufio.R
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Gateway) publishFrame(msgSim *simulator.SimulatorMsg) {
|
||||
func (p *Gateway) publishFrame(msgSim *simulator.TelemetryMsg) {
|
||||
now := time.Now()
|
||||
msg := &events.FrameMessage{
|
||||
Id: &events.FrameRef{
|
||||
@@ -136,9 +141,9 @@ func (p *Gateway) publishFrame(msgSim *simulator.SimulatorMsg) {
|
||||
|
||||
payload, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
log.Errorf("unable to marshal protobuf message: %v", err)
|
||||
p.log.Errorf("unable to marshal protobuf message: %v", err)
|
||||
}
|
||||
p.publisher.Publish(&payload)
|
||||
p.publisher.Publish(payload)
|
||||
}
|
||||
|
||||
var connect = func(address string) (io.ReadWriteCloser, error) {
|
||||
@@ -150,23 +155,23 @@ var connect = func(address string) (io.ReadWriteCloser, error) {
|
||||
}
|
||||
|
||||
type Publisher interface {
|
||||
Publish(payload *[]byte)
|
||||
Publish(payload []byte)
|
||||
}
|
||||
|
||||
func NewMqttPublisher(client mqtt.Client, topic string) Publisher {
|
||||
return &MqttPublisher{
|
||||
client: client,
|
||||
topic: topic,
|
||||
topic: topic,
|
||||
}
|
||||
}
|
||||
|
||||
type MqttPublisher struct {
|
||||
client mqtt.Client
|
||||
topic string
|
||||
topic string
|
||||
}
|
||||
|
||||
func (m *MqttPublisher) Publish(payload *[]byte) {
|
||||
token := m.client.Publish(m.topic, 0, false, *payload)
|
||||
func (m *MqttPublisher) Publish(payload []byte) {
|
||||
token := m.client.Publish(m.topic, 0, false, payload)
|
||||
token.WaitTimeout(10 * time.Millisecond)
|
||||
if err := token.Error(); err != nil {
|
||||
log.Errorf("unable to publish frame: %v", err)
|
||||
|
||||
+68
-50
@@ -12,44 +12,44 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MockPublisher struct {
|
||||
muPubEvents sync.Mutex
|
||||
publishedEvents []*[]byte
|
||||
notifyChan chan []byte
|
||||
initNotifyChan sync.Once
|
||||
}
|
||||
|
||||
func (p *MockPublisher) Publish(payload *[]byte) {
|
||||
p.muPubEvents.Lock()
|
||||
defer p.muPubEvents.Unlock()
|
||||
p.publishedEvents = append(p.publishedEvents, payload)
|
||||
func (p *MockPublisher) Close() error {
|
||||
if p.notifyChan != nil {
|
||||
close(p.notifyChan)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *MockPublisher) Events() []*[]byte {
|
||||
p.muPubEvents.Lock()
|
||||
defer p.muPubEvents.Unlock()
|
||||
eventsMsg := make([]*[]byte, len(p.publishedEvents), len(p.publishedEvents))
|
||||
copy(eventsMsg, p.publishedEvents)
|
||||
return eventsMsg
|
||||
func (p *MockPublisher) Publish(payload []byte) {
|
||||
p.notifyChan <- payload
|
||||
}
|
||||
|
||||
func (p *MockPublisher) Notify() <-chan []byte {
|
||||
p.initNotifyChan.Do(func() { p.notifyChan = make(chan []byte) })
|
||||
return p.notifyChan
|
||||
}
|
||||
|
||||
func TestPart_ListenEvents(t *testing.T) {
|
||||
connMock := ConnMock{}
|
||||
err := connMock.Listen()
|
||||
simulatorMock := SimulatorMock{}
|
||||
err := simulatorMock.Start()
|
||||
if err != nil {
|
||||
t.Errorf("unable to start mock server: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := connMock.Close(); err != nil {
|
||||
if err := simulatorMock.Close(); err != nil {
|
||||
t.Errorf("unable to close mock server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
publisher := MockPublisher{}
|
||||
|
||||
publisher := MockPublisher{publishedEvents: make([]*[]byte, 0)}
|
||||
|
||||
part := New(&publisher, connMock.Addr())
|
||||
part := New(&publisher, simulatorMock.Addr())
|
||||
go func() {
|
||||
err := part.Start()
|
||||
if err != nil {
|
||||
@@ -62,25 +62,20 @@ func TestPart_ListenEvents(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
simulatorMock.WaitConnection()
|
||||
log.Trace("read test data")
|
||||
testContent, err := ioutil.ReadFile("testdata/msg.json")
|
||||
lines := strings.Split(string(testContent), "\n")
|
||||
|
||||
for idx, line := range lines {
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
err = connMock.WriteMsg(line)
|
||||
err = simulatorMock.EmitMsg(line)
|
||||
if err != nil {
|
||||
t.Errorf("[line %v/%v] unable to write line: %v", idx+1, len(lines), err)
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
expectedFrames := 16
|
||||
if len(publisher.Events()) != expectedFrames {
|
||||
t.Errorf("invalid number of frame emmitted: %v, wants %v", len(publisher.Events()), expectedFrames)
|
||||
}
|
||||
for _, byteMsg := range publisher.Events() {
|
||||
byteMsg := <-publisher.Notify()
|
||||
var msg events.FrameMessage
|
||||
err = proto.Unmarshal(*byteMsg, &msg)
|
||||
err = proto.Unmarshal(byteMsg, &msg)
|
||||
if err != nil {
|
||||
t.Errorf("unable to unmarshal frame msg: %v", err)
|
||||
continue
|
||||
@@ -94,57 +89,80 @@ func TestPart_ListenEvents(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type ConnMock struct {
|
||||
ln net.Listener
|
||||
conn net.Conn
|
||||
muWriter sync.Mutex
|
||||
writer *bufio.Writer
|
||||
type SimulatorMock struct {
|
||||
ln net.Listener
|
||||
muConn sync.Mutex
|
||||
conn net.Conn
|
||||
writer *bufio.Writer
|
||||
newConnection chan net.Conn
|
||||
logger *log.Entry
|
||||
}
|
||||
|
||||
func (c *ConnMock) WriteMsg(p string) (err error) {
|
||||
c.muWriter.Lock()
|
||||
defer c.muWriter.Unlock()
|
||||
func (c *SimulatorMock) EmitMsg(p string) (err error) {
|
||||
c.muConn.Lock()
|
||||
defer c.muConn.Unlock()
|
||||
_, err = c.writer.WriteString(p + "\n")
|
||||
if err != nil {
|
||||
log.Errorf("unable to write response: %v", err)
|
||||
c.logger.Errorf("unable to write response: %v", err)
|
||||
}
|
||||
if err == io.EOF {
|
||||
log.Info("Connection closed")
|
||||
c.logger.Info("Connection closed")
|
||||
return err
|
||||
}
|
||||
err = c.writer.Flush()
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *ConnMock) Listen() error {
|
||||
c.muWriter.Lock()
|
||||
defer c.muWriter.Unlock()
|
||||
func (c *SimulatorMock) WaitConnection() {
|
||||
c.muConn.Lock()
|
||||
defer c.muConn.Unlock()
|
||||
c.logger.Debug("simulator waiting connection")
|
||||
if c.conn != nil {
|
||||
return
|
||||
}
|
||||
c.logger.Debug("new connection")
|
||||
conn := <-c.newConnection
|
||||
|
||||
c.conn = conn
|
||||
c.writer = bufio.NewWriter(conn)
|
||||
}
|
||||
|
||||
func (c *SimulatorMock) Start() error {
|
||||
c.logger = log.WithField("simulator", "mock")
|
||||
c.newConnection = make(chan net.Conn)
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:")
|
||||
c.ln = ln
|
||||
if err != nil {
|
||||
|
||||
return fmt.Errorf("unable to listen on port: %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
c.conn, err = c.ln.Accept()
|
||||
conn, err := c.ln.Accept()
|
||||
if err != nil && err == io.EOF {
|
||||
log.Infof("connection close: %v", err)
|
||||
c.logger.Errorf("connection close: %v", err)
|
||||
break
|
||||
}
|
||||
c.writer = bufio.NewWriter(c.conn)
|
||||
if c.newConnection == nil {
|
||||
break
|
||||
}
|
||||
c.newConnection <- conn
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConnMock) Addr() string {
|
||||
func (c *SimulatorMock) Addr() string {
|
||||
return c.ln.Addr().String()
|
||||
}
|
||||
|
||||
func (c *ConnMock) Close() error {
|
||||
log.Infof("close mock server")
|
||||
func (c *SimulatorMock) Close() error {
|
||||
c.logger.Debug("close mock server")
|
||||
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
close(c.newConnection)
|
||||
c.newConnection = nil
|
||||
err := c.ln.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to close mock server: %v", err)
|
||||
|
||||
Vendored
+1
-3
@@ -1,4 +1,3 @@
|
||||
{"msg_type":"car_loaded"}
|
||||
{"msg_type":"telemetry","steering_angle":0,"throttle":0,"speed":0.2596469,"image":"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 truncated
|
||||
{"msg_type":"telemetry","steering_angle":0,"throttle":0,"speed":0.1318146,"image":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAB4AKADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDyMu27L8v0EqcMPr61cAaWJhIMhhjcowfyqlIuxxuIdTyHXjIrRt128evPX8P8PzqWXHUy57SWFcsC8PXI4IFRRytCMg7kPbNakx8p1KZjwCqg9Dj1HpVaWJZDvGIpTnnOVf8AHt34qk+5LXY37Pxdrlv4Zm8PR3KtpNwCTBNGkgXJydpYErzyMdDyMHmoL7xBq17o1jpV5eLNZ2Jxbeail4h0wHxuxjA25x8o9BjGuEkWKN3ADDgqR1q3pM+nvfwf2lHcSWW7FwlsyrJt9ULAjI64PXGMjqEGxHymWDdvTPNKoAUdSeo7Z/Ot7WLTw1bPqEOl399eMsqtZXPlgRyREfMkisFZXU/xDIbH3V61Q0bVrvQtZtNUsz+/tpBIg5Acd1POcEZB9QaQEK6ZezafJqSWF29nG2x7gRMY42OOGbGAeV79xVUsz7S3O7vnJHH/ANavRtY+J8Wq+GtX0OTRGhtr+czwlb0ZgZmWQjlPnBlDOenDlRjArzraTjJGQx709A1FAwQPmIzntgUNISQxdmGNoyCenavRX+Ifh2XVbe8XwBpYhhglia3Bj2uzNGQx/dYyoRh0P3zyO/nskjzTvNIFDMxdhHGEUE88KoAA5PAHHtQA2OaWzmhngmaKaKRXR1baQwOQQexB5z7Vuaf4z8TaXc/bLPV5/tG2RFaQiVQsjh3IVwQCzAMSOTitbQdZ8J2tvYW+p6ZKwt3+0XNwtsjyXJyreUd7EBCwVeADtiP/AD3YI/wf4Iu/iDrtzdvAlhpfnF7mSBAqJk7vJiBzzz9FGCf4QQB/w38IN448R3E2qtM9jB+/vHL5eeRjwhOdw3YYlhnoRkEgj0Pxx8Urbw6ZvD3hqCJrq3iMLXEYHlWbDACKgGGZRnjgKcA55UeT6B4u1HQbDWLTSI0tJNVMf7yJ2H2dF35WPJJH3wNxJIA9SCMZI0hVdjBpV6heij0ouO2pDPJJK7z3UrO8jl3eVizOxOSzHuSaaJpZlMajZGTjC/eYen0pbgKzIC2AOw71PDBJKNsYManq3c/4UgY1Io4Qu8ZzyEXqamWKaZCD+7jH8K9fxNXYrSG3UvIPqzHn/PWo2vNxH2eIyDru6Aen6mi4jIhVrhWR8N3wRz9c1YiRfLBVgSvB/wA/UCtDT71I1+zz20U0RbBBXBPpz2pb1bTzj9iiVEbIwrhhnt3Pem7WCL1My5RipKgMSQQD2GMVSZSgJzs7MD71sLF5kJbjCkKc+/Sq0mn3BMi+UZMDnaM8UkORB5IaDaV3ADgE5zn0J6VBDDskZlORj+L7wH8iPer6oUiCsCuFGc9eP/1VXjj/AHm1gMqc8dM5x/WgfYbp1xbG5DX0U00K/eSCYRMw7YYqwHOP4fbitzWIob+LT7nTfDU+mrJBIS6SSTRXBj/1jx7xlQuG3DcwAA6YJOCYd25AoLEAkng/j/kfjT4pNm1Sx4xyOuTj/wCtTuTY7XwT4v1zRYjY6RFpBaN5LjzL1kjYqyqrJvd1G3Ko2AQcoOcAiua12xj0vWbu0S4sZVRgQ9hK0sHzAEBGbkgA45OeOpqJ3iTUDOsVuYjLv+zDfs25B2Zzu244znOO+eav6uLaRbbypt7RR7Nq20UI8vIMZJjc73Kn5t3zKcgliMhXCxt69qV8lndzS6H4Ttku0S03WC28zRFd7FkVZH2MwYgtjoFxggGsbwtBfW2r2mpw+HW1eATmPyHt2kimbYSU+6QWCbmHXBAbBAxUeu29gkkctndSXDXG+aQyW0UIQFsABY5HC8q3y4XAwcEEYg07TRdyu0twIrOMI93PsDCCMyKm4rwWwXXgcnNMDpdF0bS/HXixEtok0PT7a0NzfsbkOXVW+eQfKqITuUYChFAJA421VtvFmoReB18M2TiCCV3e9n8sIzhsDysrywwMknkg7eFX5s/U76znNkml2j2duthFbXIDnN1IG3uzgc4L9Mk4CL04Az44cAsoXHzfMe3t+n8qBkCgrIQrhcgAtnBzjpUsceAcDoe461Yt4wWcrEXbOckYH+eKJlkXJfAIIBC9DxmlcFuQosXml3wWHAUdTV9PtEmBEgiXP3m5P5VXtpYYcPgu/wDFtGatrdTSYEUIGeAWPP5UAxY9NQbXm3Snjl2z/nvRdukcDIpG8gcA81E8V04BmnZBnkRjHHP/ANeqxhSOYKp6gEk8nP8Ak0gW5no3lOVjJKnt128/WpXZBL8hKdOOetXF0C8lYyJERk/3gDU58Oak2CIHYgf3h/jTc4dxWdwtMFp4sOTLEQoUdTwwH6Val3kJLFGqyMgZto29u2KE0bU4nhk+ySZHB24JFX7bRr5Yhi1ZdrMAHYZIPQn8/wBKzdSPcvluYcyShlacEFzncTnINRNCp2sqbQcgOVxn61uTeHtSmHy2qJ06yCpbfw3qro0bW6sC2V/eDjmj2sO4uV22OXFuvmMRKATg4Yf54/wqU2ajTRNuG9JCre44xj6fTv7Vuy+EtRBy0OX27cB++MZ/lUEvhXW/JNqturxudwcSLhTyDnnP6Ue1h3HyuxhWyh7mOFvukZ+nFaH9nAD/AFjEdvlz/KtGHwZqsdwk7mH5ewkxWg3h3UTGD5ILKeArA9/U49TUurDuCi7nPfY1iLN53QZ4HI/+t1puq366lbWkEdqtpBZwhFiRyQ0nG+VierMSPooVf4c10Nz4evhA4SMOxGNu4D+ZqnN4R1WXzDBDAA3GPNyQOMe56U1Wh3FyswUVfL8xTztZl7+9SIybBkc4/i4xmtX/AIRXV1wJFj4GCPMJ9fb3qM+FtU2AFIunJ80nt9KftYdx8rKsAAt0BlVFI7cGq0+xQWB3cnPrjtWkNK1ONBENN4TIDhgQeetNfw/qBUYEYwehzyPyp+0h3BRZQXULZIsAElSOdv8AOplv3baUhdhgnHTNTHRLxEOIrdiOcbzzx05GKWO01OJflsUyf+mgOPbrTVSHcXLLsNUXUjn5Yk2g7mYkkVRmeTZv3kOWAJA/z71fNpqjKVa1ABBB+daiOm333Psxxj724c/rS549xqLPSBKnr+lSKrv9xHP0WnC7K/6tY1P+ygFNe6mkGHkdh7kmvMsbXJRbygZYbR/tsBTwkY+9KMf7Ck/zxVPeaXzDRYLlwPCp+47f7zY/l/jTvtLKcxokf+6Of1qj5h9aAWY4UEn2osBYeYs2Wwx96VXGRuAA9qQWkmzdJIiD0JqBmCN8jZx3qbp7AW5pgMKMEdj3quZsVC8zOcsc0wyAVUY2QXLYunxyfwPNH2mL+JCD/eQ4NU9xI6005I+9mq5RXNRZo5HA85Zc8BZxtP4H/wCvTp7GNcZLwOegkHyn6MKyOcc1Ygv7m3XakmUPVGG5fyNFgJZra5hXLKSnZlO5fzquGbOePyq/BqUAbLI9u/8Aei5U/VaumCC+j3hYpR/z0hOD+IpWQcxhlmIwT+tMKoR83B/3Aa0ZdGck+RIGP9xuGrPmtp4DiSNl+op2Hci8pCcbEPuRj+VBtFb/AJZr/wABYf8A16MkUde9FmFyfPvRu9zUZbA4GadGskvAX8qNtxCg+oo3elWotPA5kbcfSnSvDbjHAqHUV7IdikW9qlW9aEbY49p7k8moXuQxygx71EXY/WqtfdCJXneVsuSTTd5NQ/MeppwFUkkK5JnNIT6imfjS5zTAdu4pN3pSGmk+lAClyKA+SM5/CmZYnnpS07ASE++aVHdH3xuyP/eU4NRBu1ODcc0rAa9vq7FVS8QSgfxgYYf59q0YZkuVP2edJV7xyckf1rmNxpQ+GDDIYdCODSsKxvzWNtIcPE0Deo6GqU2jzICYysg9uDS22sSIAk37xfU9a0be7gmOEcIfQ0XYtUZUNmB80hz7CrOUQYUYFZct87t8vA9BSGeRhgniseSUtWa3SLc95gbY+tZ7qztuZiTTs4qNmJ6VrGCWxLYoAWl3gVEFPrS4FXYQ/eOuKcG9qaoBp3SiyAbRmgmkHWgBaKWkJxQIQnFRlyT0xTzzSYphcYScUqN70YzQFxSAeCe1Lz6U0U4GgYZNOyaM0wk54NADQeaeCaQLThQIXmkxS4NJQMMUbAetFGcUCHcCgmm7Line truncated
|
||||
{"msg_type":"telemetry","steering_angle":0,"throttle":0,"speed":0.1463221,"image":"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 truncated
|
||||
@@ -14,5 +13,4 @@
|
||||
{"msg_type":"telemetry","steering_angle":0,"throttle":0,"speed":0.01692938,"image":"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 truncated
|
||||
{"msg_type":"telemetry","steering_angle":0,"throttle":0,"speed":0.01101699,"image":"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 truncated
|
||||
{"msg_type":"telemetry","steering_angle":0,"throttle":0,"speed":0.01104343,"image":"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 truncated
|
||||
{}
|
||||
{"msg_type":"telemetry","steering_angle":0,"throttle":0,"speed":0.006377342,"image":"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 truncated
|
||||
{"msg_type":"telemetry","steering_angle":0,"throttle":0,"speed":0.006377342,"image":"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 truncated
|
||||
@@ -0,0 +1,123 @@
|
||||
package controls
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cyrilix/robocar-protobuf/go/events"
|
||||
"github.com/cyrilix/robocar-simulator/simulator"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type SteeringController interface {
|
||||
WriteSteering(message *events.SteeringMessage)
|
||||
}
|
||||
|
||||
type ThrottleController interface {
|
||||
WriteThrottle(message *events.ThrottleMessage)
|
||||
}
|
||||
|
||||
func New(address string) (*Gateway, error) {
|
||||
conn, err := net.Dial("tcp", address)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to connect to %v", address)
|
||||
}
|
||||
return &Gateway{
|
||||
conn: conn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
/* Simulator interface to publish command controls from mqtt topic */
|
||||
type Gateway struct {
|
||||
cancel chan interface{}
|
||||
|
||||
muControl sync.Mutex
|
||||
lastControl *simulator.ControlMsg
|
||||
conn io.WriteCloser
|
||||
}
|
||||
|
||||
func (g *Gateway) Start() {
|
||||
log.Info("connect to simulator")
|
||||
g.cancel = make(chan interface{})
|
||||
}
|
||||
|
||||
func (g *Gateway) Stop() {
|
||||
log.Info("close simulator gateway")
|
||||
close(g.cancel)
|
||||
|
||||
if err := g.Close(); err != nil {
|
||||
log.Printf("unexpected error while simulator connection is closed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Gateway) Close() error {
|
||||
if g.conn == nil {
|
||||
log.Warnln("no connection to close")
|
||||
return nil
|
||||
}
|
||||
if err := g.conn.Close(); err != nil {
|
||||
return fmt.Errorf("unable to close connection to simulator: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Gateway) WriteSteering(message *events.SteeringMessage) {
|
||||
g.muControl.Lock()
|
||||
defer g.muControl.Unlock()
|
||||
g.initLastControlMsg()
|
||||
|
||||
g.lastControl.Steering = message.Steering
|
||||
g.writeContent()
|
||||
}
|
||||
|
||||
func (g *Gateway) WriteThrottle(message *events.ThrottleMessage) {
|
||||
g.muControl.Lock()
|
||||
defer g.muControl.Unlock()
|
||||
g.initLastControlMsg()
|
||||
|
||||
if message.Throttle > 0 {
|
||||
g.lastControl.Throttle = message.Throttle
|
||||
g.lastControl.Brake = 0.
|
||||
} else {
|
||||
g.lastControl.Throttle = 0.
|
||||
g.lastControl.Brake = -1 * message.Throttle
|
||||
}
|
||||
|
||||
g.writeContent()
|
||||
}
|
||||
|
||||
func (g *Gateway) writeContent() {
|
||||
w := bufio.NewWriter(g.conn)
|
||||
content, err := json.Marshal(g.lastControl)
|
||||
if err != nil {
|
||||
log.Errorf("unable to marshall control msg \"%#v\": %v", g.lastControl, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = w.Write(append(content, '\n'))
|
||||
if err != nil {
|
||||
log.Errorf("unable to write control msg \"%#v\" to simulator: %v", g.lastControl, err)
|
||||
return
|
||||
}
|
||||
err = w.Flush()
|
||||
if err != nil {
|
||||
log.Errorf("unable to flush control msg \"%#v\" to simulator: %v", g.lastControl, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Gateway) initLastControlMsg() {
|
||||
if g.lastControl != nil {
|
||||
return
|
||||
}
|
||||
g.lastControl = &simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.,
|
||||
Throttle: 0.,
|
||||
Brake: 0.,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
package controls
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cyrilix/robocar-protobuf/go/events"
|
||||
"github.com/cyrilix/robocar-simulator/simulator"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGateway_WriteSteering(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
msg *events.SteeringMessage
|
||||
previousMsg *simulator.ControlMsg
|
||||
expectedMsg simulator.ControlMsg
|
||||
}{
|
||||
{"First Message",
|
||||
&events.SteeringMessage{Steering: 0.5, Confidence: 1},
|
||||
nil,
|
||||
simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.5,
|
||||
Throttle: 0,
|
||||
Brake: 0,
|
||||
}},
|
||||
{"Update steering",
|
||||
&events.SteeringMessage{Steering: -0.5, Confidence: 1},
|
||||
&simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0,
|
||||
Brake: 0,
|
||||
},
|
||||
simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: -0.5,
|
||||
Throttle: 0,
|
||||
Brake: 0,
|
||||
}},
|
||||
{"Update steering shouldn't erase throttle value",
|
||||
&events.SteeringMessage{Steering: -0.3, Confidence: 1},
|
||||
&simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0.6,
|
||||
Brake: 0.1,
|
||||
},
|
||||
simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: -0.3,
|
||||
Throttle: 0.6,
|
||||
Brake: 0.1,
|
||||
}},
|
||||
}
|
||||
|
||||
simulatorMock := ConnMock{}
|
||||
err := simulatorMock.listen()
|
||||
if err != nil {
|
||||
t.Errorf("unable to start mock server: %v", err)
|
||||
}
|
||||
defer func(){
|
||||
if err := simulatorMock.Close(); err != nil {
|
||||
t.Errorf("unable to stop simulator mock: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
server, err := New(simulatorMock.Addr())
|
||||
if err != nil {
|
||||
t.Fatalf("unable to init simulator gateway: %v", err)
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
server.lastControl = c.previousMsg
|
||||
|
||||
server.WriteSteering(c.msg)
|
||||
|
||||
ctrlMsg := <- simulatorMock.Notify()
|
||||
if *ctrlMsg != c.expectedMsg {
|
||||
t.Errorf("[%v] bad messge received: %#v, wants %#v", c.name, ctrlMsg, c.expectedMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGateway_WriteThrottle(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
msg *events.ThrottleMessage
|
||||
previousMsg *simulator.ControlMsg
|
||||
expectedMsg simulator.ControlMsg
|
||||
}{
|
||||
{"First Message",
|
||||
&events.ThrottleMessage{Throttle: 0.5, Confidence: 1},
|
||||
nil,
|
||||
simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0,
|
||||
Throttle: 0.5,
|
||||
Brake: 0,
|
||||
}},
|
||||
{"Update Throttle",
|
||||
&events.ThrottleMessage{Throttle: 0.6, Confidence: 1},
|
||||
&simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0,
|
||||
Throttle: 0.4,
|
||||
Brake: 0,
|
||||
},
|
||||
simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0,
|
||||
Throttle: 0.6,
|
||||
Brake: 0,
|
||||
}},
|
||||
{"Update steering shouldn't erase throttle value",
|
||||
&events.ThrottleMessage{Throttle: 0.3, Confidence: 1},
|
||||
&simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0.6,
|
||||
Brake: 0.,
|
||||
},
|
||||
simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0.3,
|
||||
Brake: 0.,
|
||||
}},
|
||||
{"Throttle to brake",
|
||||
&events.ThrottleMessage{Throttle: -0.7, Confidence: 1},
|
||||
&simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0.6,
|
||||
Brake: 0.,
|
||||
},
|
||||
simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0.,
|
||||
Brake: 0.7,
|
||||
}},
|
||||
{"Update brake",
|
||||
&events.ThrottleMessage{Throttle: -0.2, Confidence: 1},
|
||||
&simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0.,
|
||||
Brake: 0.5,
|
||||
},
|
||||
simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0.,
|
||||
Brake: 0.2,
|
||||
}},
|
||||
{"Brake to throttle",
|
||||
&events.ThrottleMessage{Throttle: 0.9, Confidence: 1},
|
||||
&simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0.,
|
||||
Brake: 0.4,
|
||||
},
|
||||
simulator.ControlMsg{
|
||||
MsgType: "control",
|
||||
Steering: 0.2,
|
||||
Throttle: 0.9,
|
||||
Brake: 0.,
|
||||
}},
|
||||
}
|
||||
|
||||
simulatorMock := ConnMock{}
|
||||
err := simulatorMock.listen()
|
||||
if err != nil {
|
||||
t.Errorf("unable to start mock server: %v", err)
|
||||
}
|
||||
defer func(){
|
||||
if err := simulatorMock.Close(); err != nil {
|
||||
t.Errorf("unable to stop simulator mock: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
server, err := New(simulatorMock.Addr())
|
||||
if err != nil {
|
||||
t.Fatalf("unable to init simulator gateway: %v", err)
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
server.lastControl = c.previousMsg
|
||||
|
||||
server.WriteThrottle(c.msg)
|
||||
|
||||
ctrlMsg := <- simulatorMock.Notify()
|
||||
if *ctrlMsg != c.expectedMsg {
|
||||
t.Errorf("[%v] bad messge received: %#v, wants %#v", c.name, ctrlMsg, c.expectedMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ConnMock struct {
|
||||
initMsgsOnce sync.Once
|
||||
|
||||
ln net.Listener
|
||||
notifyChan chan *simulator.ControlMsg
|
||||
initNotifyChan sync.Once
|
||||
}
|
||||
|
||||
func (c *ConnMock) Notify() <-chan *simulator.ControlMsg {
|
||||
c.initNotifyChan.Do(func() { c.notifyChan = make(chan *simulator.ControlMsg) })
|
||||
return c.notifyChan
|
||||
}
|
||||
|
||||
func (c *ConnMock) listen() error {
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:")
|
||||
c.ln = ln
|
||||
if err != nil {
|
||||
|
||||
return fmt.Errorf("unable to listen on port: %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
conn, err := c.ln.Accept()
|
||||
if err != nil {
|
||||
log.Infof("connection close: %v", err)
|
||||
break
|
||||
}
|
||||
go c.handleConnection(conn)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConnMock) Addr() string {
|
||||
return c.ln.Addr().String()
|
||||
}
|
||||
|
||||
func (c *ConnMock) handleConnection(conn net.Conn) {
|
||||
c.initNotifyChan.Do(func() { c.notifyChan = make(chan *simulator.ControlMsg) })
|
||||
reader := bufio.NewReader(conn)
|
||||
for {
|
||||
rawCmd, err := reader.ReadBytes('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
log.Info("connection closed")
|
||||
break
|
||||
}
|
||||
log.Errorf("unable to read request: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
var msg simulator.ControlMsg
|
||||
err = json.Unmarshal(rawCmd, &msg)
|
||||
if err != nil {
|
||||
log.Errorf("unable to unmarchal control msg \"%v\": %v", string(rawCmd), err)
|
||||
continue
|
||||
}
|
||||
|
||||
c.notifyChan <- &msg
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnMock) Close() error {
|
||||
log.Infof("close mock server")
|
||||
err := c.ln.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to close mock server: %v", err)
|
||||
}
|
||||
if c.notifyChan != nil {
|
||||
close(c.notifyChan)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package simulator
|
||||
|
||||
type SimulatorMsg struct {
|
||||
type TelemetryMsg struct {
|
||||
MsgType string `json:"msg_type"`
|
||||
SteeringAngle float64 `json:"steering_angle"`
|
||||
Throttle float64 `json:"throttle"`
|
||||
@@ -13,3 +13,11 @@ type SimulatorMsg struct {
|
||||
Time float64 `json:"time"`
|
||||
Cte float64 `json:"cte"`
|
||||
}
|
||||
|
||||
/* Json msg used to control cars. MsgType must be filled with "control" */
|
||||
type ControlMsg struct {
|
||||
MsgType string `json:"msg_type"`
|
||||
Steering float32 `json:"steering"`
|
||||
Throttle float32 `json:"throttle"`
|
||||
Brake float32 `json:"brake"`
|
||||
}
|
||||
Reference in new issue
Block a user