A dynamic Go implementation of the Inter-Module Communication (IMC) protocol. This library allows for communication with LSTS systems (Neptus, DUNE, etc.) by reading the protocol specification directly from an IMC.xml file.
- Dynamic Protocol Loading: Load Any
IMC.xmlversion at runtime. - Generic Message Handling: Work with messages using a simple
map[string]anyinterface. - UDP Transporter: Support for unicast and multicast communication.
- Multicast Coexistence: Implements
SO_REUSEADDRandSO_REUSEPORTto allow multiple processes to share the same IMC ports. - Typed Message Helpers: Auto-generated Go structs for type-safe field access and IDE autocomplete.
- Nested Message Support: Full recursion for
messageandmessage-listtypes. - Strict Validation: CRC16 checks and synchronization number verification.
To use imc-go in your own project:
-
Initialize your module:
go mod init my-project
-
Add the dependency: If the module is local, use the
replacedirective:go mod edit -replace imc-go=../path/to/imc-go go get imc-go
-
Import and use:
import "github.com/oceanscan/imc-go"
- Go 1.22 or later
- Access to an
IMC.xmlspecification file.
go mod tidyimport "github.com/oceanscan/imc-go"
// Parse the XML specification
xmlProto, _ := imc.ParseXML("IMC.xml")
// Create a protocol engine
proto := imc.NewProtocol(xmlProto)// Create a new UDP transporter
trans, _ := imc.NewUDPTransporter(proto, "0.0.0.0:0")
defer trans.Close()
// Create an Announce message
msg, _ := proto.CreateMessage("Announce")
msg.Fields["sys_name"] = "My-Go-Node"
msg.Fields["sys_type"] = uint8(0) // CCU
// Send to a specific address
trans.Send(msg, "127.0.0.1:6002")// Listen on the standard IMC multicast port
trans, _ := imc.NewUDPTransporter(proto, "0.0.0.0:30101")
defer trans.Close()
// Join the IMC multicast group
trans.JoinMulticast("224.0.75.69:30101")
for {
msg, addr, err := trans.Receive()
if err == nil {
abbrev := proto.Messages[msg.Header.MGID].Abbrev
fmt.Printf("Received %s from %v\n", abbrev, addr)
}
}For a more convenient development experience, you can use generated structs to avoid raw map access:
import "github.com/oceanscan/imc-go"
// Receiving and converting to typed
msg, addr, _ := trans.Receive()
abbrev := proto.Messages[msg.Header.MGID].Abbrev
// Use CreateTyped for easy conversion
typedMsg, err := proto.CreateTyped(abbrev, msg)
if err == nil {
switch m := typedMsg.(type) {
case *imc.Announce:
fmt.Printf("Received Announce from %s: Name=%s, Type=%d\n",
addr, m.SysName, m.SysType)
case *imc.EstimatedState:
fmt.Printf("Vehicle Position: Lat=%f, Lon=%f\n", m.Lat, m.Lon)
}
}
// Creating a typed message for sending
ann := imc.Announce{
SysName: "MyNode",
SysType: 2, // UUV
}
trans.Send(ann.ToMessage(), "127.0.0.1:6001")If the IMC.xml specification changes or you want to update the generated helpers, use the included generator tool:
- Place the new
IMC.xmlin the root of the project. - Run the generator:
go run cmd/gen_messages/main.goThis will update messages.go with structs for all messages defined in the XML.
The project includes several command-line tools in the cmd/ directory to demonstrate the library's capabilities.
Joins the standard LSTS multicast group and prints received Announce messages from other systems on the network.
go run cmd/multicast_listener/main.goParses a binary .lsf log file and prints message statistics.
# Make sure the test data is available
go run cmd/parse_lsf/main.goExtracts absolute latitude/longitude (in degrees) for every EstimatedState message in an LSF log by displacing the geodetic reference (Lat, Lon) by the NED offset (X, Y) on the WGS84 ellipsoid. Output is CSV.
go run cmd/estate_positions/main.go IMC.xml Data.lsf > positions.csvUpdates the typed message structs in messages.go based on the current IMC.xml.
go run cmd/gen_messages/main.goTo compile the tools for a Raspberry Pi or other ARM devices from your development machine:
GOOS=linux GOARCH=arm64 go build -o listener-arm64 cmd/multicast_listener/main.goGOOS=linux GOARCH=arm go build -o listener-arm cmd/multicast_listener/main.goThe library is cross-platform and supports Windows. To compile for Windows from Linux or macOS:
GOOS=windows GOARCH=amd64 go build -o listener.exe cmd/multicast_listener/main.go