From efad6f9125708199fc21fc8a208444e4941085de Mon Sep 17 00:00:00 2001
From: Brendan Bartels <bbartels@iastate.edu>
Date: Fri, 31 Mar 2017 18:42:24 -0500
Subject: [PATCH] quad: update fifos to use blocking I/O for inputs and outputs

---
 quad/scripts/tests/test_safety_checks.rb     | 62 ++++++++++++--------
 quad/src/virt_quad/hw_impl_unix_mio7_led.c   | 11 ++--
 quad/src/virt_quad/hw_impl_unix_pwm_input.c  | 46 ++++++++-------
 quad/src/virt_quad/hw_impl_unix_pwm_output.c | 40 +++++++------
 4 files changed, 92 insertions(+), 67 deletions(-)

diff --git a/quad/scripts/tests/test_safety_checks.rb b/quad/scripts/tests/test_safety_checks.rb
index 2ed03ed7f..b5075df08 100644
--- a/quad/scripts/tests/test_safety_checks.rb
+++ b/quad/scripts/tests/test_safety_checks.rb
@@ -16,25 +16,39 @@ MOTOR_MAX = 200000
 GEAR_ON = 170800
 GEAR_OFF = 118300
 
+MOTOR1 = "virt-quad-fifos/pwm-output-motor1"
+MOTOR2 = "virt-quad-fifos/pwm-output-motor2"
+MOTOR3 = "virt-quad-fifos/pwm-output-motor3"
+MOTOR4 = "virt-quad-fifos/pwm-output-motor4"
+
+GEAR = "virt-quad-fifos/pwm-input-gear"
+THROTTLE = "virt-quad-fifos/pwm-input-throttle"
+
+LED = "virt-quad-fifos/mio7-led"
+
 require 'test/unit/assertions'
 require 'thread'
 include Test::Unit::Assertions
 
+def read_fifo_num(fifo)
+  File.read(fifo).chomp.split("\n").last.to_i
+end
+
 # Utility functions
 def check_motors_are_off
-  motor1 = File.read("virt-quad-fifos/pwm-output-motor1")
-  motor2 = File.read("virt-quad-fifos/pwm-output-motor2")
-  motor3 = File.read("virt-quad-fifos/pwm-output-motor3")
-  motor4 = File.read("virt-quad-fifos/pwm-output-motor4")
-  assert_operator motor1.to_i, :<=, THROTTLE_MIN
-  assert_operator motor2.to_i, :<=, THROTTLE_MIN
-  assert_operator motor3.to_i, :<=, THROTTLE_MIN
-  assert_operator motor4.to_i, :<=, THROTTLE_MIN
+  motor1 = read_fifo_num(MOTOR1)
+  motor2 = read_fifo_num(MOTOR2)
+  motor3 = read_fifo_num(MOTOR3)
+  motor4 = read_fifo_num(MOTOR4)
+  assert_operator motor1, :<=, THROTTLE_MIN
+  assert_operator motor2, :<=, THROTTLE_MIN
+  assert_operator motor3, :<=, THROTTLE_MIN
+  assert_operator motor4, :<=, THROTTLE_MIN
 end
 
 def check_led(on)
-  led = File.read("virt-quad-fifos/mio7-led")
-  assert_equal(led.to_i, on)
+  led = read_fifo_num(LED)
+  assert_equal(led, on)
 end
 
 script_dir = File.expand_path(File.dirname(__FILE__))
@@ -61,47 +75,47 @@ begin
   # Check that increasing the throttle does nothing to motors
   # (because gear is still off)
   for i in (THROTTLE_MIN..THROTTLE_MAX).step(1000)
-    File.write("virt-quad-fifos/pwm-input-throttle", i)
+    File.write(THROTTLE, i)
     check_motors_are_off
     sleep 0.005
   end
 
   # Check that flipping gear to 1 while throttle is high does nothing
   # (motors should still be off, LED should still be off)
-  File.write("virt-quad-fifos/pwm-input-gear", GEAR_ON)
+  File.write(GEAR, GEAR_ON)
   sleep 0.015
   check_motors_are_off
   i = THROTTLE_MAX
   while i > THROTTLE_MID
     i -= 1000
-    File.write("virt-quad-fifos/pwm-input-throttle", i)
+    File.write(THROTTLE, i)
     check_motors_are_off
     check_led 0
     sleep 0.005
   end
 
   # (swtich GEAR back to off and bring throttle off)
-  File.write("virt-quad-fifos/pwm-input-gear", GEAR_OFF)
-  File.write("virt-quad-fifos/pwm-input-throttle", THROTTLE_MIN)
+  File.write(GEAR, GEAR_OFF)
+  File.write(THROTTLE, THROTTLE_MIN)
 
   # Check that the LED turns on when gear is flipped on
   # (motors should still be off because our throttle is low)
