diff --git a/.github/workflows/ci-nightly.yml b/.github/workflows/ci-nightly.yml index a9e05e4..e74c706 100644 --- a/.github/workflows/ci-nightly.yml +++ b/.github/workflows/ci-nightly.yml @@ -18,6 +18,8 @@ jobs: - 'nightly' os: - ubuntu-latest + - macos-latest + - windows-latest arch: - x64 steps: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7b0388..abf061e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,10 +15,12 @@ jobs: fail-fast: false matrix: version: - - '1.5' - - '1' + - '1.6' + - '1' # This automatically expands to the latest stable 1.x release. os: - ubuntu-latest + - macos-latest + - windows-latest arch: - x64 steps: @@ -39,25 +41,3 @@ jobs: ${{ runner.os }}- - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 - docs: - name: Documentation - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 - with: - version: '1' - - run: | - julia --project=docs -e ' - using Pkg - Pkg.develop(PackageSpec(path=pwd())) - Pkg.instantiate()' - - run: | - julia --project=docs -e ' - using Documenter: doctest - using BaremetalPi - doctest(BaremetalPi)' - - run: julia --project=docs docs/make.jl - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..6dcad3f --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,22 @@ +name: Documentation +on: + push: + branches: + - master + tags: '*' + pull_request: + +jobs: + docs: + name: Documenter + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@v1 + with: + version: '1' + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-docdeploy@releases/v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 19406d0..b1c69b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ BaremetalPi.jl Changelog ======================== +Version 0.2.0 +------------- + +- ![BREAKING][badge-breaking] The `@assert`s were removed and changed to + conditionals. This modification can change the behavior of the code in some + corner cases. However, the code is more robust. +- ![Bug][badge-bugfix] IOCTL calls were not working with structures (pointers), + leading to problems when using SPI. + + +Version 0.1.2 +------------- + +- ![Bug][badge-bugfix] BaremetalPi.jl is now compatible with Julia 1.7. + Version 0.1.1 ------------- diff --git a/Project.toml b/Project.toml index 8e860d6..36c91af 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "BaremetalPi" uuid = "3a90a9a9-52f9-452b-94bd-193d585bd84f" authors = ["Ronan Arraes Jardim Chagas "] -version = "0.1.1" +version = "0.2.0" [compat] julia = "1" diff --git a/docs/Project.toml b/docs/Project.toml index dfa65cd..1a6d309 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,2 +1,5 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" + +[compat] +Documenter = "~0.27" diff --git a/docs/src/man/examples/temperature.md b/docs/src/man/examples/temperature.md index 262ab26..ce683c3 100644 --- a/docs/src/man/examples/temperature.md +++ b/docs/src/man/examples/temperature.md @@ -109,7 +109,7 @@ function acquire_temperature() end # AD measurement. - V = ( (UInt16(rx_buf[2] & 3) << 8) + rx_buf[3] )*3.3/1024 + V = ((UInt16(rx_buf[2] & 3) << 8) + rx_buf[3]) * 3.3 / 1024 if V == 0 @warn("The MCP3008 measured 0V.") @@ -124,8 +124,8 @@ function acquire_temperature() # Convert the measurement to temperature # ========================================================================== - th_R = R_div*(3.3/V - 1) - T = 1/( log(th_R / th_R₀)/th_β + 1/(th_T₀ + 273.15) ) - 273.15 + th_R = R_div * (3.3 / V - 1) + T = 1 / (log(th_R / th_R₀) / th_β + 1 / (th_T₀ + 273.15)) - 273.15 return T end diff --git a/src/cmacros.jl b/src/cmacros.jl index 273764e..cdb8f64 100644 --- a/src/cmacros.jl +++ b/src/cmacros.jl @@ -33,13 +33,15 @@ const _IOC_DIRSHIFT = (_IOC_SIZESHIFT+_IOC_SIZEBITS) const _IOC_WRITE = UInt32(1) const _IOC_READ = UInt32(2) -_IOC(dir,type,nr,size) = (dir << _IOC_DIRSHIFT) | - (type << _IOC_TYPESHIFT) | - (nr << _IOC_NRSHIFT) | - (size << _IOC_SIZESHIFT) +function _IOC(dir, type, nr, size) + return (dir << _IOC_DIRSHIFT) | + (type << _IOC_TYPESHIFT) | + (nr << _IOC_NRSHIFT) | + (size << _IOC_SIZESHIFT) +end -_IOW(type,nr,size) = _IOC(_IOC_WRITE, type, nr, size) -_IOR(type,nr,size) = _IOC(_IOC_READ, type, nr, size) +_IOW(type, nr, size) = _IOC(_IOC_WRITE, type, nr, size) +_IOR(type, nr, size) = _IOC(_IOC_READ, type, nr, size) ################################################################################ # I2C @@ -82,31 +84,38 @@ const I2C_FUNC_SMBUS_READ_I2C_BLOCK = 0x04000000 const I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x08000000 const I2C_FUNC_SMBUS_HOST_NOTIFY = 0x10000000 -const I2C_FUNC_SMBUS_BYTE = (I2C_FUNC_SMBUS_READ_BYTE | - I2C_FUNC_SMBUS_WRITE_BYTE) -const I2C_FUNC_SMBUS_BYTE_DATA = (I2C_FUNC_SMBUS_READ_BYTE_DATA | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA) -const I2C_FUNC_SMBUS_WORD_DATA = (I2C_FUNC_SMBUS_READ_WORD_DATA | - I2C_FUNC_SMBUS_WRITE_WORD_DATA) -const I2C_FUNC_SMBUS_BLOCK_DATA = (I2C_FUNC_SMBUS_READ_BLOCK_DATA | - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) -const I2C_FUNC_SMBUS_I2C_BLOCK = (I2C_FUNC_SMBUS_READ_I2C_BLOCK | - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) - -const I2C_FUNC_SMBUS_EMUL = (I2C_FUNC_SMBUS_QUICK | - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_PROC_CALL | - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK | - I2C_FUNC_SMBUS_PEC) +const I2C_FUNC_SMBUS_BYTE = (I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE) -const I2C_SMBUS_BLOCK_MAX = UInt8(32) +const I2C_FUNC_SMBUS_BYTE_DATA = ( + I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA +) + +const I2C_FUNC_SMBUS_WORD_DATA = ( + I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA +) + +const I2C_FUNC_SMBUS_BLOCK_DATA = ( + I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA +) + +const I2C_FUNC_SMBUS_I2C_BLOCK = ( + I2C_FUNC_SMBUS_READ_I2C_BLOCK | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK +) +const I2C_FUNC_SMBUS_EMUL = ( + I2C_FUNC_SMBUS_QUICK | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK | + I2C_FUNC_SMBUS_PEC +) + +const I2C_SMBUS_BLOCK_MAX = UInt8(32) const I2C_SMBUS_READ = 0x01 const I2C_SMBUS_WRITE = 0x00 - const I2C_SMBUS_QUICK = UInt32(0) const I2C_SMBUS_BYTE = UInt32(1) const I2C_SMBUS_BYTE_DATA = UInt32(2) @@ -126,10 +135,10 @@ const I2C_SMBUS_I2C_BLOCK_DATA = UInt32(8) const SPI_CPHA = 0x01 const SPI_CPOL = 0x02 -const SPI_MODE_0 = (0|0) -const SPI_MODE_1 = (0|SPI_CPHA) -const SPI_MODE_2 = (SPI_CPOL|0) -const SPI_MODE_3 = (SPI_CPOL|SPI_CPHA) +const SPI_MODE_0 = (0 | 0) +const SPI_MODE_1 = (0 | SPI_CPHA) +const SPI_MODE_2 = (SPI_CPOL | 0) +const SPI_MODE_3 = (SPI_CPOL | SPI_CPHA) const SPI_CS_HIGH = 0x04 const SPI_LSB_FIRST = 0x08 @@ -140,16 +149,20 @@ const SPI_READY = 0x80 const SPI_IOC_MAGIC = UInt('k') -SPI_MSGSIZE(N) = - ( N*sizeof(struct_spi_ioc_transfer) < (1 << _IOC_SIZEBITS) ) ? - N*sizeof(struct_spi_ioc_transfer) : 0 +function SPI_MSGSIZE(N) + if (N * sizeof(struct_spi_ioc_transfer)) < (1 << _IOC_SIZEBITS) + return N * sizeof(struct_spi_ioc_transfer) + else + return 0 + end +end # In the past, we were using `NTuple{SPI_MSGSIZE(N), Cchar}` to create a type so # that the function `_IOC_TYPECHECK(t) = sizeof(t)` could retrieve the correct # size. However, this was causing 3 allocations. Thus, the system was simplified # to avoid this. Now, the functions `_IOR` and `_IOW` must receive the size # instead of the type as it was coded in the Kernel source. -SPI_IOC_MESSAGE(N) = _IOW(SPI_IOC_MAGIC, 0, sizeof(Cchar)*SPI_MSGSIZE(N)) +SPI_IOC_MESSAGE(N) = _IOW(SPI_IOC_MAGIC, 0, sizeof(Cchar) * SPI_MSGSIZE(N)) const SPI_IOC_RD_MODE = _IOR(SPI_IOC_MAGIC, 1, sizeof(__u8)) const SPI_IOC_WR_MODE = _IOW(SPI_IOC_MAGIC, 1, sizeof(__u8)) diff --git a/src/constants.jl b/src/constants.jl index 4f3cd76..95db2b2 100644 --- a/src/constants.jl +++ b/src/constants.jl @@ -22,23 +22,27 @@ const __u64 = UInt64 const GPIOMEM_SIZE = 1024 -const GPIO_MODE_GET = Dict(0b000 => :in, - 0b001 => :out, - 0b100 => :alt0, - 0b101 => :alt1, - 0b110 => :alt2, - 0b111 => :alt3, - 0b011 => :alt4, - 0b010 => :alt5) - -const GPIO_MODE_SET = Dict(:in => 0b000, - :out => 0b001, - :alt0 => 0b100, - :alt1 => 0b101, - :alt2 => 0b110, - :alt3 => 0b111, - :alt4 => 0b011, - :alt5 => 0b010) +const GPIO_MODE_GET = Dict( + 0b000 => :in, + 0b001 => :out, + 0b100 => :alt0, + 0b101 => :alt1, + 0b110 => :alt2, + 0b111 => :alt3, + 0b011 => :alt4, + 0b010 => :alt5 +) + +const GPIO_MODE_SET = Dict( + :in => 0b000, + :out => 0b001, + :alt0 => 0b100, + :alt1 => 0b101, + :alt2 => 0b110, + :alt3 => 0b111, + :alt4 => 0b011, + :alt5 => 0b010 +) ################################################################################ # SPI diff --git a/src/gpio.jl b/src/gpio.jl index 4b53c95..933925e 100644 --- a/src/gpio.jl +++ b/src/gpio.jl @@ -7,8 +7,8 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -export init_gpio, gpio_get_mode, gpio_set_mode, gpio_read, gpio_clear, gpio_set, - gpio_value +export init_gpio, gpio_get_mode, gpio_set_mode, gpio_read, gpio_clear, gpio_set +export gpio_value ################################################################################ # Initialization @@ -18,14 +18,18 @@ export init_gpio, gpio_get_mode, gpio_set_mode, gpio_read, gpio_clear, gpio_set, init_gpio() Initialize the GPIO. - """ function init_gpio() # Open and map /dev/gpiomem. try gpiomem_io = open("/dev/gpiomem", "w+") - gpiomem_map = Mmap.mmap(gpiomem_io, Vector{UInt32}, (GPIOMEM_SIZE,), 0, - grow = false) + gpiomem_map = Mmap.mmap( + gpiomem_io, + Vector{UInt32}, + (GPIOMEM_SIZE,), + 0, + grow = false + ) objects.gpiomem_io = gpiomem_io objects.gpiomem_map = gpiomem_map @@ -45,17 +49,16 @@ end gpio_get_mode(gpio::Int) Return the state of the GPIO `gpio`. - """ function gpio_get_mode(gpio::Int) - @assert objects.gpio_init "GPIO not initialized. Run init_gpio()." - @assert (0 ≤ gpio ≤ 27) "GPIO out of range." + !objects.gpio_init && error("GPIO not initialized. Run init_gpio().") + !(0 ≤ gpio ≤ 27) && error("GPIO out of range.") map = objects.gpiomem_map @inbounds begin ind = div(gpio, 10) + 1 - g = 3*(gpio % 10) + g = 3 * (gpio % 10) mask = 7 << g state = (map[ind] & mask) >> g @@ -83,18 +86,20 @@ Set the mode of the GPIO `gpio` to `mode`. `gpio` can be an integer of an * `:alt3`: GPIO will be set to alternate function 3. * `:alt4`: GPIO will be set to alternate function 4. * `:alt5`: GPIO will be set to alternate function 5. - """ function gpio_set_mode(gpio::Int, mode::Symbol) - @assert objects.gpio_init "GPIO not initialized. Run init_gpio()." - @assert (0 ≤ gpio ≤ 27) "GPIO out of range." - @assert haskey(GPIO_MODE_SET, mode) "Unknown GPIO mode." + !objects.gpio_init && error("GPIO not initialized. Run init_gpio().") + !(0 ≤ gpio ≤ 27) && error("GPIO out of range.") + + if !haskey(GPIO_MODE_SET, mode) + error("Unknown GPIO mode.") + end map = objects.gpiomem_map @inbounds begin ind = div(gpio, 10) + 1 - g = 3*(gpio % 10) + g = 3 * (gpio % 10) # We must always clear the GPIO mode before setting the new mode. This # is done by temporarily setting the GPIO to `:in`. @@ -125,14 +130,13 @@ end gpio_read(gpio::Int) Read the GPIO `gpio`. The returned value is boolean. - """ function gpio_read(gpio::Int) - @assert objects.gpio_init "GPIO not initialized. Run init_gpio()." - @assert (0 ≤ gpio ≤ 27) "GPIO out of range." + !objects.gpio_init && error("GPIO not initialized. Run init_gpio().") + !(0 ≤ gpio ≤ 27) && error("GPIO out of range.") @inbounds begin - if (objects.gpiomem_map[13+1] & (1 << gpio)) > 0 + if (objects.gpiomem_map[13 + 1] & (1 << gpio)) > 0 return true else return false @@ -148,14 +152,13 @@ end gpio_clear(gpio::Int) Clear GPIO `gpio`. - """ @inline function gpio_clear(gpio::Int) - @assert objects.gpio_init "GPIO not initialized. Run init_gpio()." - @assert (0 ≤ gpio ≤ 27) "GPIO out of range." + !objects.gpio_init && error("GPIO not initialized. Run init_gpio().") + !(0 ≤ gpio ≤ 27) && error("GPIO out of range.") @inbounds begin - objects.gpiomem_map[10+1] = 1 << gpio + objects.gpiomem_map[10 + 1] = 1 << gpio end return nothing @@ -173,14 +176,13 @@ end gpio_set(gpio::Int) Set GPIO `gpio`. - """ @inline function gpio_set(gpio::Int) - @assert objects.gpio_init "GPIO not initialized. Run init_gpio()." - @assert (0 ≤ gpio ≤ 27) "GPIO out of range." + !objects.gpio_init && error("GPIO not initialized. Run init_gpio().") + !(0 ≤ gpio ≤ 27) && error("GPIO out of range.") @inbounds begin - objects.gpiomem_map[7+1] = 1 << gpio + objects.gpiomem_map[7 + 1] = 1 << gpio end return nothing @@ -203,18 +205,17 @@ bits that are `1` will be set. gpio_value(v::BitVector) Convert the bit array `v` to `Int` and call `gpio_value(::Int)`. - """ function gpio_value(v::Integer) - @assert objects.gpio_init "GPIO not initialized. Run init_gpio()." - @assert (v ≥ 0) "`v` cannot be negative." + !objects.gpio_init && error("GPIO not initialized. Run init_gpio().") + (v < 0) && error("`v` cannot be negative.") @inbounds begin # Set the GPIO. - objects.gpiomem_map[7+1] = v & 0xFFFFFFF + objects.gpiomem_map[7 + 1] = v & 0xFFFFFFF # Clear the GPIOs. - objects.gpiomem_map[10+1] = (~UInt32(v)) & 0xFFFFFFF + objects.gpiomem_map[10 + 1] = (~UInt32(v)) & 0xFFFFFFF end return nothing diff --git a/src/i2c.jl b/src/i2c.jl index 59f2a78..0c67af7 100644 --- a/src/i2c.jl +++ b/src/i2c.jl @@ -7,11 +7,11 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -export init_i2c, close_i2c, i2c_get_funcs, i2c_slave, i2c_slave_force, - i2c_smbus_read_byte, i2c_smbus_read_byte_data, i2c_smbus_read_word_data, - i2c_smbus_read_i2c_block_data!, i2c_smbus_read_i2c_block_data, - i2c_smbus_write_byte, i2c_smbus_write_byte_data, - i2c_smbus_write_word_data, i2c_smbus_write_i2c_block_data +export init_i2c, close_i2c, i2c_get_funcs, i2c_slave, i2c_slave_force +export i2c_smbus_read_byte, i2c_smbus_read_byte_data, i2c_smbus_read_word_data +export i2c_smbus_read_i2c_block_data!, i2c_smbus_read_i2c_block_data +export i2c_smbus_write_byte, i2c_smbus_write_byte_data +export i2c_smbus_write_word_data, i2c_smbus_write_i2c_block_data ################################################################################ # Initialization @@ -22,12 +22,10 @@ export init_i2c, close_i2c, i2c_get_funcs, i2c_slave, i2c_slave_force, Initialize the I2C devices. `devices` can be a string with the path to `i2cdev` or a vector of strings with a set of I2C devices that will be initialized. - """ @inline init_i2c(device::String) = init_i2c([device]) function init_i2c(devices::AbstractVector{String}) - # Number of devices that the user wants to initialize. num_init_devices = length(devices) @@ -68,7 +66,6 @@ end close_i2c() Close all I2C connections. - """ function close_i2c() if objects.i2c_init @@ -93,11 +90,10 @@ Return a vector with the available I2C functions in the device `devid`. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ @inline function i2c_get_funcs(devid::Int) - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") return objects.i2cdev[devid].funcs end @@ -113,11 +109,10 @@ Select the slave device in address `address` using I2C device `devid`. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ function i2c_slave(devid::Integer, address::Integer) - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") i2cdev = objects.i2cdev[devid] @@ -133,11 +128,10 @@ Force selection of slave device in address `address` using I2C device `devid`. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ function i2c_slave_force(devid::Integer, address::Integer) - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") i2cdev = objects.i2cdev[devid] @@ -157,19 +151,20 @@ the read byte. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ function i2c_smbus_read_byte(devid::Integer) - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") i2cdev = objects.i2cdev[devid] # Create the SMBUS IOCTL structure to issue the ioctl command. - smbus = struct_i2c_smbus_ioctl_data(I2C_SMBUS_READ, - 0, - I2C_SMBUS_BYTE, - pointer(i2cdev.bbyte)) + smbus = struct_i2c_smbus_ioctl_data( + I2C_SMBUS_READ, + 0, + I2C_SMBUS_BYTE, + pointer(i2cdev.bbyte) + ) _ioctl(fd(i2cdev.io), I2C_SMBUS, Ref(smbus)) @@ -184,19 +179,20 @@ This function return the read byte. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ function i2c_smbus_read_byte_data(devid::Integer, command::Integer) - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") i2cdev = objects.i2cdev[devid] # Create the SMBUS IOCTL structure to issue the ioctl command. - smbus = struct_i2c_smbus_ioctl_data(I2C_SMBUS_READ, - command, - I2C_SMBUS_BYTE_DATA, - pointer(i2cdev.bbyte)) + smbus = struct_i2c_smbus_ioctl_data( + I2C_SMBUS_READ, + command, + I2C_SMBUS_BYTE_DATA, + pointer(i2cdev.bbyte) + ) _ioctl(fd(i2cdev.io), I2C_SMBUS, Ref(smbus)) @@ -211,19 +207,20 @@ This function return the read word. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ function i2c_smbus_read_word_data(devid::Integer, command::Integer) - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + (0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") i2cdev = objects.i2cdev[devid] # Create the SMBUS IOCTL structure to issue the ioctl command. - smbus = struct_i2c_smbus_ioctl_data(I2C_SMBUS_READ, - command, - I2C_SMBUS_WORD_DATA, - pointer(i2cdev.bword)) + smbus = struct_i2c_smbus_ioctl_data( + I2C_SMBUS_READ, + command, + I2C_SMBUS_WORD_DATA, + pointer(i2cdev.bword) + ) _ioctl(fd(i2cdev.io), I2C_SMBUS, Ref(smbus)) @@ -255,15 +252,22 @@ the function `init_i2c` was called. Due to the view returned by this functions, it performs one allocation. If this is not wanted, then use the in-place version `i2c_smbus_read_i2c_block_data!`. - """ -function i2c_smbus_read_i2c_block_data(devid::Integer, command::Integer, - size::Integer) +function i2c_smbus_read_i2c_block_data( + devid::Integer, + command::Integer, + size::Integer +) + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") + + if size < 0 + error("The `size` must be larger than 0.") + end - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." - @assert (size > 0) "The `size` must be larger than 0." - @assert (size ≤ I2C_SMBUS_BLOCK_MAX) "I2C block data cannot read more than $(I2C_SMBUS_BLOCK_MAX) bytes." + if size > I2C_SMBUS_BLOCK_MAX + error("I2C block data cannot read more than $(I2C_SMBUS_BLOCK_MAX) bytes.") + end i2cdev = objects.i2cdev[devid] data = i2cdev.bblock @@ -272,14 +276,16 @@ function i2c_smbus_read_i2c_block_data(devid::Integer, command::Integer, @inbounds data[1] = size # Create the SMBUS IOCTL structure to issue the ioctl command. - smbus = struct_i2c_smbus_ioctl_data(I2C_SMBUS_READ, - command, - I2C_SMBUS_I2C_BLOCK_DATA, - pointer(data)) + smbus = struct_i2c_smbus_ioctl_data( + I2C_SMBUS_READ, + command, + I2C_SMBUS_I2C_BLOCK_DATA, + pointer(data) + ) _ioctl(fd(i2cdev.io), I2C_SMBUS, Ref(smbus)) - return view(data, 1:size+1) + return view(data, 1:(size + 1)) end """ @@ -292,18 +298,24 @@ length of `data` minus 1. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ -function i2c_smbus_read_i2c_block_data!(devid::Integer, command::Integer, - data::Vector{UInt8}) - - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." +function i2c_smbus_read_i2c_block_data!( + devid::Integer, + command::Integer, + data::Vector{UInt8} +) + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") size = length(data) - @assert (size ≤ I2C_SMBUS_BLOCK_MAX+1) "I2C block data cannot read more than $(I2C_SMBUS_BLOCK_MAX) bytes." - @assert (size > 1) "The `data` array must have at least 2 elements." + if size > I2C_SMBUS_BLOCK_MAX + 1 + error("I2C block data cannot read more than $(I2C_SMBUS_BLOCK_MAX) bytes.") + end + + if size ≤ 1 + error("The `data` array must have at least 2 elements.") + end i2cdev = objects.i2cdev[devid] @@ -311,10 +323,12 @@ function i2c_smbus_read_i2c_block_data!(devid::Integer, command::Integer, @inbounds data[1] = size - 1 # Create the SMBUS IOCTL structure to issue the ioctl command. - smbus = struct_i2c_smbus_ioctl_data(I2C_SMBUS_READ, - command, - I2C_SMBUS_I2C_BLOCK_DATA, - pointer(data)) + smbus = struct_i2c_smbus_ioctl_data( + I2C_SMBUS_READ, + command, + I2C_SMBUS_I2C_BLOCK_DATA, + pointer(data) + ) _ioctl(fd(i2cdev.io), I2C_SMBUS, Ref(smbus)) @@ -331,19 +345,20 @@ Perform a SMBUS write byte with value `value` using the I2C device `devid`. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ function i2c_smbus_write_byte(devid::Integer, value::Integer) - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") i2cdev = objects.i2cdev[devid] # Create the SMBUS IOCTL structure to issue the ioctl command. - smbus = struct_i2c_smbus_ioctl_data(I2C_SMBUS_WRITE, - value, - I2C_SMBUS_BYTE, - C_NULL) + smbus = struct_i2c_smbus_ioctl_data( + I2C_SMBUS_WRITE, + value, + I2C_SMBUS_BYTE, + C_NULL + ) _ioctl(fd(i2cdev.io), I2C_SMBUS, Ref(smbus)) @@ -358,12 +373,14 @@ I2C device `devid`. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ -function i2c_smbus_write_byte_data(devid::Integer, command::Integer, - value::Integer) - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." +function i2c_smbus_write_byte_data( + devid::Integer, + command::Integer, + value::Integer +) + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") i2cdev = objects.i2cdev[devid] @@ -371,10 +388,12 @@ function i2c_smbus_write_byte_data(devid::Integer, command::Integer, data = i2cdev.bbyte @inbounds data[1] = value - smbus = struct_i2c_smbus_ioctl_data(I2C_SMBUS_WRITE, - command, - I2C_SMBUS_BYTE_DATA, - pointer(data)) + smbus = struct_i2c_smbus_ioctl_data( + I2C_SMBUS_WRITE, + command, + I2C_SMBUS_BYTE_DATA, + pointer(data) + ) _ioctl(fd(i2cdev.io), I2C_SMBUS, Ref(smbus)) @@ -389,12 +408,14 @@ I2C device `devid`. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ -function i2c_smbus_write_word_data(devid::Integer, command::Integer, - value::Integer) - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." +function i2c_smbus_write_word_data( + devid::Integer, + command::Integer, + value::Integer +) + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") i2cdev = objects.i2cdev[devid] @@ -402,10 +423,12 @@ function i2c_smbus_write_word_data(devid::Integer, command::Integer, data = i2cdev.bword @inbounds data[1] = value - smbus = struct_i2c_smbus_ioctl_data(I2C_SMBUS_WRITE, - command, - I2C_SMBUS_WORD_DATA, - pointer(data)) + smbus = struct_i2c_smbus_ioctl_data( + I2C_SMBUS_WRITE, + command, + I2C_SMBUS_WORD_DATA, + pointer(data) + ) _ioctl(fd(i2cdev.io), I2C_SMBUS, Ref(smbus)) @@ -420,17 +443,20 @@ using the I2C device `devid`. `devid` is the ID of the I2C device considering the initialization order when the function `init_i2c` was called. - """ -function i2c_smbus_write_i2c_block_data(devid::Integer, command::Integer, - values::Vector{UInt8}) - - @assert objects.i2c_init "I2C not initialized. Run init_i2c()." - @assert (0 < devid ≤ length(objects.i2cdev)) "I2C device ID is out of bounds." +function i2c_smbus_write_i2c_block_data( + devid::Integer, + command::Integer, + values::Vector{UInt8} +) + !objects.i2c_init && error("I2C not initialized. Run init_i2c().") + !(0 < devid ≤ length(objects.i2cdev)) && error("I2C device ID is out of bounds.") size = length(values) - @assert (size ≤ I2C_SMBUS_BLOCK_MAX) "I2C block data cannot write more than $(I2C_SMBUS_BLOCK_MAX) bytes." + if size > I2C_SMBUS_BLOCK_MAX + error("I2C block data cannot write more than $(I2C_SMBUS_BLOCK_MAX) bytes.") + end i2cdev = objects.i2cdev[devid] @@ -441,14 +467,16 @@ function i2c_smbus_write_i2c_block_data(devid::Integer, command::Integer, # If we use a slice here, then one allocation will be performed because of # the required `view` that will be created. @inbounds for i = 1:size - data[i+1] = values[i] + data[i + 1] = values[i] end # Create the SMBUS IOCTL structure to issue the ioctl command. - smbus = struct_i2c_smbus_ioctl_data(I2C_SMBUS_WRITE, - command, - I2C_SMBUS_I2C_BLOCK_DATA, - pointer(data)) + smbus = struct_i2c_smbus_ioctl_data( + I2C_SMBUS_WRITE, + command, + I2C_SMBUS_I2C_BLOCK_DATA, + pointer(data) + ) _ioctl(fd(i2cdev.io), I2C_SMBUS, Ref(smbus)) diff --git a/src/ioctl.jl b/src/ioctl.jl index aad7902..314a7eb 100644 --- a/src/ioctl.jl +++ b/src/ioctl.jl @@ -9,19 +9,32 @@ @inline _ioctl(io::IOStream, args...) = _ioctl(fd(io), args...) -function _ioctl(fd::Integer, request::Integer, arg::T) where T <: Number - ret = ccall(:ioctl, Cint, (Cint, Culong, T), fd, request, arg) - ret < 0 && throw(SystemError("Error in IOCTL call", Libc.errno())) - return ret -end +for (Tj, Tc) in ( + (Int8, Cchar), + (Int16, Cshort), + (Int32, Cint), + (Int64, Clonglong), + (UInt8, Cuchar), + (UInt16, Cushort), + (UInt32, Cuint), + (UInt64, Culonglong), + (Float32, Cfloat), + (Float64, Cdouble) +) + @eval function _ioctl(fd::Integer, request::Integer, arg::$Tj) + ret = ccall(:ioctl, Cint, (Cint, Culong, $Tc), fd, request, arg) + ret < 0 && throw(SystemError("Error in IOCTL call", Libc.errno())) + return ret + end -function _ioctl(fd::Integer, request::Integer, arg::Base.RefValue{T}) where T - ret = ccall(:ioctl, Cint, (Cint, Culong, Ref{T}), fd, request, arg) - ret < 0 && throw(SystemError("Error in IOCTL call", Libc.errno())) - return ret + @eval function _ioctl(fd::Integer, request::Integer, arg::AbstractVector{$Tj}) + ret = ccall(:ioctl, Cint, (Cint, Culong, Ref{$Tc}), fd, request, arg) + ret < 0 && throw(SystemError("Error in IOCTL call", Libc.errno())) + return ret + end end -function _ioctl(fd::Integer, request::Integer, arg::AbstractVector{T}) where T +function _ioctl(fd::Integer, request::Integer, arg::Base.RefValue{T}) where T ret = ccall(:ioctl, Cint, (Cint, Culong, Ref{T}), fd, request, arg) ret < 0 && throw(SystemError("Error in IOCTL call", Libc.errno())) return ret diff --git a/src/spi.jl b/src/spi.jl index 1852915..171c4d0 100644 --- a/src/spi.jl +++ b/src/spi.jl @@ -23,21 +23,22 @@ or a vector of strings with a set of SPI devices that will be initialized. * `mode`: Set the mode of the SPI. (**Default** = 0) * `max_speed_hz`: Maximum allowed speed in SPI communication [Hz]. - (**Default** = 4_000_000) + (**Default** = 4_000_000) * `bits_per_word`: Number of bits per word in SPI communication. - (**Default** = 8) + (**Default** = 8) Notice that all keywords can be a `Integer`, when the configuration will be applied to all SPI devices, or a `Vector` of `Integers`, when different configurations can be applied to the initialized devices. - """ @inline init_spi(devices::String; kwargs...) = init_spi([devices]; kwargs...) -function init_spi(devices::AbstractVector{String}; - mode::Union{Integer,Vector{Integer}} = 0, - max_speed_hz::Union{Integer,Vector{Integer}} = 4_000_000, - bits_per_word::Union{Integer,Vector{Integer}} = 8) +function init_spi( + devices::AbstractVector{String}; + mode::Union{Integer, Vector{Integer}} = 0, + max_speed_hz::Union{Integer, Vector{Integer}} = 4_000_000, + bits_per_word::Union{Integer, Vector{Integer}} = 8 +) # Number of devices that the user wants to initialize. num_init_devices = length(devices) @@ -63,9 +64,9 @@ function init_spi(devices::AbstractVector{String}; spidev = Vector{SPIDEV}(undef, 0) @inbounds for i = 1:num_init_devices - @assert (mode[i] ≥ 0) error("Invalid SPI mode.") - @assert (max_speed_hz[i] > 0) error("Invalid maximum speed [Hz].") - @assert (bits_per_word[i] > 0) error("Invalid number of bits per word.") + (mode[i] < 0) && error("Invalid SPI mode.") + (max_speed_hz[i] ≤ 0) && error("Invalid maximum speed [Hz].") + (bits_per_word[i] ≤ 0) && error("Invalid number of bits per word.") try # Open the device @@ -108,7 +109,6 @@ end close_spi() Close all SPI connections. - """ function close_spi() if objects.spi_init @@ -148,11 +148,12 @@ the number of words received. # Keywords The same keywords of `spi_transfer!` can be used. - """ -function spi_transfer(devid::Integer, tx_buf::AbstractVector{T}; kwargs...) where - T<:Integer - +function spi_transfer( + devid::Integer, + tx_buf::AbstractVector{T}; + kwargs... +) where T<:Integer # Allocate the vector that will hold the returned words. rx_buf = zeros(T, length(tx_buf)) @@ -162,8 +163,11 @@ function spi_transfer(devid::Integer, tx_buf::AbstractVector{T}; kwargs...) wher return rx_buf, ret end -function spi_transfer(devid::Integer, tx_buf::AbstractVector{T}; kwargs...) where - T<:Vector{U} where U<:Integer +function spi_transfer( + devid::Integer, + tx_buf::AbstractVector{T}; + kwargs... +) where T<:(Vector{U} where U<:Integer) # Allocate the vectors that will hold the returned words. rx_buf = zeros.(U, length.(tx_buf)) @@ -199,36 +203,47 @@ This function returns the number of bytes received. # Keywords * `max_speed_hz`: If > 0, then override the default maximum transfer speed with - this value [Hz]. (**Default** = 0) + this value [Hz]. (**Default** = 0) * `delay_usecs`: If ≥ 0, then override the default delay with this value. - (**Default** = -1) + (**Default** = -1) * `bits_per_word`: If > 0, then override the number of bits per word with this - value. (**Default** = 0) + value. (**Default** = 0) * `cs_change`: If `false`, the deselect the device at the end of the transfer. - """ -function spi_transfer!(devid::Integer, - tx_buf::AbstractVector{T}, - rx_buf::AbstractVector{T}; - max_speed_hz::Integer = 0, - delay_usecs::Integer = -1, - bits_per_word::Integer = 8, - cs_change::Bool = false) where T<:Vector{U} where U <:Integer - - @assert objects.spi_init "SPI not initialized. Run init_spi()." - @assert (0 < devid ≤ length(objects.spidev)) "SPI device ID is out of bounds." +function spi_transfer!( + devid::Integer, + tx_buf::AbstractVector{T}, + rx_buf::AbstractVector{T}; + max_speed_hz::Integer = 0, + delay_usecs::Integer = -1, + bits_per_word::Integer = 8, + cs_change::Bool = false +) where T<:(Vector{U} where U <:Integer) + + !objects.spi_init && error("SPI not initialized. Run init_spi().") + !(0 < devid ≤ length(objects.spidev)) && error("SPI device ID is out of bounds.") spidev = objects.spidev[devid] # Number of messages to be transmitted. num_msgs = length(tx_buf) - @assert (length(rx_buf) ≥ num_msgs) "The number of buffers in `rx_buf` must be equal or bigger than the number of buffers in `tx_buf`." + if length(rx_buf) ≥ num_msgs + error("The number of buffers in `rx_buf` must be equal or bigger than the number of buffers in `tx_buf`.") + end # Check default parameters. - max_speed_hz ≤ 0 && (max_speed_hz = spidev.max_speed_hz) - delay_usecs < 0 && (delay_usecs = 0) - bits_per_word ≤ 0 && (bits_per_word = spidev.bits_per_word) + if max_speed_hz ≤ 0 + max_speed_hz = spidev.max_speed_hz + end + + if delay_usecs < 0 + delay_usecs = 0 + end + + if bits_per_word ≤ 0 + bits_per_word = spidev.bits_per_word + end # Check if we can use the allocated buffer to transfer the message. if num_msgs > _SPI_BUFFER_SIZE @@ -240,59 +255,82 @@ function spi_transfer!(devid::Integer, @inbounds for i = 1:num_msgs msg_size = length(tx_buf[i]) - @assert (msg_size*bits_per_word ≤ objects.spi_buffer_size*8) "The message to be transmitted is larger than the SPI buffer." - @assert (length(rx_buf[i]) ≥ msg_size) "The length of `rx_buf[i]` must be equal or bigger than that of `tx_buf[i]`." + if msg_size * bits_per_word > objects.spi_buffer_size * 8 + error("The message to be transmitted is larger than the SPI buffer.") + end + + if length(rx_buf[i]) < msg_size + error("The length of `rx_buf[i]` must be equal or bigger than that of `tx_buf[i]`.") + end # Create the structure that contains the information of the SPI transfer. - descs[i] = struct_spi_ioc_transfer(pointer(tx_buf[i]), - pointer(rx_buf[i]), - # In SPI, the number of transmitted - # and received words are always the - # same. - msg_size*sizeof(U), - max_speed_hz, - delay_usecs, - bits_per_word, - cs_change) + descs[i] = struct_spi_ioc_transfer( + pointer(tx_buf[i]), + pointer(rx_buf[i]), + # In SPI, the number of transmitted and received words are always + # the same. + msg_size * sizeof(U), + max_speed_hz, + delay_usecs, + bits_per_word, + cs_change + ) end # Execute the transfer. return _ioctl(fd(spidev.io), SPI_IOC_MESSAGE(num_msgs), descs) end -function spi_transfer!(devid::Integer, - tx_buf::AbstractVector{T}, - rx_buf::AbstractVector{T}; - max_speed_hz::Integer = 0, - delay_usecs::Integer = -1, - bits_per_word::Integer = 8, - cs_change::Bool = false) where T<:Integer +function spi_transfer!( + devid::Integer, + tx_buf::AbstractVector{T}, + rx_buf::AbstractVector{T}; + max_speed_hz::Integer = 0, + delay_usecs::Integer = -1, + bits_per_word::Integer = 8, + cs_change::Bool = false +) where T<:Integer - @assert objects.spi_init "SPI not initialized. Run init_spi()." - @assert (0 < devid ≤ length(objects.spidev)) "SPI device ID is out of bounds." + !objects.spi_init && error("SPI not initialized. Run init_spi().") + !(0 < devid ≤ length(objects.spidev)) && error("SPI device ID is out of bounds.") spidev = objects.spidev[devid] # Check default parameters. - max_speed_hz ≤ 0 && (max_speed_hz = spidev.max_speed_hz) - delay_usecs < 0 && (delay_usecs = 0) - bits_per_word ≤ 0 && (bits_per_word = spidev.bits_per_word) + if max_speed_hz ≤ 0 + max_speed_hz = spidev.max_speed_hz + end + + if delay_usecs < 0 + delay_usecs = 0 + end + + if bits_per_word ≤ 0 + bits_per_word = spidev.bits_per_word + end msg_size = length(tx_buf) - @assert (msg_size*bits_per_word ≤ objects.spi_buffer_size*8) "The message to be transmitted is larger than the SPI buffer." - @assert (length(rx_buf) ≥ msg_size) "The length of `rx_buf` must be equal or bigger than that of `tx_buf`." + if msg_size * bits_per_word > objects.spi_buffer_size * 8 + error("The message to be transmitted is larger than the SPI buffer.") + end + + if length(rx_buf) < msg_size + error("The length of `rx_buf` must be equal or bigger than that of `tx_buf`.") + end # Create the structure that contains the information of the SPI transfer. - desc = struct_spi_ioc_transfer(pointer(tx_buf), - pointer(rx_buf), - # In SPI, the number of transmitted and - # received words are always the same. - msg_size*sizeof(T), - max_speed_hz, - delay_usecs, - bits_per_word, - cs_change) + desc = struct_spi_ioc_transfer( + pointer(tx_buf), + pointer(rx_buf), + # In SPI, the number of transmitted and received words are always the + # same. + msg_size * sizeof(T), + max_speed_hz, + delay_usecs, + bits_per_word, + cs_change + ) # Execute the transfer. return _ioctl(fd(spidev.io), SPI_IOC_MESSAGE(1), Ref(desc)) diff --git a/src/types.jl b/src/types.jl index 6436199..4f9df92 100644 --- a/src/types.jl +++ b/src/types.jl @@ -20,8 +20,15 @@ mutable struct I2CDEV bword::Vector{UInt16} bblock::Vector{UInt8} - I2CDEV(io, funcs) = new(io, funcs, UInt8[0x00], UInt16[0x00], - zeros(UInt8, I2C_SMBUS_BLOCK_MAX + 1)) + function I2CDEV(io, funcs) + return new( + io, + funcs, + UInt8[0x00], + UInt16[0x00], + zeros(UInt8, I2C_SMBUS_BLOCK_MAX + 1) + ) + end end struct struct_i2c_smbus_ioctl_data{T} @@ -30,8 +37,9 @@ struct struct_i2c_smbus_ioctl_data{T} size::__u32 data::T - struct_i2c_smbus_ioctl_data(read_write, command, size, data::T) where T= - new{T}(__u8(read_write), __u8(command), __u32(size), data) + function struct_i2c_smbus_ioctl_data(read_write, command, size, data::T) where T + return new{T}(__u8(read_write), __u8(command), __u32(size), data) + end end ################################################################################ @@ -53,12 +61,29 @@ struct struct_spi_ioc_transfer pad::__u16 end -struct_spi_ioc_transfer(tx_buf, rx_buf, len, speed_hz, delay_usecs, - bits_per_word, cs_change) = - struct_spi_ioc_transfer(__u64(tx_buf), __u64(rx_buf), __u32(len), - __u32(speed_hz), __u16(delay_usecs), - __u8(bits_per_word), __u8(cs_change), __u8(0), - __u8(0), __u16(0)) +function struct_spi_ioc_transfer( + tx_buf, + rx_buf, + len, + speed_hz, + delay_usecs, + bits_per_word, + cs_change +) + return struct_spi_ioc_transfer( + __u64(tx_buf), + __u64(rx_buf), + __u32(len), + __u32(speed_hz), + __u16(delay_usecs), + __u8(bits_per_word), + __u8(cs_change), + __u8(0), + __u8(0), + __u16(0) + ) +end + mutable struct SPIDEV io::IOStream max_speed_hz::Int @@ -68,9 +93,14 @@ mutable struct SPIDEV bdescs::Vector{struct_spi_ioc_transfer} end -SPIDEV(io, max_speed_hz, bits_per_word) = - SPIDEV(io, max_speed_hz, bits_per_word, - Vector{struct_spi_ioc_transfer}(undef, _SPI_BUFFER_SIZE)) +function SPIDEV(io, max_speed_hz, bits_per_word) + return SPIDEV( + io, + max_speed_hz, + bits_per_word, + Vector{struct_spi_ioc_transfer}(undef, _SPI_BUFFER_SIZE) + ) +end ################################################################################ # Global @@ -81,7 +111,6 @@ SPIDEV(io, max_speed_hz, bits_per_word) = This structure stores global objects, such as the IO file and the memory mappings. - """ mutable struct Objects # GPIO @@ -102,6 +131,13 @@ mutable struct Objects spi_buffer_size::Int end -const objects = Objects(false, IOStream(""), Vector{UInt32}(undef,0), - false, Vector{I2CDEV}(undef, 0), - false, Vector{SPIDEV}(undef, 0), 4096) +const objects = Objects( + false, + IOStream(""), + Vector{UInt32}(undef, 0), + false, + Vector{I2CDEV}(undef, 0), + false, + Vector{SPIDEV}(undef, 0), + 4096 +)