February 10, 2022

Case closed on Nordic's nRF52-DK

Case closed on Nordic's nRF52-DK
Bluetooth Low Energy firmware applications have their inherent complexities. They’re structured as event-driven systems. That basically mean they react to “events” that can occur at any time. That’s physical event sources like button presses, battery alerts, and sensors inputs, but also to incoming Bluetooth communications from an App.

Bluetooth Low Energy firmware applications have their inherent complexities. They’re structured as event-driven systems. That basically mean they react to “events” that can occur at any time.  That’s physical event sources like button presses, battery alerts, and sensors inputs, but also to incoming Bluetooth communications from an App. In our experience, even top-tier chip vendors like Nordic Semiconductors provide subpar guidance on how to best orchestrate this system of events and reactions.

#include 

using namespace std;

//! fibonacci numbers with gratuitous use of templates.
//! \param n an index into the fibonacci series
//! \param fib0 element 0 of the series
//! \return the nth element of the fibonacci series
template 
T fib(unsigned int n, const T& fib0) {
  T a(fib0), b(fib0);
  for (; n; --n) {
    T tmp(a);
    a += b;
    b = tmp;
  }
  return a;
}

int main(int argc, char **argv) {
  cout << fib(10, 1U);
}

// Sample file using the Google C++ coding standard.
//
// http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
//
// General rules:
//   - Indents are two spaces. No tabs should be used anywhere.
//   - Each line must be at most 80 characters long.
//   - Comments can be // or /* but // is most commonly used.
//   - File names should be lower_case.c or lower-case.c
//
// Note: The Google C++ coding standard is a C++ coding standard. There are
// aspects specific to C that the coding standard does not specify, and these
// exceptions are noted below.

#include 
#include 

// For macros, use ALL_CAPS separated by underscore:
#define FLAG_FOO 0x0

// If a macro's replacement is not just a literal, enclose it in parentheses:
#define FLAG_BAZ (0x1 << 3)

// For constants, use k followed by PascalCase:
const int kStateFoo = 0;

// Type names should be PascalCase.
// Note: the Google coding standard does not specify how to format a struct
// name that has not been typedef-ed. I am following the lower_case separated
// by underscores format for now but this can be changed later.
typedef struct linked_list LinkedList;

// Enum values can either look like macros:
typedef enum {
  MODE_FOO,
  MODE_BAR,
  MODE_BAZ,
  MODE_QUX
} Mode;

// or they can look like contants:
typedef enum {
  kStateFoo,
  kStateBar,
  kStateBaz,
  kStateQux
} State;

// Names of members of structs are lower_case and separated by underscores:
typedef struct sample {
  int first_field;
  bool second_field;
  Mode mode;
  State state;
  struct sample *next;
} Sample;

// Function names are PascalCase. Opening braces come at the end of the last
// line for the function declaration rather than on the next line.
bool SampleEqual(Sample *self, Sample *other) {
  // Local variables are lower_case and separated by underscores.
  if (self == NULL && other == NULL) {
    return true;
  }

  if (self == NULL || other == NULL) {
    return false;
  }

  // For statements that span multiple lines, break after the logical operator
  // and align each line with the start of the first line.
  if (self->first_field == other->first_field &&
      self->second_field == other->second_field &&
      self->state == other->state &&
      self->mode == other->mode &&
      self->next == other->next) {
    return true;
  }
  // If the previous block ends with areturn (or break or continue), do not
  // follow it with an else.
  return false;
}

// For function declarations that span multiple lines, then align subsequent
// lines with the first parameter.
Sample *SampleNew(int first_field,
                  bool second_field,
                  Mode mode,
                  State state,
                  Sample *next) {
  Sample *sample = (Sample *) malloc(sizeof(*sample));
  if (sample == NULL) {
    return NULL;
  }

  memset(sample, 0, sizeof(sample));
  sample->first_field = first_field;
  sample->second_field = second_field;
  sample->mode = mode;
  sample->state = state;
  sample->next = next;
  return sample;
}

Sample *SampleClone(Sample *sample) {
  if (sample == NULL) {
    return NULL;
  }
  // For function calls that span multiple lines, align each subsequent line.
  return SampleNew(sample->first_field,
                   sample->second_field,
                   sample->mode,
                   sample->state,
                   sample->next);
}

// For function declarations (and function calls) where you cannot fit
// the parameters with the first after the opening parentheses, then align
// the parameters indented four spaces on the next line:
static void SampleDoSomethingWithALongName(
    Sample *sample,
    int parameter_with_a_long_name,
    bool another_parameter,
    int another_parameter) {
  if (sample == NULL) {
    return;
  }

  // else and else if comes after the previous closing brace and not on the
  // next line.
  bool local_variable;
  if (parameter_with_a_long_name == kStateFoo) {
    local_variable = true;
  } else {
    local_variable = false;
  }
  sample->first_parameter += another_parameter;
  sample->second_parameter |= local_variable;
}


static float = 1.345;
String test = "I am a string. How do I look?"


An unsuspecting developer may feel they’re using a lean approach, linking event sources in code to their corresponding reactions in a piecemeal fashion. The complexity of this patch network soon grows exponentially and starts feeling like a firmware savant is required just to make sense of it all. As the project grows, the event-reaction mappings grow in quantity and likely require being dynamically re-mapped in different modes of operation. If left untreated, the affliction can get the best of you, spreading faster than you add features. If you’re anything like us, there’s an inevitable face-the-music moment where this event-driven spaghetti code can no longer be tolerated.

This isn’t the glutinous spaghetti that you bite with your teeth. It’s the kind that compiles into bytes and bites to deal with. If you’re not aware of spaghetti code and its nauseating effects, then let’s briefly recap.  “Spaghetti code” is a slang term for code with convoluted structure, so much that it’s difficult to debug and and maintain it.

Ray Kampmeier
THT founder