-  File.write("virt-quad-fifos/pwm-input-gear", GEAR_ON)
+  File.write(GEAR, GEAR_ON)
   sleep 0.010
   check_led 1
   check_motors_are_off
 
   # Check that motors turn on
-  File.write("virt-quad-fifos/pwm-input-throttle", THROTTLE_MID)
+  File.write(THROTTLE, THROTTLE_MID)
   motor1 = []
   motor2 = []
   motor3 = []
   motor4 = []
   for i in 0..100
-    motor1.push(File.read("virt-quad-fifos/pwm-output-motor1").to_i)
-    motor2.push(File.read("virt-quad-fifos/pwm-output-motor2").to_i)
-    motor3.push(File.read("virt-quad-fifos/pwm-output-motor3").to_i)
-    motor4.push(File.read("virt-quad-fifos/pwm-output-motor4").to_i)
+    motor1.push(read_fifo_num(MOTOR1))
+    motor2.push(read_fifo_num(MOTOR2))
+    motor3.push(read_fifo_num(MOTOR3))
+    motor4.push(read_fifo_num(MOTOR4))
     sleep 0.005
   end
   average1 = motor1.inject(:+).to_f / motor1.size
@@ -114,16 +128,16 @@ begin
 
   # Check that gear switch kills the motors
   # (and that light goes off)
-  File.write("virt-quad-fifos/pwm-input-gear", GEAR_OFF)
+  File.write(GEAR, GEAR_OFF)
   sleep 0.015
   check_motors_are_off
   check_led 0
 
   # (Bring the RC throttle back down)
-  File.write("virt-quad-fifos/pwm-input-throttle", THROTTLE_MIN)
+  File.write(THROTTLE, THROTTLE_MIN)
 
   # Check that we can resume flight
-  File.write("virt-quad-fifos/pwm-input-gear", GEAR_ON)
+  File.write(GEAR, GEAR_ON)
   sleep 0.015
   check_led 1
 
diff --git a/quad/src/virt_quad/hw_impl_unix_mio7_led.c b/quad/src/virt_quad/hw_impl_unix_mio7_led.c
index 521542378..6aef66752 100644
--- a/quad/src/virt_quad/hw_impl_unix_mio7_led.c
+++ b/quad/src/virt_quad/hw_impl_unix_mio7_led.c
@@ -25,6 +25,7 @@ int unix_mio7_led_reset(struct LEDDriver *self) {
 
   // Start up worker thread whose job is to update the caches
   pthread_create(&worker, 0, output_cached_led, NULL);
+
   return 0;
 }
 
