Skip to content

Commit

Permalink
Add basic documentation for adding core functionality for add-on (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
InfraredAces authored Sep 27, 2024
1 parent c9f7420 commit 2eb60d0
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 3 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</p>

<p>
GP2040-CE is compatible with PC, PS3 and PS4, Nintendo Switch, Steam Deck, MiSTer and Android.
GP2040-CE is compatible with PC, PS3, PS4, PS5, Nintendo Switch, Xbox One, Steam Deck, MiSTer and Android.
</p>

## Links
Expand All @@ -33,7 +33,7 @@ Full documentation can be found at [https://gp2040-ce.info](https://gp2040-ce.in
## Features

- Select from 13 input modes including X-Input, Nintendo Switch, Playstation 4/5, Xbox One, D-Input, and Keyboard
- Overclocked polling rate for an average of 0.76ms of input latency in Xinput and on average 1.72 for Playstation 4/5.
- Input latency average of 0.76ms in Xinput and 0.91ms for Playstation 5.
- Multiple SOCD cleaning modes - Up Priority (a.k.a. Stickless), Neutral, and Second Input Priority.
- Left and Right stick emulation via D-pad inputs as well as dedicated toggle switches.
- Dual direction via D-pad + LS/RS.
Expand Down
17 changes: 17 additions & 0 deletions development/add-on-basics.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: Basics
# tags:
# -
pagination_next: null
pagination_prev: null
description: "Documentation on the minimum requirements for a GP2040-CE add-on."
---

# Basics

## General Process

1. Complete core add-on functionality in the source file with directly hard-coded values based on `#define` macros in the add-on's header files
2. Once basic add-on functionality is confirmed, create necessary enumerations in `config.proto` for add-on options to be saved into protobuf and and then set them in `config_utils.cpp`
3. Replace directly hard-coded values using `#define` macros in source file with the values set in `config_utils.cpp`
4. Create Web Configurator pages, components, and interfaces to manipulate and save user set values to protobuf
205 changes: 205 additions & 0 deletions development/add-on-core-functionality.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
---
title: Core Functionality
# tags:
# -
pagination_next: null
pagination_prev: null
description: "Documentation on the minimum requirements for a GP2040-CE add-on to function. Note: This does not include web configuration functionality and saving post-compile options to protobuf."
---

# Core Functionality

### CMAKE

The first thing to do is to make sure that CMAKE is able to see and add your add-on source files, link any libraries that you create, and include any subfolders for header files you added for add-on functionality.

```cpp
add_executable(${PROJECT_NAME}
...
src/addons/addon_name.cpp
...
)

target_link_libraries(${PROJECT_NAME}
...
AdditionalLibraryName
...
)

target_include_directories(${PROJECT_NAME} PUBLIC
...
headers/folder/subfolder
...
)
```

#### Add-On

Include all necessary files to `/CMakeLists.txt`

1. Add Add-on executable (i.e. `src/addons/addon_name.cpp`) under `add_executable(${PROJECT_NAME}`
- If any .cpp files in folders outside of `src/addons/` were created for operation of the add-on, they must be included under `add_executable(${PROJECT_NAME}` as well,
2. Add any add-on header files and folders outside of `/headers/addons` (i.e. `/headers/folder/subfolder/addonHeader.h`) to `target_include_directories(${PROJECT_NAME} PUBLIC`

#### Additional Libraries

1. Add library to `CMakeLists.txt`
2. Add library to `lib/CMakeLists.txt`
3. Create `lib/AdditionalLibrary/CMakeLists.txt`
4. Add necessary source and header files to `lib/AdditionalLibrary/`

### Main Program (gp2040.cpp)

#### Add Add-on Include

```cpp
#include "addons/addon_name.cpp"
```

#### Load Add-on

```cpp
addons.LoadAddon(new AddonName(), CORE0_Input)
```

:::info CORE0_Input vs CORE1_Input

- `CORE0_Input` is typically input or input-related tasks
- `CORE1_Input` tends to be auxillary output processes (Display, RGB LEDs, etc) and input that include additional USB processing.

:::

### Header Files

You will need to create a header file for add-on in `/headers/addons/ADDON_NAME.h`

```cpp
#ifndef ADDON_NAME_H
#define ADDON_NAME_H

#include "gpaddon.h"
#include "GamepadEnums.h"
#include "BoardConfig.h"
#include "enums.pb.h"

#ifndef ADDON_NAME_ENABLED
#define ADDON_NAME_ENABLED 0
#endif

#define ADDON_PIN -1

// IO Module Name
#define AddonName "Add-on Name"

class AddonNameAddon : public GPAddon
{
public:
virtual void bootProcess() {}
virtual bool available();
virtual void setup();
virtual void preprocess();
virtual void process();
virtual std::string name() { return AddonName; }

private:

};

```

### Source File

You will need to create a source file for add-on in `/src/addons/ADDON_NAME..cpp`. This will be the majority of your add-ons functionality.

```cpp
#include "addons/ADDON_NAME.h"
#include "storagemanager.h"
#include "config.pb.h"

bool AddonNameAddon::available()
{
return Storage::getInstance().getAddonOptions().addonNameOptions.enabled;
}

void AddonNameAddon::setup()
{
}

void AddonNameAddon::preprocess()
{
}

void AddonNameAddon::process()
{
}
```

#### `available()`

This function is called once on create to determine whether the addon will be included in the processing loop. You would typically check if the addon's enabled flag is toggled in options and then return that boolean flag. There might be other options you'd want to look at, but that all depends on what's important to know before you turn the add-on on (e.g. checking if GPIO pins are set properly first).

#### `setup()`

This function is called once if `available()` returns true to set up any objects/variables that are needed prior to the main loop. Here you will want to prepare any GPIO pin assignments or create objects that the processing loop needs to function when `preprocess()` and `process()` are called.

#### `preprocess()`

This function is called on the `GP2040::run()` loop prior to processing the gamepad state. This is where you will want to change and modify the gamepad state according to the intended function of your add-on.

#### `process()`

This function is called on the `GP2040::run()` or `GP2040Aux::run()` loop after processing gamepad state. This is where you will want to change and modify the gamepad state according to the intended function of your add-on.

### Protobuf

:::warning

Unless absolutely necessary, do not rename or reorder the enumerations in `config.proto` and `enums.proto`. Doing so will break compatibility with previous versions of the firmware. Simply append any new enumerations if more are necessary.

:::

#### `config.proto`

Once you have the add-on working using the directly hardcoded `#define` macros in `addonName.h`, you will want to add the options to `/proto/config.proto` so that those options will be properly allocated memory space in protobuf. By doing so, you can later read and write values to be saved to protobuf using the Web Configurator and web interface.

In addition to options specific to the add-on you are developing, you will need to add an enum for the new add-on to the `AddonOptions`.

```cpp
message AddOnNameOptions {
optional bool enabled = 1;
optional uint32 addonSetting = 2;
}

message AddonOptions {
...
optional AddonOptions addonNameOptions = XX;
}
```

#### `enums.proto`

When a variable can take certain values, it is useful to use enumerations. It encapsulates all possible values from a specific group. In order to use enumerations, it will be necessary to add these enumerations to `proto/enums.proto` so that they can be used in your add-on as well as potentially in other parts of the firmware.

```cpp
enum AddonEnum
{
options (nanopb_enumopt).long_names = false;

ENUM_OPTION_1 = 0;
ENUM_OPTION_2 = 1;
...
}
```

#### `configs_utils.cpp`

- Add set properties to `src/configs_utils.cpp`
- Remember to add all properties to `config.proto`

```cpp
#include "addons/addon_name.h"

// addonOptions.addonNameOptions
INIT_UNSET_PROPERTY(config.addonOptions.addonNameOptions, enabled, ADDON_NAME_ENABLED);

```
12 changes: 11 additions & 1 deletion sidebarsDevelopment.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,17 @@
"type": "category",
"label": "Firmware",
"collapsed": false,
"items": ["firmware-development"]
"items": [
{
"type": "category",
"label": "Add-ons",
"collapsed": false,
"items": [
"add-on-basics",
"add-on-core-functionality"
]
}
]
},
{
"type": "category",
Expand Down

0 comments on commit 2eb60d0

Please sign in to comment.