diff --git a/cmd/average_position/main.go b/cmd/average_position/main.go new file mode 100644 index 0000000..19e504b --- /dev/null +++ b/cmd/average_position/main.go @@ -0,0 +1,149 @@ +package main + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "log/slog" + "os" + + reach "forge.cadoles.com/cadoles/go-emlid/reach/client" + "forge.cadoles.com/cadoles/go-emlid/reach/client/logger" + "forge.cadoles.com/cadoles/go-emlid/reach/client/protocol" + "forge.cadoles.com/cadoles/go-emlid/reach/client/protocol/v2/model" + "github.com/mitchellh/mapstructure" + "github.com/pkg/errors" +) + +var ( + host string = "192.168.42.1" + rawLogLevel string = "ERROR" +) + +func init() { + flag.StringVar(&rawLogLevel, "log-level", rawLogLevel, "log level") + flag.StringVar(&host, "host", host, "the reachrs module host") +} + +type Coordinates struct { + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + Height float64 `json:"height"` +} + +type Payload struct { + Coordinates Coordinates `json:"coordinates"` + AntennaOffset float64 `json:"antenna_offset"` +} + +func main() { + flag.Parse() + + ctx := context.Background() + client := reach.NewClient(host) + + logLevel, err := logger.ParseLevel(rawLogLevel) + if err != nil { + fmt.Printf("[FATAL] %+v", errors.WithStack(err)) + os.Exit(1) + } + + slog.SetLogLoggerLevel(logLevel) + + if err := client.Connect(ctx); err != nil { + fmt.Printf("[FATAL] %+v", errors.WithStack(err)) + os.Exit(1) + } + + defer func() { + if err := client.Close(ctx); err != nil { + fmt.Printf("[FATAL] %+v", errors.WithStack(err)) + os.Exit(1) + } + }() + + // récupération de la configurationa actuelle de la base + config, err := retrieveAndProcessConfig(ctx, client) + if err != nil { + fmt.Printf("[FATAL] %+v", errors.WithStack(err)) + os.Exit(1) + } + latitude := config.BaseMode.BaseCoordinates.Coordinates.Latitude + longitude := config.BaseMode.BaseCoordinates.Coordinates.Longitude + height := config.BaseMode.BaseCoordinates.Coordinates.Height + antennaOffset := config.BaseMode.BaseCoordinates.AntennaOffset + fmt.Printf("setting base (latitude: %v, longitude: %v, height: %v, antennaOffset: %v", latitude, longitude, height, antennaOffset) + + opts := []protocol.SetBaseOptionFunc{ + protocol.WithBaseLatitude(latitude), + protocol.WithBaseLongitude(longitude), + protocol.WithBaseHeight(height), + protocol.WithBaseAntennaOffset(antennaOffset), + protocol.WithBaseMode("single-and-hold"), + } + // Passage de la base en "single-and-hold" permettant la collecte des données + if err := client.SetBase(ctx, opts...); err != nil { + fmt.Printf("[FATAL] %+v", errors.WithStack(err)) + return + } + + client.AveragePosition(ctx) + broadcasts, err := reach.OnMessageType(ctx, client, "task_status") + if err != nil { + fmt.Printf("[FATAL] %+v", errors.WithStack(err)) + os.Exit(1) + } + + for b := range broadcasts { + + data, err := json.MarshalIndent(b, "", " ") + if err != nil { + fmt.Printf("[ERROR] %+v", errors.WithStack(err)) + continue + } + fmt.Println(string(data)) + var payload Payload + err = mapstructure.Decode(b.Payload, &payload) + if err != nil { + fmt.Printf("Erreur de désérialisation : %v\n", err) + continue + } + + // la collecte est terminée, enregistrement du résultat en configuration + if b.State == "completed" { + fmt.Printf("lat: %g, long: %g, altitude:%g", payload.Coordinates.Latitude, payload.Coordinates.Longitude, payload.Coordinates.Height) + + opts := []protocol.SetBaseOptionFunc{ + protocol.WithBaseLatitude(payload.Coordinates.Latitude), + protocol.WithBaseLongitude(payload.Coordinates.Longitude), + protocol.WithBaseHeight(payload.Coordinates.Height), + protocol.WithBaseAntennaOffset(payload.AntennaOffset), + protocol.WithBaseMode("manual"), + } + // enregistrement du résultat en configuration + if err := client.SetBase(ctx, opts...); err != nil { + fmt.Printf("[FATAL] %+v", errors.WithStack(err)) + return + } + } + + } +} + +func retrieveAndProcessConfig(ctx context.Context, client *reach.Client) (*model.Configuration, error) { + + configData, err := client.Configuration(ctx) + if err != nil { + fmt.Printf("[ERROR] %+v", errors.WithStack(err)) + + } + var config model.Configuration + err = mapstructure.Decode(configData, &config) + if err != nil { + fmt.Printf("[ERROR] %+v", errors.WithStack(err)) + + } + return &config, nil + +} diff --git a/reach/client/helper.go b/reach/client/helper.go index 2e37c29..4c8ab12 100644 --- a/reach/client/helper.go +++ b/reach/client/helper.go @@ -41,6 +41,7 @@ func OnMessage[T any](ctx context.Context, client *Client, mType string) (chan T type Broadcast struct { Name string `mapstructure:"name" json:"name"` Payload any `mapstructure:"payload" json:"payload"` + State string `mapstructure:"state" json:"state"` } // OnBroadcast listens for ReachView "broadcast" messages @@ -52,3 +53,13 @@ func OnBroadcast(ctx context.Context, client *Client) (chan Broadcast, error) { return ch, nil } + +// OnMessageType listens for ReachView type of messages +func OnMessageType(ctx context.Context, client *Client, messageType string) (chan Broadcast, error) { + ch, err := OnMessage[Broadcast](ctx, client, messageType) + if err != nil { + return nil, errors.WithStack(err) + } + + return ch, nil +} diff --git a/reach/client/operations.go b/reach/client/operations.go index d446bd8..313415c 100644 --- a/reach/client/operations.go +++ b/reach/client/operations.go @@ -152,4 +152,18 @@ func (c *Client) Reboot(ctx context.Context) error { return nil } +// AveragePosition implements protocol.Operations. +func (c *Client) AveragePosition(ctx context.Context) error { + _, ops, err := c.getProtocol(ctx) + if err != nil { + return errors.WithStack(err) + } + + if err := ops.AveragePosition(ctx); err != nil { + return errors.WithStack(err) + } + + return nil +} + var _ protocol.Operations = &Client{} diff --git a/reach/client/protocol/operations.go b/reach/client/protocol/operations.go index 72a5bae..29a3f7e 100644 --- a/reach/client/protocol/operations.go +++ b/reach/client/protocol/operations.go @@ -41,4 +41,6 @@ type Operations interface { // Reboot restarts the module Reboot(ctx context.Context) error + + AveragePosition(ctx context.Context) error } diff --git a/reach/client/protocol/v1/operations.go b/reach/client/protocol/v1/operations.go index 6c1ea16..3a910c0 100644 --- a/reach/client/protocol/v1/operations.go +++ b/reach/client/protocol/v1/operations.go @@ -363,4 +363,19 @@ func (o *Operations) Version(ctx context.Context) (string, bool, error) { return strings.TrimSpace(res.Version), res.Stable, nil } +func (o *Operations) AveragePosition(ctx context.Context) error { + var err error + + go func() { + <-ctx.Done() + err = ctx.Err() + }() + + if err = o.client.Emit("task", map[string]string{"name": "average_base_coordinates"}); err != nil { + return err + } + + return err +} + var _ protocol.Operations = &Operations{} diff --git a/reach/client/protocol/v2/operations.go b/reach/client/protocol/v2/operations.go index 7a8afb1..06e58f3 100644 --- a/reach/client/protocol/v2/operations.go +++ b/reach/client/protocol/v2/operations.go @@ -264,4 +264,19 @@ func (o *Operations) On(ctx context.Context, event string) (chan any, error) { return out, nil } +func (o *Operations) AveragePosition(ctx context.Context) error { + var err error + + go func() { + <-ctx.Done() + err = ctx.Err() + }() + + if err = o.client.Emit("task", &model.Action{Name: "average_base_coordinates"}); err != nil { + return err + } + + return err +} + var _ protocol.Operations = &Operations{}