@@ -47,12 +48,10 @@ int unix_mio7_led_turn_off(struct LEDDriver *self) {
 void * output_cached_led() {
   char buff[16];
   while (1) {
-    usleep(500); // don't spam the reader
-    int fifo = open(led_fifo_name, O_WRONLY | O_NONBLOCK);
-    if (fifo >= 0) {
-      sprintf(buff, "%d ", on);
-      write(fifo, buff, strlen(buff));
-    }
+    int fifo = open(led_fifo_name, O_WRONLY);
+    sprintf(buff, "%d\n", on);
+    write(fifo, buff, strlen(buff));
     close(fifo);
+    usleep(500); // don't spam the reader
   }
 }
diff --git a/quad/src/virt_quad/hw_impl_unix_pwm_input.c b/quad/src/virt_quad/hw_impl_unix_pwm_input.c
index 75805653c..b48746109 100644
--- a/quad/src/virt_quad/hw_impl_unix_pwm_input.c
+++ b/quad/src/virt_quad/hw_impl_unix_pwm_input.c
@@ -5,7 +5,7 @@
 #include <fcntl.h>
 #include <pthread.h>
 
-void * update_input_caches();
+void * update_input_cache();
 
 static char *input_names[6];
 static int fifos[6];
@@ -21,18 +21,13 @@ int unix_pwm_input_reset(struct PWMInputDriver *self) {
   input_names[5] = "pwm-input-flap";
 
   mkdir(VIRT_QUAD_FIFOS_DIR, 0777);
+
+  // Start up worker thread whose job is to update the caches
   int i;
   for (i = 0; i < 6; i += 1) {
-    unlink(input_names[i]);
-    char fifoname[64];
-    sprintf(fifoname, "%s/%s", VIRT_QUAD_FIFOS_DIR, input_names[i]);
-    mkfifo(fifoname, 0666);
-    fifos[i] = open(fifoname, O_RDONLY | O_NONBLOCK);
+    pthread_create(&worker, 0, update_input_cache, &i);
   }
 
-  // Start up worker thread whose job is to update the caches
-  pthread_create(&worker, 0, update_input_caches, NULL);
-
   cache[0] = THROTTLE_MIN;
   cache[1] = ROLL_CENTER;
   cache[2] = PITCH_CENTER;
@@ -55,19 +50,30 @@ int unix_pwm_input_read(struct PWMInputDriver *self,
   return 0;
 }
 
-void * update_input_caches() {
+void * update_input_cache(void *arg) {
+  int *cache_index = arg;
+  int i = *cache_index;
   char buff[16];
-  int i;
+
+  // Setup FIFO
+  unlink(input_names[i]);
+  char fifoname[64];
+  sprintf(fifoname, "%s/%s", VIRT_QUAD_FIFOS_DIR, input_names[i]);
+  mkfifo(fifoname, 0666);
+  fifos[i] = open(fifoname, O_RDONLY);
+
+  // Block while waiting for reads
   while (1) {
-    for (i = 0; i < 6; i += 1) {
-      int bytes_read = read(fifos[i], buff, 15);
-      if (bytes_read >= 6) {
-        buff[bytes_read] = '\0';
-        unsigned long val = strtoll(buff, NULL, 10);
-        if (val < max && val > min) {
-          cache[i] = val;
-          printf("%s: %d\n", input_names[i], val);
-        }
+    int bytes_read = read(fifos[i], buff, 15);
+    if (bytes_read > 0) {
+      buff[bytes_read] = '\0';
+      unsigned long val = strtoll(buff, NULL, 10);
+      if (val < max && val > min) {
+	cache[i] = val;
+	printf("%s: %d\n", input_names[i], val);
+      }
+      else {
+	printf("%s: Bad value - input not received\n", input_names[i]);
       }
     }
   }
diff --git a/quad/src/virt_quad/hw_impl_unix_pwm_output.c b/quad/src/virt_quad/hw_impl_unix_pwm_output.c
index 03f9815cf..71b89c4f4 100644
--- a/quad/src/virt_quad/hw_impl_unix_pwm_output.c
+++ b/quad/src/virt_quad/hw_impl_unix_pwm_output.c
@@ -6,12 +6,17 @@
 #include <pthread.h>
 #include <unistd.h>
 
-void * output_caches();
+void * output_cache();
 
 static char *output_pwms[4];
 static unsigned long cache[4];
 pthread_t worker;
 
+static int zero = 0;
+static int one = 1;
+static int two = 2;
+static int three = 3;
+
 int unix_pwm_output_reset(struct PWMOutputDriver *self) {
   output_pwms[0] = VIRT_QUAD_FIFOS_DIR "/pwm-output-motor1";
   output_pwms[1] = VIRT_QUAD_FIFOS_DIR "/pwm-output-motor2";
@@ -19,14 +24,12 @@ int unix_pwm_output_reset(struct PWMOutputDriver *self) {
   output_pwms[3] = VIRT_QUAD_FIFOS_DIR "/pwm-output-motor4";
 
   mkdir(VIRT_QUAD_FIFOS_DIR, 0777);
-  int i;
-  for (i = 0; i < 4; i += 1) {
-    unlink(output_pwms[i]);
-    mkfifo(output_pwms[i], 0666);
-  }
 
   // Start up worker thread whose job is to update the caches
-  pthread_create(&worker, 0, output_caches, NULL);
+  pthread_create(&worker, 0, output_cache, &zero);
+  pthread_create(&worker, 0, output_cache, &one);
+  pthread_create(&worker, 0, output_cache, &two);
+  pthread_create(&worker, 0, output_cache, &three);
 
   return 0;
 }
@@ -41,19 +44,22 @@ int unix_pwm_output_write(struct PWMOutputDriver *self,
   return 0;
 }
 
-void * output_caches() {
+void * output_cache(void *arg) {
+  int *output_index = arg;
   char buff[16];
-  int i;
+  int i = *output_index;
+
+  // Setup FIFO
+  unlink(output_pwms[i]);
+  mkfifo(output_pwms[i], 0666);
+
+  // Block while waiting for someone to listen
   while (1) {
+    int fifo = open(output_pwms[i], O_WRONLY);
+    sprintf(buff, "%ld\n", cache[i]);
+    write(fifo, buff, strlen(buff));
+    close(fifo);
     usleep(500); // don't spam the reader
-    for (i = 0; i < 4; i += 1) {
-      int fifo = open(output_pwms[i], O_WRONLY | O_NONBLOCK);
-      if (fifo >= 0) {
-        sprintf(buff, " %ld ", cache[i]);
-        write(fifo, buff, strlen(buff));
-      }
-      close(fifo);
-    }
   }
   return NULL;
 }
-- 
GitLab