Skip to content

padcom/mavlink-mappings-gen

Repository files navigation

node-mavlink-gen

A powerful source code generator for node-mavlink-compatible classes. Uses the same code that powers the mavlink-mappings package used by node-mavlink.

Usage

It's really easy to get going!

$ npx node-mavlink-gen@latest minimal.xml

(You can get the minimal.xml file from here)

After you run the command the generator will read all the files you specified in the command line and generate source code for each module. If you have specified multiple files those will instead be written to their respective files.

Getting a colored output

There is a way to easily get the code syntax highlighted using the source-highlight utility:

$ npx node-mavlink-gen minimal.xml | source-highlight -s javascript -f esc256 | less -r

Generating custom definitions

Sometimes the vast number of messages just isn't enough and a new message could make all the difference.

You may consider writing the a class definition by hand, which is definitely possible but it may be a tedious and error-prone process. To ease the pain the entire generator is exposed for anyone to use:

Generating based on XML source

One thing that will allow you to basically generate all definitions in one go is to base them on a mavlink xml definition file. For a list of supported features look at the original XML definitions. At the moment minimal, common, development, ardupilotmega, asluav, icarus, storm32, ualberta and uavionix definitions are recognized by the generator.

async function generateAll(input: string, output: Writer, moduleName: string = '')

Generating based on data

This is a much more tedious process but it allows you to use something completely different to read the definitions from. There are a few interfaces that you'll have to get familiar with (like EnumDef, MessageDef and CommandTypeDef) but after you'll get them the generator should produce valid definitions.

This is how the generateAll() function does it:

const { enumDefs, messageDefs, commandTypeDefs } = await new XmlDataSource().parse(input)

const enums = processEnums(output, enumDefs)
const messages = processMessages(output, messageDefs)
const commands = processCommands(output, moduleName, commandTypeDefs)
processRegistries(output, messages, commands)

return { enums, messages, commands }

Debugging issues

Disclaimer:

The generator is basically available as-is. There is, and never will be, any support for anything else that doesn't work at the moment. If you want to have a problem fixed that impacts you - create a PR, I promise I'll look at it. If you have a feature request - create a PR that implements that feature.

With that out of the way let's see what can we do to understand the problems we might encounter.

Going single

If only part of the generation fails the entire generated content is lost. But there is hope! You can process each enum, message and command separately:

Generating a single enum

function generateEnum(output: Writer, enum: {
  name: string
  description: string[]
  values: {
    name: string
    value: string
    description: string[]
    hasLocation: boolean
    isDestination: boolean
    params: {
      name: string
      label: string
      description: string
      index: string
      units: string
      minValue: string
      maxValue: string
      increment: string
    }[]
  }[]
  source: {
    name: string
  }
})

Generating a single message

function generateMessage(output: Writer, message: {
  id: string
  name: string
  description: string[]
  magic?: number
  payloadLength?: number
  source: {
    name: string
  }
  deprecated?: {
    description: string
    since: string
    replacedBy: string
  }
  fields: {
    name: string
    description: string[]
    fieldSize: number
    extension: boolean
    arrayLength: number
    fieldType: string
    size: number
    units: string
    type: string
    source: {
      name: string
    }
  }[]
})

Generating a single command

function generateCommand(output: Writer, command: {
  description: string[],
  hasLocation: boolean,
  isDestination: boolean,
  field: string,
  name: string,
  params: {
    name: string,
    index: string,
    description: string[]
    label: string
    units: string
    minValue: string
    maxValue: string
    increment: string
  }[]
  source: {
    commonPrefix?: string
  }
})

Generating other elements separately

Pretty much every single part of the code can be generated in separation to everything else. Use that to understand better the inputs and the generated output. Functions like generateEnumValueParams(...) or generateMessageDefinitionFields() are there for you to use in those cases where you just don't get what's going on.

Generating magic number (aka crc_extra) value

Writing a definition of a message manually is an intense task at best. The one thing that is the least straightforward is the generation of a proper crc_extra (referred by node-mavlink as magic value) value:

function calculateCrcExtra(messageSourceName: string, fields: {
  extension: boolean
  itemType: string
  fieldSize: number
  arrayLength?: number
  source: { type: string, name: string }
}[])

Generating registry for magic numbers

A registry of magic numbers (aka crc_extra) can also be generated:

  fs.writeFileSync('magic-numbers.ts', generateMagicNumbers(magicNumbers))

About

Command-line utility to generate node-mavlink compatible message definitions from official XML definitions

Resources

License

Stars

Watchers

Forks

Packages

No packages published