From 22ff84d6b0d7a0c8021dc5dfa38406765d63f35b Mon Sep 17 00:00:00 2001
From: mgreiff <marcusgreiff.93@hotmail.com>
Date: Fri, 25 Aug 2017 03:02:11 +0200
Subject: [PATCH] Include PWM manipulation

TODO: Write better tests (currently just experiments)
TODO: Test a combinatino of universaln and universala
TODO: Test after merge..
---
 src/BeagleBone/BeagleBone.jl  |  3 +-
 src/BeagleBone/BeagleBone.jl~ | 86 +++++++++++++++++++++++++++++++++
 src/BeagleBone/PWM.jl         | 91 +++++++++++++++++++++++++++++++++++
 src/BeagleBone/PWM.jl~        | 91 +++++++++++++++++++++++++++++++++++
 test/BeagleBone/PWM_test.jl   | 40 +++++++++++++++
 test/BeagleBone/PWM_test.jl~  | 40 +++++++++++++++
 6 files changed, 350 insertions(+), 1 deletion(-)
 create mode 100644 src/BeagleBone/BeagleBone.jl~
 create mode 100644 src/BeagleBone/PWM.jl
 create mode 100644 src/BeagleBone/PWM.jl~
 create mode 100644 test/BeagleBone/PWM_test.jl
 create mode 100644 test/BeagleBone/PWM_test.jl~

diff --git a/src/BeagleBone/BeagleBone.jl b/src/BeagleBone/BeagleBone.jl
index 934bf47..0799a05 100644
--- a/src/BeagleBone/BeagleBone.jl
+++ b/src/BeagleBone/BeagleBone.jl
@@ -5,9 +5,10 @@
 include("Debug.jl")
 include("SysLED.jl")
 include("GPIO.jl")
+include("PWM.jl")
 
 #List of available devices and their constructors
