Tutorial on how to write an OSD plugin
A tutorial by Alexey Belyaev.
A short instruction on how to assemble plugins, using the example of OSD Plugin for RubyFPV
Ideally, it is better
to use Linux or Darvin for assembly, but it also builds perfectly on Windows.
For assembly we need:
1. Source code RubyFPV (https://github.com/PetruSoroaga/RubyFPV)
2. Source code of OSD Plugin (https://github.com/.../code/r_plugins_osd/my_plugin_source.cpp)
3. Make tool packet for build control (for Windows: https://gnuwin32.sourceforge.net/packages/make.htm)
4. GCC for ARM AArch32 target with hard float arm-none-linux-gnueabihf (for Widows: https://developer.arm.com/downloads/-/gnu-a)
5. Developer IDE VSCode (https://code.visualstudio.com/download)
That seems to be all.
Note: I've heard a
lot of opinions and seen a lot of instructions where the authors claim that a
“special” compiler is needed to build for Raspberry, but in practice everything
is much simpler. Suitable universal for ARM.
I will not tell you
how to install the packages described above, this is not what this instruction
is about. They are assumed to be installed.
The minimum set of
source code consists of 2 files of the plugin itself and the RubyFPV source code:
RubyFPV
code\
licenses\
mavlink\
res\
...
Plugin\
Makefile
my_plugin_source.cpp
The file
my_plugin_source.cpp contains the code of the plugin itself, in this case it is
completely the same code from the “RubyFPV source
package”
But the Makefile file requires special attention, its contents are the following:
VER_MAJOR := 1
VERSION := $(VER_MAJOR).0.1
PREFIX := arm-linux-gnueabihf-
GPP := $(PREFIX)g++
GCC := $(PREFIX)gcc
PLATFORM = -march=armv7-a -mfloat-abi=hard -mfpu=neon-vfpv4
INCLUDES += -I../../RubyFPV/code
LDFLAGS= -lrt -lpthread -lc -shared $(LIBS)
CFLAGS += $(PLATFORM) -fno-stack-protector -Wall -O0 -D _GNU_SOURCE
-Wno-address-of-packed-member $(INCLUDES)
CPPFLAGS= $(PLATFORM) $(CFLAGS) --std=gnu++17
OUTPUT := build
.PHONY: clean all
all: my_plugin
$(OUTPUT)/%.o: %.cpp mk-dirs
$(GPP) $(CPPFLAGS) -c -o $@ $<
my_plugin: $(OUTPUT)/my_plugin_source.o mk-dirs
$(GCC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)/my_plugin_source.o -Wl,-soname, my_plugin.so.$(VER_MAJOR) -o $(OUTPUT)/my_plugin.so.$(VERSION)
mk-dirs:
mkdir ./$(OUTPUT)
clean:
rm -fr $(OUTPUT)
Note: I do not
pretend that the example has the only one correct solution.
Let's take a closer
look at the important points:
1.
VER_MAJOR
and VERSION variables for easy maintenance of the plugin version
2.
PREFIX it
is necessary to set the “prefix” of the GCC executable files for assembly for
the ARM platform, for the case of Raspberry Pi this is AArch32 with hard float
3.
PLATFORM compiler
switches, specifying the hard float option and the architecture of a specific
processor.
The above keys will
allow you to collect the “correct” binary code from any system.
1.
-Wno-address-of-packed-member key required to hide warnings
when building mavlink
(https://mavlink.io/en/mavgen_c/#waddress-of-packed-member) in case your plugin
will use its functionality.
The plugin is built
normally using the make all commands, there are no special features here.
Now a little about the ease of development. VSCode
and several plugins will help us with this.
In my opinion the minimum set is:
1. C/C++ (https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
2. C/C++ Extension Pack (https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools-extension-pack)
3. Makefile Tools (https://marketplace.visualstudio.com/items?itemName=ms-vscode.makefile-tools)
4.
Better C++ Syntax (https://marketplace.visualstudio.com/items?itemName=jeff-hykin.better-cpp-syntax)
Also in the project
you need to create a file .vscode/c_cpp_properties.json with the following contents:
{
"configurations": [
{
"name": "Raspberry",
"includePath": [
"${workspaceRoot}/**",
"${workspaceRoot}/../RubyFPV/code"
],
"defines": [
"_GNU_SOURCE"
],
"compilerPath": "arm-linux-gnueabihf-g++.exe",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-arm",
"configurationProvider": "ms-vscode.makefile-tools",
"cStandard": "gnu17",
"mergeConfigurations": false,
"browse": {
"path": [
"${workspaceRoot}/**",
"${workspaceRoot}/../RubyFPV/code"
],
"limitSymbolsToIncludedHeaders": true
}
}
],
"version": 4
}
The result should look
something like this:
You can see that code addition works and you can move on to methods from
the main RubyFPV code