From 25aa435f34efb3a3f07833ccac6a67def59c400f Mon Sep 17 00:00:00 2001
From: mgreiff <marcusgreiff.93@hotmail.com>
Date: Mon, 15 Apr 2019 20:22:19 +0200
Subject: [PATCH] Revised PWM functionality to be compatible with the 4.14
 kernel

---
 src/BeagleBone/IO_Object.jl | 23 +++++++++----
 src/BeagleBone/PWM.jl       | 66 ++++++++++++++++++++++---------------
 test/BeagleBone/PWM_test.jl | 10 +++---
 3 files changed, 60 insertions(+), 39 deletions(-)

diff --git a/src/BeagleBone/IO_Object.jl b/src/BeagleBone/IO_Object.jl
index 9215ea2..bc25ddb 100644
--- a/src/BeagleBone/IO_Object.jl
+++ b/src/BeagleBone/IO_Object.jl
@@ -44,14 +44,23 @@ const gpio_channels =[
   "gpio7"
 ]
 
-# These pins are exported with the Device Tree Overlay cape-universaln (default)
+# Device Tree Overlay cape-universaln (default) before the v.4.14 kernel
+#const pwm_pins = Dict(
+#    "P9.22" => ("PWM0A", "pwmchip0", "0"),
+#    "P9.21" => ("PWM0B", "pwmchip0", "1"),
+#    "P9.14" => ("PWM1A", "pwmchip2", "0"),
+#    "P9.16" => ("PWM1B", "pwmchip2", "1"),
+#    "P8.19" => ("PWM2A", "pwmchip4", "0"),
+#    "P8.13" => ("PWM2B", "pwmchip4", "1"),
+#)
+# After and including the 4.14 kernel
 const pwm_pins = Dict(
-    "P9.22" => ("PWM0A", "pwmchip0", "0"),
-    "P9.21" => ("PWM0B", "pwmchip0", "1"),
-    "P9.14" => ("PWM1A", "pwmchip2", "0"),
-    "P9.16" => ("PWM1B", "pwmchip2", "1"),
-    "P8.19" => ("PWM2A", "pwmchip4", "0"),
-    "P8.13" => ("PWM2B", "pwmchip4", "1"),
+    "P9.22" => ("1", "pwmchip1", "0"), # PWM0A
+    "P9.21" => ("1", "pwmchip1", "1"), # PWM0B
+    "P9.14" => ("4", "pwmchip4", "0"), # PWM1A
+    "P9.16" => ("4", "pwmchip4", "1"), # PWM1B
+    "P8.19" => ("7", "pwmchip7", "0"), # PWM2A
+    "P8.13" => ("7", "pwmchip7", "1"), # PWM2B
 )
 
 # These pins are exported with the Device Tree Overlay cape-universala
diff --git a/src/BeagleBone/PWM.jl b/src/BeagleBone/PWM.jl
index c554de5..1e91d9a 100644
--- a/src/BeagleBone/PWM.jl
+++ b/src/BeagleBone/PWM.jl
@@ -1,8 +1,21 @@
 """
     PWM(i::Int32)
 This device allows for low level PWM control of selected pins. The valid pins
-dictionary pwm_pins relates to memory adresses in of the AM3359 chip, see p.182
+dictionary pwm_pins relates to memory adresses in of the AM3359 chip, see p.184
 in www.ti.com/product/AM3359/technicaldocuments.
+
+    pwm = PWM(1)
+    write!(pwm, (1,"1"))
+    write!(pwm, (2, "1000000000"))
+    write!(pwm, (3, "800000000"))
+
+The operation of reading the current output value of the GPIO is done by
+
+    read(pwm, 1)
+    read(pwm, 2)
+    read(pwm, 3)
+
+See the test/BeagleBone/GPIO_test.jl for more examples.
 """
 
 struct PWM <: IO_Object
@@ -20,13 +33,14 @@ struct PWM <: IO_Object
 
         # Setup filestreams
         pins = collect(keys(pwm_pins))