-const DEVICES = Dict("debug" => Debug(), "sysled" => SysLED(), "gpio" => GPIO())
+const DEVICES = Dict("debug" => Debug(), "sysled" => SysLED(), "gpio" => GPIO(), "pwm" => PWM())
 
 """
     dev = getdev(devname)
diff --git a/src/BeagleBone/BeagleBone.jl~ b/src/BeagleBone/BeagleBone.jl~
new file mode 100644
index 0000000..934bf47
--- /dev/null
+++ b/src/BeagleBone/BeagleBone.jl~
@@ -0,0 +1,86 @@
+# Devices should define a type `T` with methods:
+# write!(::T, identifier, val)
+# read(::T, identifier)
+
+include("Debug.jl")
+include("SysLED.jl")
+include("GPIO.jl")
+
+#List of available devices and their constructors
+const DEVICES = Dict("debug" => Debug(), "sysled" => SysLED(), "gpio" => GPIO())
+
+"""
+    dev = getdev(devname)
+    Gets the device corresponding to the name `devname`
+"""
+function getdev(devname)
+    dev = try
+        DEVICES[devname]
+    catch
+        error("Device $devname does not exist")
+    end
+    return dev
+end
+
+"""
+    bbparse(cmd)
+Parse and execute the command `cmd`
+"""
+bbparse(any) = error("Unexpected input: $any")
+
+"""
+    bbparse(l::Tuple)
+Parse input on the form `l=(iswrite, ndev, cmd1, cmd2, ..., cmdn)``
+where if `iswrite`
+    `cmdi = (devname, id, val)`
+    and if not `iswrite`
+    `cmdi = (devname, id)`
+"""
+function bbparse(l::Tuple)
+    iswrite = l[1]::Bool            #True if write command, false if read
+    ndev = l[2]::Int32              #Number of devices/commands
+    for i = 1:ndev
+        command = l[2+i]::Tuple
+        dev = getdev(command[1])
+        if iswrite
+            write!(dev, command[2], command[3])
+        else
+            val = read(dev, command[2])
+            println("$val")
+            #TODO return somewhere
+        end
+    end
+end
+
+"""
+    run_server(port=2001)
+Run a server on `port` that listens for commands from computer
+"""
+function run_server(port=2001)
+    server = listen(port)
+    @async while isopen(server)
+        try
+            sock = accept(server)
+            @async while isopen(sock)
+                try
+                    l = deserialize(sock);
+                    println("deserialize: $l")
+                    bbparse(l)
+                catch err
+                    if !isopen(sock) && isa(err, Base.EOFError)
+                        println("Connection to server closed")
+                    else
+                        throw(err)
+                    end
+                end
+            end
+        catch err
+            if isa(err,Base.UVError) && err.prefix == "accept"
+                println("Server closed successfully")
+            else
+                throw(err)
+            end
+        end
+    end
+    return server
+end
diff --git a/src/BeagleBone/PWM.jl b/src/BeagleBone/PWM.jl
new file mode 100644
index 0000000..54a0bdc
--- /dev/null
+++ b/src/BeagleBone/PWM.jl
@@ -0,0 +1,91 @@
+"""
+This script allows for low level PWM control of selected pins
+The valid pins dictionary relates to memory adresses in of the
+AM3359 chip, see p.182 in
+
+    www.ti.com/product/AM3359/technicaldocuments
+"""
+
+struct PWM
+end
+
+# These pins are exported with the Device Tree Overlay cape-universaln (default)
+validPins = 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"),
+)
+
+# These pins are exported with the Device Tree Overlay cape-universala
+#    "P8.36" => ("PWM1A", "pwmchip1", "0"),
+#    "P9.29" => ("PWM0B", "pwmchip0", "1"),
+#    "P8.46" => ("PWM2B", "pwmchip2", "1")
+#    "P8.45" => ("PWM2A", "pwmchip2", "0"),
+#    "P8.34" => ("PWM1B", "pwmchip1", "1"),
+#    "P9.31" => ("PWM0A", "pwmchip0", "0"),
+
+function setup(::PWM, pin::String)
+    if pin in keys(validPins)
+
+        # Configure the pin to run PWM if possible
+        Base.run(`config-pin $(pin) pwm`)
+
+        # Find chip and export number
+        chip = validPins[pin][2]
+        filename = "/sys/class/pwm/$(chip)/export"
+        exportNumber = validPins[pin][3]
+
+        # Export the filestructure of the corresponding chip
+        write(filename, exportNumber)
+    else
+        error("The pin write $(pin) does not support PWM")
+    end
+    return
+end
+
+function teardown(::PWM, pin::String)
+    if pin in keys(validPins)
+        # Find chip and export number
+        chip = validPins[pin][2]
+        filename = "/sys/class/pwm/$(chip)/unexport"
+        exportNumber = validPins[pin][3]
+        
+        # Export the filestructure of the corresponding chip
+        write(filename, exportNumber)
+    else
+        error("The pin write $(pin) does not support PWM")
+    end
+    return
+end
+
+function write!(::PWM, pin::String, operation::Int32, entry::String)
+    !(pin in keys(validPins)) && error("Invalid PWM pin: $(pin))")
+    (operation <= 0 || operation > 4) && error("Invalid GPIO operation: $operation")
+
+    # TODO: Error checks
+    if operation == 1
+        directory = "enable"
+
+    end
+    if operation == 2
+        directory = "period"
+
+    end
+    if operation == 3
+        directory = "duty_cycle"
+
+    end
+    if operation == 4
+        directory = "polarity"
+
+    end
+
+    filename = "/sys/class/pwm/$(validPins[pin][2])/pwm$(validPins[pin][3])/$(directory)"
+    file = open(filename, "r+")
+    write(file, "$(entry)")
+    close(file)
+    return
+end
diff --git a/src/BeagleBone/PWM.jl~ b/src/BeagleBone/PWM.jl~
new file mode 100644
index 0000000..54a0bdc
--- /dev/null
+++ b/src/BeagleBone/PWM.jl~
@@ -0,0 +1,91 @@
+"""
+This script allows for low level PWM control of selected pins
+The valid pins dictionary relates to memory adresses in of the
+AM3359 chip, see p.182 in
+
+    www.ti.com/product/AM3359/technicaldocuments
+"""
+
+struct PWM
+end
+
+# These pins are exported with the Device Tree Overlay cape-universaln (default)
+validPins = 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"),
+)
+
+# These pins are exported with the Device Tree Overlay cape-universala
+#    "P8.36" => ("PWM1A", "pwmchip1", "0"),
+#    "P9.29" => ("PWM0B", "pwmchip0", "1"),
+#    "P8.46" => ("PWM2B", "pwmchip2", "1")
+#    "P8.45" => ("PWM2A", "pwmchip2", "0"),
+#    "P8.34" => ("PWM1B", "pwmchip1", "1"),
+#    "P9.31" => ("PWM0A", "pwmchip0", "0"),
+
+function setup(::PWM, pin::String)
+    if pin in keys(validPins)
+
+        # Configure the pin to run PWM if possible
+        Base.run(`config-pin $(pin) pwm`)
+
+        # Find chip and export number
+        chip = validPins[pin][2]
+        filename = "/sys/class/pwm/$(chip)/export"
+        exportNumber = validPins[pin][3]
+
+        # Export the filestructure of the corresponding chip
+        write(filename, exportNumber)
+    else
+        error("The pin write $(pin) does not support PWM")
+    end
+    return
+end
+
+function teardown(::PWM, pin::String)
+    if pin in keys(validPins)
+        # Find chip and export number
+        chip = validPins[pin][2]
+        filename = "/sys/class/pwm/$(chip)/unexport"
+        exportNumber = validPins[pin][3]
+        
+        # Export the filestructure of the corresponding chip
+        write(filename, exportNumber)
+    else
+        error("The pin write $(pin) does not support PWM")
+    end
+    return
+end
+
+function write!(::PWM, pin::String, operation::Int32, entry::String)
+    !(pin in keys(validPins)) && error("Invalid PWM pin: $(pin))")
+    (operation <= 0 || operation > 4) && error("Invalid GPIO operation: $operation")
+
+    # TODO: Error checks
+    if operation == 1
+        directory = "enable"
+
+    end
+    if operation == 2
+        directory = "period"
+
+    end
+    if operation == 3
+        directory = "duty_cycle"
+
+    end
+    if operation == 4
+        directory = "polarity"
+
+    end
+
+    filename = "/sys/class/pwm/$(validPins[pin][2])/pwm$(validPins[pin][3])/$(directory)"
+    file = open(filename, "r+")
+    write(file, "$(entry)")
+    close(file)
+    return
+end
diff --git a/test/BeagleBone/PWM_test.jl b/test/BeagleBone/PWM_test.jl
new file mode 100644
index 0000000..2f9a2b1
--- /dev/null
+++ b/test/BeagleBone/PWM_test.jl
@@ -0,0 +1,40 @@
+include("../../src/LabConnection.jl")
+using LabConnection.BeagleBone
+import LabConnection.BeagleBone: getdev, write!, setup, teardown
+
+pins = Dict(
+    "P9.22" => ("PWM0A", "pwmchip0", "0"),
+    "P9.21" => ("PWM0B", "pwmchip0", "1"),
+    "P9.14" => ("PWM1A", "pwmchip0", "0"),
+    "P9.16" => ("PWM1B", "pwmchip0", "1"),
+    "P8.19" => ("PWM2A", "pwmchip0", "0"),
+    "P8.13" => ("PWM2B", "pwmchip0", "1"),
+)
+
+dev = getdev("pwm")
+
+println("Running first experiment on selected pins...")
+for pin in keys(pins)
+    println("Testing pin $(pin)")
+    setup(dev, pin)
+    write!(dev, pin, 2, "100000000")
+    write!(dev, pin, 3, "50000000")
+    write!(dev, pin, 1, "1")
+    sleep(1)
+    write!(dev, pin, 1, "0")
+    teardown(dev, pin)
+end
+
+
+println("Running second experiment on pin $(pin)...")
+pin = "P9.22"
+setup(dev, pin)
+write!(dev, pin, 2, "1000000000")
+write!(dev, pin, 3, "250000000")
+write!(dev, pin, 1, "1")
+sleep(5.0)
+write!(dev, pin, 3, "500000000")
+sleep(5.0)
+write!(dev, pin, 3, "750000000")
+write!(dev, pin, 1, "0")
+teardown(dev, pin)
diff --git a/test/BeagleBone/PWM_test.jl~ b/test/BeagleBone/PWM_test.jl~
new file mode 100644
index 0000000..2f9a2b1
--- /dev/null
+++ b/test/BeagleBone/PWM_test.jl~
@@ -0,0 +1,40 @@
+include("../../src/LabConnection.jl")
+using LabConnection.BeagleBone
+import LabConnection.BeagleBone: getdev, write!, setup, teardown
+
+pins = Dict(
+    "P9.22" => ("PWM0A", "pwmchip0", "0"),
+    "P9.21" => ("PWM0B", "pwmchip0", "1"),
+    "P9.14" => ("PWM1A", "pwmchip0", "0"),
+    "P9.16" => ("PWM1B", "pwmchip0", "1"),
+    "P8.19" => ("PWM2A", "pwmchip0", "0"),
+    "P8.13" => ("PWM2B", "pwmchip0", "1"),
+)
+
+dev = getdev("pwm")
+
+println("Running first experiment on selected pins...")
+for pin in keys(pins)
+    println("Testing pin $(pin)")
+    setup(dev, pin)
+    write!(dev, pin, 2, "100000000")
+    write!(dev, pin, 3, "50000000")
+    write!(dev, pin, 1, "1")
+    sleep(1)
+    write!(dev, pin, 1, "0")
+    teardown(dev, pin)
+end
+
+
+println("Running second experiment on pin $(pin)...")
+pin = "P9.22"
+setup(dev, pin)
+write!(dev, pin, 2, "1000000000")
+write!(dev, pin, 3, "250000000")
+write!(dev, pin, 1, "1")
+sleep(5.0)
+write!(dev, pin, 3, "500000000")
+sleep(5.0)
+write!(dev, pin, 3, "750000000")
+write!(dev, pin, 1, "0")
+teardown(dev, pin)
-- 
GitLab