Revisiting "Safely Sending Signals"

If you are starting to program Blinks, one of the must read information about how to do that is the “Safely Sending Signals” series by @danking222. That solution and his explanation of it really helps understanding how to propagate state across a cluster of Blinks. For reference, here are the posts:

Before I even realized those tutorials tutorials existed, I started rolling out my own version of propagating signals that although a lot more complex, also allows for more complex information to be transmitted (and replies to the information to be received for that matter).

Because of GGJ, I decided to look deeper into how Move38 recommended doing it (which was using Dan’s approach) and although it works really well, I was bothered by the fact that we had to use 2 bits of the face value for the house-keeping (remember there are only 6 bits available in the official Blinklib).

Thinking a bit more about it, I realized that the main issue it was trying to solve was the fact that simply setting a face value and checking face values from neighbors does not work as we would change our own value from A to B but then would read A back from a neighbor and basically getting the end result that nothing happens (either that or the state would keep ping-ponging from one value to another).

And then it downed on me that there is a different way to solve it that seems to work equally well and does not use the extra 2 bits. Here is my version of the program in “Safely Sending Signals”:

enum GameModes {
  MODE1,
  MODE2,
  MODE3,
  MODE4
};                               // these modes will simply be different colors
static byte game_mode_ = MODE1;  // the default mode when the game begins

static byte cached_face_value_[FACE_COUNT];  // Cache values received on all faces.

void setup() {}

void loop() {
  // Step 1: Check for changed values and cache what we get.
  FOREACH_FACE(face) {
    if (isValueReceivedOnFaceExpired(face)) continue;

    byte face_value = getLastValueReceivedOnFace(face);

    if (cached_face_value_[face] != face_value) {
      // State changed. Update our own.
      game_mode_ = face_value;
    }

    cached_face_value_[face] = face_value;
  }

  if (buttonSingleClicked()) {
    // Button clicked. Move to the next game mode.
    game_mode_ = (game_mode_ + 1) % 4;
  }

  // Render the current mode color.
  switch (game_mode_) {
    case MODE1:
      setColor(RED);
      break;
    case MODE2:
      setColor(YELLOW);
      break;
    case MODE3:
      setColor(GREEN);
      break;
    case MODE4:
      setColor(CYAN);
      break;
  }

  // Report our state to all connected Blinks.
  setValueSentOnAllFaces(game_mode_);
}

In other words, what I do is to cache the value received from a face and if that value did not change (even if it is different from my own value), I do nothing. Note this version was simplified to use the full face value but it works the same for values using only some of the bits.

It turns out that this code is also a lot simpler (and I assume easier to understand), which is a plus.

Hope this might help other developers.

4 Likes

I updated the post above to fix typos and to add some comments to the code.

Hey this looks similar to something I ended up trying to do with just the value on face propagating across all the blinks for mine too but it ended up not working out. But using the cache as a way to detect state change like you did here would have probably fixed this now that I think back on it. :thinking: now to go back and re-write my jam project for the third time…