-        pin = pins[i]
+        pin  = pins[i]
         chip = pwm_pins[pin][2]
+        location = "$(basedir)/$(pwm_pins[pin][2])/pwm-$(pwm_pins[pin][1]):$(pwm_pins[pin][3])"
 
-        enable_filestream = open("$(basedir)/$(pwm_pins[pin][2])/pwm$(pwm_pins[pin][3])/enable","r+")
-        period_filestream = open("$(basedir)/$(pwm_pins[pin][2])/pwm$(pwm_pins[pin][3])/period","r+")
-        duty_cycle_filestream = open("$(basedir)/$(pwm_pins[pin][2])/pwm$(pwm_pins[pin][3])/duty_cycle","r+")
-        polarity_filestream = open("$(basedir)/$(pwm_pins[pin][2])/pwm$(pwm_pins[pin][3])/polarity","r+")
+        enable_filestream = open("$(location)/enable","r+")
+        period_filestream = open("$(location)/period","r+")
+        duty_cycle_filestream = open("$(location)/duty_cycle","r+")
+        polarity_filestream = open("$(location)/polarity","r+")
         return new(i, pin, chip, basedir, [enable_filestream, period_filestream, duty_cycle_filestream, polarity_filestream])
     end
 end
@@ -37,17 +51,17 @@ Writes an entry to an operation on the PWM, of the form args = (operation, entry
 """
 function write!(pwm::PWM, args::Tuple{Int32,String}, debug::Bool=false)
     debug && return
-
     operation, entry = args[1], args[2]
-    (operation < 1 || operation > length(pwm.filestreams)) && error("Invalid PWM operation: $operation")
 
-    # Input data check
-    assert_pwm_write(operation, entry)
+    operation ∉ [1,2,3,4] && error("Invalid PWM operation $operation for writing")
 
-    # Write to file
-    seekstart(pwm.filestreams[operation])
-    write(pwm.filestreams[operation], "$entry\n")
-    flush(pwm.filestreams[operation])
+    if assert_pwm_write(operation, entry)
+        seekstart(pwm.filestreams[operation])
+        write(pwm.filestreams[operation], "$entry\n")
+        #flush(pwm.filestreams[operation])
+    else
+        error("Invalid entry for PWM operation $(operation): $(entry)")
+    end
 end
 
 """
@@ -55,34 +69,31 @@ end
 Assertsion for the PWM input data.
 """
 function assert_pwm_write(operation::Int32, entry::String)
-  if operation == "1"
-    entry ∉ ["0", "1"] && error("Invalid SysLED entry $(entry), valid options are 0 and 1 ::String")
+  if operation == 1
+    entry in ["0", "1"] || error("Invalid PWM entry $(entry), valid options are 0 and 1 of type ::String")
   else
     number = try
       parse(Int32, entry)
     catch
       error("Invalid SysLED entry $(entry), cannot parse as Int32")
     end
-    (number < 0 || number > 100000000) && error("Invalid SysLED entry $(entry), not in the range [0,100000000]")
+    !(number < 0 || number > 1000000000) || error("Invalid PWM entry $(entry), not in the range [0,1000000000]")
   end
 end
 
 """
     l = read(pwm::PWM, operation::Int32, debug::Bool=false)
-Reads the current value from an operation on a GPIO.
+Reads the current value from an operation on a PWM pin.
 """
 function read(pwm::PWM, operation::Int32, debug::Bool=false)
   debug && return
   # Filestreams 1, 2 and 3 are readable
-  operation ∉ [1,2,3,4] && error("Invalid GPIO operation: $operation for reading")
+  operation ∉ [1,2,3,4] && error("Invalid PWM operation: $operation for reading")
   seekstart(pwm.filestreams[operation])
   l = readline(pwm.filestreams[operation])
   return l
 end
 
-
-
-
 """
     teardown!(pwd::PWM)
 Closes all open streams on the PWM, and unexports it from the file system
@@ -101,7 +112,7 @@ function teardown(pwm::PWM, debug::Bool=false)
     try
       rm("$(pwm.basedir)/$(pwm_pins[pwm.pin][2])/pwm$(pwm_pins[pwm.pin][3])"; recursive=true)
     catch
-      error("Could not remove the requested GPIO testfiles for channel $(pwm_pins[pwm.pin][2])/pwm$(pwm_pins[pwm.pin][3]).")
+      error("Could not remove the requested PWM testfiles for channel $(pwm_pins[pwm.pin][2])/pwm$(pwm_pins[pwm.pin][3]).")
     end
   else
     #Unexport filestructure
@@ -112,8 +123,8 @@ function teardown(pwm::PWM, debug::Bool=false)
 end
 
 """
-    export_gpio(i::Int32, debug::Bool=false)
-Export the GPIO file system, either for real-time or testing usecases.
+    export_pwm(i::Int32, debug::Bool=false)
+Export the PWM file system, either for real-time or testing usecases.
 """
 function export_pwm(i::Int32)
   # Find chip and export number
@@ -137,7 +148,7 @@ function export_pwm(i::Int32)
       f = open("$(complete_path)/duty_cycle", "w"); write(f,"0"); close(f);
       f = open("$(complete_path)/polarity", "w"); write(f,"0"); close(f);
     catch
-      error("Could not open the requested GPIO testfiles for $(complete_path).")
+      error("Could not open the requested PWM testfiles for $(complete_path).")
     end
   else
     basedir = "/sys/class/pwm"
@@ -147,6 +158,7 @@ function export_pwm(i::Int32)
 
     # Export the filestructure of the corresponding chip
     filename = "/sys/class/pwm/$(chip)/export"
+    println(filename)
     exportNumber = pwm_pins[pin][3]
     write(filename, exportNumber)
   end
@@ -155,7 +167,7 @@ end
 
 """
     to_string(pwm::PWM,, debug::Bool=false)
-Generates a string representation of the GPIO device.
+Generates a string representation of the PWM pin.
 """
 function to_string(pwm::PWM, debug::Bool=false)
   debug && return
diff --git a/test/BeagleBone/PWM_test.jl b/test/BeagleBone/PWM_test.jl
index dcd6fa9..18bf4a2 100644
--- a/test/BeagleBone/PWM_test.jl
+++ b/test/BeagleBone/PWM_test.jl
@@ -59,13 +59,13 @@ using Test
         @test_throws ErrorException write!(device, (Int32(1), "-1"))
         @test_throws ErrorException write!(device, (Int32(1), "bad_entry"))
         @test_throws ErrorException write!(device, (Int32(2), "-1"))
-        @test_throws ErrorException write!(device, (Int32(2), "100000001"))
+        @test_throws ErrorException write!(device, (Int32(2), "1000000001"))
         @test_throws ErrorException write!(device, (Int32(2), "bad_entry"))
         @test_throws ErrorException write!(device, (Int32(3), "-1"))
-        @test_throws ErrorException write!(device, (Int32(3), "100000001"))
+        @test_throws ErrorException write!(device, (Int32(3), "1000000001"))
         @test_throws ErrorException write!(device, (Int32(3), "bad_entry"))
         @test_throws ErrorException write!(device, (Int32(4), "-1"))
-        @test_throws ErrorException write!(device, (Int32(4), "100000001"))
+        @test_throws ErrorException write!(device, (Int32(4), "1000000001"))
         @test_throws ErrorException write!(device, (Int32(4), "bad_entry"))
 
         # Close Gpio
@@ -81,8 +81,8 @@ using Test
         for ii = 1:length(pwm_pins)
             device = initdev("pwm", Int32(ii))
             # Operation 2 -> in/out, set out
-            write!(device, (Int32(2), "100000000"))
-            @test read(device, Int32(2)) == "100000000"
+            write!(device, (Int32(2), "1000000000"))
+            @test read(device, Int32(2)) == "1000000000"
             write!(device, (Int32(3), "50000000"))
             @test read(device, Int32(3)) == "50000000"
             write!(device, (Int32(1), "1"))
-- 
GitLab