Using A Custom Face Value With The Custom Blinklib

I thought I would give an example of using customized face values with the Custom Blinklib as I think this is an easier way to create more advanced games than using datagrams. The example below shows how to create the usual “single click changes color across the cluster” example but with a custom face value. Note that this example would not need and does not use everything provided by the face value but all we want to show is how to use it so this is fine.

The first thing to do is to create a project in the usual way but making sure that you use the Custom Blinklib instead of the official one.

Now lets define our face value. Create a file called face_value.h with the following contents:

#ifndef FACE_VALUE_H_
#define FACE_VALUE_H_

#include <blinklib.h>

struct FaceValue {
  // Our face value has a single data member which is an array of 5 bytes.
  byte data[5];

  // Because structs are not directly comparable, we need to overload the equality
  // operator.
  bool operator==(const FaceValue& f) const {
    // Save some storage space by interpreting the first 4 bytes as an uint32
    // and comparing that. In the end this is simply comparing every single byte in
    // the current face value and the one we are being compared to.
    return (*((uint32_t*)(data)) == *((uint32_t*)(f.data))) &&
           (data[4] == f.data[4]);
  }

  // Implement inequality based on equality. This should have been done by the
  // Compiler automatically but it was not. So we do it here. 
  bool operator!=(const FaceValue& f) const { return !(*this == f); }
};

#endif  // FACE_VALUE_H_

The above is simpler than it looks. I just wanted to use some tricks to show types of things you can do but you could as well, for example, just manually compare each byte in the array.

Now that we have our face value, we just need to tell the Custom Blinklib to use it. Create a sub-directory called config inside your project directory and create a file called blinklib_config.h with the following contents:

#ifndef BLINKLIB_CONFIG_H_
#define BLINKLIB_CONFIG_H_

#include "face_value.h"  // Our FaceValue.

// We are not using datagrams so we can save both space and memory by fully 
// disabling them.
#define BGA_CUSTOM_BLINKLIB_DISABLE_DATAGRAM

// Tell the Custom Blinklib to use our face value.
#define BGA_CUSTOM_BLINKLIB_FACE_VALUE_TYPE FaceValue

// Tweak timeouts as the bigger than usual face value would cause faces to timeout if 
// we do not do this. The right value to use will depend on the specific program and 
// how much work it does on every loop iteration.
#define BGA_CUSTOM_BLINKLIB_SEND_PROBE_TIMEOUT_MS 210
#define BGA_CUSTOM_BLINKLIB_FACE_EXPIRATION_TIMEOUT_MS 260

#endif  // BLINKLIB_CONFIG_H_

Now we can go straight to our program. Create a file called face_value.ino in your project directory (or any name.ino you might want) with the following contents:

#include <blinklib.h>
#include <face_value.h>

void setup() {}

static FaceValue value_;  // Our current face value.
static FaceValue previous_values_[FACE_COUNT];  // Face value on all faces.

// Colors we will use.
static Color colors_[] = {RED, GREEN, BLUE, YELLOW, MAGENTA, ORANGE, WHITE};

// Note that calls to all face value related functions look exactly the same. Only 
// handling the value changes.
void loop() {
  FOREACH_FACE(face) {
    if (isValueReceivedOnFaceExpired(face)) continue;

    if (previous_values_[face] != getLastValueReceivedOnFace(face)) {
      value_ = getLastValueReceivedOnFace(face);
      previous_values_[face] = value_;
    }
  }

  if (buttonSingleClicked()) {
    // We only sue the first byte for this example.
    value_.data[0]++;
  }

  // Set color based on the first byte of the face value data.
  setColor(colors_[value_.data[0] % 7]);

  // Send our face value on all faces.
  setValueSentOnAllFaces(value_);

  FOREACH_FACE(face) {
    // Check again if faces are expired and, if they are , set them to OFF. This helps
    // tweak the timeouts in blinklib_config.h. This could have bene doen in the other
    // face loop but I wanted to show this explicitly.
    if (isValueReceivedOnFaceExpired(face)) setColorOnFace(OFF, face);
  }
}

And that is it. Now you have a 5 byte face value to do as you please. :slight_smile: