Skip to content

omadon/RallyController-V2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

17 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

RCntrl Firmware v2 by Omadon

Version: 2.40

Custom firmware for the StylesRallyIndustries Bluetooth Navigation / Digital Roadbook Controller.

Author: [email protected]


Required Libraries

  • NimBLE-Arduino 2.5.0
  • HijelHID_BLEKeyboard 0.5.0
  • Keypad 3.1.1

Differences from Original Firmware

  • Uses the Keypad library with an event handler for simpler button state handling.
  • Supports two controllers in daisy chain, connected to each other or to the controller box.
  • Keypad scanning allows daisy chaining using UTP cables (5/6 wires for buttons + 2 wires for LED).
  • Up to 8 different profiles:
    • Short press of buttons 1–8 β†’ select profiles 1–8
    • Long press of buttons 1–4 β†’ select profiles 5–8
  • Button mapping tables (normal + media) are split into two halves:
    • First half β†’ short press mappings
    • Second half β†’ long press mappings
    • Long press uses dedicated mapping if defined; otherwise short-press behavior repeats.
  • Profile change sequence: press 1-2-3-4 then the button number of desired profile.
  • Press sequence 4-3-2-1-4-3-2-1 to execute BLE factory reset. It plays a visual SOS LED signal for user confirmation.
  • Selected profile is saved in NVS, surviving controller reboot.
  • Profiles can send normal keys (letters, numbers, arrows, etc.) or media keys (volume/playback).
    Lookup order: normal β†’ media.
  • LED support (external or internal):
    • Blinking when not connected to Bluetooth
    • Optional keepalive blinking (default 10h)
    • Blink on each button press
    • Profile change feedback: LED blinks number of selected profile after 1-2-3-4 sequence
  • Set DEBUG = 0 for production use.

Mapping Table Layout (per profile)

profiles_normal[NUM_PROFILES*2][NUM_KEYS]
profiles_media [NUM_PROFILES*2][NUM_KEYS]

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Short press mappings    β”‚   Long press mappings     β”‚
β”‚   (rows 0–7 = profiles)   β”‚   (rows 8–15 = profiles)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Example (Profile 1):

  • profiles_normal[0][keyX] β†’ short press normal key
  • profiles_media[0][keyX] β†’ short press media key
  • profiles_normal[8][keyX] β†’ long press normal key
  • profiles_media[8][keyX] β†’ long press media key

Lookup logic:

  1. On short press β†’ check normal[profile], fallback to media[profile]
  2. On long press β†’ check normal[profile+NUM_PROFILES], if empty then check media[profile+NUM_PROFILES]

πŸŽ›οΈ Profiles & Key Mapping Guide

The firmware supports 8 independent profiles, each with:

  • 8 button slots (your controller may only use 4 buttons, but the code is scalable).
  • Two actions per button:
    • Short press
    • Long press

Each button can be mapped to:

  1. Normal keys (keyboard keys)
    β†’ letters, numbers, arrows, function keys ('a', '1', KEY_RETURN, KEY_UP_ARROW, …).
    β†’ defined in profiles_normal.

  2. Media keys (consumer/media controls)
    β†’ volume, play/pause, next/previous track (KEY_MEDIA_PLAY_PAUSE, KEY_MEDIA_VOLUME_UP, …).
    β†’ defined in profiles_media.

  3. Instant keys (timing control)
    β†’ determines when a key event is sent:

    • Instant (1) β†’ key is sent immediately on button down.
    • Non-instant (0) β†’ key is sent on button release.
    • Direct (2) β†’ bleKeyboard.press. β†’ defined in instant_keys.

πŸ”‘ How profiles are structured

  • profiles_normal:

    • First 8 rows β†’ short press mappings (profiles 1–8).
    • Next 8 rows β†’ long press mappings (profiles 9–16).
  • profiles_media:

    • Same structure as above (short first, then long).

Example:

