Skip to content
Snippets Groups Projects
Select Git revision
2 results Searching

BeagleBone.jl

Blame
  • BeagleBone.jl 6.75 KiB
    const READ = Int32(0)
    const WRITE = Int32(1)
    const INIT = Int32(2)
    
    include("IO_Object.jl")
    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, "pwm" => PWM)
    
    #Currently active devices on the BeagleBone
    active_devices = Dict{String,Dict{Int32,IO_Object}}("debug" => Dict{Int32,Debug}(), "sysled" => Dict{Int32,SysLED}(),
                                                              "gpio" => Dict{Int32,GPIO}(), "pwm" => Dict{Int32,PWM}())
    
    """
        active_device = initdev(dev_name::String, i:Int32)
    Initializes a new device of type 'dev_name' at index 'i' on the BeagleBone,
    and adds it to the dict of currently active devices. Returns the initialized
    device 'active_device'.
    """
    function initdev(dev_name::String, i::Int32)
        #Check if the type of device is valid
        dev_constr = try
             DEVICES[dev_name]
         catch
             error("Device $dev_name does not exist")
         end
        #Check if the device index is already in use
        haskey(active_devices[dev_name],i) && error("Index $i is already in use for device $dev_name")
        #Construct a new device and add it to dict of currently active devices
        active_device = dev_constr(i)
        active_devices[dev_name][i] = active_device
        return active_device
    end
    
    """
        closedev(dev_name::String, i::Int32)
    Closes down a currently active device of type 'dev_name' at index 'i' on the BeagleBone,
    and removes it from the dict of currently active devices.
    """
    function closedev(dev_name::String, i::Int32)
        active_device = try
            active_devices[dev_name][i]
        catch
            error("No device of type $dev_name at index $i is currently active")
        end
        #Call the teardown method on the device, to close all file-streams and
        #unexport the device from the BeagleBone
        teardown(active_device)
    
        #Remove the device from the dict of active devices
        delete!(active_devices[dev_name], i)
    end
    
    """
        dev = getdev(dev_name::String, i::Int32)
    Retrieves the active device of type `dev_name` at index 'i'.
    """
    function getdev(dev_name::String, i::Int32)
        dev = try
            active_devices[dev_name][i]
        catch
            error("No device of type $dev_name at index $i is currently active")
        end
        return dev
    end
    
    """
        message = listdev()
    Lists all the active devices as an insidence array for testing.
        """
    function listdev()
        message = "Complete overview of active devices"
        count = zeros(length(keys(DEVICES)))
        for (index, key) in enumerate(keys(DEVICES))
            count[index] = length(active_devices[key])
        end
        return count
    end
    
    """
        message = printdev()
    Prints all the active devices and writes out specifics of a single devices.
    """
    function printdev(dev_name::String, i::Int32)
        println("Complete overview of active devices")
        for (index, key) in enumerate(keys(DEVICES))
            println(" *    $(key) - $(length(active_devices[key]))")
        end
        try
            dev = active_devices[dev_name][i]
            println(to_string(dev))
        catch
            println("\nNo device of type $dev_name at index $i is currently active")
        end
    end
    
    """
        bbparse(cmd)
    Parse and execute the command `cmd`.
    """
    bbparse(any) = error("Unexpected input: $any")
    
    function bbsend(sock, vals)#, timestamps)
        serialize(sock, vals)#, (timestamps...)))
    end
    
    """
        bbparse(l::Tuple, sock)
    Parse input on the form `l=(operation, ndev, cmd1, cmd2, ..., cmdn)`
    where if `operation==1` (write)
        `cmdi = (devname, id, val)`
        and if `operation==0` (read)
        `cmdi = (devname, id)`
        and if `operation==2` (initialize)
        `cmdi = (devname, id)`
    and send back on socket (vals, timestamps).
    """
    function bbparse(l::Tuple, sock)
        operation = l[1]::Int32           #1 if write command, 0 if read, 2 if init
        ndev = l[2]::Int32              #Number of devices/commands
        if operation == WRITE
            for i = 1:ndev
                command = l[2+i]::Tuple
                dev = getdev(command[1], command[2])
                write!(dev, command[3])
            end
            return
        elseif operation == READ
            #TODO fix to have at least partial type stability
            vals = Array{Any,1}(undef,ndev)
            timestamps = Array{UInt64,1}(undef,ndev)
            for i = 1:ndev
                command = l[2+i]::Tuple
                dev = getdev(command[1], command[2])
                vals[i] = read(dev)
                timestamps[i] = UInt64(0)#time_ns()
            end
            bbsend(sock, (vals, timestamps))
            return
        elseif operation == INIT
            for i = 1:ndev
                command = l[2+i]::Tuple
                dev = initdev(command[1], command[2])
            end
            return
        else
            error("Unknown operation $operation, cmd: $l")
        end
    end
    
    global __waiting_first_connection__ = false
    """
        run_server(port=2001; debug=false)
    Run a server on `port` that listens for commands from computer
    Optional debug keyword disables blinking system leds.
    """
    function run_server(port=2001; debug=false)
        global __waiting_first_connection__ = true
        server = listen(IPv4(0), port) # IPv4(0) means listen from any ip
        @async while isopen(server)
            try
                @async while __waiting_first_connection__ && !debug
                    #Blink SysLED 2 when waiting for first connection to signal availability
                    led = initdev("sysled",Int32(2))
                    write!(led, "1")
                    sleep(0.4)
                    write!(led, "0")
                    sleep(0.2)
                    write!(led, "1")
                    sleep(0.4)
                    write!(led, "0")
                    sleep(0.8)
                    closedev("sysled", Int32(2))
                end
                sock = accept(server)
                __waiting_first_connection__ = false
                @async while isopen(sock)
                    try
                        l = deserialize(sock);
                        println("deserialized:")
                        println(l)
                        try
                            bbparse(l, sock)
                        catch err
                            @warn "Failure in bbparse, server should keep running, error:"
                            println(err)
                        end
                    catch err
                        if !isopen(sock) && (isa(err, Base.EOFError) || isa(err, Base.UVError))
                            println("Connection to server closed")
                            # TODO teardown and remove all devices
                        else
                            println("error: $(typeof(err))")
                            println("err: $err")
                            rethrow(err)
                        end
                    end
                end
            catch err
                if isa(err,Base.UVError) && err.prefix == "accept"
                    println("Server closed successfully")
                else
                    rethrow()
                end
            end
        end
        return server
    end