Adding events to OLED

I’ve been trying to understand the OLED code, because I would like to be able to set a display of battery charging, or the percentage charged or whatever. But I clearly don’t understand how does the timing iteration of things happen. I haven’t even understood how time is iterated in a style.
I went straight to charging.h, saber.h and events.h. And may be is because I only know C and nothing fancier than an overloading of an operator. But I can’t see how things iterate and how events are generated. Nor how one “hooks” to an event.
I did noticed that you have five colors, so may be with 5 or 7 pictures it would be enough. Like starting the charge, five levels (might be animated) and done. If you can help me a bit on how this work I might be able to write some pseudo code (or even actual code).

5 colors? Not sure what that is referring to.

In general, the oled display code is split into two pieces:

  1. A “controller” which decides what is shown
  2. A “driver” which sends the drawn images to the display

In most cases, what you want to mess with is the controller. Either by adding things to it, or by creating a new one.

The driver calls fillFrameBuffer on the controller to have it draw things. This can happen multiple times per image, so the controller has to be ready to re-draw the same frame over and over again if needed.

The controller also inherits from SaberBase, which lets it receive the same events that blades and hybrid font does, and lets it select what to draw based on that. You can see a selection of what it does with that here:

So far all of this is fairly simple, where gets complicated is when loading images and animations from the SD card…

I was referring to the “charging.h” in particular, which has 5 “levels” or colors:


// Usage: &style_charging
// return value: POINTER
// Charging blade style.
// Slowly pulsating battery indicator.

#include "blade_style.h"

class StyleCharging : public BladeStyle {
  void activate() override {
    STDOUT.println("Charging Style");
  void run(BladeBase *blade) override {
    int black_mix = 128 + 100 * sinf(millis() / 500.0);
    float volts = battery_monitor.battery();
    Color8 colors[] = {
      Color8(0,255,0),   // Green > 4.0
    float x = (4.0 - volts) * 2.0;
    int i = floorf(x);
    i = clampi32(i, 0, NELEM(colors) - 2);
    // Blend colors over 0.1 volts.
    int blend = (x - i) * 10 * 255;
    blend = clampi32(blend, 0, 255);
    Color8 c = colors[i].mix(colors[i + 1], blend);
    c = c.mix(Color8(), black_mix);
    int num_leds = blade->num_leds();

    float min_volts = 2.7;
    float max_volts = 4.2;
    float pos = (volts - min_volts) * num_leds / (max_volts - min_volts);
    int p = pos * 32;
    for (int i = 0; i < num_leds; i++) {
      blade->set(i, Color16(Color8().mix(c, std::max(0, 256 - abs(p - i * 32)))));

  bool NoOnOff() override { return true; }
  bool Charging() override { return true; }
  bool IsHandled(HandledFeature effect) override { return false; }
// No need to templetize this one, as there are no arguments.
StyleFactoryImpl<StyleCharging> style_charging;


From that code I guess I could also send something to the OLED, or it doesn’t works that way? I will have to investigate the headers you mentioned tomorrow.

I see.
the OLED display already have a battery level meter though:

(PLI means “power level indicator”)



And while it may be a little counterproductive to keep the display on while trying to charge the battery, in the current GitHub Master, you can use #define PLI_OFF_TIME to set how long until it turns off.
However, will only work if you don’t have an idle.bmp showing and it’s actually the PLI being displayed.
IDLE_OFF_TIME is the other timer, although I think that’s bypassed if you’re using a Charging style.

I assume this refers to the time before the battery level display shuts off? The saber I’ve just built has this at about 5 seconds I think. Is that the parameter that this define controls?

Also can this define be added to the config.ini file that’s kept in the folder on the SD card that contains all the other OLED files, or does it have to be added to the main config?

It’s a relatively new define that goes in your main config file.
It will blank the display (power off with latest updates) at the specified time if the PLI is showing.

I’ve literally just got round to looking into it, and I can see by default that it follows the font/boot display time. Think I’m gonna change it to 30 * 1000 to make it 30 seconds. :slight_smile:

Are we talking about 6.7 or 7? Because I’ve been trying to understand the code in my local repository (6.7) and I’ve found many differences with the code in the default Github repository. Not the least of all that prof has been fixing indenting tabs. If made understanding my local repository pretty confusing.

I would suggest just referring to the latest master version on GitHub.
While perusing older code can prove educational, it’s probably best to wrap your head around how things are most currently implemented so as not to “waste” brain cell resources on outdated things.