// Profile 4, short press
{ KEY_F6, KEY_F7, KEY_RETURN, KEY_F5, KEY_UP_ARROW, KEY_LEFT_ARROW, KEY_RIGHT_ARROW, KEY_DOWN_ARROW },

// Profile 4, long press
{ 0, 0, 0, 0, 0, 0, 0, 0 },

✏️ Editing a profile

  1. Open keymapings.h.
  2. Find the profile you want to edit.
  3. Update profiles_normal (for standard keyboard keys) or profiles_media (for media keys).
    • Use 0 in one table if you want the key to come from the other table.
  4. Adjust instant_keys if you want to enable long press behavior.
    • Keys set to '0' are delayed until button release (non-instant).
    • Keys set to '1' are sent immediately (instant).

πŸ›  Example: Custom DMD2 profile

Let’s configure Profile 4 like this:

  • Button 1 β†’ short press = F6, long press = F6
  • Button 2 β†’ short press = F7, long press = F7
  • Button 3 β†’ short press = ENTER, long press = ENTER
  • Button 4 β†’ short press = F5, long press = F5
  • Buttons 5-8 (Controller 2) Up/Left/Right/Down arrows

Code changes:

// profiles_normal (Profile 4 short press)
{ KEY_F6, KEY_F7, KEY_RETURN, KEY_F5, KEY_UP_ARROW, KEY_LEFT_ARROW, KEY_RIGHT_ARROW, KEY_DOWN_ARROW },

// profiles_normal (Profile 4 long press)
{ 0, 0, 0, 0, 0, 0, 0, 0 },

// profiles_media (Profile 4 short press)
{ 0, 0, 0, 0, 0, 0, 0, 0 },

// profiles_media (Profile 4 long press)
{ 0, 0, 0, 0, 0, 0, 0, 0 },

// instant_keys (Profile 4)
{'1', '1', '1', '1', '1', '1', '1', '1'},

// BTDeviceInfo (Profile 4)
{ "BarButtons",    "S.R.I. Omadon", 55 }, // Profil 4

πŸ›  Example: Custom media profile

Let’s configure Profile 3 like this:

  • Button 1 β†’ short press = Next, long press = Play/Pause
  • Button 2 β†’ short press = Previous, long press = Stop
  • Button 3 β†’ short press = VolumeUP, long press = repeat VolumeUP
  • Button 4 β†’ short press = VolumeDOWN, long press = repeat VolumeDOWN
  • Buttons 5-8 (Controller 2) Up/Left/Right/Down arrows

Code changes:

// profiles_normal (Profile 3 short press) zero in normal mapping says look at the media mapping
{ 0, 0, 0, 0, KEY_UP_ARROW, KEY_LEFT_ARROW, KEY_RIGHT_ARROW, KEY_DOWN_ARROW },

// profiles_media (Profile 3 short press)
{ KEY_MEDIA_NEXT_TRACK, KEY_MEDIA_PREVIOUS_TRACK, KEY_MEDIA_VOLUME_UP, KEY_MEDIA_VOLUME_DOWN, 0, 0, 0, 0 },

// profiles_media (Profile 3 long press)
{ KEY_MEDIA_PLAY_PAUSE, KEY_MEDIA_STOP, 0, 0, 0, 0, 0, 0 },

// instant_keys (Profile 3) buttons 1 and 2 are removed from instant keys
{'0', '0', '1', '1', '1', '1', '1', '1'},

Explanation:

  • profiles_normal is filled with zeros for Button 1 & 2 β†’ they are resolved via profiles_media.
  • instant_keys marks Button 1 & 2 as non-instant (so long press detection works).

πŸ“‹ Default Profiles Overview

