From f87a087540b8a6fba8cee728e11861b7799645a7 Mon Sep 17 00:00:00 2001
From: Joshua Saxby <joshua.a.saxby@gmail.com>
Date: Thu, 5 Mar 2020 18:47:51 +0000
Subject: [PATCH] Implemented Slave pair method This completes the pairing
 functionality

---
 source/main.cpp | 89 +++++++++++++++++++++++++++++++++----------------
 1 file changed, 60 insertions(+), 29 deletions(-)

diff --git a/source/main.cpp b/source/main.cpp
index ded7c11..047622c 100755
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -115,37 +115,12 @@ private:
         }
         // successful execution continues here
         // wait for the pin to stay LO for 500ms
-        unsigned long start_time = ubit.systemTime();
-        unsigned long now_time = start_time;
-        do {
-            /*
-             * NOTE: this is a busy wait loop with no sleep()
-             * this is okay as we're deliberately allowing this function to
-             * block the entire system, it's documented as such and we also can
-             * only sleep to a 6ms precision, but we want to time as accurately
-             * as possible for the pairing process
-             */
-            now_time = ubit.systemTime();
-            pin_state = ubit.io.pin[COMMS_PIN_NUMBER].getDigitalValue();
-        } while (pin_state == 0 and (now_time - start_time) < 500);
+        unsigned long start_time, now_time;
+        this->busy_wait_on_pin(0, 500, pin_state, start_time, now_time);
         // check to make sure we didn't break out of the loop because of HI pin
         if (pin_state != 0) return false;
         // there's definitely no-one else transmitting on the line, now we transmit
-        start_time = ubit.systemTime();
-        now_time = start_time;
-        ubit.io.pin[COMMS_PIN_NUMBER].setDigitalValue(1);
-        // wait 500ms
-        do {
-            /*
-             * NOTE: as with the previous loop, this is a busy wait loop
-             * it's particularly important that this one is accurately timed,
-             * as we expect ourself and the Slave to synchronise clocks on the
-             * falling edge of this pulse we send
-             */
-            now_time = ubit.systemTime();
-        } while ((now_time - start_time) < 500);
-        // bring line LO
-        ubit.io.pin[COMMS_PIN_NUMBER].setDigitalValue(0);
+        this->busy_wait_drive_pin(500, start_time, now_time);
         // now_time is the clock synchronisation timestamp
         this->synchronisation_timestamp = now_time;
         // now, wait up to 100ms for a reply from the Slave
@@ -164,7 +139,62 @@ private:
         return this->await_synchronisation();
     }
 
-    bool pair_as_slave();
+    bool pair_as_slave() {
+        // check the pin can read digital values
+        int pin_state = ubit.io.pin[COMMS_PIN_NUMBER].getDigitalValue();
+        if (pin_state == MICROBIT_NOT_SUPPORTED) return false; // oh no, it can't
+        // otherwise, it can read digital values
+        // now, wait up to 10000ms for Master to drive the line HI
+        unsigned long start_time, end_time;
+        this->busy_wait_on_pin(0, 10000, pin_state, start_time, end_time);
+        // clarify the loop ended because pin is now indeed HI
+        if (pin_state != 1) return false; // we timed out
+        // otherwise, line is HI, wait for it to stay that way at least 450ms
+        this->busy_wait_on_pin(1, 450, pin_state, start_time, end_time);
+        // clarify the loop ended because timeout occurred (pin should be HI)
+        if (pin_state != 1) return false; // pin went LO, that's not correct
+        // wait up to 100 more ms for line to go LO
+        this->busy_wait_on_pin(1, 100, pin_state, start_time, end_time);
+        // if line is still HI, then it's overrun
+        if (pin_state == 1) return false;
+        // otherwise, it's now our turn to bring the line HI
+        // the most recent end_time is also the sync point, store that first
+        this->synchronisation_timestamp = end_time;
+        // drive line HI
+        this->busy_wait_drive_pin(500, start_time, end_time);
+        // now we just need to await synchronisation
+        return this->await_synchronisation();
+    }
+
+    /**
+     * @brief Drives the comms pin HI and performs a busy-wait loop for a given
+     * duration, before driving the pin LO again.
+     * @param duration length of time in ms to drive the pin HI for
+     * @param start_time[out] system timestamp (ms) that the pin went HI
+     * @param end_time[out] system timestamp (ms) that the pin went LO
+     */
+    void busy_wait_drive_pin(
+        unsigned long duration
+        unsigned long& start_time,
+        unsigned long& end_time
+    ) {
+        start_time = ubit.systemTime();
+        end_time = start_time;
+        ubit.io.pin[COMMS_PIN_NUMBER].setDigitalValue(1);
+        // wait for specified duration
+        do {
+            /*
+             * NOTE: this is a busy wait loop with no sleep()
+             * this is okay as we're deliberately allowing this function to
+             * block the entire system, it's documented as such and we also can
+             * only sleep to a 6ms precision, but we want to time as accurately
+             * as possible
+             */
+            end_time = ubit.systemTime();
+        } while ((end_time - start_time) < duration);
+        // bring line LO
+        ubit.io.pin[COMMS_PIN_NUMBER].setDigitalValue(0);
+    }
 
     /**
      * @brief Performs a busy-wait loop, continuously checking the comms pin
@@ -224,6 +254,7 @@ private:
         do {
             now_time = ubit.systemTime();
         } while (now_time < sync_time);
+        return true; // at this point, now both Master and Slave are synchronised
     }
 
     unsigned long synchronisation_timestamp;
-- 
GitLab