Skip to content

Commit 84f5d13

Browse files
committed
auto register data structs with SimConnect#RegisterDataDefinition
1 parent 6c03cca commit 84f5d13

File tree

7 files changed

+185
-55
lines changed

7 files changed

+185
-55
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.env
22
build-vfrmap-upload.sh
33
vfrmap.exe
4+
vfrmap-win64.zip
45
request_data.exe
56
_vendor

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# msfs2020-go
2+
3+
simconnect package [msfs2020-go/simconnect](simconnect/) connects to microsoft flight simulator 2020 using golang.
4+
5+
cross-compiles from macos/linux, no other dependencies required. produces a single binary with no other files or configuration required.
6+
7+
## status
8+
9+
[msfs2020-go/simconnect](simconnect/) package currently only implements enough of the simconnect api for [examples](examples/) and [vfrmap](vfrmap).
10+
11+
## download
12+
13+
program zips are uploaded [here](https://github.com/lian/msfs2020-go/releases)
14+
15+
## tools
16+
17+
* [vfrmap](vfrmap/) web server that shows your current MSFS2020 plane position in google maps inside the browser
18+
19+
## examples
20+
21+
* [examples/request_data](examples/request_data/) port of `MSFS-SDK/Samples/SimConnectSamples/RequestData/RequestData.cpp`
22+

examples/request_data/main.go

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@ import (
1212

1313
type Report struct {
1414
simconnect.RecvSimobjectDataByType
15-
Title [256]byte
16-
Kohlsman float64
17-
Altitude float64
18-
Latitude float64
19-
Longitude float64
15+
Title [256]byte `name:"TITLE"`
16+
Kohlsman float64 `name:"Kohlsman setting hg" unit:"inHg"`
17+
Altitude float64 `name:"Plane Altitude" unit:"feet"`
18+
Latitude float64 `name:"Plane Latitude" unit:"degrees"`
19+
Longitude float64 `name:"Plane Longitude" unit:"degrees"`
20+
}
21+
22+
func (r *Report) RequestData(s *simconnect.SimConnect) {
23+
defineID := s.GetDefineID(r)
24+
requestID := defineID
25+
s.RequestDataOnSimObjectType(requestID, defineID, 0, simconnect.SIMOBJECT_TYPE_USER)
2026
}
2127

2228
func main() {
@@ -26,19 +32,15 @@ func main() {
2632
}
2733
fmt.Println("Connected to Flight Simulator!")
2834

29-
defineID := simconnect.DWORD(0)
30-
s.AddToDataDefinition(defineID, "Title", "", simconnect.DATATYPE_STRING256)
31-
s.AddToDataDefinition(defineID, "Kohlsman setting hg", "inHg", simconnect.DATATYPE_FLOAT64)
32-
s.AddToDataDefinition(defineID, "Plane Altitude", "feet", simconnect.DATATYPE_FLOAT64)
33-
s.AddToDataDefinition(defineID, "Plane Latitude", "degrees", simconnect.DATATYPE_FLOAT64)
34-
s.AddToDataDefinition(defineID, "Plane Longitude", "degrees", simconnect.DATATYPE_FLOAT64)
35+
report := &Report{}
36+
s.RegisterDataDefinition(report)
37+
report.RequestData(s)
3538

36-
fmt.Println("SubscribeToSystemEvent")
37-
eventSimStartID := simconnect.DWORD(0)
38-
s.SubscribeToSystemEvent(eventSimStartID, "SimStart")
39-
40-
requestID := simconnect.DWORD(0)
41-
s.RequestDataOnSimObjectType(requestID, defineID, 0, simconnect.SIMOBJECT_TYPE_USER)
39+
/*
40+
fmt.Println("SubscribeToSystemEvent")
41+
eventSimStartID := simconnect.DWORD(0)
42+
s.SubscribeToSystemEvent(eventSimStartID, "SimStart")
43+
*/
4244

4345
for {
4446
ppData, r1, err := s.GetNextDispatch()
@@ -70,8 +72,8 @@ func main() {
7072
//spew.Dump(recvEvent)
7173

7274
switch recvEvent.EventID {
73-
case eventSimStartID:
74-
fmt.Println("SimStart Event")
75+
//case eventSimStartID:
76+
// fmt.Println("SimStart Event")
7577
default:
7678
fmt.Println("unknown SIMCONNECT_RECV_ID_EVENT", recvEvent.EventID)
7779
}
@@ -81,10 +83,10 @@ func main() {
8183
fmt.Println("SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE")
8284

8385
switch recvData.RequestID {
84-
case requestID:
85-
report := *(*Report)(ppData)
86+
case s.DefineMap["Report"]:
87+
report := (*Report)(ppData)
8688
fmt.Printf("REPORT: %s: GPS: %.6f,%.6f Altitude: %.0f\n", report.Title, report.Latitude, report.Longitude, report.Altitude)
87-
s.RequestDataOnSimObjectType(requestID, defineID, 0, simconnect.SIMOBJECT_TYPE_USER)
89+
report.RequestData(s)
8890
}
8991

9092
default:

simconnect/defs.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package simconnect
22

3+
import "fmt"
4+
35
// MSFS-SDK/SimConnect\ SDK/include/SimConnect.h
46

57
const E_FAIL uint32 = 0x80004005
@@ -30,6 +32,36 @@ const (
3032
DATATYPE_MAX // enum limit
3133
)
3234

35+
func derefDataType(fieldType string) (DWORD, error) {
36+
var dataType DWORD
37+
switch fieldType {
38+
case "int32":
39+
dataType = DATATYPE_INT32
40+
case "int64":
41+
dataType = DATATYPE_INT64
42+
case "float32":
43+
dataType = DATATYPE_FLOAT32
44+
case "float64":
45+
dataType = DATATYPE_FLOAT64
46+
case "[8]byte":
47+
dataType = DATATYPE_STRING8
48+
case "[32]byte":
49+
dataType = DATATYPE_STRING32
50+
case "[64]byte":
51+
dataType = DATATYPE_STRING64
52+
case "[128]byte":
53+
dataType = DATATYPE_STRING128
54+
case "[256]byte":
55+
dataType = DATATYPE_STRING256
56+
case "[260]byte":
57+
dataType = DATATYPE_STRING260
58+
default:
59+
return 0, fmt.Errorf("DATATYPE not implemented: %s", fieldType)
60+
}
61+
62+
return dataType, nil
63+
}
64+
3365
const (
3466
RECV_ID_NULL DWORD = iota
3567
RECV_ID_EXCEPTION

simconnect/simconnect.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"io/ioutil"
1111
"os"
1212
"path/filepath"
13+
"reflect"
1314
"syscall"
1415
"unsafe"
1516
)
@@ -22,11 +23,14 @@ var proc_SimConnect_GetNextDispatch *syscall.LazyProc
2223
var proc_SimConnect_RequestDataOnSimObjectType *syscall.LazyProc
2324

2425
type SimConnect struct {
25-
handle unsafe.Pointer
26+
handle unsafe.Pointer
27+
DefineMap map[string]DWORD
2628
}
2729

2830
func New(name string) (*SimConnect, error) {
29-
s := &SimConnect{}
31+
s := &SimConnect{
32+
DefineMap: map[string]DWORD{"_last": 0},
33+
}
3034

3135
if proc_SimConnect_Open == nil {
3236
exePath, err := os.Executable()
@@ -81,6 +85,49 @@ func New(name string) (*SimConnect, error) {
8185
return s, nil
8286
}
8387

88+
func (s *SimConnect) GetDefineID(a interface{}) DWORD {
89+
structName := reflect.TypeOf(a).Elem().Name()
90+
91+
id, ok := s.DefineMap[structName]
92+
if !ok {
93+
id = s.DefineMap["_last"]
94+
s.DefineMap[structName] = id
95+
s.DefineMap["_last"] = id + 1
96+
}
97+
98+
return id
99+
}
100+
101+
func (s *SimConnect) RegisterDataDefinition(a interface{}) error {
102+
defineID := s.GetDefineID(a)
103+
104+
v := reflect.ValueOf(a).Elem()
105+
for j := 1; j < v.NumField(); j++ {
106+
fieldName := v.Type().Field(j).Name
107+
nameTag, _ := v.Type().Field(j).Tag.Lookup("name")
108+
unitTag, _ := v.Type().Field(j).Tag.Lookup("unit")
109+
110+
fieldType := v.Field(j).Kind().String()
111+
if fieldType == "array" {
112+
fieldType = fmt.Sprintf("[%d]byte", v.Field(j).Type().Len())
113+
}
114+
115+
if nameTag == "" {
116+
return fmt.Errorf("%s name tag not found", fieldName)
117+
}
118+
119+
dataType, err := derefDataType(fieldType)
120+
if err != nil {
121+
return err
122+
}
123+
124+
s.AddToDataDefinition(defineID, nameTag, unitTag, dataType)
125+
//fmt.Printf("fieldName: %s fieldType: %s nameTag: %s unitTag: %s\n", fieldName, fieldType, nameTag, unitTag)
126+
}
127+
128+
return nil
129+
}
130+
84131
func (s *SimConnect) Close() error {
85132
// SimConnect_Open(
86133
// HANDLE * phSimConnect,

vfrmap/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# msfs2020-go/vfrmap
2+
3+
web server that shows your current MSFS2020 plane position in google maps inside the browser
4+
5+
## install
6+
7+
* download latest release zip [here](https://github.com/lian/msfs2020-go/releases)
8+
* unzip `vfrmap-win64.zip`
9+
10+
## run
11+
* run `vfrmap.exe`
12+
* browse to http://localhost:9000
13+
14+
## arguments
15+
16+
* `-v` show program version
17+
* `-api-key` use your own gmap api-key
18+
* `-verbose` verbose output
19+
20+
## change visualisation
21+
22+
if you want to change how the webpage looks then copy and change [index.html](html/index.html) to the same folder as `vfrmap.exe` and relaunch the program.
23+
24+
## compile
25+
26+
`GOOS=windows GOARCH=amd64 go build github.com/lian/msfs2020-go/vfrmap` or see [build-vfrmap.sh](https://github.com/lian/msfs2020-go/blob/master/build-vfrmap.sh)
27+
28+
## screenshots
29+
30+
![screenshot](https://i.imgur.com/YllMEvG.png)

vfrmap/main.go

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,22 @@ import (
2222

2323
type Report struct {
2424
simconnect.RecvSimobjectDataByType
25-
Title [256]byte
26-
Altitude float64
27-
Latitude float64
28-
Longitude float64
29-
Heading float64
30-
Airspeed float64
31-
VerticalSpeed float64
32-
Flaps float64
33-
Trim float64
34-
RudderTrim float64
25+
Title [256]byte `name:"TITLE"`
26+
Altitude float64 `name:"INDICATED ALTITUDE" unit:"feet"` // PLANE ALTITUDE or PLANE ALT ABOVE GROUND
27+
Latitude float64 `name:"PLANE LATITUDE" unit:"degrees"`
28+
Longitude float64 `name:"PLANE LONGITUDE" unit:"degrees"`
29+
Heading float64 `name:"PLANE HEADING DEGREES TRUE" unit:"degrees"`
30+
Airspeed float64 `name:"AIRSPEED INDICATED" unit:"knot"`
31+
VerticalSpeed float64 `name:"VERTICAL SPEED" unit:"ft/min"`
32+
Flaps float64 `name:"TRAILING EDGE FLAPS LEFT ANGLE" unit:"degrees"`
33+
Trim float64 `name:"ELEVATOR TRIM PCT" unit:"percent"`
34+
RudderTrim float64 `name:"RUDDER TRIM PCT" unit:"percent"`
35+
}
36+
37+
func (r *Report) RequestData(s *simconnect.SimConnect) {
38+
defineID := s.GetDefineID(r)
39+
requestID := defineID
40+
s.RequestDataOnSimObjectType(requestID, defineID, 0, simconnect.SIMOBJECT_TYPE_USER)
3541
}
3642

3743
var buildVersion string
@@ -46,7 +52,7 @@ var mapApiKey string
4652
func main() {
4753
flag.BoolVar(&showVersion, "v", false, "version")
4854
flag.BoolVar(&verbose, "verbose", false, "verbose output")
49-
flag.StringVar(&httpListen, "listen", "localhost:9000", "http listen")
55+
flag.StringVar(&httpListen, "listen", "0.0.0.0:9000", "http listen")
5056
flag.StringVar(&mapApiKey, "api-key", "", "gmap api-key")
5157
flag.Parse()
5258

@@ -71,29 +77,20 @@ func main() {
7177
}
7278
fmt.Println("Connected to Flight Simulator!")
7379

74-
defineID := simconnect.DWORD(0)
75-
requestID := simconnect.DWORD(0)
76-
s.AddToDataDefinition(defineID, "Title", "", simconnect.DATATYPE_STRING256)
77-
s.AddToDataDefinition(defineID, "INDICATED ALTITUDE", "feet", simconnect.DATATYPE_FLOAT64)
78-
//s.AddToDataDefinition(defineID, "PLANE ALT ABOVE GROUND", "feet", simconnect.DATATYPE_FLOAT64)
79-
//s.AddToDataDefinition(defineID, "PLANE ALTITUDE", "feet", simconnect.DATATYPE_FLOAT64)
80-
s.AddToDataDefinition(defineID, "PLANE LATITUDE", "degrees", simconnect.DATATYPE_FLOAT64)
81-
s.AddToDataDefinition(defineID, "PLANE LONGITUDE", "degrees", simconnect.DATATYPE_FLOAT64)
82-
s.AddToDataDefinition(defineID, "PLANE HEADING DEGREES TRUE", "degrees", simconnect.DATATYPE_FLOAT64)
83-
s.AddToDataDefinition(defineID, "AIRSPEED INDICATED", "knot", simconnect.DATATYPE_FLOAT64)
84-
s.AddToDataDefinition(defineID, "VERTICAL SPEED", "ft/min", simconnect.DATATYPE_FLOAT64)
85-
s.AddToDataDefinition(defineID, "TRAILING EDGE FLAPS LEFT ANGLE", "degrees", simconnect.DATATYPE_FLOAT64)
86-
s.AddToDataDefinition(defineID, "ELEVATOR TRIM PCT", "percent", simconnect.DATATYPE_FLOAT64)
87-
s.AddToDataDefinition(defineID, "RUDDER TRIM PCT", "percent", simconnect.DATATYPE_FLOAT64)
80+
report := &Report{}
81+
err = s.RegisterDataDefinition(report)
82+
if err != nil {
83+
panic(err)
84+
}
85+
86+
report.RequestData(s)
8887

8988
/*
9089
fmt.Println("SubscribeToSystemEvent")
9190
eventSimStartID := simconnect.DWORD(0)
9291
s.SubscribeToSystemEvent(eventSimStartID, "SimStart")
9392
*/
9493

95-
s.RequestDataOnSimObjectType(requestID, defineID, 0, simconnect.SIMOBJECT_TYPE_USER)
96-
9794
go func() {
9895
for {
9996
ppData, r1, err := s.GetNextDispatch()
@@ -136,9 +133,8 @@ func main() {
136133
//fmt.Println("SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE")
137134

138135
switch recvData.RequestID {
139-
case requestID:
140-
report := *(*Report)(ppData)
141-
//fmt.Printf("REPORT: %s: GPS: %.6f,%.6f Altitude: %.0f Heading: %.1f\n", report.Title, report.Latitude, report.Longitude, report.Altitude, report.Heading)
136+
case s.DefineMap["Report"]:
137+
report = (*Report)(ppData)
142138

143139
if verbose {
144140
fmt.Printf("REPORT: %#v\n", report)
@@ -156,7 +152,7 @@ func main() {
156152
"rudder_trim": fmt.Sprintf("%.1f", report.RudderTrim),
157153
})
158154

159-
s.RequestDataOnSimObjectType(requestID, defineID, 0, simconnect.SIMOBJECT_TYPE_USER)
155+
report.RequestData(s)
160156
}
161157

162158
default:

0 commit comments

Comments
 (0)