Golang pointer receiver compilation error

September 5, 2019

I recently ran into a common problem while doing a bit of work in Go. I did a fair amount of searching and didn’t find any good help on it. I did finally figure it out, and when I did I realized how correct, and misleading, the message is.

Here’s the basics of what I wanted to do:

type usefulInterface interface {
    DoSomething()
}

func helloThere() {
    var aVar usefulInterface
    //  get something that implements the usefulInterfaace
    aVar.DoSomething()
}

Fundamentally, I’ve got an interface because I’m going to use a Factory or a Strategy pattern and I’m abstracting one bit of code from another by using the interface (standard design stuff).

Now let’s implement the interface:

type usefulService struct{}

func (theService *usefulService) DoSomething() {
    log.Println("myService.DoSomething")
}

Nothing special here, a typical implementation.

Now the fun part:

func newUsefulService() usefulService {
    service := usefulService{}
    return service
}

func helloThere() {
    var aVar usefulInterface
    aVar = newUsefulService() // method has pointer receiver error here
    aVar.DoSomething()
}

And there’s the error:

cannot use newUsefulService() (type usefulService) as type usefulInterface in assignment:
usefulService does not implement usefulInterface (DoSomething method has pointer receiver)

The whole thing revolves around the phrase “pointer receiver”. This is Golang specific terminology for the (theService *usefulService) part of the function expression binding the DoSomething method to the usefulService type. In this case, I’m using a pointer receiver ( the *usefulService) as opposed to a value receiver: (theService usefulService)

Ah!!! So, all I have to do is change these to value receivers and the interface implementation will work!

func (theService usefulService) DoSomething() {
    log.Println("myService.DoSomething")
}

And there it is, everything compiles.

HOWEVER!!!

The DoSomething method has a VALUE RECEIVER… the method gets a COPY of the usefulService structure… mutations of the structure won’t be preserved between calls!

How do you have a pointer receiver and assign to the interface variable? The newUsefulService function needs to return a pointer to the service, not a value…

Switching usefulService.DoSomething() to a pointer receiver and adjusting newUsefulService() to return a pointer fixes everything:

func (theService *usefulService) DoSomething() {
    log.Println("myService.DoSomething")
}

func newUsefulService() *usefulService {
    service := usefulService{}
    return &service
}

So the error message

does not implement ( method has pointer receiver)

is pointing out a mismatch in the use of pointers relative to your interface, your struct method, and your variable assignment.

Agile Practices: Retrospectives

June 19, 2019

Looking today at the other side of the timebox, after the timebox finishes, does your team take a moment to reflect, review, or celebrate?  If you are not, you’re really missing out on a great opportunity to allow the team to see their successes, to self-improve and for management to actively work for the team.  Further, you’re not following the Agile Manifesto’s 12th principle:

At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.
http://agilemanifesto.org/principles.html

Allowing the team to see their successes is vitally important.  Engineers are all too often focused on the current and next sets of problems.  They rarely see what it is that they’ve actually accomplished.  It is even more rare for an engineer to meet with a real end user, to see what they’ve built being actively used.  I personally have found those opportunities to be hugely energizing, but have only had them occur occasionally.  The retrospective gives the team a chance to identify things, people, situations that worked well, exceeded expectations, or were all around good.

The reasons for not conducting retrospectives usually involve team negatives and timelines.

There isn’t time in the schedule

Your timelines are so tight that a 1 hour team meeting puts the schedule at risk?  It is too invasive to have the team come together and find ways to work better?  You really think that how things are done today is the absolute best way?  There’s no possible improvements?  The team is too untrustworthy to constructively find improvements in themselves, or their processes or the environments?

But, there is time for the weekly leadership/status meeting where the team is told they are behind schedule and need to find ways to get this whole thing done more quickly?  There’s time for the quarterly townhall where they are told how awesome the company is doing and how important their work is to the continued success of said company, Rah! Rah! Rah!?  I would suggest that you can afford to squeeze an actually useful meeting into your schedule, especially one that can reveal useful actions to positively affect the development effort.

We’ll do it after each release

This is a step in the right direction.  However, waiting until the end of a release cycle (sometimes 3 or 4 2-week sprints, yes? So, 6- 8 weeks?) is fraught with near term bias issues as well as delays in affecting change.  It really needs to be done after each timebox.  That said, depending on your situation and how directly the team is involved with production deployments, turning the release activities into a celebratory conclusion of many weeks of hard effort can count for a fair amount of team building.  It can also help create a culture where everyone on the team becomes willing to pitch in to ensure everything goes well with the deployments.

The team is so hyper critical of each other

They likely need guidance on how to be constructive during this process.  Too often retrospectives become opportunities for upset team members to call out others.  Each team culture is going to be different, but we can never allow anyone to single another out negatively.  Criticize the tools, the process, or the environments, but not each other.  It just isn’t productive or useful.  If this is all new to the team then some grace and forgiveness should be allowed, but perpetual disregard for this should not be tolerated and the offending team member should be removed from the meeting.

Management tears down the team

This is one of the main reasons why I prefer retrospectives to primarily be the immediate development team, the scrum master and the product manager.  The rest of the stakeholders can read the summary notes and recommendations.  If you have excellent relationships and communication with the other stakeholders, then ok – that’s actually how it is supposed to be.  But most teams don’t have this ideal.  Having the management team criticize the team directly and consistently typically doesn’t improve anything.  Worse, in these situations the team’s recommendations and advisements are usually dismissed or ignored.

What you have here is an adversarial situation where the team isn’t trusted.  If the team isn’t trusted we’ve also lost track of the 5th principle:

Build projects around motivated individuals.  Give them the environment and support they need, and trust them to get the job done.
http://agilemanifesto.org/principles.html

We need to trust the team

And we need to help them constructively get through the retrospective.  We need to first encourage the identification of successes during the increment.  I don’t care how badly the sprint went, some things went well or were done as planned.  Secondly, we need to keep the team’s identified improvements focused on tools, processes, environment, etc., and away from personal attacks.  This perspective is critical.

I like to see retrospectives in a closed meeting room with a lot of 3″x3″ post-it notes, preferably in two different colors.  The size of the note restricts most people to simple phrases or a sentence or two and the colors are used to identify successes and improvements.  Each team member must put one up for each, but no more than 3 for each.  YMMV here but the idea is to require the team to think in both areas, but limit the totality of things that need to be categorized.  The scrum master then reviews them all, talking through each with the team to ensure that it is understood, and categorizes it with the team’s blessing.  Finally, we re-walk through the categories and identify ways of capitalizing on the successes and improvements making recommendations to the team leadership and to themselves as specific as practical.

Reflection is good

We generally don’t do enough of it as individual developers, and definitely not as teams.  Retrospectives provide that opportunity for the team to think about what just happened, celebrating the good, self-correcting what it can and find ways for management to intercede on its behalf.  Not doing a retrospective relegates feedback and reflection to ad-hoc processes that rarely results in the kinds of overall improvements the team at large can achieve when working together.

Agile Practices: Timebox Planning

June 17, 2019

With timeboxes in general reviewed, I’m going to next look at the edges of the timebox starting with the process by which the team accepts work into a timebox.  As discussed as part of timeboxes, the team itself must be doing the commitment.  However, even if they are not, the two ideas presented below will still be applicable.

How much can we get done during a timebox?

This is a common pain point for teams.  This is especially true when the team itself isn’t making the commitment.  Without some empirical data aiding the selection of work most anything chosen is likely a guess, or worst, simply forced on the team.  The Agile Manifesto’s Principle 8 is all about sustainable development for the team and stakeholders.  Timebox planning is critical to achieving that sustainability.

Team Velocity

Team velocity allows the team and stakeholders to estimate what amount of work may be achievable during a timebox.  It isn’t a guarantee of the commitment but it is an interesting estimate that’s more refined than t-shirt sizing.  After the team plans a few times (say 3-4 timeboxes) the number of story points that are actually completed in each timebox can be averaged – this average becomes the team’s velocity.  For timebox planning, the velocity allows us to look at the prioritized backlog and draw a line at where the team can PROBABLY get to (sum of story points above the line being approximately the current value of the velocity).  What specifically the team can commit to is going to depend on how the story tasking goes and the general story point values above that line.

The team’s velocity can, and will, change over time.  The team will get better, improving common development tasks and designs, create optimizations such that the previous story sizes baselines now are misaligned.  The team will also change composition over time.  Adding and removing team members will create jitter in the velocity value.  Company holidays will do that as well.  If a team works together long enough a moving average of the velocity can smooth out some of that jitter.

Story Tasking

Story tasking is also something I don’t often see during the planning ceremony.  More often I’ll see a set of stories dropped in front of the team that they’ve never seen before and then specific team members asked to take on certain stories.  Some of the remainder of the team tries to figure out however they can contribute by volunteering for what they can.  Eventually the leads realize that not everyone has an assignment so they dole them out to people ill prepared to handle them.

What I prefer to see is taking the highest priority story off the backlog and then breaking it down into the individually necessary tasks for the story.  The team should do this together.  Those with direct knowledge/responsibility should be the principle contributors to the task list, but those who are not should also listen in, learning, asking questions, even suggesting some tasks that were overlooked (e.g. “So, after you’ve finished with that new API, who updates the client facing documentation with the new entry point details?”)

Task sequencing and/or dependencies are noted and then these tasks are estimated in terms of the number of hours necessary to complete for a single person.  I prefer to see individual tasks being no more one logical business day worth of effort (there’s good arguments that 6 hours is the most hours per day a developer should commit to due to obligatory overhead: scrum meetings, grooming, weekly team meetings, random training, etc.).  If a task is two business days I’d prefer to see two tasks created.  This allows the team to see daily progress on the story board and it better allows for the identification of stalling stories.

The tasks are then assigned to members of the team (preferably voluntarily but sometimes they just have to be assigned).  At some point a developer will reach the maximum number of work hours in the timebox and is no longer eligible to pick up new work without putting an equivalent number of hours back onto the table for the team to pick up.  How this is negotiated is going to be specific to the dynamics of each team.

Once all of the developers have maxed out their hours of assignable tasks, no more stories can be added to the increment.  In an ideal world, the tasking works out perfectly with an exact right amount of work for every member of the team.   Of course this never happens, so when there’s more hours of tasks than available developers, that story is put back down and not included in the timebox commitment.  The team then looks down the priority list to see if we can find one that can be pulled in instead.

If there is none that can be reasonably pulled in, then we don’t worry about it and we proceed with the stories that have been committed to.  If everything goes well, and there’s time left in the timebox at the end, the team can review the backlog again to see if anything new has come up that can be pulled in easily.  But, we all know that the development process is non-linear with circumstances and events causing delays or problems that can easily use the available time.

The Team’s Commitment

All of this comes back to ways of helping the team own the commitment of the timebox.  Velocity helps the team itself directly understand what recent historical has said they can accomplish.  Story tasking helps ensures that neither the team, nor any individual, is over-committed.  Together, the team should become comfortable with its ability to commit to work within a timebox and be able to operate at a sustainable pace.  Further, management can use the measurable values to aid the short and near term planning efforts.  To not use these practices removes useful tools from which both the team and management can benefit.

Agile Practices: Timeboxes

June 13, 2019

The first of my key agile practices are timeboxes/sprints/increments.  They are common to most agile development methodologies.  The purpose is to set a scope for the development team to achieve during a fixed period of time.  Traditional recommendations are for timeboxes are 1 to 4 weeks, but YMMV.  The intent is to allow the team to focus on a (relatively) fixed set of deliverables ideally that can be put into production at the conclusion of the timebox.

Timeboxes by themselves are a neutral practice.  Their effectivity is determined by a few things that go around them, the most influential is who is doing the commitment for the timebox.  Ideally, the commitment is done by the team.  They pick the top-most stories from a prioritized, and groomed, backlog until they are uncomfortable with making any additional commitment.  I’ll go into timebox planning in a later post.

In reality, the backlog is often not groomed or prioritized, and the team often isn’t who is making the commitment.  Skipping over the issue of the backlog for now, if the team isn’t making the commitment, then who is?  Typically, it is going to be the team/technical lead or the product manager.

When I see this circumstance (and I personally have been in this situation, both as the lead and as a team member), we have to look at why.  It is often the case that someone, possibly in an overseeing management role, or the lead or product managers themselves, considers the person doing the commitment to be better than the team at-large at estimating what the team can do.

This is a possible red flag (yes, I’m going to red flag my past self).  Let’s say the commitments are perfect… the person making the commitment for the team is getting it perfect every time – each feature is completed on schedule, is fully tested and works perfectly in production just as it was imagined it would.  In this perfect scenario, the team is still losing out.  We never provide safe ways to fail and learn.  We never develop new leaders or new experts.  We have traded improving the team for the repeated successful delivery of the product.

But, the sprints are not actually successful, are they? 

More typically, what we have is Agile’s version of a death march – the increment is not completed, and instead of learning from the failure, we double up on the commitment for the next timebox… we might even start suggesting that we need an integration or stabilization sprint to account for the software not being ready for delivery at the end of the timebox.  Management starts to think that the team is incapable of executing properly… they must need some more training on how to be a high performing team…

But, this is fixable. 

Allowing the team to make the commitment both fixes a number of things and brings to light real team problems for management to consider.  Side-stepping problems related to the team being self-destructive, when the team makes a commitment, the team then owns the delivery of the commitment.  People tend to try to meet their obligations when they make them for themselves.  People tend to disregard obligations when others make them for others…

What if they are wrong and:

  1. They completed everything early?  If we’re before the completion of the sprint take the team back to the backlog and find something they thing they can finish in the remaining time.  During the next sprint planning, bump the commitment level a bit and see how it goes.  Having a few extra prioritized stories ready to go as stretch goals or for contingency purposes is “a good thing”.
  2. They tried to accomplish more than they could?  Assuming they did successfully deliver some stories, lower the commitment level for the next increment a bit.
  3. They didn’t complete anything?  There are many causes for this: weak stories, weak tasking, weak team knowledge, etc.   Looking at how the team analyzes the successes and failures of the timebox and their recommendations via the retrospective will be critical here.
  4. They won’t commit to anything?  There are no easy answers here, but you’ve probably created a culture that precludes failure or are offering stories that the team doesn’t have enough detail or knowledge to bring to completion (ignoring the analysis paralysis sorts of situations).  The fear culture is something that’s going to require a lot of work to improve, but in both cases, trying to break up the existing stories into smaller stories that have less risk, ambiguity, or failure paths, is going to move the team in the right direction.

After allowing the team to make the timebox commitment we can’t expect them to get it correct the first few times – this is an experimentally learned process.  The value is in the team’s ownership of the commitment.

What if they don’t build enough fast enough?

Well, that’s something different entirely.  Agile doesn’t build code faster, it builds what is currently important.  The common problem here is where there’s a whole number of equally super urgently high priority that must be done by next Thursday…. I’ve seen in both agile and waterfall where management individually assigns tasks/stories/whatever to team members in an effort to push important/pet/special/not-prioritized things forward.  These efforts often fail.  If they do work, then it is because of the hero work of some small number (one?) of team members.  Everything about this is wrong.  Management comes to single out these hero workers as the examples of “the best” employees when in fact the rest of the team is trying to pick up the obligations of those who were “re-prioritized” increasing the pressure and probability of failure on the remainder of the team.

Oh, but the production support obligations!

If you’re dealing with a couple of high priority issues per timebox, then understand that some minor impact (read: stories that won’t be completed) will occur to the commitment (scenario b above).  If you’re dealing with a lot of high priority issues per timebox, have the team commit to an appropriately lesser effort per timebox, BUT (this is where the prioritized backlog shines) ensure there are extra stories ready to go in case there’s time left in the timebox to pick up some extra work.  In either case make sure all issues completed during the timebox after commitment are reported and identified as accomplishments.  Over time the team will naturally adjust the commitment to be what it needs to be.

Timeboxes are a critical component of most agile systems

But timeboxes alone don’t solve anything.  If the team isn’t making the commitment then the team won’t own the commitment.  We need to look also at the timebox planning, retrospectives and team composition as they all feedback directly into the success of the team and what can be done during the timebox.

Agile Practices: What Works, What Doesn’t, and Why IMO

June 13, 2019

I’m not a certified agile coach or scrum master.  I’m an experienced technical/team lead/architect who has built high performing teams and delivered successful projects in many industries using different technology sets.  I’m an agile-ist at heart, but have worked and lead through variations of waterfall.  I’ve seen teams (mine in some cases) struggle with agile.

However, I think I’ve narrowed down some key practices that when done well, can significantly enhance the productivity of the team.  The interesting thing is that most of these practices are facilitating, each helps the others, so when one of them is substantially broken, the whole process falls apart on itself.

That said, it is all fixable.  Even with an imperfect team, and in imperfect circumstances (read: most people’s situations),  we can make improvements that can start making the team’s life better.  However, there are some things that can’t be easily overcome.  When seen, these are red flags that may need significant effort by the management team to influence.

Key Practices

Pedersen’s Software Development Principles

March 26, 2019

Over the last year I’ve had a couple of opportunities to teach the fundamentals of Software Engineering over the course of a week.  Each week I wrap the discussion with these 7 “principles” which I’ve found to be very consistent across my career.

  1. (Pedersen’s Conjecture) All software design problems can be addressed by the correct application of the principles of coupling and cohesion.
  2. Powers of 2 just work better with computers. So when you have the opportunity to pick a number, use a power of 2; unless you’re trying to break something, then use a power of 2 +/- 1 or 2.
  3. Unit tests are not a burden, they are the demonstration of professionalism that is all too commonly lacking in our peers.
  4. The desire to optimize anything should be treated as a cold symptom. You should get some sleep before continuing down that path.
  5. Any magic used to make a developer’s life easier always breaks in a way and at a time as to make their life much worse.
  6. There are 100 ways to do anything in software; 2 are known good, 2 are known bad, the remaining 96 are all arguable.
  7. A test that is intermittently failing will change to constantly failing immediately before any deadline thereby causing you to spend time fixing the test now when you can least afforded to so.

Sending MIDI data with the Launchpad Pro

May 10, 2017

Now that we have basic pad handling in place it is time to start doing something musical with the Launchpad Pro.   So I’m going to replicate something akin to the chromatic keys mode of the Launchpad Pro?  No, I’m not going to replicate the whole new scales mode that was released with firmware version 1.4, but we’ll step generally into that direction.

There are two key parts to this:

  • Initial rendering of the display
  • Reacting to the key press and generating the midi event

Rendering the Chromatic Key Display

I’m going to make a few simplifying assumptions for the purpose of this demonstration:

  1. The tonic will be C and nothing else, no changes
  2. No shifting of the octaves – what’s on grid is what you get