Profile Short Press (Normal) Short Press (Media) Long Press (Normal) Long Press (Media) Instant Keys
1 =, -, r, c, ↑, ←, β†’, ↓ – – – All instant
2 – Prev, Next, Vol-, Vol+ – – All instant
3 – Next, Prev, Vol+, Vol- – Play/Pause, Stop Btn 1&2 non-instant
4 F6, F7, Enter, F5, ↑, ←, β†’, ↓ – – – All instant
5 F1–F8 – – – All instant
6 =, -, N, C, ↑, ←, β†’, ↓ – D (Btn3) – Btn 3 non-instant
7 F1–F8 Prev, Next, Play/Pause F9–F12 – All non-instant
8 ↑, ←, β†’, ↓, F6, F7, Enter, F5 – – – All instant

OTA Firmware Update

RCntrl V2 supports dual-stage Over-The-Air firmware updates.

The controller first attempts to download firmware from GitHub Releases.

If GitHub OTA fails, it automatically falls back to a local HTTP server.


Firmware Naming

Firmware binaries use the following naming format:

<BOARD_NAME>-<PROFILE>.bin

Examples:

ESP32-C3-12F-1.bin
ESP32-C3-12F-4.bin
LOLIN-C3-MINI-2.bin

Profile-Aware OTA

RCntrl V2 supports profile-specific firmware images.

This allows hosting different firmware builds with predefined key mappings, so users can install ready-made layouts without compiling firmware themselves.

Example use cases:

Profile Example Purpose
1 Default universal firmware
2 Media control
3 Rally navigation
4 Roadbook tablet control
5-8 Custom user layouts

Default OTA Behaviour

Profile 1 is the mandatory fallback firmware.

This binary should always be available.

Example:

ESP32-C3-12F-1.bin

After boot, OTA always defaults to profile 1.

This ensures a valid firmware image is always available, even if profile-specific firmware files are not hosted.


Selecting Profile-Specific Firmware

Firmware for profiles 2-8 is optional.

To request a profile-specific firmware image, you must explicitly select that profile before starting OTA.

This applies even if that profile is already active.

Example

If profile 4 is currently active and you want OTA to download:

ESP32-C3-12F-4.bin

You must reselect profile 4 before starting OTA.

This intentionally prevents OTA failures caused by missing profile-specific firmware files.


Why This Design?

This OTA design guarantees:

  • Profile 1 always works as universal recovery firmware
  • Optional profile firmware can be hosted only when needed
  • Users explicitly choose non-default firmware variants
  • OTA remains reliable even with partial firmware availability

Primary OTA (GitHub Release)

Firmware is downloaded from the latest GitHub release.

Example:

https://github.com/<repo>/releases/latest/download/ESP32-C3-12F-1.bin

Secondary OTA Fallback (Local HTTP)

If GitHub OTA fails, RCntrl V2 attempts local OTA using the current gateway IP on port 8080.

Example:

http://192.168.43.1:8080/ESP32-C3-12F-1.bin

Local OTA Using Android Hotspot

1. Enable Android Hotspot

Configure hotspot SSID and password to match firmware settings.


2. Start a Local HTTP Server

Recommended Android app:

Simple HTTP Server

Configure it to serve files on port:

8080

3. Copy Firmware Binary

Place the correct firmware file in the HTTP server root directory.

Example:

ESP32-C3-12F-1.bin

4. Trigger OTA Update

The controller will:

  1. Attempt GitHub OTA
  2. Automatically fall back to local OTA if GitHub fails

Recommended Workflow

Standard users

Use profile 1 OTA firmware.


Advanced users

Host additional profile-specific firmware builds for custom key mappings.


OTA Safety

If a profile-specific firmware file does not exist, simply reselect profile 1 and retry OTA.

This guarantees recovery using the default firmware image.


πŸš€ Workflow

  1. Edit keymapings.h.
  2. Recompile the firmware.
  3. Flash the firmware to ESP32.
  4. Switch to the desired profile and test.

License

This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License.
To view a copy of this license, visit CC BY-NC 4.0
or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.

About

RCntrl firmware v2 by Omadon

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors