refactor(protocol-ctrl): execute_steps coroutine
refactor(protocol-ctrl): execute_steps coroutine

Prior to this commit, protocol execution was managed by the protocol
controller through chained `run_step()` method calls linked by
`_on_step_complete()` callbacks.  However, this code was somewhat
difficult to follow and required special handling in the case where a
single step was executed.

In this commit, refactor the protocol controller to:

 - Execute protocol steps in the `run_protocol()` method using the new
   `execute_steps()` coroutine.
 - Execute a single step (without executing the whole protocol) in the
   `run_step()` method using the new `execute_step()` coroutine.

wheeler-microfluidics/microdrop