So, given those assumptions we can start with pad 11 as C2, which is MIDI note 36 (check out the nice reference at midikits.net and we can initialize our grid data from there using Novation’s partially overlapping row layout.

#define TONIC_R  (32)
#define TONIC_G  (0)
#define TONIC_B  (32)

#define WHITEKEY_R (0)
#define WHITEKEY_G (0)
#define WHITEKEY_B (63)

#define BLACKKEY_R (0)
#define BLACKKEY_G (0)
#define BLACKKEY_B (0)

#define BLACK_R (0)
#define BLACK_G (0)
#define BLACK_B (0)

u8 notegrid[100];
u8 colorgrid[100];
u8 tonic = 36;

void app_init()
{
  u8 note = tonic ;

  for ( u8 i = 0 ; i < 100 ; i++ ) 
  {
    if ( i < 10  || i > 90) 
    {
      // lowest or highest row
      notegrid[i] = -1 ;
      colorgrid[i] = -1 ;
      hal_plot_led( TYPEPAD, i, BLACK_R, BLACK_G, BLACK_B ) ;
    }
    else if ( i % 10 == 0 )
    {
      // left column
      if ( i > 10 )
      {
        note -= 3; // new row so back up the note index a bit
      }
      
      notegrid[i] = -1 ;
      colorgrid[i] = -1 ;
      hal_plot_led( TYPEPAD, i, BLACK_R, BLACK_G, BLACK_B ) ;
    }
    else if ( i % 10 == 9 )
    {
      // right column
      notegrid[i] = -1 ;
      colorgrid[i] = -1 ;
      hal_plot_led( TYPEPAD, i, BLACK_R, BLACK_G, BLACK_B ) ;
    }
    else
    {
      notegrid[i] = note;
      if ( IsNoteTonic(note) )
      {
        colorgrid[i] = 2 ;  //flag for tonic
        hal_plot_led( TYPEPAD, i, TONIC_R, TONIC_G, TONIC_B ) ;
      }
      else if ( IsNoteWhiteKey(note) )
      {
        colorgrid[i]  =1 ; // flag for white key
        hal_plot_led( TYPEPAD, i, WHITEKEY_R, WHITEKEY_G, WHITEKEY_B ) ;
      }
      else
      {
        colorgrid[i] = 0 ; // flag for black key
        hal_plot_led( TYPEPAD, i, BLACKKEY_R, BLACKKEY_G, BLACKKEY_B ) ;
      }

      note++ ;
    }
  }
}

This code will initialize arrays of note and color data as well as set the initial pad colors.  The colors should looks something similar to the normal Novation chromatic scale mode.

Determining the colors of the musical pads comes down to a couple of functions that rely on midi data arrangements:

u8 IsNoteTonic( u8 note )
{
  // any multiple of tonic + 12 will mod to 0
  return (( (note-tonic) % 12) == 0) ;  
}

u8 IsNoteWhiteKey( u8 note )
{
  if ( (note %12) == 0 ) return 1; //C
  if ( ((note-2)%12) == 0) return 1; //D
  if ( ((note-4)%12) == 0) return 1; //E
  if ( ((note-5)%12) == 0) return 1; //F
  if ( ((note-7)%12) == 0) return 1; //G
  if ( ((note-9)%12) == 0) return 1; //A
  if ( ((note-11)%12) == 0) return 1; //B
  return 0 ;
}

u8 IsNoteBlackKey(u8 note)
{
  if ( ((note-1) %12) == 0) return 1; //C#
  if ( ((note-3) %12) == 0) return 1; //D#
  if ( ((note-6) %12) == 0) return 1; //F#
  if ( ((note-8) %12) == 0) return 1; //G#
  if ( ((note-10) %12) == 0) return 1; //A#
  return 0;
}

N.B. we could flip the white/black key assignment logic in app_init by using the IsNoteBlackKey function and save a couple of CPU cycles since the IsNoteBlackKey function is two if-statements shorter in the worst case.

Sending MIDI

The hal_send_midi function is what we are really interested in today.  It takes 4 parameters, the first of which is the port to send the MIDI data out on.  We can choose DINMIDI for the traditional 5 pin DIN MIDI connector, or USBMIDI to send out the USB connection (to be received by something like Ableton).  There is also USBSTANDALONE, but unfortunately I have been unable to locate any documentation about that setting.

The last three parameters are the heart of MIDI data.  Many MIDI messages amount to sending three bytes of data: a MIDISTATUS byte and two data bytes.  For this post I’m only interested in sending NOTE ON and OFF messages.  The MIDI status byte is divided into two nibbles where the high nibble indicates the type of message (NOTE ON, NOTE OFF, PROGRAM CHANGE, CONTROL CHANGE, etc.) and the low nibble indicates the MIDI channel.   If we set up constants for NOTE ON and OFF with the data in the high nibble (i.e. 0x90 for on and 0x80 for off), we can bit-wise OR the channel number into the low lower nibble.  For example:

u8 midistatus = 0x90 | 0x01 ;  // MIDI NOTE ON for channel 2

The remaining two data bytes are specific to each type of message.  In our case, NOTE ON/OFF requires the note to play (we can use the notegrid array for that value) and the velocity of the pad press.

The app_surface_event method is interesting in that while it provides a velocity value (the third parameter “value”), it really only allows for key press velocity, not key off velocity.  It uses a value of 0 to indicate key off and 1-127 as the key on velocity.  So, in our case we can use the value parameter to tell us to send a MIDI NOTE ON or OFF, and use it to send the MIDI NOTE ON velocity value.  For NOTE OFF we will have to make something up…

Putting it all together

Let’s put that to use in the app_surface_event function:

#define MIDI_STATUS_NOTE_OFF (0x80)
#define MIDI_STATUS_NOTE_ON (0x90)

// actual midi channel is 6
// as that's where my http://www.audiothingies.com/product/micromonsta/ is...
u8 midiChannel = 5; 

void app_surface_event(u8 type, u8 index, u8 value)
{
  if ( type == TYPEPAD )
  {
    if ( index < 10 || index > 90 )
    {
      // top or bottom rows
    }
    else if ( (index % 10 == 0) || (index % 10 == 9) )
    {
      // left or right columns
    }
    else
    {
      // ONLY CARE ABOUT THE CENTER 64 PADS
      u8 lightUpLowerRow = (index % 10 < 4) && (index > 20);
      u8 lightUpUpperRow = (index % 10 > 5) && (index < 80);

      // VALUE == 0 INDICATES PAD BEING RELEASED
      if ( value == 0 )
      {
        if ( colorgrid[index] == 2 )
        {
          hal_plot_led( TYPEPAD, index, TONIC_R, TONIC_G, TONIC_B ) ;

          if ( lightUpLowerRow )
          {
            // light up the pad on the lower row
            hal_plot_led( TYPEPAD, index-5, TONIC_R, TONIC_G, TONIC_B ) ;
          }
          else if ( lightUpUpperRow )
          {
            // light up the pad on the upper row
            hal_plot_led( TYPEPAD, index+5, TONIC_R, TONIC_G, TONIC_B ) ;
          }
        }
        else if ( colorgrid[index] == 1 )
        {
          hal_plot_led( TYPEPAD, index, WHITEKEY_R, WHITEKEY_G, WHITEKEY_B ) ;

          if ( lightUpLowerRow )
          {
            hal_plot_led( TYPEPAD, index-5, WHITEKEY_R, WHITEKEY_G, WHITEKEY_B ) ;
          }
          else if ( lightUpUpperRow )
          {
            hal_plot_led( TYPEPAD, index+5, WHITEKEY_R, WHITEKEY_G, WHITEKEY_B ) ;
          }
        }
        else
        {
          hal_plot_led( TYPEPAD, index, BLACKKEY_R, BLACKKEY_G, BLACKKEY_B ) ;

          if ( lightUpLowerRow )
          {
            hal_plot_led( TYPEPAD, index-5, BLACKKEY_R, BLACKKEY_G, BLACKKEY_B ) ;
          }
          else if ( lightUpUpperRow )
          {
            hal_plot_led( TYPEPAD, index+5, BLACKKEY_R, BLACKKEY_G, BLACKKEY_B ) ;
          }
        }
        // SEND MIDI NOTE OFF with high velocity since we don't know what it was
        hal_send_midi( DINMIDI, MIDI_STATUS_NOTE_OFF | midiChannel, notegrid[index], 127) ;
      }
      else
      {
        hal_plot_led( TYPEPAD, index, KEYPRESS_R, KEYPRESS_G, KEYPRESS_B ) ;

        if ( lightUpLowerRow )
        {
          // light up the pad on the lower row
          hal_plot_led( TYPEPAD, index-5, KEYPRESS_R, KEYPRESS_G, KEYPRESS_B ) ;
        }
        else if ( lightUpUpperRow )
        {
          // light up the pad on the upper row
          hal_plot_led( TYPEPAD, index+5, KEYPRESS_R, KEYPRESS_G, KEYPRESS_B ) ;
        }
        
        //SEND MIDI NOTE ON with provided value as velocity
        hal_send_midi( DINMIDI, MIDI_STATUS_NOTE_ON | midiChannel, notegrid[index], value) ;
      }
    }
  }
}

I don’t love all that duplication of if-statements but there’s really only one real alternative algorithm and it leads to less readable code for no significant benefit.

Wrapping up

Throw that all in an app.c, compile it (with the missing callbacks) and load it into your Launchpad Pro.  You will end up with an overlapping chromatic grid similar to the normal one that emits to MIDI channel 6.

Steps beyond this would be:

  • Support moving through the octaves
  • Hook the SETUP button to allow the user to:
    • pick a MIDI channel
    • pick a scale
    • Pick a key

Handling Pad Events on the Launchpad Pro

March 19, 2017

Building from the basic understanding of how to affect the Launchpad Pro pads, the next thing we will be interested in doing is taking an action when a pad is pressed.

The API defines a number of callbacks that we can hook into to do interesting things. The one we’re interested in today is:

void app_surface_event(u8 type, u8 index, u8 value);

Like the hal_plot_led API call, the type parameter is either TYPEPAD or TYPESETUP allowing us to know when the setup button is pressed as opposed to a normal pad. Similarly, the index parameter tells us which pad is pressed (and can be ignored when the type parameter is TYPESETUP).

The last parameter, value, is different. When a pad is initially pressed, the app_surface_event callback is invoked with a value 1-127. When the button is released, the app_surface_event is invoked with a value of 0. You can see this in action with this bit of code:

void app_surface_event(u8 type, u8 index, u8 value)
{
    hal_plot_led( TYPEPAD, index, value/2, value/2, value/2) ;
}

It will initially alter the pressed button to be some intensity of white depending on how hard the button was pressed. When the button is released a second event with a value of 0 will be received and the pad will turn off.

It is important to note that without the code above pressing a button has no effect. However, that means we can make it do anything we want it to do… such as sending MIDI data…

Setting the Colors on the Launchpad Pro’s Pads

March 18, 2017

Now that I have figured out how to re-program the firmware on the Launchpad Pro it is time to do something useful with it. There’s multiple parts to what I have in mind but today I experimented with coloring the pads.

There is a nice API for setting the color of a pad. From the app.h include file we find:

void hal_plot_led(u8 type, u8 index, u8 red, u8 green, u8 blue);

The first parameter, type, has two possible values: TYPEPAD and TYPESETUP. TYPEPAD is used to address the round and square pads on the Launchpad Pro. TYPESETUP is used for the recessed setup button in the upper left corner of the device. When using TYPESETUP, the second parameter (index) is ignored and the color of the vertical LED on the bottom edge of the device is altered.

The second parameter, index, is used to address the pads on the device. Check out the Novation documentation for a nice picture of the pad indexing but the summary is this: values 0 to 99 starting from the bottom left corner, moving left to right and moving up. So the “Record Arm” button is index 1, while the “User” button is index 98. Indexes 0, 9, 90 and 99 are not mapped to anything. One might think that index 90 would address the Setup button, but it does not.

The last three parameters are fairly obvious: the red, green and blue values required to render a color. Note that RGB values are often expressed as values 0-255. The Launchpad Pro uses 0-63. Therefore, if you use a site like http://htmlcolorcodes.com/color-names/ to find colors you will need to divide the individual values by 4 for similar colors on the Launchpad Pro. RGB(0,0,0) normally corresponds with black. But for our Launchpad, it turns the pad off.

With the API well in hand I’m going to need to create visual differences between a button that’s active and a button that’s available but not active, and a button that’s off or unavailable. Certainly, RGB(0,0,0) will suffice for off/unavailable but how should we represent available but not active? Working with good strong colors like RGB(63,0,0) and RGB(32,0,32) I experimentally determined that dividing each value by 4 or 8 yields a clear enough difference between the full color (active) and reduced color (available) but still allows for a color that properly represents the full/active color.  So, for a nice purple with active/full as RGB(32,0,32) we can use RGB(8,0,8) for the inactive/available situations.

Instructions for Launchpad Pro Firmware Development

March 11, 2017

A bit ago while I was answering a question in the Facebook Circuit Owners group I mentioned that I’d not been able to figure out how to program my Launchpad Pro. It didn’t sit well with me after I wrote that statement. I’ve been a software developer for a long time and embedded systems is my original area of specialty.  What could possibly be that hard about it? So, I went back for a second (actually third) look at what it took…

The original release of the Launchpad Pro celebrated the open platform that Novation was providing as part of the product release. The primary documentation for working with that platform is at https://github.com/dvhdr/launchpad-pro. Turns out, while there’s a fair bit of documentation there, the reality is it is just barely enough documentation to get it done, and it is not quite right (at least not on the master branch). I’ve determined there’s a couple of other branches, one of which has the major corrections in it that I make below, but none with fully detailed instructions.

The end result was that I was able to get some firmware into my Launchpad Pro.  But, it wasn’t perfectly straightforward.  So, I’ve decided to provide some updated and more detailed instructions.  I do presume some reasonable knowledge of software development but hopefully this helps the Novation Launchpad Pro community.

Prerequisites

These instructions are MS Windows biased, but I think they should translate to MacOS easily enough.

You will need the following tools installed and ready to go:

  • A git client
    • git will need to be in your command line path
  • An ssh client (e.g.: part of MinGW)
    • ssh will need to be in your command line path
  • Vagrant
  • VirtualBox
  • A MIDI tool that can send sys-ex (e.g. MIDI-OX)

My personal laptop has Win10 and 8G of RAM on it and for me it is just barely sufficient. I really can’t run much other than the VirtualBox and MIDI-OX at the same time.

First Steps

  • Find or create a folder to work in
  • Open a command prompt in that work folder
  • Execute:
git clone --recursive https://github.com/dvhdr/launchpad-pro.git
  • This creates a launchpad-pro folder in the that work folder

You now have the basic Launchpad Pro files on your computer.

However, the Ubuntu image that is going to be used in this setup has changed since the code was uploaded to github. Therefore, we need to make a small change to one of the files downloaded.

  • Move to the launchpad-pro folder and open the Vagrantfile in a text editor
  • Find the line that starts with ‘config.vm.box’
  • Change it as follows, Before:
config.vm.box = "drmyersii/ubuntu-desktop-14.04-x64"
  • After
config.vm.box = "drm2/ubuntu-14.04-desktop-x64"

Novation support graciously point me at the new location when I asked about why there was a problem originally (and this nicely agrees with the last change on the raw-ADC branch that I found after I asked…).

VM Setup

  • Using your command prompt, move into the launchpad-pro folder
  • Execute:
 vagrant up

Let vagrant complete its work before moving on or logging into the VM.

  • Log you into the Ubuntu VirtualBox instance, execute:
 vagrant ssh
  • Execute:
make

The make is going to run for a good bit of time but we can do a couple of things while it is doing its thing.

Ubuntu/Eclipse Setup

The new Ubuntu image that we are using does not include an Eclipse installation (despite what the original docs say). But, it is not hard to set up.

  • Switch over to the VirtualBox instance and log into VirtualBox
    • It should already be running at this point with the vagrant user prompting for the password – just use “vagrant” as it the password
    • You may get prompted to update. I didn’t, but it is something that should be done soon to ensure all of the security patches are installed if you’re going to use this for anything beyond Launchpad Pro development
  • On the left sidebar there is an icon that looks something like an orange portfolio with an A on it. It is the Ubuntu Software Center. Launch it.
  • In the upper right of the Software Center, there’s a search field. Type in “eclipse” and look for “Eclipse Integrated Development Environment”.
  • Click on that row and there should be an “install” button. Install it.
    • This will take a little bit of time.
    • At the end of the install you will be prompted to authenticate the installation – just use vagrant password again.
    • The install button eventually change to “remove” (don’t remove it)
    • Note that there is now a new Eclipse icon in the left sidebar.
  • Launch Eclipse
    • If prompted for a workspace, accept the default and check the box to make it the default.

Once Eclipse shows you the main window we need to do a bit of configuration in Eclipse

  • Go to the Help/Install New Software… menu
    • I’m not sure what GUI Ubuntu is using these days but they hide the standard toolbar in the top status bar. Simply move your mouse up to the top bar next to the “Eclipse” text and the menu will reveal itself. Yes, I agree, really questionable UX…
  • Using the combobox to the immediate left of the “Add…” button, pick “Indigo Update Site”
  • Scroll down the list to the Programming Languages area and expand the list.
  • Select the “C/C++ Development Tools”
  • Leave the defaults alone from here out and click Next as many times as necessary until you can click Finish, which you also click.
    • You may get prompted to acknowledge licensing agreements and what not… do what you need to do.
  • When it is finished you will be prompted to restart Eclipse. Don’t. Instead, shut Eclipse down completely
    • This is just for the ease of the next step. Normally the restart is just fine.

We need to go back to our ssh session and check on the progress of our make command. When it is done we can switch back to the VirtualBox.

Pulling in the Source Tree

We now have a development environment for building our Launchpad Pro firmware but we need to pull the source code into Eclipse.

  • Launch Eclipse
  • File, Import…
  • Find C/C++ in the list and expand it.
  • Click on “Existing code as Makefile project” and then click “Next”.

It turns out that the launchpad-pro folder in your main computer’s work  folder is mapped into the VirtualBox’s /vagrant folder.

  • Put “/vagrant” in the “Existing code location” text field
  • Set the project name to whatever you want (it defaults to “vagrant” which is probably fine in some situations but isn’t for ours IMO)
  • Leave the other things alone and click “Finish”
    • If you have not closed the “Welcome” tab, go ahead and do so.

Building the Default Code

We now have a project in the upper left of Eclipse with the name we provided in the previous dialog. Time to build this thing:

  • Right click on the project and select “Clean Project”
  • Right click on the project and select “Build Project”

There is now a launchpad_pro.syx file in the launchpad-pro/build folder.

Upload to the Launchpad Pro

Finally, we have a binary image to upload into the Launchpad Pro. Ensure your Launchpad is plugged into your computer (and in bootloader mode) and using your SysEx tool of choice (I use MIDI-OX) to upload it (from <your-work-folder>\launchpad-pro\build\launchpad_pro.syx) and restart the Launchpad Pro.

You might have to hit the setup button to start the new firmware but it is there and running.

Useful References