parent
6ad76786b7
commit
205ccbce1d
@ -0,0 +1,9 @@
|
|||||||
|
package: libws2811
|
||||||
|
Version: 1.1.0-1
|
||||||
|
Section: base
|
||||||
|
Priority: optional
|
||||||
|
Architecture: armhf
|
||||||
|
Depends:
|
||||||
|
Maintainer: Jeremy Garff (jer@jers.net)
|
||||||
|
Description: Raspberry Pi WS281X Library
|
||||||
|
LED Control Library for the Raspberry Pi.
|
@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# summary of how this script can be called:
|
||||||
|
# * <postinst> `configure' <most-recently-configured-version>
|
||||||
|
# * <old-postinst> `abort-upgrade' <new version>
|
||||||
|
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||||
|
# <new-version>
|
||||||
|
# * <postinst> `abort-remove'
|
||||||
|
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||||
|
# <failed-install-package> <version> `removing'
|
||||||
|
# <conflicting-package> <version>
|
||||||
|
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||||
|
# the debian-policy package
|
||||||
|
|
||||||
|
# source debconf library
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
# Source dbconfig-common functions
|
||||||
|
if [ -f /usr/share/dbconfig-common/dpkg/postinst.pgsql ]; then
|
||||||
|
. /usr/share/dbconfig-common/dpkg/postinst.pgsql
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
|
||||||
|
configure)
|
||||||
|
ldconfig
|
||||||
|
;;
|
||||||
|
|
||||||
|
abort-upgrade|abort-remove|abort-deconfigure)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "postinst called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
db_stop
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
~
|
@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# summary of how this script can be called:
|
||||||
|
# * <postinst> `configure' <most-recently-configured-version>
|
||||||
|
# * <old-postinst> `abort-upgrade' <new version>
|
||||||
|
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||||
|
# <new-version>
|
||||||
|
# * <postinst> `abort-remove'
|
||||||
|
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||||
|
# <failed-install-package> <version> `removing'
|
||||||
|
# <conflicting-package> <version>
|
||||||
|
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||||
|
# the debian-policy package
|
||||||
|
|
||||||
|
# source debconf library
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
# Source dbconfig-common functions
|
||||||
|
if [ -f /usr/share/dbconfig-common/dpkg/postinst.pgsql ]; then
|
||||||
|
. /usr/share/dbconfig-common/dpkg/postinst.pgsql
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
|
||||||
|
remove)
|
||||||
|
ldconfig
|
||||||
|
;;
|
||||||
|
|
||||||
|
abort-upgrade|abort-remove|abort-deconfigure)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "postrm called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
db_stop
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
~
|
@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# summary of how this script can be called:
|
||||||
|
# * <postinst> `configure' <most-recently-configured-version>
|
||||||
|
# * <old-postinst> `abort-upgrade' <new version>
|
||||||
|
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||||
|
# <new-version>
|
||||||
|
# * <postinst> `abort-remove'
|
||||||
|
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||||
|
# <failed-install-package> <version> `removing'
|
||||||
|
# <conflicting-package> <version>
|
||||||
|
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||||
|
# the debian-policy package
|
||||||
|
|
||||||
|
# source debconf library
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
# Source dbconfig-common functions
|
||||||
|
if [ -f /usr/share/dbconfig-common/dpkg/postinst.pgsql ]; then
|
||||||
|
. /usr/share/dbconfig-common/dpkg/postinst.pgsql
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
|
||||||
|
remove|upgrade|deconfigure)
|
||||||
|
;;
|
||||||
|
|
||||||
|
abort-upgrade|abort-remove|abort-deconfigure)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "postinst called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
db_stop
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
@ -0,0 +1,24 @@
|
|||||||
|
Copyright (c) 2014, jgarff
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
@ -0,0 +1,95 @@
|
|||||||
|
#
|
||||||
|
# SConscript
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
#
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
# provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
# conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
# of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
# provided with the distribution.
|
||||||
|
# 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
# or promote products derived from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
Import(['clean_envs'])
|
||||||
|
|
||||||
|
tools_env = clean_envs['userspace'].Clone()
|
||||||
|
|
||||||
|
|
||||||
|
# Build Library
|
||||||
|
lib_srcs = Split('''
|
||||||
|
mailbox.c
|
||||||
|
ws2811.c
|
||||||
|
pwm.c
|
||||||
|
pcm.c
|
||||||
|
dma.c
|
||||||
|
rpihw.c
|
||||||
|
''')
|
||||||
|
|
||||||
|
version_hdr = tools_env.Version('version')
|
||||||
|
ws2811_lib = tools_env.Library('libws2811', lib_srcs)
|
||||||
|
tools_env['LIBS'].append(ws2811_lib)
|
||||||
|
|
||||||
|
# Shared library (if required)
|
||||||
|
ws2811_slib = tools_env.SharedLibrary('libws2811', lib_srcs)
|
||||||
|
|
||||||
|
# Test Program
|
||||||
|
srcs = Split('''
|
||||||
|
main.c
|
||||||
|
''')
|
||||||
|
|
||||||
|
objs = []
|
||||||
|
for src in srcs:
|
||||||
|
objs.append(tools_env.Object(src))
|
||||||
|
|
||||||
|
test = tools_env.Program('test', objs + tools_env['LIBS'])
|
||||||
|
|
||||||
|
Default([test, ws2811_lib])
|
||||||
|
|
||||||
|
package_version = "1.1.0-1"
|
||||||
|
package_name = 'libws2811_%s' % package_version
|
||||||
|
|
||||||
|
debian_files = [
|
||||||
|
'DEBIAN/control',
|
||||||
|
'DEBIAN/postinst',
|
||||||
|
'DEBIAN/prerm',
|
||||||
|
'DEBIAN/postrm',
|
||||||
|
]
|
||||||
|
|
||||||
|
package_files_desc = [
|
||||||
|
[ '/usr/lib', ws2811_slib ],
|
||||||
|
]
|
||||||
|
|
||||||
|
package_files = []
|
||||||
|
for target in package_files_desc:
|
||||||
|
package_files.append(tools_env.Install(package_name + target[0], target[1]))
|
||||||
|
|
||||||
|
for deb_file in debian_files:
|
||||||
|
package_files.append(
|
||||||
|
tools_env.Command('%s/%s' % (package_name, deb_file), deb_file, [
|
||||||
|
Copy("$TARGET", "$SOURCE"),
|
||||||
|
Chmod("$TARGET", 0755)
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
package = tools_env.Command('%s.deb' % package_name, package_files,
|
||||||
|
'cd %s; dpkg-deb --build %s' % (Dir('.').abspath, package_name));
|
||||||
|
|
||||||
|
Alias("deb", package)
|
||||||
|
|
@ -0,0 +1,76 @@
|
|||||||
|
#
|
||||||
|
# SConstruct
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
#
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
# provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
# conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
# of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
# provided with the distribution.
|
||||||
|
# 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
# or promote products derived from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
opts = Variables()
|
||||||
|
opts.Add(BoolVariable('V',
|
||||||
|
'Verbose build',
|
||||||
|
False))
|
||||||
|
|
||||||
|
opts.Add('TOOLCHAIN',
|
||||||
|
'Set toolchain for cross compilation (e.g. arm-linux-gnueabihf)',
|
||||||
|
'')
|
||||||
|
|
||||||
|
platforms = [
|
||||||
|
[
|
||||||
|
'userspace', # Target Name
|
||||||
|
[ 'linux', 'version' ], # Scons tool (linux, avr, etc.)
|
||||||
|
{ # Special environment setup
|
||||||
|
'CPPPATH' : [
|
||||||
|
],
|
||||||
|
'LINKFLAGS' : [
|
||||||
|
"-lrt",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
clean_envs = {}
|
||||||
|
for platform, tool, flags in platforms:
|
||||||
|
env = Environment(
|
||||||
|
options = opts,
|
||||||
|
tools = tool,
|
||||||
|
toolpath = ['.'],
|
||||||
|
ENV = {'PATH' : os.environ['PATH']},
|
||||||
|
LIBS = [],
|
||||||
|
)
|
||||||
|
env.MergeFlags(flags)
|
||||||
|
clean_envs[platform] = env
|
||||||
|
|
||||||
|
Help(opts.GenerateHelpText(clean_envs))
|
||||||
|
|
||||||
|
if env['TOOLCHAIN'] != '':
|
||||||
|
env['CC'] = env['TOOLCHAIN'] + '-gcc'
|
||||||
|
env['AR'] = env['TOOLCHAIN'] + '-ar'
|
||||||
|
|
||||||
|
Export(['clean_envs'])
|
||||||
|
SConscript('SConscript');
|
||||||
|
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* clk.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CLK_H__
|
||||||
|
#define __CLK_H__
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t ctl;
|
||||||
|
#define CM_CLK_CTL_PASSWD (0x5a << 24)
|
||||||
|
#define CM_CLK_CTL_MASH(val) ((val & 0x3) << 9)
|
||||||
|
#define CM_CLK_CTL_FLIP (1 << 8)
|
||||||
|
#define CM_CLK_CTL_BUSY (1 << 7)
|
||||||
|
#define CM_CLK_CTL_KILL (1 << 5)
|
||||||
|
#define CM_CLK_CTL_ENAB (1 << 4)
|
||||||
|
#define CM_CLK_CTL_SRC_GND (0 << 0)
|
||||||
|
#define CM_CLK_CTL_SRC_OSC (1 << 0)
|
||||||
|
#define CM_CLK_CTL_SRC_TSTDBG0 (2 << 0)
|
||||||
|
#define CM_CLK_CTL_SRC_TSTDBG1 (3 << 0)
|
||||||
|
#define CM_CLK_CTL_SRC_PLLA (4 << 0)
|
||||||
|
#define CM_CLK_CTL_SRC_PLLC (5 << 0)
|
||||||
|
#define CM_CLK_CTL_SRC_PLLD (6 << 0)
|
||||||
|
#define CM_CLK_CTL_SRC_HDMIAUX (7 << 0)
|
||||||
|
uint32_t div;
|
||||||
|
#define CM_CLK_DIV_PASSWD (0x5a << 24)
|
||||||
|
#define CM_CLK_DIV_DIVI(val) ((val & 0xfff) << 12)
|
||||||
|
#define CM_CLK_DIV_DIVF(val) ((val & 0xfff) << 0)
|
||||||
|
} __attribute__((packed, aligned(4))) cm_clk_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PWM and PCM clock offsets from https://www.scribd.com/doc/127599939/BCM2835-Audio-clocks
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define CM_PCM_OFFSET (0x00101098)
|
||||||
|
#define CM_PWM_OFFSET (0x001010a0)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __CLK_H__ */
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* dma.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "dma.h"
|
||||||
|
|
||||||
|
|
||||||
|
// DMA address mapping by DMA number index
|
||||||
|
static const uint32_t dma_offset[] =
|
||||||
|
{
|
||||||
|
DMA0_OFFSET,
|
||||||
|
DMA1_OFFSET,
|
||||||
|
DMA2_OFFSET,
|
||||||
|
DMA3_OFFSET,
|
||||||
|
DMA4_OFFSET,
|
||||||
|
DMA5_OFFSET,
|
||||||
|
DMA6_OFFSET,
|
||||||
|
DMA7_OFFSET,
|
||||||
|
DMA8_OFFSET,
|
||||||
|
DMA9_OFFSET,
|
||||||
|
DMA10_OFFSET,
|
||||||
|
DMA11_OFFSET,
|
||||||
|
DMA12_OFFSET,
|
||||||
|
DMA13_OFFSET,
|
||||||
|
DMA14_OFFSET,
|
||||||
|
DMA15_OFFSET,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t dmanum_to_offset(int dmanum)
|
||||||
|
{
|
||||||
|
int array_size = sizeof(dma_offset) / sizeof(dma_offset[0]);
|
||||||
|
|
||||||
|
if (dmanum >= array_size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dma_offset[dmanum];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* dma.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DMA_H__
|
||||||
|
#define __DMA_H__
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DMA Control Block in Main Memory
|
||||||
|
*
|
||||||
|
* Note: Must start at a 256 byte aligned address.
|
||||||
|
* Use corresponding register field definitions.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t ti;
|
||||||
|
uint32_t source_ad;
|
||||||
|
uint32_t dest_ad;
|
||||||
|
uint32_t txfr_len;
|
||||||
|
uint32_t stride;
|
||||||
|
uint32_t nextconbk;
|
||||||
|
uint32_t resvd_0x18[2];
|
||||||
|
} __attribute__((packed, aligned(4))) dma_cb_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DMA register set
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t cs;
|
||||||
|
#define RPI_DMA_CS_RESET (1 << 31)
|
||||||
|
#define RPI_DMA_CS_ABORT (1 << 30)
|
||||||
|
#define RPI_DMA_CS_DISDEBUG (1 << 29)
|
||||||
|
#define RPI_DMA_CS_WAIT_OUTSTANDING_WRITES (1 << 28)
|
||||||
|
#define RPI_DMA_CS_PANIC_PRIORITY(val) ((val & 0xf) << 20)
|
||||||
|
#define RPI_DMA_CS_PRIORITY(val) ((val & 0xf) << 16)
|
||||||
|
#define RPI_DMA_CS_ERROR (1 << 8)
|
||||||
|
#define RPI_DMA_CS_WAITING_OUTSTANDING_WRITES (1 << 6)
|
||||||
|
#define RPI_DMA_CS_DREQ_STOPS_DMA (1 << 5)
|
||||||
|
#define RPI_DMA_CS_PAUSED (1 << 4)
|
||||||
|
#define RPI_DMA_CS_DREQ (1 << 3)
|
||||||
|
#define RPI_DMA_CS_INT (1 << 2)
|
||||||
|
#define RPI_DMA_CS_END (1 << 1)
|
||||||
|
#define RPI_DMA_CS_ACTIVE (1 << 0)
|
||||||
|
uint32_t conblk_ad;
|
||||||
|
uint32_t ti;
|
||||||
|
#define RPI_DMA_TI_NO_WIDE_BURSTS (1 << 26)
|
||||||
|
#define RPI_DMA_TI_WAITS(val) ((val & 0x1f) << 21)
|
||||||
|
#define RPI_DMA_TI_PERMAP(val) ((val & 0x1f) << 16)
|
||||||
|
#define RPI_DMA_TI_BURST_LENGTH(val) ((val & 0xf) << 12)
|
||||||
|
#define RPI_DMA_TI_SRC_IGNORE (1 << 11)
|
||||||
|
#define RPI_DMA_TI_SRC_DREQ (1 << 10)
|
||||||
|
#define RPI_DMA_TI_SRC_WIDTH (1 << 9)
|
||||||
|
#define RPI_DMA_TI_SRC_INC (1 << 8)
|
||||||
|
#define RPI_DMA_TI_DEST_IGNORE (1 << 7)
|
||||||
|
#define RPI_DMA_TI_DEST_DREQ (1 << 6)
|
||||||
|
#define RPI_DMA_TI_DEST_WIDTH (1 << 5)
|
||||||
|
#define RPI_DMA_TI_DEST_INC (1 << 4)
|
||||||
|
#define RPI_DMA_TI_WAIT_RESP (1 << 3)
|
||||||
|
#define RPI_DMA_TI_TDMODE (1 << 1)
|
||||||
|
#define RPI_DMA_TI_INTEN (1 << 0)
|
||||||
|
uint32_t source_ad;
|
||||||
|
uint32_t dest_ad;
|
||||||
|
uint32_t txfr_len;
|
||||||
|
#define RPI_DMA_TXFR_LEN_YLENGTH(val) ((val & 0xffff) << 16)
|
||||||
|
#define RPI_DMA_TXFR_LEN_XLENGTH(val) ((val & 0xffff) << 0)
|
||||||
|
uint32_t stride;
|
||||||
|
#define RPI_DMA_STRIDE_D_STRIDE(val) ((val & 0xffff) << 16)
|
||||||
|
#define RPI_DMA_STRIDE_S_STRIDE(val) ((val & 0xffff) << 0)
|
||||||
|
uint32_t nextconbk;
|
||||||
|
uint32_t debug;
|
||||||
|
} __attribute__((packed, aligned(4))) dma_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define DMA0_OFFSET (0x00007000)
|
||||||
|
#define DMA1_OFFSET (0x00007100)
|
||||||
|
#define DMA2_OFFSET (0x00007200)
|
||||||
|
#define DMA3_OFFSET (0x00007300)
|
||||||
|
#define DMA4_OFFSET (0x00007400)
|
||||||
|
#define DMA5_OFFSET (0x00007500)
|
||||||
|
#define DMA6_OFFSET (0x00007600)
|
||||||
|
#define DMA7_OFFSET (0x00007700)
|
||||||
|
#define DMA8_OFFSET (0x00007800)
|
||||||
|
#define DMA9_OFFSET (0x00007900)
|
||||||
|
#define DMA10_OFFSET (0x00007a00)
|
||||||
|
#define DMA11_OFFSET (0x00007b00)
|
||||||
|
#define DMA12_OFFSET (0x00007c00)
|
||||||
|
#define DMA13_OFFSET (0x00007d00)
|
||||||
|
#define DMA14_OFFSET (0x00007e00)
|
||||||
|
#define DMA15_OFFSET (0x00e05000)
|
||||||
|
|
||||||
|
|
||||||
|
#define PAGE_SIZE (1 << 12)
|
||||||
|
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||||
|
#define PAGE_OFFSET(page) (page & (PAGE_SIZE - 1))
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t dmanum_to_offset(int dmanum);
|
||||||
|
|
||||||
|
#endif /* __DMA_H__ */
|
@ -0,0 +1,28 @@
|
|||||||
|
## Deprecated
|
||||||
|
|
||||||
|
This Go code is being phased out and replaced with https://github.com/rpi-ws281x/rpi-ws281x-go
|
||||||
|
|
||||||
|
For issues and bugs with (or contributions to) the Go library, please see: https://github.com/rpi-ws281x/rpi-ws281x-go/issues
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Run a demo
|
||||||
|
|
||||||
|
As this is just a Go wrapper for the library you must clone this into your `$GOPATH` as you would any other Go program.
|
||||||
|
Your path to the project should be:
|
||||||
|
```
|
||||||
|
$GOPATH/src/github.com/jgraff/rpi_ws281x
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
As listed in the `ws2811.go` file ensure to copy `ws2811.h`, `rpihw.h`, and `pwm.h` in a GCC include path (e.g. `/usr/local/include`) and
|
||||||
|
`libws2811.a` in a GCC library path (e.g. `/usr/local/lib`).
|
||||||
|
|
||||||
|
To run the basic example run the following commands:
|
||||||
|
```
|
||||||
|
cd golang/examples
|
||||||
|
go build basic.go
|
||||||
|
sudo ./basic
|
||||||
|
```
|
||||||
|
|
||||||
|
If everything worked you should see a basic color wipe for the first 16 LEDs on your strip.
|
@ -0,0 +1,60 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
"os"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jgarff/rpi_ws281x/golang/ws2811"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
pin = 18
|
||||||
|
count = 16
|
||||||
|
brightness = 255
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defer ws2811.Fini()
|
||||||
|
err := ws2811.Init(pin, count, brightness)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Press Ctr-C to quit.")
|
||||||
|
fmt.Println("Creating blue color wipe")
|
||||||
|
err = colorWipe(uint32(0x000020))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error during wipe " + err.Error())
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Creating red color wipe")
|
||||||
|
err = colorWipe(uint32(0x002000))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error during wipe " + err.Error())
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Creating green color wipe")
|
||||||
|
err = colorWipe(uint32(0x200000))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error during wipe " + err.Error())
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func colorWipe(color uint32) error {
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
ws2811.SetLed(i, color)
|
||||||
|
err := ws2811.Render()
|
||||||
|
if err != nil {
|
||||||
|
ws2811.Clear()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
// Copyright (c) 2015, Jacques Supcik, HEIA-FR
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
// * Neither the name of the <organization> nor the
|
||||||
|
// names of its contributors may be used to endorse or promote products
|
||||||
|
// derived from this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||||
|
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Interface to ws2811 chip (neopixel driver). Make sure that you have
|
||||||
|
ws2811.h, rpihw.h, and pwm.h in a GCC include path (e.g. /usr/local/include) and
|
||||||
|
libws2811.a in a GCC library path (e.g. /usr/local/lib).
|
||||||
|
See https://github.com/jgarff/rpi_ws281x for instructions
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ws2811
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -std=c99
|
||||||
|
#cgo LDFLAGS: -lws2811
|
||||||
|
#include "ws2811.go.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init(gpioPin int, ledCount int, brightness int) error {
|
||||||
|
C.ledstring.channel[0].gpionum = C.int(gpioPin)
|
||||||
|
C.ledstring.channel[0].count = C.int(ledCount)
|
||||||
|
C.ledstring.channel[0].brightness = C.uint8_t(brightness)
|
||||||
|
res := int(C.ws2811_init(&C.ledstring))
|
||||||
|
if res == 0 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New(fmt.Sprintf("Error ws2811.init.%d", res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fini() {
|
||||||
|
C.ws2811_fini(&C.ledstring)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Render() error {
|
||||||
|
res := int(C.ws2811_render(&C.ledstring))
|
||||||
|
if res == 0 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New(fmt.Sprintf("Error ws2811.render.%d", res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Wait() error {
|
||||||
|
res := int(C.ws2811_wait(&C.ledstring))
|
||||||
|
if res == 0 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New(fmt.Sprintf("Error ws2811.wait.%d", res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetLed(index int, value uint32) {
|
||||||
|
C.ws2811_set_led(&C.ledstring, C.int(index), C.uint32_t(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clear() {
|
||||||
|
C.ws2811_clear(&C.ledstring)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetBitmap(a []uint32) {
|
||||||
|
C.ws2811_set_bitmap(&C.ledstring, unsafe.Pointer(&a[0]), C.int(len(a)*4))
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/***********************************************************************************
|
||||||
|
* Copyright (c) 2015, Jacques Supcik, HEIA-FR
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the <organization> nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
***********************************************************************************/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ws2811.h>
|
||||||
|
|
||||||
|
ws2811_t ledstring = {
|
||||||
|
.freq = 800000,
|
||||||
|
.dmanum = 10,
|
||||||
|
.channel = {
|
||||||
|
[0] = {
|
||||||
|
.gpionum = 18,
|
||||||
|
.count = 256,
|
||||||
|
.invert = 0,
|
||||||
|
.brightness = 32,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.gpionum = 0,
|
||||||
|
.count = 0,
|
||||||
|
.invert = 0,
|
||||||
|
.brightness = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void ws2811_set_led(ws2811_t *ws2811, int index, uint32_t value) {
|
||||||
|
ws2811->channel[0].leds[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2811_clear(ws2811_t *ws2811) {
|
||||||
|
for (int chan = 0; chan < RPI_PWM_CHANNELS; chan++) {
|
||||||
|
ws2811_channel_t *channel = &ws2811->channel[chan];
|
||||||
|
memset(channel->leds, 0, sizeof(ws2811_led_t) * channel->count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2811_set_bitmap(ws2811_t *ws2811, void* a, int len) {
|
||||||
|
memcpy(ws2811->channel[0].leds, a, len);
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* gpio.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GPIO_H__
|
||||||
|
#define __GPIO_H__
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t fsel[6]; // GPIO Function Select
|
||||||
|
uint32_t resvd_0x18;
|
||||||
|
uint32_t set[2]; // GPIO Pin Output Set
|
||||||
|
uint32_t resvd_0x24;
|
||||||
|
uint32_t clr[2]; // GPIO Pin Output Clear
|
||||||
|
uint32_t resvd_0x30;
|
||||||
|
uint32_t lev[2]; // GPIO Pin Level
|
||||||
|
uint32_t resvd_0x3c;
|
||||||
|
uint32_t eds[2]; // GPIO Pin Event Detect Status
|
||||||
|
uint32_t resvd_0x48;
|
||||||
|
uint32_t ren[2]; // GPIO Pin Rising Edge Detect Enable
|
||||||
|
uint32_t resvd_0x54;
|
||||||
|
uint32_t fen[2]; // GPIO Pin Falling Edge Detect Enable
|
||||||
|
uint32_t resvd_0x60;
|
||||||
|
uint32_t hen[2]; // GPIO Pin High Detect Enable
|
||||||
|
uint32_t resvd_0x6c;
|
||||||
|
uint32_t len[2]; // GPIO Pin Low Detect Enable
|
||||||
|
uint32_t resvd_0x78;
|
||||||
|
uint32_t aren[2]; // GPIO Pin Async Rising Edge Detect
|
||||||
|
uint32_t resvd_0x84;
|
||||||
|
uint32_t afen[2]; // GPIO Pin Async Falling Edge Detect
|
||||||
|
uint32_t resvd_0x90;
|
||||||
|
uint32_t pud; // GPIO Pin Pull up/down Enable
|
||||||
|
uint32_t pudclk[2]; // GPIO Pin Pull up/down Enable Clock
|
||||||
|
uint32_t resvd_0xa0[4];
|
||||||
|
uint32_t test;
|
||||||
|
} __attribute__((packed, aligned(4))) gpio_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define GPIO_OFFSET (0x00200000)
|
||||||
|
|
||||||
|
|
||||||
|
static inline void gpio_function_set(volatile gpio_t *gpio, uint8_t pin, uint8_t function)
|
||||||
|
{
|
||||||
|
int regnum = pin / 10;
|
||||||
|
int offset = (pin % 10) * 3;
|
||||||
|
uint8_t funcmap[] = { 4, 5, 6, 7, 3, 2 }; // See datasheet for mapping
|
||||||
|
|
||||||
|
if (function > 5)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio->fsel[regnum] &= ~(0x7 << offset);
|
||||||
|
gpio->fsel[regnum] |= ((funcmap[function]) << offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void gpio_level_set(volatile gpio_t *gpio, uint8_t pin, uint8_t level)
|
||||||
|
{
|
||||||
|
int regnum = pin >> 5;
|
||||||
|
int offset = (pin & 0x1f);
|
||||||
|
|
||||||
|
if (level)
|
||||||
|
{
|
||||||
|
gpio->set[regnum] = (1 << offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gpio->clr[regnum] = (1 << offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void gpio_output_set(volatile gpio_t *gpio, uint8_t pin, uint8_t output)
|
||||||
|
{
|
||||||
|
int regnum = pin / 10;
|
||||||
|
int offset = (pin % 10) * 3;
|
||||||
|
uint8_t function = output ? 1 : 0; // See datasheet for mapping
|
||||||
|
|
||||||
|
gpio->fsel[regnum] &= ~(0x7 << offset);
|
||||||
|
gpio->fsel[regnum] |= ((function & 0x7) << offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __GPIO_H__ */
|
@ -0,0 +1,84 @@
|
|||||||
|
#
|
||||||
|
# linux.py
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
#
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
# provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
# conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
# of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
# provided with the distribution.
|
||||||
|
# 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
# or promote products derived from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
import SCons
|
||||||
|
import string
|
||||||
|
import array
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas']
|
||||||
|
|
||||||
|
|
||||||
|
def linux_tools(env):
|
||||||
|
for tool in tools:
|
||||||
|
env.Tool(tool)
|
||||||
|
|
||||||
|
if not env['V']:
|
||||||
|
env['ARCOMSTR'] = 'AR ${TARGET}'
|
||||||
|
env['ASCOMSTR'] = 'AS ${TARGET}'
|
||||||
|
env['CCCOMSTR'] = 'CC ${TARGET}'
|
||||||
|
env['CXXCOMSTR'] = 'C++ ${TARGET}'
|
||||||
|
env['LINKCOMSTR'] = 'LINK ${TARGET}'
|
||||||
|
env['RANLIBCOMSTR'] = 'RANLIB ${TARGET}'
|
||||||
|
|
||||||
|
def linux_flags(env):
|
||||||
|
env.MergeFlags({
|
||||||
|
'CPPFLAGS' : '''
|
||||||
|
-fPIC
|
||||||
|
-g
|
||||||
|
-O2
|
||||||
|
-Wall
|
||||||
|
-Wextra
|
||||||
|
-Werror
|
||||||
|
'''.split(),
|
||||||
|
}),
|
||||||
|
env.MergeFlags({
|
||||||
|
'LINKFLAGS' : '''
|
||||||
|
'''.split()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def linux_builders(env):
|
||||||
|
env.Append(BUILDERS = {
|
||||||
|
'Program' : SCons.Builder.Builder(
|
||||||
|
action = SCons.Action.Action('${LINK} -o ${TARGET} ${SOURCES} ${LINKFLAGS}',
|
||||||
|
'${LINKCOMSTR}'),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
# The following are required functions by SCons when incorporating through tools
|
||||||
|
def exists(env):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def generate(env, **kwargs):
|
||||||
|
[f(env) for f in (linux_tools, linux_flags, linux_builders)]
|
||||||
|
|
@ -0,0 +1,292 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2012, Broadcom Europe Ltd.
|
||||||
|
Copyright (c) 2016, Jeremy Garff
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holder nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "mailbox.h"
|
||||||
|
|
||||||
|
|
||||||
|
void *mapmem(uint32_t base, uint32_t size, const char *mem_dev) {
|
||||||
|
uint32_t pagemask = ~0UL ^ (getpagesize() - 1);
|
||||||
|
uint32_t offsetmask = getpagesize() - 1;
|
||||||
|
int mem_fd;
|
||||||
|
void *mem;
|
||||||
|
|
||||||
|
mem_fd = open(mem_dev, O_RDWR | O_SYNC);
|
||||||
|
if (mem_fd < 0) {
|
||||||
|
perror("Can't open /dev/mem");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, base & pagemask);
|
||||||
|
if (mem == MAP_FAILED) {
|
||||||
|
perror("mmap error\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(mem_fd);
|
||||||
|
|
||||||
|
return (char *)mem + (base & offsetmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *unmapmem(void *addr, uint32_t size) {
|
||||||
|
uint32_t pagemask = ~0UL ^ (getpagesize() - 1);
|
||||||
|
uintptr_t baseaddr = (uintptr_t)addr & pagemask;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
s = munmap((void *)baseaddr, size);
|
||||||
|
if (s != 0) {
|
||||||
|
perror("munmap error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* use ioctl to send mbox property message
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int mbox_property(int file_desc, void *buf) {
|
||||||
|
int fd = file_desc;
|
||||||
|
int ret_val = -1;
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
fd = mbox_open();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd >= 0) {
|
||||||
|
ret_val = ioctl(fd, IOCTL_MBOX_PROPERTY, buf);
|
||||||
|
|
||||||
|
if (ret_val < 0) {
|
||||||
|
perror("ioctl_set_msg failed\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_desc < 0) {
|
||||||
|
mbox_close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mem_alloc(int file_desc, uint32_t size, uint32_t align, uint32_t flags) {
|
||||||
|
int i=0;
|
||||||
|
uint32_t p[32];
|
||||||
|
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x3000c; // (the tag id)
|
||||||
|
p[i++] = 12; // (size of the buffer)
|
||||||
|
p[i++] = 12; // (size of the data)
|
||||||
|
p[i++] = size; // (num bytes? or pages?)
|
||||||
|
p[i++] = align; // (alignment)
|
||||||
|
p[i++] = flags; // (MEM_FLAG_L1_NONALLOCATING)
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
if (mbox_property(file_desc, p) < 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mem_free(int file_desc, uint32_t handle) {
|
||||||
|
int i=0;
|
||||||
|
uint32_t p[32];
|
||||||
|
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x3000f; // (the tag id)
|
||||||
|
p[i++] = 4; // (size of the buffer)
|
||||||
|
p[i++] = 4; // (size of the data)
|
||||||
|
p[i++] = handle;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mem_lock(int file_desc, uint32_t handle) {
|
||||||
|
int i=0;
|
||||||
|
uint32_t p[32];
|
||||||
|
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x3000d; // (the tag id)
|
||||||
|
p[i++] = 4; // (size of the buffer)
|
||||||
|
p[i++] = 4; // (size of the data)
|
||||||
|
p[i++] = handle;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
if (mbox_property(file_desc, p) < 0)
|
||||||
|
return ~0;
|
||||||
|
else
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mem_unlock(int file_desc, uint32_t handle) {
|
||||||
|
int i=0;
|
||||||
|
uint32_t p[32];
|
||||||
|
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x3000e; // (the tag id)
|
||||||
|
p[i++] = 4; // (size of the buffer)
|
||||||
|
p[i++] = 4; // (size of the data)
|
||||||
|
p[i++] = handle;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i * sizeof(*p); // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t execute_code(int file_desc, uint32_t code, uint32_t r0, uint32_t r1,
|
||||||
|
uint32_t r2, uint32_t r3, uint32_t r4, uint32_t r5) {
|
||||||
|
int i=0;
|
||||||
|
uint32_t p[32];
|
||||||
|
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x30010; // (the tag id)
|
||||||
|
p[i++] = 28; // (size of the buffer)
|
||||||
|
p[i++] = 28; // (size of the data)
|
||||||
|
p[i++] = code;
|
||||||
|
p[i++] = r0;
|
||||||
|
p[i++] = r1;
|
||||||
|
p[i++] = r2;
|
||||||
|
p[i++] = r3;
|
||||||
|
p[i++] = r4;
|
||||||
|
p[i++] = r5;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i * sizeof(*p); // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t qpu_enable(int file_desc, uint32_t enable) {
|
||||||
|
int i=0;
|
||||||
|
uint32_t p[32];
|
||||||
|
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x30012; // (the tag id)
|
||||||
|
p[i++] = 4; // (size of the buffer)
|
||||||
|
p[i++] = 4; // (size of the data)
|
||||||
|
p[i++] = enable;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i * sizeof(*p); // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t execute_qpu(int file_desc, uint32_t num_qpus, uint32_t control,
|
||||||
|
uint32_t noflush, uint32_t timeout) {
|
||||||
|
int i = 0;
|
||||||
|
uint32_t p[32];
|
||||||
|
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
p[i++] = 0x30011; // (the tag id)
|
||||||
|
p[i++] = 16; // (size of the buffer)
|
||||||
|
p[i++] = 16; // (size of the data)
|
||||||
|
p[i++] = num_qpus;
|
||||||
|
p[i++] = control;
|
||||||
|
p[i++] = noflush;
|
||||||
|
p[i++] = timeout; // ms
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i * sizeof(*p); // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
int mbox_open(void) {
|
||||||
|
int file_desc;
|
||||||
|
char filename[64];
|
||||||
|
|
||||||
|
file_desc = open("/dev/vcio", 0);
|
||||||
|
if (file_desc >= 0) {
|
||||||
|
return file_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open a char device file used for communicating with kernel mbox driver
|
||||||
|
sprintf(filename, "/tmp/mailbox-%d", getpid());
|
||||||
|
unlink(filename);
|
||||||
|
if (mknod(filename, S_IFCHR|0600, makedev(100, 0)) < 0) {
|
||||||
|
perror("Failed to create mailbox device\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
file_desc = open(filename, 0);
|
||||||
|
if (file_desc < 0) {
|
||||||
|
perror("Can't open device file\n");
|
||||||
|
unlink(filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
unlink(filename);
|
||||||
|
|
||||||
|
return file_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbox_close(int file_desc) {
|
||||||
|
close(file_desc);
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2012, Broadcom Europe Ltd.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holder nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
|
||||||
|
#define MAJOR_NUM 100
|
||||||
|
#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
|
||||||
|
|
||||||
|
#define DEV_MEM "/dev/mem"
|
||||||
|
#define DEV_GPIOMEM "/dev/gpiomem"
|
||||||
|
|
||||||
|
int mbox_open(void);
|
||||||
|
void mbox_close(int file_desc);
|
||||||
|
|
||||||
|
unsigned get_version(int file_desc);
|
||||||
|
unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags);
|
||||||
|
unsigned mem_free(int file_desc, unsigned handle);
|
||||||
|
unsigned mem_lock(int file_desc, unsigned handle);
|
||||||
|
unsigned mem_unlock(int file_desc, unsigned handle);
|
||||||
|
void *mapmem(unsigned base, unsigned size, const char *mem_dev);
|
||||||
|
void *unmapmem(void *addr, unsigned size);
|
||||||
|
|
||||||
|
unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5);
|
||||||
|
unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout);
|
||||||
|
unsigned qpu_enable(int file_desc, unsigned enable);
|
@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
* newtest.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static char VERSION[] = "XX.YY.ZZ";
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "clk.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "pwm.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#include "ws2811.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(stuff) (sizeof(stuff) / sizeof(stuff[0]))
|
||||||
|
|
||||||
|
// defaults for cmdline options
|
||||||
|
#define TARGET_FREQ WS2811_TARGET_FREQ
|
||||||
|
#define GPIO_PIN 18
|
||||||
|
#define DMA 10
|
||||||
|
//#define STRIP_TYPE WS2811_STRIP_RGB // WS2812/SK6812RGB integrated chip+leds
|
||||||
|
#define STRIP_TYPE WS2811_STRIP_GBR // WS2812/SK6812RGB integrated chip+leds
|
||||||
|
//#define STRIP_TYPE SK6812_STRIP_RGBW // SK6812RGBW (NOT SK6812RGB)
|
||||||
|
|
||||||
|
#define WIDTH 8
|
||||||
|
#define HEIGHT 8
|
||||||
|
#define LED_COUNT (WIDTH * HEIGHT)
|
||||||
|
|
||||||
|
int width = WIDTH;
|
||||||
|
int height = HEIGHT;
|
||||||
|
int led_count = LED_COUNT;
|
||||||
|
|
||||||
|
int clear_on_exit = 0;
|
||||||
|
|
||||||
|
ws2811_t ledstring =
|
||||||
|
{
|
||||||
|
.freq = TARGET_FREQ,
|
||||||
|
.dmanum = DMA,
|
||||||
|
.channel =
|
||||||
|
{
|
||||||
|
[0] =
|
||||||
|
{
|
||||||
|
.gpionum = GPIO_PIN,
|
||||||
|
.count = LED_COUNT,
|
||||||
|
.invert = 0,
|
||||||
|
.brightness = 255,
|
||||||
|
.strip_type = STRIP_TYPE,
|
||||||
|
},
|
||||||
|
[1] =
|
||||||
|
{
|
||||||
|
.gpionum = 0,
|
||||||
|
.count = 0,
|
||||||
|
.invert = 0,
|
||||||
|
.brightness = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
ws2811_led_t *matrix;
|
||||||
|
|
||||||
|
static uint8_t running = 1;
|
||||||
|
|
||||||
|
void matrix_render(void)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
for (y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
ledstring.channel[0].leds[(y * width) + x] = matrix[y * width + x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void matrix_raise(void)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
for (y = 0; y < (height - 1); y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
// This is for the 8x8 Pimoroni Unicorn-HAT where the LEDS in subsequent
|
||||||
|
// rows are arranged in opposite directions
|
||||||
|
matrix[y * width + x] = matrix[(y + 1)*width + width - x - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void matrix_clear(void)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
for (y = 0; y < (height ); y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
matrix[y * width + x] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dotspos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||||
|
ws2811_led_t dotcolors[] =
|
||||||
|
{
|
||||||
|
0x00200000, // red
|
||||||
|
0x00201000, // orange
|
||||||
|
0x00202000, // yellow
|
||||||
|
0x00002000, // green
|
||||||
|
0x00002020, // lightblue
|
||||||
|
0x00000020, // blue
|
||||||
|
0x00100010, // purple
|
||||||
|
0x00200010, // pink
|
||||||
|
};
|
||||||
|
|
||||||
|
ws2811_led_t dotcolors_rgbw[] =
|
||||||
|
{
|
||||||
|
0x00200000, // red
|
||||||
|
0x10200000, // red + W
|
||||||
|
0x00002000, // green
|
||||||
|
0x10002000, // green + W
|
||||||
|
0x00000020, // blue
|
||||||
|
0x10000020, // blue + W
|
||||||
|
0x00101010, // white
|
||||||
|
0x10101010, // white + W
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void matrix_bottom(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < (int)(ARRAY_SIZE(dotspos)); i++)
|
||||||
|
{
|
||||||
|
dotspos[i]++;
|
||||||
|
if (dotspos[i] > (width - 1))
|
||||||
|
{
|
||||||
|
dotspos[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ledstring.channel[0].strip_type == SK6812_STRIP_RGBW) {
|
||||||
|
matrix[dotspos[i] + (height - 1) * width] = dotcolors_rgbw[i];
|
||||||
|
} else {
|
||||||
|
matrix[dotspos[i] + (height - 1) * width] = dotcolors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ctrl_c_handler(int signum)
|
||||||
|
{
|
||||||
|
(void)(signum);
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_handlers(void)
|
||||||
|
{
|
||||||
|
struct sigaction sa =
|
||||||
|
{
|
||||||
|
.sa_handler = ctrl_c_handler,
|
||||||
|
};
|
||||||
|
|
||||||
|
sigaction(SIGINT, &sa, NULL);
|
||||||
|
sigaction(SIGTERM, &sa, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parseargs(int argc, char **argv, ws2811_t *ws2811)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
static struct option longopts[] =
|
||||||
|
{
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
|
{"dma", required_argument, 0, 'd'},
|
||||||
|
{"gpio", required_argument, 0, 'g'},
|
||||||
|
{"invert", no_argument, 0, 'i'},
|
||||||
|
{"clear", no_argument, 0, 'c'},
|
||||||
|
{"strip", required_argument, 0, 's'},
|
||||||
|
{"height", required_argument, 0, 'y'},
|
||||||
|
{"width", required_argument, 0, 'x'},
|
||||||
|
{"version", no_argument, 0, 'v'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
c = getopt_long(argc, argv, "cd:g:his:vx:y:", longopts, &index);
|
||||||
|
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
/* handle flag options (array's 3rd field non-0) */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h':
|
||||||
|
fprintf(stderr, "%s version %s\n", argv[0], VERSION);
|
||||||
|
fprintf(stderr, "Usage: %s \n"
|
||||||
|
"-h (--help) - this information\n"
|
||||||
|
"-s (--strip) - strip type - rgb, grb, gbr, rgbw\n"
|
||||||
|
"-x (--width) - matrix width (default 8)\n"
|
||||||
|
"-y (--height) - matrix height (default 8)\n"
|
||||||
|
"-d (--dma) - dma channel to use (default 10)\n"
|
||||||
|
"-g (--gpio) - GPIO to use\n"
|
||||||
|
" If omitted, default is 18 (PWM0)\n"
|
||||||
|
"-i (--invert) - invert pin output (pulse LOW)\n"
|
||||||
|
"-c (--clear) - clear matrix on exit.\n"
|
||||||
|
"-v (--version) - version information\n"
|
||||||
|
, argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'g':
|
||||||
|
if (optarg) {
|
||||||
|
int gpio = atoi(optarg);
|
||||||
|
/*
|
||||||
|
PWM0, which can be set to use GPIOs 12, 18, 40, and 52.
|
||||||
|
Only 12 (pin 32) and 18 (pin 12) are available on the B+/2B/3B
|
||||||
|
PWM1 which can be set to use GPIOs 13, 19, 41, 45 and 53.
|
||||||
|
Only 13 is available on the B+/2B/PiZero/3B, on pin 33
|
||||||
|
PCM_DOUT, which can be set to use GPIOs 21 and 31.
|
||||||
|
Only 21 is available on the B+/2B/PiZero/3B, on pin 40.
|
||||||
|
SPI0-MOSI is available on GPIOs 10 and 38.
|
||||||
|
Only GPIO 10 is available on all models.
|
||||||
|
|
||||||
|
The library checks if the specified gpio is available
|
||||||
|
on the specific model (from model B rev 1 till 3B)
|
||||||
|
|
||||||
|
*/
|
||||||
|
ws2811->channel[0].gpionum = gpio;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
ws2811->channel[0].invert=1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
clear_on_exit=1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
if (optarg) {
|
||||||
|
int dma = atoi(optarg);
|
||||||
|
if (dma < 14) {
|
||||||
|
ws2811->dmanum = dma;
|
||||||
|
} else {
|
||||||
|
printf ("invalid dma %d\n", dma);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'y':
|
||||||
|
if (optarg) {
|
||||||
|
height = atoi(optarg);
|
||||||
|
if (height > 0) {
|
||||||
|
ws2811->channel[0].count = height * width;
|
||||||
|
} else {
|
||||||
|
printf ("invalid height %d\n", height);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
if (optarg) {
|
||||||
|
width = atoi(optarg);
|
||||||
|
if (width > 0) {
|
||||||
|
ws2811->channel[0].count = height * width;
|
||||||
|
} else {
|
||||||
|
printf ("invalid width %d\n", width);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
if (optarg) {
|
||||||
|
if (!strncasecmp("rgb", optarg, 4)) {
|
||||||
|
ws2811->channel[0].strip_type = WS2811_STRIP_RGB;
|
||||||
|
}
|
||||||
|
else if (!strncasecmp("rbg", optarg, 4)) {
|
||||||
|
ws2811->channel[0].strip_type = WS2811_STRIP_RBG;
|
||||||
|
}
|
||||||
|
else if (!strncasecmp("grb", optarg, 4)) {
|
||||||
|
ws2811->channel[0].strip_type = WS2811_STRIP_GRB;
|
||||||
|
}
|
||||||
|
else if (!strncasecmp("gbr", optarg, 4)) {
|
||||||
|
ws2811->channel[0].strip_type = WS2811_STRIP_GBR;
|
||||||
|
}
|
||||||
|
else if (!strncasecmp("brg", optarg, 4)) {
|
||||||
|
ws2811->channel[0].strip_type = WS2811_STRIP_BRG;
|
||||||
|
}
|
||||||
|
else if (!strncasecmp("bgr", optarg, 4)) {
|
||||||
|
ws2811->channel[0].strip_type = WS2811_STRIP_BGR;
|
||||||
|
}
|
||||||
|
else if (!strncasecmp("rgbw", optarg, 4)) {
|
||||||
|
ws2811->channel[0].strip_type = SK6812_STRIP_RGBW;
|
||||||
|
}
|
||||||
|
else if (!strncasecmp("grbw", optarg, 4)) {
|
||||||
|
ws2811->channel[0].strip_type = SK6812_STRIP_GRBW;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf ("invalid strip %s\n", optarg);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
fprintf(stderr, "%s version %s\n", argv[0], VERSION);
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
/* getopt_long already reported error? */
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
default:
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
ws2811_return_t ret;
|
||||||
|
|
||||||
|
sprintf(VERSION, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO);
|
||||||
|
|
||||||
|
parseargs(argc, argv, &ledstring);
|
||||||
|
|
||||||
|
matrix = malloc(sizeof(ws2811_led_t) * width * height);
|
||||||
|
|
||||||
|
setup_handlers();
|
||||||
|
|
||||||
|
if ((ret = ws2811_init(&ledstring)) != WS2811_SUCCESS)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ws2811_init failed: %s\n", ws2811_get_return_t_str(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (running)
|
||||||
|
{
|
||||||
|
matrix_raise();
|
||||||
|
matrix_bottom();
|
||||||
|
matrix_render();
|
||||||
|
|
||||||
|
if ((ret = ws2811_render(&ledstring)) != WS2811_SUCCESS)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ws2811_render failed: %s\n", ws2811_get_return_t_str(ret));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 15 frames /sec
|
||||||
|
usleep(1000000 / 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear_on_exit) {
|
||||||
|
matrix_clear();
|
||||||
|
matrix_render();
|
||||||
|
ws2811_render(&ledstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
ws2811_fini(&ledstring);
|
||||||
|
|
||||||
|
printf ("\n");
|
||||||
|
return ret;
|
||||||
|
}
|
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* pcm.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
* PCM version Copyright (c) 2016 Ton van Overbeek <tvoverbeek @ gmail.com>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "pcm.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Mapping of Pin to alternate function for PCM_CLK
|
||||||
|
const pcm_pin_table_t pcm_pin_clk[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.pinnum = 18,
|
||||||
|
.altnum = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pinnum = 28,
|
||||||
|
.altnum = 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mapping of Pin to alternate function for PCM_FS
|
||||||
|
const pcm_pin_table_t pcm_pin_fs[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.pinnum = 19,
|
||||||
|
.altnum = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pinnum = 29,
|
||||||
|
.altnum = 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mapping of Pin to alternate function for PCM_DIN
|
||||||
|
const pcm_pin_table_t pcm_pin_din[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.pinnum = 20,
|
||||||
|
.altnum = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pinnum = 30,
|
||||||
|
.altnum = 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mapping of Pin to alternate function for PCM_DOUT
|
||||||
|
const pcm_pin_table_t pcm_pin_dout[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.pinnum = 21,
|
||||||
|
.altnum = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pinnum = 31,
|
||||||
|
.altnum = 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const pcm_pin_tables_t pcm_pin_tables[NUM_PCMFUNS] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.pins = pcm_pin_clk,
|
||||||
|
.count = sizeof(pcm_pin_clk) / sizeof(pcm_pin_clk[0]),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pins = pcm_pin_fs,
|
||||||
|
.count = sizeof(pcm_pin_fs) / sizeof(pcm_pin_fs[0]),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pins = pcm_pin_din,
|
||||||
|
.count = sizeof(pcm_pin_din) / sizeof(pcm_pin_din[0]),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pins = pcm_pin_dout,
|
||||||
|
.count = sizeof(pcm_pin_dout) / sizeof(pcm_pin_dout[0]),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int pcm_pin_alt(int pcmfun, int pinnum)
|
||||||
|
{
|
||||||
|
if (pcmfun < 0 || pcmfun > 3) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const pcm_pin_tables_t *pintable = &pcm_pin_tables[pcmfun];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < pintable->count; i++)
|
||||||
|
{
|
||||||
|
if (pintable->pins[i].pinnum == pinnum)
|
||||||
|
{
|
||||||
|
return pintable->pins[i].altnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* pcm.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
* PCM version Copyright (c) Ton van Overbeek <tvoverbeek @ gmail.com>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PCM_H__
|
||||||
|
#define __PCM_H__
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Pin mapping of alternate pin configuration for PCM
|
||||||
|
*
|
||||||
|
* GPIO ALT PCM_CLK ALT PCM-FS ALT PCM_DIN ALT PCM_DOUT
|
||||||
|
*
|
||||||
|
* 18 0
|
||||||
|
* 19 0
|
||||||
|
* 20 0
|
||||||
|
* 21 0
|
||||||
|
* 28 2
|
||||||
|
* 29 2
|
||||||
|
* 30 2
|
||||||
|
* 31 2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t cs;
|
||||||
|
#define RPI_PCM_CS_STBY (1 << 25)
|
||||||
|
#define RPI_PCM_CS_SYNC (1 << 24)
|
||||||
|
#define RPI_PCM_CS_RXSEX (1 << 23)
|
||||||
|
#define RPI_PCM_CS_RXF (1 << 22)
|
||||||
|
#define RPI_PCM_CS_TXE (1 << 21)
|
||||||
|
#define RPI_PCM_CS_RXD (1 << 20)
|
||||||
|
#define RPI_PCM_CS_TXD (1 << 19)
|
||||||
|
#define RPI_PCM_CS_RXR (1 << 18)
|
||||||
|
#define RPI_PCM_CS_TXW (1 << 17)
|
||||||
|
#define RPI_PCM_CS_RXERR (1 << 16)
|
||||||
|
#define RPI_PCM_CS_TXERR (1 << 15)
|
||||||
|
#define RPI_PCM_CS_RXSYNC (1 << 14)
|
||||||
|
#define RPI_PCM_CS_TXSYNC (1 << 13)
|
||||||
|
#define RPI_PCM_CS_DMAEN (1 << 9)
|
||||||
|
#define RPI_PCM_CS_RXTHR(val) ((val & 0x03) << 7)
|
||||||
|
#define RPI_PCM_CS_TXTHR(val) ((val & 0x03) << 5)
|
||||||
|
#define RPI_PCM_CS_RXCLR (1 << 4)
|
||||||
|
#define RPI_PCM_CS_TXCLR (1 << 3)
|
||||||
|
#define RPI_PCM_CS_TXON (1 << 2)
|
||||||
|
#define RPI_PCM_CS_RXON (1 << 1)
|
||||||
|
#define RPI_PCM_CS_EN (1 << 0)
|
||||||
|
uint32_t fifo;
|
||||||
|
uint32_t mode;
|
||||||
|
#define RPI_PCM_MODE_CLK_DIS (1 << 28)
|
||||||
|
#define RPI_PCM_MODE_PDMN (1 << 27)
|
||||||
|
#define RPI_PCM_MODE_PDME (1 << 26)
|
||||||
|
#define RPI_PCM_MODE_FRXP (1 << 25)
|
||||||
|
#define RPI_PCM_MODE_FTXP (1 << 24)
|
||||||
|
#define RPI_PCM_MODE_CLKM (1 << 23)
|
||||||
|
#define RPI_PCM_MODE_CLKI (1 << 22)
|
||||||
|
#define RPI_PCM_MODE_FSM (1 << 21)
|
||||||
|
#define RPI_PCM_MODE_FSI (1 << 20)
|
||||||
|
#define RPI_PCM_MODE_FLEN(val) ((val & 0x3ff) << 10)
|
||||||
|
#define RPI_PCM_MODE_FSLEN(val) ((val & 0x3ff) << 0)
|
||||||
|
uint32_t rxc;
|
||||||
|
#define RPI_PCM_RXC_CH1WEX (1 << 31)
|
||||||
|
#define RPI_PCM_RXC_CH1EN (1 << 30)
|
||||||
|
#define RPI_PCM_RXC_CH1POS(val) ((val & 0x3ff) << 20)
|
||||||
|
#define RPI_PCM_RXC_CH1WID(val) ((val & 0x0f) << 16)
|
||||||
|
#define RPI_PCM_RXC_CH2WEX (1 << 15)
|
||||||
|
#define RPI_PCM_RXC_CH2EN (1 << 14)
|
||||||
|
#define RPI_PCM_RXC_CH2POS(val) ((val & 0x3ff) << 4)
|
||||||
|
#define RPI_PCM_RXC_CH2WID(val) ((val & 0x0f) << 0)
|
||||||
|
uint32_t txc;
|
||||||
|
#define RPI_PCM_TXC_CH1WEX (1 << 31)
|
||||||
|
#define RPI_PCM_TXC_CH1EN (1 << 30)
|
||||||
|
#define RPI_PCM_TXC_CH1POS(val) ((val & 0x3ff) << 20)
|
||||||
|
#define RPI_PCM_TXC_CH1WID(val) ((val & 0x0f) << 16)
|
||||||
|
#define RPI_PCM_TXC_CH2WEX (1 << 15)
|
||||||
|
#define RPI_PCM_TXC_CH2EN (1 << 14)
|
||||||
|
#define RPI_PCM_TXC_CH2POS(val) ((val & 0x3ff) << 4)
|
||||||
|
#define RPI_PCM_TXC_CH2WID(val) ((val & 0x0f) << 0)
|
||||||
|
uint32_t dreq;
|
||||||
|
#define RPI_PCM_DREQ_TX_PANIC(val) ((val & 0x7f) << 24)
|
||||||
|
#define RPI_PCM_DREQ_RX_PANIC(val) ((val & 0x7f) << 16)
|
||||||
|
#define RPI_PCM_DREQ_TX(val) ((val & 0x7f) << 8)
|
||||||
|
#define RPI_PCM_DREQ_RX(val) ((val & 0x7f) << 0)
|
||||||
|
uint32_t inten;
|
||||||
|
#define RPI_PCM_INTEN_RXERR (1 << 3)
|
||||||
|
#define RPI_PCM_INTEN_TXERR (1 << 2)
|
||||||
|
#define RPI_PCM_INTEN_RXR (1 << 1)
|
||||||
|
#define RPI_PCM_INTEN_TXW (1 << 0)
|
||||||
|
uint32_t intstc;
|
||||||
|
#define RPI_PCM_INTSTC_RXERR (1 << 3)
|
||||||
|
#define RPI_PCM_INTSTC_TXERR (1 << 2)
|
||||||
|
#define RPI_PCM_INTSTC_RXR (1 << 1)
|
||||||
|
#define RPI_PCM_INTSTC_TXW (1 << 0)
|
||||||
|
uint32_t gray;
|
||||||
|
#define RPI_PCM_GRAY_RXFIFOLEVEL(val) ((val & 0x3f) << 16)
|
||||||
|
#define RPI_PCM_GRAY_FLUSHED(val) ((val & 0x3f) << 10
|
||||||
|
#define RPI_PCM_GRAY_RXLEVEL(val) ((val & 0x3f) << 4)
|
||||||
|
#define RPI_PCM_GRAY_FLUSH (1 << 2)
|
||||||
|
#define RPI_PCM_GRAY_CLR (1 << 1)
|
||||||
|
#define RPI_PCM_GRAY_EN (1 << 0)
|
||||||
|
} __attribute__((packed, aligned(4))) pcm_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define PCM_OFFSET (0x00203000)
|
||||||
|
#define PCM_PERIPH_PHYS (0x7e203000)
|
||||||
|
|
||||||
|
#define NUM_PCMFUNS 4
|
||||||
|
#define PCMFUN_CLK 0
|
||||||
|
#define PCMFUN_FS 1
|
||||||
|
#define PCMFUN_DIN 2
|
||||||
|
#define PCMFUN_DOUT 3
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int pinnum;
|
||||||
|
int altnum;
|
||||||
|
} pcm_pin_table_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const int count;
|
||||||
|
const pcm_pin_table_t *pins;
|
||||||
|
} pcm_pin_tables_t;
|
||||||
|
|
||||||
|
|
||||||
|
int pcm_pin_alt(int pcmfun, int pinnum);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __PCM_H__ */
|
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* pwm.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "ws2811.h"
|
||||||
|
|
||||||
|
#include "pwm.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Mapping of Pin to alternate function for PWM channel 0
|
||||||
|
const pwm_pin_table_t pwm_pin_chan0[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.pinnum = 12,
|
||||||
|
.altnum = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pinnum = 18,
|
||||||
|
.altnum = 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pinnum = 40,
|
||||||
|
.altnum = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mapping of Pin to alternate function for PWM channel 1
|
||||||
|
const pwm_pin_table_t pwm_pin_chan1[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.pinnum = 13,
|
||||||
|
.altnum = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pinnum = 19,
|
||||||
|
.altnum = 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pinnum = 41,
|
||||||
|
.altnum = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pinnum = 45,
|
||||||
|
.altnum = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const pwm_pin_tables_t pwm_pin_tables[RPI_PWM_CHANNELS] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.pins = pwm_pin_chan0,
|
||||||
|
.count = sizeof(pwm_pin_chan0) / sizeof(pwm_pin_chan0[0]),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pins = pwm_pin_chan1,
|
||||||
|
.count = sizeof(pwm_pin_chan1) / sizeof(pwm_pin_chan1[0]),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int pwm_pin_alt(int chan, int pinnum)
|
||||||
|
{
|
||||||
|
const pwm_pin_tables_t *pintable = &pwm_pin_tables[chan];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < pintable->count; i++)
|
||||||
|
{
|
||||||
|
if (pintable->pins[i].pinnum == pinnum)
|
||||||
|
{
|
||||||
|
return pintable->pins[i].altnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* pwm.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PWM_H__
|
||||||
|
#define __PWM_H__
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Pin mappint of alternate pin configuration for PWM
|
||||||
|
*
|
||||||
|
* GPIO ALT PWM0 ALT PWM1
|
||||||
|
*
|
||||||
|
* 12 0
|
||||||
|
* 13 0
|
||||||
|
* 18 5
|
||||||
|
* 19 5
|
||||||
|
* 40 0
|
||||||
|
* 41 0
|
||||||
|
* 45 0
|
||||||
|
* 52 1
|
||||||
|
* 53 1
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define RPI_PWM_CHANNELS 2
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t ctl;
|
||||||
|
#define RPI_PWM_CTL_MSEN2 (1 << 15)
|
||||||
|
#define RPI_PWM_CTL_USEF2 (1 << 13)
|
||||||
|
#define RPI_PWM_CTL_POLA2 (1 << 12)
|
||||||
|
#define RPI_PWM_CTL_SBIT2 (1 << 11)
|
||||||
|
#define RPI_PWM_CTL_RPTL2 (1 << 10)
|
||||||
|
#define RPI_PWM_CTL_MODE2 (1 << 9)
|
||||||
|
#define RPI_PWM_CTL_PWEN2 (1 << 8)
|
||||||
|
#define RPI_PWM_CTL_MSEN1 (1 << 7)
|
||||||
|
#define RPI_PWM_CTL_CLRF1 (1 << 6)
|
||||||
|
#define RPI_PWM_CTL_USEF1 (1 << 5)
|
||||||
|
#define RPI_PWM_CTL_POLA1 (1 << 4)
|
||||||
|
#define RPI_PWM_CTL_SBIT1 (1 << 3)
|
||||||
|
#define RPI_PWM_CTL_RPTL1 (1 << 2)
|
||||||
|
#define RPI_PWM_CTL_MODE1 (1 << 1)
|
||||||
|
#define RPI_PWM_CTL_PWEN1 (1 << 0)
|
||||||
|
uint32_t sta;
|
||||||
|
#define RPI_PWM_STA_STA4 (1 << 12)
|
||||||
|
#define RPI_PWM_STA_STA3 (1 << 11)
|
||||||
|
#define RPI_PWM_STA_STA2 (1 << 10)
|
||||||
|
#define RPI_PWM_STA_STA1 (1 << 9)
|
||||||
|
#define RPI_PWM_STA_BERR (1 << 8)
|
||||||
|
#define RPI_PWM_STA_GAP04 (1 << 7)
|
||||||
|
#define RPI_PWM_STA_GAP03 (1 << 6)
|
||||||
|
#define RPI_PWM_STA_GAP02 (1 << 5)
|
||||||
|
#define RPI_PWM_STA_GAP01 (1 << 4)
|
||||||
|
#define RPI_PWM_STA_RERR1 (1 << 3)
|
||||||
|
#define RPI_PWM_STA_WERR1 (1 << 2)
|
||||||
|
#define RPI_PWM_STA_EMPT1 (1 << 1)
|
||||||
|
#define RPI_PWM_STA_FULL1 (1 << 0)
|
||||||
|
uint32_t dmac;
|
||||||
|
#define RPI_PWM_DMAC_ENAB (1 << 31)
|
||||||
|
#define RPI_PWM_DMAC_PANIC(val) ((val & 0xff) << 8)
|
||||||
|
#define RPI_PWM_DMAC_DREQ(val) ((val & 0xff) << 0)
|
||||||
|
uint32_t resvd_0x0c;
|
||||||
|
uint32_t rng1;
|
||||||
|
uint32_t dat1;
|
||||||
|
uint32_t fif1;
|
||||||
|
uint32_t resvd_0x1c;
|
||||||
|
uint32_t rng2;
|
||||||
|
uint32_t dat2;
|
||||||
|
} __attribute__((packed, aligned(4))) pwm_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define PWM_OFFSET (0x0020c000)
|
||||||
|
#define PWM_PERIPH_PHYS (0x7e20c000)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int pinnum;
|
||||||
|
int altnum;
|
||||||
|
} pwm_pin_table_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const int count;
|
||||||
|
const pwm_pin_table_t *pins;
|
||||||
|
} pwm_pin_tables_t;
|
||||||
|
|
||||||
|
|
||||||
|
int pwm_pin_alt(int chan, int pinnum);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __PWM_H__ */
|
@ -0,0 +1,9 @@
|
|||||||
|
*.pyc
|
||||||
|
*.so
|
||||||
|
build/
|
||||||
|
*.egg-info/
|
||||||
|
rpi_ws281x.py
|
||||||
|
rpi_ws281x_wrap.c
|
||||||
|
_rpi_ws281x.py
|
||||||
|
*.egg
|
||||||
|
*.zip
|
@ -0,0 +1,49 @@
|
|||||||
|
## Deprecated
|
||||||
|
|
||||||
|
This Python code is being phased out and replaced with https://github.com/rpi-ws281x/rpi-ws281x-python
|
||||||
|
|
||||||
|
If you're just looking to install the Python library, you can: `sudo pip install rpi_ws281x` or `sudo pip3 install rpi_ws281x` depending on your Python version of choice or find releases here: https://github.com/rpi-ws281x/rpi-ws281x-python/releases
|
||||||
|
|
||||||
|
For issues and bugs with (or contributions to) the Python library, please see: https://github.com/rpi-ws281x/rpi-ws281x-python/issues
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
As this is just a python wrapper for the library you must first follow
|
||||||
|
the build instructions in the parent directory.
|
||||||
|
When complete, you can build this python wrapper:
|
||||||
|
```
|
||||||
|
sudo apt-get install python-dev swig
|
||||||
|
python ./setup.py build
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
If you are rebuilding after fetching some updated commits, you might need to
|
||||||
|
remove the build directory first
|
||||||
|
```
|
||||||
|
rm -rf ./build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
If you want to install the library (in a virtualenv or in the system), so that you can `import neopixel` from anywhere, you need to run:
|
||||||
|
|
||||||
|
```
|
||||||
|
python ./setup.py install
|
||||||
|
```
|
||||||
|
|
||||||
|
Depending on where you are installing, root privileges may be needed (prepend `sudo` to the install command).
|
||||||
|
|
||||||
|
|
||||||
|
## Run a demo
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo PYTHONPATH=".:build/lib.linux-armv7l-2.7" python examples/strandtest.py
|
||||||
|
```
|
||||||
|
|
||||||
|
If you installed the library, there is no need to specify `PYTHONPATH`:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo python examples/strandtest.py
|
||||||
|
```
|
@ -0,0 +1,75 @@
|
|||||||
|
# NeoPixel library strandtest example
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
#
|
||||||
|
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
|
||||||
|
# various animations on a strip of NeoPixels.
|
||||||
|
import time
|
||||||
|
|
||||||
|
from neopixel import *
|
||||||
|
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 494 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_CHANNEL = 0
|
||||||
|
LED_STRIP = ws.SK6812_STRIP_RGBW
|
||||||
|
#LED_STRIP = ws.SK6812W_STRIP
|
||||||
|
|
||||||
|
class Led:
|
||||||
|
leds = []
|
||||||
|
def __init__(self, id, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
Led.leds.append(self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def colorFromIntensity(intensity):
|
||||||
|
#intensity should be 0-255
|
||||||
|
if intensity>20:
|
||||||
|
return Color(0,int(intensity),int(intensity/2),int(intensity/8)+20)
|
||||||
|
else:
|
||||||
|
return Color(0,0,0,20)
|
||||||
|
|
||||||
|
def intensityFromDistance(distance):
|
||||||
|
if distance<0:
|
||||||
|
return 0
|
||||||
|
intensity = 255-(distance/3)
|
||||||
|
if intensity < 0:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return intensity
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
print ('Press Ctrl-C to quit.')
|
||||||
|
|
||||||
|
with open("leds.txt", "r") as infile:
|
||||||
|
for line in infile:
|
||||||
|
entry = [int(x) for x in line.split(',')]
|
||||||
|
Led(entry[0], entry[1], entry[2])
|
||||||
|
|
||||||
|
# all LEDs now ready
|
||||||
|
edge = -500
|
||||||
|
t = 0
|
||||||
|
while True:
|
||||||
|
t+=1
|
||||||
|
for i, led in enumerate(Led.leds):
|
||||||
|
if t % 2 ==0:
|
||||||
|
strip.setPixelColor(i, Color(0b10101010,
|
||||||
|
0b10101010,
|
||||||
|
0b10101010,
|
||||||
|
0b10101010))
|
||||||
|
else:
|
||||||
|
strip.setPixelColor(i, Color(0,0,0,0))
|
||||||
|
strip.show()
|
||||||
|
time.sleep(1)
|
@ -0,0 +1,221 @@
|
|||||||
|
# NeoPixel library strandtest example
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
#
|
||||||
|
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
|
||||||
|
# various animations on a strip of NeoPixels.
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
|
from neopixel import *
|
||||||
|
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 494 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_CHANNEL = 0
|
||||||
|
LED_STRIP = ws.SK6812_STRIP_RGBW
|
||||||
|
#LED_STRIP = ws.SK6812W_STRIP
|
||||||
|
|
||||||
|
class Led:
|
||||||
|
leds = []
|
||||||
|
def __init__(self, id, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
Led.leds.append(self)
|
||||||
|
|
||||||
|
class Star:
|
||||||
|
stars = []
|
||||||
|
def __init__(self):
|
||||||
|
self.starstate = 0
|
||||||
|
self.starBrightness = 0
|
||||||
|
self.starCountdown = 0
|
||||||
|
self.starLED = 50
|
||||||
|
Star.stars.append(self)
|
||||||
|
|
||||||
|
def update(self, strip):
|
||||||
|
if self.starstate == 0:
|
||||||
|
self.starBrightness += 3
|
||||||
|
if self.starBrightness > 120:
|
||||||
|
self.starstate = 1
|
||||||
|
if self.starstate == 1:
|
||||||
|
self.starBrightness -= self.starBrightness/100.0
|
||||||
|
if self.starBrightness < 5:
|
||||||
|
self.starstate = 2
|
||||||
|
self.starBrightness = 0
|
||||||
|
self.starCountdown = random.randint(100, 500)
|
||||||
|
if self.starstate == 2:
|
||||||
|
self.starCountdown -= 1
|
||||||
|
if self.starCountdown == 0:
|
||||||
|
self.starLED = 0
|
||||||
|
otherStars = [s.starLED for s in Star.stars]
|
||||||
|
goodPlace = False
|
||||||
|
while not goodPlace:
|
||||||
|
self.starLED = random.randint(0,493)
|
||||||
|
goodPlace = True
|
||||||
|
if self.starLED in range(236, 349):
|
||||||
|
goodPlace = False
|
||||||
|
if Led.leds[self.starLED].y < random.random():
|
||||||
|
goodPlace = False
|
||||||
|
for otherStar in otherStars:
|
||||||
|
if abs(self.starLED-otherStar)<4:
|
||||||
|
goodPlace = False
|
||||||
|
|
||||||
|
self.starstate = 0
|
||||||
|
|
||||||
|
brightness = int(self.starBrightness + (self.starBrightness * random.random())/20.0)
|
||||||
|
|
||||||
|
strip.setPixelColor(self.starLED, Color(0,0,int(brightness/2),brightness))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def wheel(pos):
|
||||||
|
"""Generate rainbow colors across 0-255 positions."""
|
||||||
|
if pos < 85:
|
||||||
|
return Color(pos * 3, 255 - pos * 3, 0)
|
||||||
|
elif pos < 170:
|
||||||
|
pos -= 85
|
||||||
|
return Color(255 - pos * 3, 0, pos * 3)
|
||||||
|
else:
|
||||||
|
pos -= 170
|
||||||
|
return Color(0, pos * 3, 255 - pos * 3)
|
||||||
|
|
||||||
|
|
||||||
|
def colorFromIntensity(intensity):
|
||||||
|
#intensity should be 0-255
|
||||||
|
if intensity>20:
|
||||||
|
return Color(0,intensity,intensity/2,intensity/8+20)
|
||||||
|
else:
|
||||||
|
return Color(0,0,0,20)
|
||||||
|
|
||||||
|
def intensityFromDistance(distance):
|
||||||
|
if distance<0:
|
||||||
|
return 0
|
||||||
|
intensity = 255-(distance/3)
|
||||||
|
if intensity < 0:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return intensity
|
||||||
|
|
||||||
|
def turnOnChain(chain):
|
||||||
|
for light in chain:
|
||||||
|
strip.setPixelColor(light, Color(0,255,0,0))
|
||||||
|
strip.setPixelColor(light+1, Color(0,255,0,0))
|
||||||
|
strip.setPixelColor(light+2, Color(0,0,0,0))
|
||||||
|
strip.setPixelColor(light-1, Color(0,0,0,0))
|
||||||
|
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
print ('Press Ctrl-C to quit.')
|
||||||
|
|
||||||
|
with open("leds.txt", "r") as infile:
|
||||||
|
for line in infile:
|
||||||
|
entry = [int(x) for x in line.split(',')]
|
||||||
|
Led(entry[0], entry[1], entry[2])
|
||||||
|
|
||||||
|
limits = [ min([l.x for l in Led.leds]), max([l.x for l in Led.leds]), min([l.y for l in Led.leds]), max([l.y for l in Led.leds])]
|
||||||
|
for l in Led.leds:
|
||||||
|
l.y = ( float(l.y - float(limits[3])) / (limits[2]-limits[3]) )
|
||||||
|
l.x = ( float(l.x - float(limits[0])) / (limits[3]-limits[2]) )
|
||||||
|
|
||||||
|
x_max = max([l.x for l in Led.leds])
|
||||||
|
print ("Maximum X: {}".format(x_max))
|
||||||
|
|
||||||
|
|
||||||
|
# all LEDs now ready
|
||||||
|
edge = -500
|
||||||
|
counter = 1
|
||||||
|
hider = 0
|
||||||
|
animation = 0
|
||||||
|
|
||||||
|
stars = []
|
||||||
|
for i in range(0, 10):
|
||||||
|
Star()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for i, led in enumerate(Led.leds):
|
||||||
|
# intensity = intensityFromDistance(edge-(led.x - led.y/3))
|
||||||
|
# strip.setPixelColor(i, colorFromIntensity(intensity))
|
||||||
|
# blueness = int(i/2)%25
|
||||||
|
if(i > 236 and i<349):
|
||||||
|
# Gör bokstaven A grön
|
||||||
|
strip.setPixelColor(i, Color(70,13,0,5))
|
||||||
|
else:
|
||||||
|
blueness = int((1.0-led.y)**3 * 60) if led.y>0.10 else 0
|
||||||
|
if blueness < 5:
|
||||||
|
blueness = 5
|
||||||
|
#redness = int((led.x / x_max)**2 * 255)
|
||||||
|
redness = int((1.0-led.y)**8 * 4)
|
||||||
|
strip.setPixelColor(i, Color(0,redness,blueness,0))
|
||||||
|
|
||||||
|
|
||||||
|
# strip.setPixelColor(440, Color(random.randint(68,72),random.randint(68,72),random.randint(68,72),random.randint(4,6)))
|
||||||
|
|
||||||
|
|
||||||
|
# lights = [257, 334, 283, 249, 290, 346, 299, 311, 242]
|
||||||
|
# for light in lights:
|
||||||
|
# strip.setPixelColor(light, Color(0,255,0,0))
|
||||||
|
# strip.setPixelColor(light+1, Color(0,255,0,0))
|
||||||
|
# strip.setPixelColor(light+2, Color(0,0,0,0))
|
||||||
|
# strip.setPixelColor(light-1, Color(0,0,0,0))
|
||||||
|
chain0 = [260, 274]
|
||||||
|
chain1 = [254, 334, 283]
|
||||||
|
chain2 = [247, 290, 346]
|
||||||
|
chain3 = [299, 314, 241]
|
||||||
|
|
||||||
|
strip.setPixelColor(264, Color(0,0,0,50))
|
||||||
|
strip.setPixelColor(265, Color(160,255,0, 20))
|
||||||
|
strip.setPixelColor(266, Color(160,255,0, 20))
|
||||||
|
strip.setPixelColor(267, Color(160,255,0, 20))
|
||||||
|
strip.setPixelColor(268, Color(0,0,0,50))
|
||||||
|
|
||||||
|
animation+=1
|
||||||
|
animation %= 400
|
||||||
|
if animation>= 0 and animation <50:
|
||||||
|
turnOnChain(chain0)
|
||||||
|
turnOnChain(chain2)
|
||||||
|
if animation >=50 and animation <100:
|
||||||
|
turnOnChain(chain1)
|
||||||
|
turnOnChain(chain2)
|
||||||
|
if animation >=100 and animation <150:
|
||||||
|
turnOnChain(chain1)
|
||||||
|
turnOnChain(chain3)
|
||||||
|
if animation >=150 and animation <200:
|
||||||
|
turnOnChain(chain2)
|
||||||
|
turnOnChain(chain3)
|
||||||
|
if animation >=200 and animation <250:
|
||||||
|
turnOnChain(chain0)
|
||||||
|
turnOnChain(chain2)
|
||||||
|
if animation >=250 and animation <300:
|
||||||
|
turnOnChain(chain0)
|
||||||
|
turnOnChain(chain3)
|
||||||
|
if animation >=300 and animation <350:
|
||||||
|
turnOnChain(chain1)
|
||||||
|
turnOnChain(chain3)
|
||||||
|
if animation >=350 and animation <400:
|
||||||
|
turnOnChain(chain1)
|
||||||
|
turnOnChain(chain0)
|
||||||
|
|
||||||
|
|
||||||
|
for star in Star.stars:
|
||||||
|
star.update(strip)
|
||||||
|
|
||||||
|
|
||||||
|
#time.sleep(0.05)
|
||||||
|
counter +=1
|
||||||
|
strip.show()
|
||||||
|
|
||||||
|
|
||||||
|
# edge+=10
|
||||||
|
# if edge>5000:
|
||||||
|
# edge = -500
|
||||||
|
# time.sleep(0.01)
|
@ -0,0 +1,160 @@
|
|||||||
|
# NeoPixel library strandtest example
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
#
|
||||||
|
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
|
||||||
|
# various animations on a strip of NeoPixels.
|
||||||
|
import random
|
||||||
|
from neopixel import ws, Adafruit_NeoPixel, Color
|
||||||
|
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 494 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
|
||||||
|
LED_FREQ_HZ = 1200000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # Invert when using NPN transistor level shift
|
||||||
|
LED_CHANNEL = 0
|
||||||
|
LED_STRIP = ws.SK6812_STRIP_RGBW
|
||||||
|
|
||||||
|
|
||||||
|
class Led:
|
||||||
|
leds = []
|
||||||
|
|
||||||
|
def __init__(self, id, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
Led.leds.append(self)
|
||||||
|
|
||||||
|
|
||||||
|
class Star:
|
||||||
|
stars = []
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.starstate = 0
|
||||||
|
self.starBrightness = 0
|
||||||
|
self.starCountdown = 0
|
||||||
|
self.starLED = 50
|
||||||
|
Star.stars.append(self)
|
||||||
|
|
||||||
|
def update(self, strip):
|
||||||
|
if self.starstate == 0:
|
||||||
|
self.starBrightness += 3
|
||||||
|
if self.starBrightness > 120:
|
||||||
|
self.starstate = 1
|
||||||
|
if self.starstate == 1:
|
||||||
|
self.starBrightness -= self.starBrightness/100.0
|
||||||
|
if self.starBrightness < 5:
|
||||||
|
self.starstate = 2
|
||||||
|
self.starBrightness = 0
|
||||||
|
self.starCountdown = random.randint(100, 500)
|
||||||
|
if self.starstate == 2:
|
||||||
|
self.starCountdown -= 1
|
||||||
|
if self.starCountdown == 0:
|
||||||
|
self.starLED = 0
|
||||||
|
otherStars = [s.starLED for s in Star.stars]
|
||||||
|
goodPlace = False
|
||||||
|
while not goodPlace:
|
||||||
|
self.starLED = random.randint(0, 493)
|
||||||
|
goodPlace = True
|
||||||
|
if Led.leds[self.starLED].y < random.random():
|
||||||
|
goodPlace = False
|
||||||
|
for otherStar in otherStars:
|
||||||
|
if abs(self.starLED-otherStar) < 4:
|
||||||
|
goodPlace = False
|
||||||
|
|
||||||
|
self.starstate = 0
|
||||||
|
|
||||||
|
brightness = int(self.starBrightness + (self.starBrightness * random.random())/20.0)
|
||||||
|
|
||||||
|
strip.setPixelColor(self.starLED, Color(0, 0, int(brightness/2), brightness))
|
||||||
|
|
||||||
|
|
||||||
|
def wheel(pos):
|
||||||
|
"""Generate rainbow colors across 0-255 positions."""
|
||||||
|
if pos < 85:
|
||||||
|
return Color(pos * 3, 255 - pos * 3, 0)
|
||||||
|
elif pos < 170:
|
||||||
|
pos -= 85
|
||||||
|
return Color(255 - pos * 3, 0, pos * 3)
|
||||||
|
else:
|
||||||
|
pos -= 170
|
||||||
|
return Color(0, pos * 3, 255 - pos * 3)
|
||||||
|
|
||||||
|
|
||||||
|
def colorFromIntensity(intensity):
|
||||||
|
# Intensity should be 0-255
|
||||||
|
if intensity > 20:
|
||||||
|
return Color(0, intensity, intensity/2, intensity/8+20)
|
||||||
|
else:
|
||||||
|
return Color(0, 0, 0, 20)
|
||||||
|
|
||||||
|
|
||||||
|
def intensityFromDistance(distance):
|
||||||
|
if distance < 0:
|
||||||
|
return 0
|
||||||
|
intensity = 255-(distance/3)
|
||||||
|
if intensity < 0:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return intensity
|
||||||
|
|
||||||
|
|
||||||
|
def turnOnChain(chain):
|
||||||
|
for light in chain:
|
||||||
|
strip.setPixelColor(light, Color(0, 255, 0, 0))
|
||||||
|
strip.setPixelColor(light+1, Color(0, 255, 0, 0))
|
||||||
|
strip.setPixelColor(light+2, Color(0, 0, 0, 0))
|
||||||
|
strip.setPixelColor(light-1, Color(0, 0, 0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA,
|
||||||
|
LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL,
|
||||||
|
LED_STRIP)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
print('Press Ctrl-C to quit.')
|
||||||
|
|
||||||
|
with open("leds.txt", "r") as infile:
|
||||||
|
for line in infile:
|
||||||
|
entry = [int(x) for x in line.split(',')]
|
||||||
|
Led(entry[0], entry[1], entry[2])
|
||||||
|
|
||||||
|
limits = [min([l.x for l in Led.leds]),
|
||||||
|
max([l.x for l in Led.leds]),
|
||||||
|
min([l.y for l in Led.leds]),
|
||||||
|
max([l.y for l in Led.leds])]
|
||||||
|
for l in Led.leds:
|
||||||
|
l.y = (float(l.y - float(limits[3])) / (limits[2]-limits[3]))
|
||||||
|
l.x = (float(l.x - float(limits[0])) / (limits[3]-limits[2]))
|
||||||
|
|
||||||
|
x_max = max([l.x for l in Led.leds])
|
||||||
|
print("Maximum X: {}".format(x_max))
|
||||||
|
|
||||||
|
# all LEDs now ready
|
||||||
|
edge = -500
|
||||||
|
counter = 1
|
||||||
|
hider = 0
|
||||||
|
animation = 0
|
||||||
|
|
||||||
|
stars = []
|
||||||
|
for i in range(0, 10):
|
||||||
|
Star()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for i, led in enumerate(Led.leds):
|
||||||
|
blueness = int((1.0-led.y)**3 * 60) if led.y > 0.10 else 0
|
||||||
|
if blueness < 5:
|
||||||
|
blueness = 5
|
||||||
|
redness = int((1.0-led.y)**8 * 4)
|
||||||
|
strip.setPixelColor(i, Color(0, redness, blueness, 0))
|
||||||
|
|
||||||
|
for star in Star.stars:
|
||||||
|
star.update(strip)
|
||||||
|
|
||||||
|
counter += 1
|
||||||
|
strip.show()
|
@ -0,0 +1,160 @@
|
|||||||
|
# NeoPixel library strandtest example
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
#
|
||||||
|
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
|
||||||
|
# various animations on a strip of NeoPixels.
|
||||||
|
import random
|
||||||
|
from neopixel import ws, Adafruit_NeoPixel, Color
|
||||||
|
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 494 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # Invert when using NPN transistor level shift
|
||||||
|
LED_CHANNEL = 0
|
||||||
|
LED_STRIP = ws.SK6812_STRIP_RGBW
|
||||||
|
|
||||||
|
|
||||||
|
class Led:
|
||||||
|
leds = []
|
||||||
|
|
||||||
|
def __init__(self, id, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
Led.leds.append(self)
|
||||||
|
|
||||||
|
|
||||||
|
class Star:
|
||||||
|
stars = []
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.starstate = 0
|
||||||
|
self.starBrightness = 0
|
||||||
|
self.starCountdown = 0
|
||||||
|
self.starLED = 50
|
||||||
|
Star.stars.append(self)
|
||||||
|
|
||||||
|
def update(self, strip):
|
||||||
|
if self.starstate == 0:
|
||||||
|
self.starBrightness += 3
|
||||||
|
if self.starBrightness > 120:
|
||||||
|
self.starstate = 1
|
||||||
|
if self.starstate == 1:
|
||||||
|
self.starBrightness -= self.starBrightness/100.0
|
||||||
|
if self.starBrightness < 5:
|
||||||
|
self.starstate = 2
|
||||||
|
self.starBrightness = 0
|
||||||
|
self.starCountdown = random.randint(100, 500)
|
||||||
|
if self.starstate == 2:
|
||||||
|
self.starCountdown -= 1
|
||||||
|
if self.starCountdown == 0:
|
||||||
|
self.starLED = 0
|
||||||
|
otherStars = [s.starLED for s in Star.stars]
|
||||||
|
goodPlace = False
|
||||||
|
while not goodPlace:
|
||||||
|
self.starLED = random.randint(0, 493)
|
||||||
|
goodPlace = True
|
||||||
|
if Led.leds[self.starLED].y < random.random():
|
||||||
|
goodPlace = False
|
||||||
|
for otherStar in otherStars:
|
||||||
|
if abs(self.starLED-otherStar) < 4:
|
||||||
|
goodPlace = False
|
||||||
|
|
||||||
|
self.starstate = 0
|
||||||
|
|
||||||
|
brightness = int(self.starBrightness + (self.starBrightness * random.random())/20.0)
|
||||||
|
|
||||||
|
strip.setPixelColor(self.starLED, Color(0, 0, int(brightness/2), brightness))
|
||||||
|
|
||||||
|
|
||||||
|
def wheel(pos):
|
||||||
|
"""Generate rainbow colors across 0-255 positions."""
|
||||||
|
if pos < 85:
|
||||||
|
return Color(pos * 3, 255 - pos * 3, 0)
|
||||||
|
elif pos < 170:
|
||||||
|
pos -= 85
|
||||||
|
return Color(255 - pos * 3, 0, pos * 3)
|
||||||
|
else:
|
||||||
|
pos -= 170
|
||||||
|
return Color(0, pos * 3, 255 - pos * 3)
|
||||||
|
|
||||||
|
|
||||||
|
def colorFromIntensity(intensity):
|
||||||
|
# Intensity should be 0-255
|
||||||
|
if intensity > 20:
|
||||||
|
return Color(0, intensity, intensity/2, intensity/8+20)
|
||||||
|
else:
|
||||||
|
return Color(0, 0, 0, 20)
|
||||||
|
|
||||||
|
|
||||||
|
def intensityFromDistance(distance):
|
||||||
|
if distance < 0:
|
||||||
|
return 0
|
||||||
|
intensity = 255-(distance/3)
|
||||||
|
if intensity < 0:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return intensity
|
||||||
|
|
||||||
|
|
||||||
|
def turnOnChain(chain):
|
||||||
|
for light in chain:
|
||||||
|
strip.setPixelColor(light, Color(0, 255, 0, 0))
|
||||||
|
strip.setPixelColor(light+1, Color(0, 255, 0, 0))
|
||||||
|
strip.setPixelColor(light+2, Color(0, 0, 0, 0))
|
||||||
|
strip.setPixelColor(light-1, Color(0, 0, 0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA,
|
||||||
|
LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL,
|
||||||
|
LED_STRIP)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
print('Press Ctrl-C to quit.')
|
||||||
|
|
||||||
|
with open("leds.txt", "r") as infile:
|
||||||
|
for line in infile:
|
||||||
|
entry = [int(x) for x in line.split(',')]
|
||||||
|
Led(entry[0], entry[1], entry[2])
|
||||||
|
|
||||||
|
limits = [min([l.x for l in Led.leds]),
|
||||||
|
max([l.x for l in Led.leds]),
|
||||||
|
min([l.y for l in Led.leds]),
|
||||||
|
max([l.y for l in Led.leds])]
|
||||||
|
for l in Led.leds:
|
||||||
|
l.y = (float(l.y - float(limits[3])) / (limits[2]-limits[3]))
|
||||||
|
l.x = (float(l.x - float(limits[0])) / (limits[3]-limits[2]))
|
||||||
|
|
||||||
|
x_max = max([l.x for l in Led.leds])
|
||||||
|
print("Maximum X: {}".format(x_max))
|
||||||
|
|
||||||
|
# all LEDs now ready
|
||||||
|
edge = -500
|
||||||
|
counter = 1
|
||||||
|
hider = 0
|
||||||
|
animation = 0
|
||||||
|
|
||||||
|
stars = []
|
||||||
|
for i in range(0, 10):
|
||||||
|
Star()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for i, led in enumerate(Led.leds):
|
||||||
|
blueness = int((1.0-led.y)**3 * 60) if led.y > 0.10 else 0
|
||||||
|
if blueness < 5:
|
||||||
|
blueness = 5
|
||||||
|
redness = int((1.0-led.y)**8 * 4)
|
||||||
|
strip.setPixelColor(i, Color(0, redness, blueness, 0))
|
||||||
|
|
||||||
|
for star in Star.stars:
|
||||||
|
star.update(strip)
|
||||||
|
|
||||||
|
counter += 1
|
||||||
|
strip.show()
|
@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
sudo PYTHONPATH=".:build/lib.linux-armv7l-2.7" python3 animate.py
|
@ -0,0 +1,82 @@
|
|||||||
|
# NeoPixel library strandtest example
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
#
|
||||||
|
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
|
||||||
|
# various animations on a strip of NeoPixels.
|
||||||
|
import time
|
||||||
|
|
||||||
|
from neopixel import *
|
||||||
|
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 494 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_CHANNEL = 0
|
||||||
|
LED_STRIP = ws.SK6812_STRIP_RGBW
|
||||||
|
#LED_STRIP = ws.SK6812W_STRIP
|
||||||
|
|
||||||
|
class Led:
|
||||||
|
leds = []
|
||||||
|
def __init__(self, id, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
Led.leds.append(self)
|
||||||
|
|
||||||
|
def wheel(pos):
|
||||||
|
"""Generate rainbow colors across 0-255 positions."""
|
||||||
|
if pos < 85:
|
||||||
|
return Color(pos * 3, 255 - pos * 3, 0)
|
||||||
|
elif pos < 170:
|
||||||
|
pos -= 85
|
||||||
|
return Color(255 - pos * 3, 0, pos * 3)
|
||||||
|
else:
|
||||||
|
pos -= 170
|
||||||
|
return Color(0, pos * 3, 255 - pos * 3)
|
||||||
|
|
||||||
|
|
||||||
|
def colorFromIntensity(intensity):
|
||||||
|
#intensity should be 0-255
|
||||||
|
if intensity>20:
|
||||||
|
return Color(int(intensity/2),int(intensity/2),int(intensity/2),max(int(intensity),20))
|
||||||
|
else:
|
||||||
|
return Color(0,0,0,20)
|
||||||
|
|
||||||
|
def intensityFromDistance(distance):
|
||||||
|
if distance<0:
|
||||||
|
return 0
|
||||||
|
intensity = 255-(distance/3)
|
||||||
|
if intensity < 0:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return intensity
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
print ('Press Ctrl-C to quit.')
|
||||||
|
|
||||||
|
with open("leds.txt", "r") as infile:
|
||||||
|
for line in infile:
|
||||||
|
entry = [int(x) for x in line.split(',')]
|
||||||
|
Led(entry[0], entry[1], entry[2])
|
||||||
|
|
||||||
|
# all LEDs now ready
|
||||||
|
edge = -500
|
||||||
|
while True:
|
||||||
|
# counter = 0
|
||||||
|
for i, led in enumerate(Led.leds):
|
||||||
|
intensity = intensityFromDistance(edge-(led.x - led.y/3))
|
||||||
|
strip.setPixelColor(i, colorFromIntensity(intensity))
|
||||||
|
strip.show()
|
||||||
|
edge+=10
|
||||||
|
if edge>5000:
|
||||||
|
edge = -500
|
||||||
|
# time.sleep(0.01)
|
@ -0,0 +1 @@
|
|||||||
|
aniamte_starrynight.py
|
@ -0,0 +1,104 @@
|
|||||||
|
# Example of low-level Python wrapper for rpi_ws281x library.
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com), Jeremy Garff (jer@jers.net)
|
||||||
|
#
|
||||||
|
# This is an example of how to use the SWIG-generated _rpi_ws281x module.
|
||||||
|
# You probably don't want to use this unless you are building your own library,
|
||||||
|
# because the SWIG generated module is clunky and verbose. Instead look at the
|
||||||
|
# high level Python port of Adafruit's NeoPixel Arduino library in strandtest.py.
|
||||||
|
#
|
||||||
|
# This code will animate a number of WS281x LEDs displaying rainbow colors.
|
||||||
|
import time
|
||||||
|
|
||||||
|
import _rpi_ws281x as ws
|
||||||
|
|
||||||
|
# LED configuration.
|
||||||
|
LED_CHANNEL = 0
|
||||||
|
LED_COUNT = 16 # How many LEDs to light.
|
||||||
|
LED_FREQ_HZ = 800000 # Frequency of the LED signal. Should be 800khz or 400khz.
|
||||||
|
LED_DMA_NUM = 10 # DMA channel to use, can be 0-14.
|
||||||
|
LED_GPIO = 18 # GPIO connected to the LED signal line. Must support PWM!
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = 0 # Set to 1 to invert the LED signal, good if using NPN
|
||||||
|
# transistor as a 3.3V->5V level converter. Keep at 0
|
||||||
|
# for a normal/non-inverted signal.
|
||||||
|
#LED_STRIP = ws.WS2811_STRIP_RGB
|
||||||
|
#LED_STRIP = ws.WS2811_STRIP_GBR
|
||||||
|
#LED_STRIP = ws.SK6812_STRIP_RGBW
|
||||||
|
LED_STRIP = ws.SK6812W_STRIP
|
||||||
|
|
||||||
|
|
||||||
|
# Define colors which will be used by the example. Each color is an unsigned
|
||||||
|
# 32-bit value where the lower 24 bits define the red, green, blue data (each
|
||||||
|
# being 8 bits long).
|
||||||
|
DOT_COLORS = [ 0x200000, # red
|
||||||
|
0x201000, # orange
|
||||||
|
0x202000, # yellow
|
||||||
|
0x002000, # green
|
||||||
|
0x002020, # lightblue
|
||||||
|
0x000020, # blue
|
||||||
|
0x100010, # purple
|
||||||
|
0x200010 ] # pink
|
||||||
|
|
||||||
|
|
||||||
|
# Create a ws2811_t structure from the LED configuration.
|
||||||
|
# Note that this structure will be created on the heap so you need to be careful
|
||||||
|
# that you delete its memory by calling delete_ws2811_t when it's not needed.
|
||||||
|
leds = ws.new_ws2811_t()
|
||||||
|
|
||||||
|
# Initialize all channels to off
|
||||||
|
for channum in range(2):
|
||||||
|
channel = ws.ws2811_channel_get(leds, channum)
|
||||||
|
ws.ws2811_channel_t_count_set(channel, 0)
|
||||||
|
ws.ws2811_channel_t_gpionum_set(channel, 0)
|
||||||
|
ws.ws2811_channel_t_invert_set(channel, 0)
|
||||||
|
ws.ws2811_channel_t_brightness_set(channel, 0)
|
||||||
|
|
||||||
|
channel = ws.ws2811_channel_get(leds, LED_CHANNEL)
|
||||||
|
|
||||||
|
ws.ws2811_channel_t_count_set(channel, LED_COUNT)
|
||||||
|
ws.ws2811_channel_t_gpionum_set(channel, LED_GPIO)
|
||||||
|
ws.ws2811_channel_t_invert_set(channel, LED_INVERT)
|
||||||
|
ws.ws2811_channel_t_brightness_set(channel, LED_BRIGHTNESS)
|
||||||
|
ws.ws2811_channel_t_strip_type_set(channel, LED_STRIP)
|
||||||
|
|
||||||
|
ws.ws2811_t_freq_set(leds, LED_FREQ_HZ)
|
||||||
|
ws.ws2811_t_dmanum_set(leds, LED_DMA_NUM)
|
||||||
|
|
||||||
|
# Initialize library with LED configuration.
|
||||||
|
resp = ws.ws2811_init(leds)
|
||||||
|
if resp != ws.WS2811_SUCCESS:
|
||||||
|
message = ws.ws2811_get_return_t_str(resp)
|
||||||
|
raise RuntimeError('ws2811_init failed with code {0} ({1})'.format(resp, message))
|
||||||
|
|
||||||
|
# Wrap following code in a try/finally to ensure cleanup functions are called
|
||||||
|
# after library is initialized.
|
||||||
|
try:
|
||||||
|
offset = 0
|
||||||
|
while True:
|
||||||
|
# Update each LED color in the buffer.
|
||||||
|
for i in range(LED_COUNT):
|
||||||
|
# Pick a color based on LED position and an offset for animation.
|
||||||
|
color = DOT_COLORS[(i + offset) % len(DOT_COLORS)]
|
||||||
|
|
||||||
|
# Set the LED color buffer value.
|
||||||
|
ws.ws2811_led_set(channel, i, color)
|
||||||
|
|
||||||
|
# Send the LED color data to the hardware.
|
||||||
|
resp = ws.ws2811_render(leds)
|
||||||
|
if resp != ws.WS2811_SUCCESS:
|
||||||
|
message = ws.ws2811_get_return_t_str(resp)
|
||||||
|
raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, message))
|
||||||
|
|
||||||
|
# Delay for a small period of time.
|
||||||
|
time.sleep(0.25)
|
||||||
|
|
||||||
|
# Increase offset to animate colors moving. Will eventually overflow, which
|
||||||
|
# is fine.
|
||||||
|
offset += 1
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Ensure ws2811_fini is called before the program quits.
|
||||||
|
ws.ws2811_fini(leds)
|
||||||
|
# Example of calling delete function to clean up structure memory. Isn't
|
||||||
|
# strictly necessary at the end of the program execution here, but is good practice.
|
||||||
|
ws.delete_ws2811_t(leds)
|
@ -0,0 +1,107 @@
|
|||||||
|
# NeoPixel library strandtest example
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
#
|
||||||
|
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
|
||||||
|
# various animations on a strip of NeoPixels.
|
||||||
|
import time
|
||||||
|
|
||||||
|
from neopixel import *
|
||||||
|
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 494 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_CHANNEL = 0
|
||||||
|
LED_STRIP = ws.SK6812_STRIP_RGBW
|
||||||
|
#LED_STRIP = ws.SK6812W_STRIP
|
||||||
|
|
||||||
|
|
||||||
|
# Define functions which animate LEDs in various ways.
|
||||||
|
def colorWipe(strip, color, wait_ms=15):
|
||||||
|
"""Wipe color across display a pixel at a time."""
|
||||||
|
for i in range(strip.numPixels()):
|
||||||
|
strip.setPixelColor(i, color)
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
|
||||||
|
def theaterChase(strip, color, wait_ms=15, iterations=10):
|
||||||
|
"""Movie theater light style chaser animation."""
|
||||||
|
for j in range(iterations):
|
||||||
|
for q in range(3):
|
||||||
|
for i in range(0, strip.numPixels(), 3):
|
||||||
|
strip.setPixelColor(i+q, color)
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
for i in range(0, strip.numPixels(), 3):
|
||||||
|
strip.setPixelColor(i+q, 0)
|
||||||
|
|
||||||
|
def wheel(pos):
|
||||||
|
"""Generate rainbow colors across 0-255 positions."""
|
||||||
|
if pos < 85:
|
||||||
|
return Color(pos * 3, 255 - pos * 3, 0)
|
||||||
|
elif pos < 170:
|
||||||
|
pos -= 85
|
||||||
|
return Color(255 - pos * 3, 0, pos * 3)
|
||||||
|
else:
|
||||||
|
pos -= 170
|
||||||
|
return Color(0, pos * 3, 255 - pos * 3)
|
||||||
|
|
||||||
|
def rainbow(strip, wait_ms=15, iterations=1):
|
||||||
|
"""Draw rainbow that fades across all pixels at once."""
|
||||||
|
for j in range(256*iterations):
|
||||||
|
for i in range(strip.numPixels()):
|
||||||
|
strip.setPixelColor(i, wheel((i+j) & 255))
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
|
||||||
|
def rainbowCycle(strip, wait_ms=15, iterations=5):
|
||||||
|
"""Draw rainbow that uniformly distributes itself across all pixels."""
|
||||||
|
for j in range(256*iterations):
|
||||||
|
for i in range(strip.numPixels()):
|
||||||
|
strip.setPixelColor(i, wheel(((i * 256 // strip.numPixels()) + j) & 255))
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
|
||||||
|
def theaterChaseRainbow(strip, wait_ms=15):
|
||||||
|
"""Rainbow movie theater light style chaser animation."""
|
||||||
|
for j in range(256):
|
||||||
|
for q in range(3):
|
||||||
|
for i in range(0, strip.numPixels(), 3):
|
||||||
|
strip.setPixelColor(i+q, wheel((i+j) % 255))
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
for i in range(0, strip.numPixels(), 3):
|
||||||
|
strip.setPixelColor(i+q, 0)
|
||||||
|
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
print ('Press Ctrl-C to quit.')
|
||||||
|
while True:
|
||||||
|
# Color wipe animations.
|
||||||
|
colorWipe(strip, Color(255, 0, 0)) # Red wipe
|
||||||
|
colorWipe(strip, Color(0, 255, 0)) # Blue wipe
|
||||||
|
colorWipe(strip, Color(0, 0, 255)) # Green wipe
|
||||||
|
colorWipe(strip, Color(0, 0, 0, 255)) # White wipe
|
||||||
|
colorWipe(strip, Color(255, 255, 255)) # Composite White wipe
|
||||||
|
colorWipe(strip, Color(255, 255, 255, 255)) # Composite White + White LED wipe
|
||||||
|
# Theater chase animations.
|
||||||
|
theaterChase(strip, Color(127, 0, 0)) # Red theater chase
|
||||||
|
theaterChase(strip, Color(0, 127, 0)) # Green theater chase
|
||||||
|
theaterChase(strip, Color(0, 0, 127)) # Blue theater chase
|
||||||
|
theaterChase(strip, Color(0, 0, 0, 127)) # White theater chase
|
||||||
|
theaterChase(strip, Color(127, 127, 127, 0)) # Composite White theater chase
|
||||||
|
theaterChase(strip, Color(127, 127, 127, 127)) # Composite White + White theater chase
|
||||||
|
# Rainbow animations.
|
||||||
|
rainbow(strip)
|
||||||
|
rainbowCycle(strip)
|
||||||
|
theaterChaseRainbow(strip)
|
@ -0,0 +1,52 @@
|
|||||||
|
# NeoPixel library strandtest example
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
#
|
||||||
|
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
|
||||||
|
# various animations on a strip of NeoPixels.
|
||||||
|
import time
|
||||||
|
|
||||||
|
from neopixel import *
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 30 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_CHANNEL = 0
|
||||||
|
#LED_STRIP = ws.SK6812_STRIP_RGBW
|
||||||
|
LED_STRIP = ws.SK6812W_STRIP
|
||||||
|
|
||||||
|
|
||||||
|
# Define functions which animate LEDs in various ways.
|
||||||
|
def colorWipe(strip, color, wait_ms=50):
|
||||||
|
"""Wipe color across display a pixel at a time."""
|
||||||
|
for i in range(strip.numPixels()):
|
||||||
|
strip.setPixelColor(i, color)
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_STRIP)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
print ('Press Ctrl-C to quit.')
|
||||||
|
while True:
|
||||||
|
# Color wipe animations.
|
||||||
|
colorWipe(strip, Color(255, 0, 0), 0) # Red wipe
|
||||||
|
time.sleep(2)
|
||||||
|
colorWipe(strip, Color(0, 255, 0), 0) # Blue wipe
|
||||||
|
time.sleep(2)
|
||||||
|
colorWipe(strip, Color(0, 0, 255), 0) # Green wipe
|
||||||
|
time.sleep(2)
|
||||||
|
colorWipe(strip, Color(0, 0, 0, 255), 0) # White wipe
|
||||||
|
time.sleep(2)
|
||||||
|
colorWipe(strip, Color(255, 255, 255), 0) # Composite White wipe
|
||||||
|
time.sleep(2)
|
||||||
|
colorWipe(strip, Color(255, 255, 255, 255), 0) # Composite White + White LED wipe
|
||||||
|
time.sleep(2)
|
@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# NeoPixel library light-painting example
|
||||||
|
# Author: Gary Servin (garyservin@gmail.com)
|
||||||
|
#
|
||||||
|
# Lightpainting example for displaying images one column at a time and capturing
|
||||||
|
# it by taking a long exposure photograph.
|
||||||
|
# Based on https://github.com/scottjgibson/PixelPi
|
||||||
|
|
||||||
|
import time
|
||||||
|
from neopixel import *
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
# Button
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
|
||||||
|
# Lightpainting
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 128 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (18 uses PWM!).
|
||||||
|
#LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53
|
||||||
|
|
||||||
|
BUTTON_CHANNEL = 19 # GPIO pin connected to the start button
|
||||||
|
|
||||||
|
def UnColor(color):
|
||||||
|
return ((color >> 24) & 0xFF , (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF)
|
||||||
|
|
||||||
|
def lightpaint(filename, frame_rate=100, column_rate=1, reverse_x=False, reverse_y=False, loop=False):
|
||||||
|
img = Image.open(filename).convert("RGB")
|
||||||
|
|
||||||
|
# Check that the height of the image is greater than or equal the number of LEDs on the strip
|
||||||
|
if(img.size[1] < LED_COUNT):
|
||||||
|
raise Exception("Image height is smaller than led strip size. Required height = {}".format(LED_COUNT))
|
||||||
|
elif(img.size[1] > LED_COUNT):
|
||||||
|
print "Resizing image"
|
||||||
|
new_width = LED_COUNT * img.size[0] / img.size[1]
|
||||||
|
img = img.resize((new_width, LED_COUNT), Image.ANTIALIAS)
|
||||||
|
|
||||||
|
input_image = img.load()
|
||||||
|
image_width = img.size[0]
|
||||||
|
|
||||||
|
column = [0 for x in range(image_width)]
|
||||||
|
for x in range(image_width):
|
||||||
|
column[x] = [None] * (LED_COUNT)
|
||||||
|
|
||||||
|
for x in range(image_width):
|
||||||
|
for y in range(LED_COUNT):
|
||||||
|
value = input_image[x, y]
|
||||||
|
column[x][y] = Color(value[1], value[0], value[2])
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Wait for button to be pressed before displaying image
|
||||||
|
if not loop:
|
||||||
|
print("Waiting for button to be pressed")
|
||||||
|
GPIO.wait_for_edge(BUTTON_CHANNEL, GPIO.FALLING)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
x_range = range(image_width)
|
||||||
|
if reverse_x:
|
||||||
|
x_range.reverse()
|
||||||
|
|
||||||
|
y_range = range(LED_COUNT)
|
||||||
|
if reverse_y:
|
||||||
|
y_range.reverse()
|
||||||
|
|
||||||
|
for x in x_range:
|
||||||
|
led_pos = 0
|
||||||
|
for y in y_range:
|
||||||
|
strip.setPixelColor(led_pos, column[x][y])
|
||||||
|
led_pos += 1
|
||||||
|
strip.show()
|
||||||
|
time.sleep(column_rate / 1000.0)
|
||||||
|
|
||||||
|
# Wait for `frame_rate` ms before drawing a new frame
|
||||||
|
time.sleep(frame_rate / 1000.0)
|
||||||
|
|
||||||
|
# Define functions which animate LEDs in various ways.
|
||||||
|
def colorWipe(strip, color, wait_ms=50):
|
||||||
|
"""Wipe color across display a pixel at a time."""
|
||||||
|
for i in range(strip.numPixels()):
|
||||||
|
strip.setPixelColor(i, color)
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Process arguments
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit')
|
||||||
|
parser.add_argument('-f', '--file', action='store', help='Filename to display')
|
||||||
|
parser.add_argument('-r', '--frame_rate', action='store', default=100, help='Rate between each frame. Defines how fast a new frame is displayed')
|
||||||
|
parser.add_argument('-l', '--column_rate', action='store', default=1, help='Rate between each column. Defines how fast or slow you need to move the stick')
|
||||||
|
parser.add_argument('-b', '--brightness', action='store', default=10, help='Brightness of the LED. Set to 0 for darkest and 255 for brightest')
|
||||||
|
parser.add_argument('-x', '--reverse_x', action='store_true', help='Reverse the image in the X direction')
|
||||||
|
parser.add_argument('-y', '--reverse_y', action='store_true', help='Reverse the image in the Y direction')
|
||||||
|
parser.add_argument('--loop', action='store_true', help='Play frames in a loop')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, args.brightness, LED_CHANNEL)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
# Button
|
||||||
|
GPIO.setmode(GPIO.BOARD)
|
||||||
|
GPIO.setup(BUTTON_CHANNEL, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||||
|
|
||||||
|
print ('Press Ctrl-C to quit.')
|
||||||
|
if not args.clear:
|
||||||
|
print('Use "-c" argument to clear LEDs on exit')
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
print ('Lightpaint.')
|
||||||
|
lightpaint(args.file, float(args.frame_rate), float(args.column_rate), args.reverse_x, args.reverse_y, args.loop)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
if args.clear:
|
||||||
|
colorWipe(strip, Color(0,0,0), 10)
|
||||||
|
GPIO.cleanup()
|
@ -0,0 +1,98 @@
|
|||||||
|
# Example of low-level Python wrapper for rpi_ws281x library.
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com), Jeremy Garff (jer@jers.net)
|
||||||
|
#
|
||||||
|
# This is an example of how to use the SWIG-generated _rpi_ws281x module.
|
||||||
|
# You probably don't want to use this unless you are building your own library,
|
||||||
|
# because the SWIG generated module is clunky and verbose. Instead look at the
|
||||||
|
# high level Python port of Adafruit's NeoPixel Arduino library in strandtest.py.
|
||||||
|
#
|
||||||
|
# This code will animate a number of WS281x LEDs displaying rainbow colors.
|
||||||
|
import time
|
||||||
|
|
||||||
|
import _rpi_ws281x as ws
|
||||||
|
|
||||||
|
# LED configuration.
|
||||||
|
LED_CHANNEL = 0
|
||||||
|
LED_COUNT = 16 # How many LEDs to light.
|
||||||
|
LED_FREQ_HZ = 800000 # Frequency of the LED signal. Should be 800khz or 400khz.
|
||||||
|
LED_DMA_NUM = 10 # DMA channel to use, can be 0-14.
|
||||||
|
LED_GPIO = 18 # GPIO connected to the LED signal line. Must support PWM!
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = 0 # Set to 1 to invert the LED signal, good if using NPN
|
||||||
|
# transistor as a 3.3V->5V level converter. Keep at 0
|
||||||
|
# for a normal/non-inverted signal.
|
||||||
|
|
||||||
|
# Define colors which will be used by the example. Each color is an unsigned
|
||||||
|
# 32-bit value where the lower 24 bits define the red, green, blue data (each
|
||||||
|
# being 8 bits long).
|
||||||
|
DOT_COLORS = [ 0x200000, # red
|
||||||
|
0x201000, # orange
|
||||||
|
0x202000, # yellow
|
||||||
|
0x002000, # green
|
||||||
|
0x002020, # lightblue
|
||||||
|
0x000020, # blue
|
||||||
|
0x100010, # purple
|
||||||
|
0x200010 ] # pink
|
||||||
|
|
||||||
|
|
||||||
|
# Create a ws2811_t structure from the LED configuration.
|
||||||
|
# Note that this structure will be created on the heap so you need to be careful
|
||||||
|
# that you delete its memory by calling delete_ws2811_t when it's not needed.
|
||||||
|
leds = ws.new_ws2811_t()
|
||||||
|
|
||||||
|
# Initialize all channels to off
|
||||||
|
for channum in range(2):
|
||||||
|
channel = ws.ws2811_channel_get(leds, channum)
|
||||||
|
ws.ws2811_channel_t_count_set(channel, 0)
|
||||||
|
ws.ws2811_channel_t_gpionum_set(channel, 0)
|
||||||
|
ws.ws2811_channel_t_invert_set(channel, 0)
|
||||||
|
ws.ws2811_channel_t_brightness_set(channel, 0)
|
||||||
|
|
||||||
|
channel = ws.ws2811_channel_get(leds, LED_CHANNEL)
|
||||||
|
|
||||||
|
ws.ws2811_channel_t_count_set(channel, LED_COUNT)
|
||||||
|
ws.ws2811_channel_t_gpionum_set(channel, LED_GPIO)
|
||||||
|
ws.ws2811_channel_t_invert_set(channel, LED_INVERT)
|
||||||
|
ws.ws2811_channel_t_brightness_set(channel, LED_BRIGHTNESS)
|
||||||
|
|
||||||
|
ws.ws2811_t_freq_set(leds, LED_FREQ_HZ)
|
||||||
|
ws.ws2811_t_dmanum_set(leds, LED_DMA_NUM)
|
||||||
|
|
||||||
|
# Initialize library with LED configuration.
|
||||||
|
resp = ws.ws2811_init(leds)
|
||||||
|
if resp != ws.WS2811_SUCCESS:
|
||||||
|
message = ws.ws2811_get_return_t_str(resp)
|
||||||
|
raise RuntimeError('ws2811_init failed with code {0} ({1})'.format(resp, message))
|
||||||
|
|
||||||
|
# Wrap following code in a try/finally to ensure cleanup functions are called
|
||||||
|
# after library is initialized.
|
||||||
|
try:
|
||||||
|
offset = 0
|
||||||
|
while True:
|
||||||
|
# Update each LED color in the buffer.
|
||||||
|
for i in range(LED_COUNT):
|
||||||
|
# Pick a color based on LED position and an offset for animation.
|
||||||
|
color = DOT_COLORS[(i + offset) % len(DOT_COLORS)]
|
||||||
|
|
||||||
|
# Set the LED color buffer value.
|
||||||
|
ws.ws2811_led_set(channel, i, color)
|
||||||
|
|
||||||
|
# Send the LED color data to the hardware.
|
||||||
|
resp = ws.ws2811_render(leds)
|
||||||
|
if resp != ws.WS2811_SUCCESS:
|
||||||
|
message = ws.ws2811_get_return_t_str(resp)
|
||||||
|
raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, message))
|
||||||
|
|
||||||
|
# Delay for a small period of time.
|
||||||
|
time.sleep(0.25)
|
||||||
|
|
||||||
|
# Increase offset to animate colors moving. Will eventually overflow, which
|
||||||
|
# is fine.
|
||||||
|
offset += 1
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Ensure ws2811_fini is called before the program quits.
|
||||||
|
ws.ws2811_fini(leds)
|
||||||
|
# Example of calling delete function to clean up structure memory. Isn't
|
||||||
|
# strictly necessary at the end of the program execution here, but is good practice.
|
||||||
|
ws.delete_ws2811_t(leds)
|
@ -0,0 +1,78 @@
|
|||||||
|
# NeoPixel library strandtest example
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
#
|
||||||
|
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
|
||||||
|
# various animations on a strip of NeoPixels.
|
||||||
|
import time
|
||||||
|
|
||||||
|
from neopixel import *
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_1_COUNT = 30 # Number of LED pixels.
|
||||||
|
LED_1_PIN = 18 # GPIO pin connected to the pixels (must support PWM! GPIO 13 and 18 on RPi 3).
|
||||||
|
LED_1_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_1_DMA = 10 # DMA channel to use for generating signal (Between 1 and 14)
|
||||||
|
LED_1_BRIGHTNESS = 128 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_1_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_1_CHANNEL = 0 # 0 or 1
|
||||||
|
LED_1_STRIP = ws.SK6812_STRIP_GRBW
|
||||||
|
|
||||||
|
LED_2_COUNT = 15 # Number of LED pixels.
|
||||||
|
LED_2_PIN = 13 # GPIO pin connected to the pixels (must support PWM! GPIO 13 or 18 on RPi 3).
|
||||||
|
LED_2_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_2_DMA = 11 # DMA channel to use for generating signal (Between 1 and 14)
|
||||||
|
LED_2_BRIGHTNESS = 128 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_2_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_2_CHANNEL = 1 # 0 or 1
|
||||||
|
LED_2_STRIP = ws.WS2811_STRIP_GRB
|
||||||
|
|
||||||
|
def multiColorWipe(color1, color2, wait_ms=5):
|
||||||
|
global strip1
|
||||||
|
global strip2
|
||||||
|
"""Wipe color across multiple LED strips a pixel at a time."""
|
||||||
|
for i in range(strip1.numPixels()):
|
||||||
|
if i % 2:
|
||||||
|
# even number
|
||||||
|
strip1.setPixelColor(i, color1)
|
||||||
|
strip2.setPixelColor(i / 2, color2)
|
||||||
|
strip1.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
strip2.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
else:
|
||||||
|
# odd number
|
||||||
|
strip1.setPixelColor(i, color1)
|
||||||
|
strip1.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def blackout(strip):
|
||||||
|
for i in range(max(strip1.numPixels(), strip1.numPixels())):
|
||||||
|
strip.setPixelColor(i, Color(0,0,0))
|
||||||
|
strip.show()
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create NeoPixel objects with appropriate configuration for each strip.
|
||||||
|
strip1 = Adafruit_NeoPixel(LED_1_COUNT, LED_1_PIN, LED_1_FREQ_HZ, LED_1_DMA, LED_1_INVERT, LED_1_BRIGHTNESS, LED_1_CHANNEL, LED_1_STRIP)
|
||||||
|
strip2 = Adafruit_NeoPixel(LED_2_COUNT, LED_2_PIN, LED_2_FREQ_HZ, LED_2_DMA, LED_2_INVERT, LED_2_BRIGHTNESS, LED_2_CHANNEL, LED_2_STRIP)
|
||||||
|
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip1.begin()
|
||||||
|
strip2.begin()
|
||||||
|
|
||||||
|
print ('Press Ctrl-C to quit.')
|
||||||
|
|
||||||
|
# Black out any LEDs that may be still on for the last run
|
||||||
|
blackout(strip1)
|
||||||
|
blackout(strip2)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
# Multi Color wipe animations.
|
||||||
|
multiColorWipe(Color(255, 0, 0), Color(255, 0, 0)) # Red wipe
|
||||||
|
multiColorWipe(Color(0, 255, 0), Color(0, 255, 0)) # Blue wipe
|
||||||
|
multiColorWipe(Color(0, 0, 255), Color(0, 0, 255)) # Green wipe
|
||||||
|
multiColorWipe(Color(255, 255, 255), Color(255, 255, 255)) # Composite White wipe
|
||||||
|
multiColorWipe(Color(0, 0, 0, 255), Color(0, 0, 0)) # White wipe
|
||||||
|
multiColorWipe(Color(255, 255, 255, 255), Color(0, 0, 0)) # Composite White + White LED wipe
|
@ -0,0 +1,72 @@
|
|||||||
|
# Based on NeoPixel library and strandtest example by Tony DiCola (tony@tonydicola.com)
|
||||||
|
# To be used with a 12x1 NeoPixel LED stripe.
|
||||||
|
# Place the LEDs in a circle an watch the time go by ...
|
||||||
|
# red = hours
|
||||||
|
# blue = minutes 1-5
|
||||||
|
# green = seconds
|
||||||
|
# (To run the program permanently and with autostart use systemd.)
|
||||||
|
|
||||||
|
import time
|
||||||
|
import datetime
|
||||||
|
import math
|
||||||
|
|
||||||
|
from neopixel import *
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 12 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
# True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_INVERT = False
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(
|
||||||
|
LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
for i in range(0, strip.numPixels(), 1):
|
||||||
|
strip.setPixelColor(i, Color(0, 0, 0))
|
||||||
|
while True:
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
|
||||||
|
# Low light during 19-8 o'clock
|
||||||
|
if(8 < now.hour < 19):
|
||||||
|
strip.setBrightness(200)
|
||||||
|
else:
|
||||||
|
strip.setBrightness(25)
|
||||||
|
|
||||||
|
hour = now.hour % 12
|
||||||
|
minute = now.minute / 5
|
||||||
|
second = now.second / 5
|
||||||
|
secondmodulo = now.second % 5
|
||||||
|
timeslot_in_microseconds = secondmodulo * 1000000 + now.microsecond
|
||||||
|
for i in range(0, strip.numPixels(), 1):
|
||||||
|
secondplusone = second + 1 if(second < 11) else 0
|
||||||
|
secondminusone = second - 1 if(second > 0) else 11
|
||||||
|
colorarray = [0, 0, 0]
|
||||||
|
|
||||||
|
if i == second:
|
||||||
|
if timeslot_in_microseconds < 2500000:
|
||||||
|
colorarray[0] = int(
|
||||||
|
0.0000508 * timeslot_in_microseconds) + 126
|
||||||
|
else:
|
||||||
|
colorarray[0] = 382 - \
|
||||||
|
int(0.0000508 * timeslot_in_microseconds)
|
||||||
|
if i == secondplusone:
|
||||||
|
colorarray[0] = int(0.0000256 * timeslot_in_microseconds)
|
||||||
|
if i == secondminusone:
|
||||||
|
colorarray[0] = int(
|
||||||
|
0.0000256 * timeslot_in_microseconds) * -1 + 128
|
||||||
|
if i == minute:
|
||||||
|
colorarray[2] = 200
|
||||||
|
if i == hour:
|
||||||
|
colorarray[1] = 200
|
||||||
|
strip.setPixelColor(
|
||||||
|
i, Color(colorarray[0], colorarray[1], colorarray[2]))
|
||||||
|
strip.show()
|
||||||
|
time.sleep(0.1)
|
@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# NeoPixel library strandtest example
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
#
|
||||||
|
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
|
||||||
|
# various animations on a strip of NeoPixels.
|
||||||
|
|
||||||
|
import time
|
||||||
|
from neopixel import *
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
# LED strip configuration:
|
||||||
|
LED_COUNT = 16 # Number of LED pixels.
|
||||||
|
LED_PIN = 18 # GPIO pin connected to the pixels (18 uses PWM!).
|
||||||
|
#LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
|
||||||
|
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
|
||||||
|
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
|
||||||
|
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
|
||||||
|
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
|
||||||
|
LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Define functions which animate LEDs in various ways.
|
||||||
|
def colorWipe(strip, color, wait_ms=50):
|
||||||
|
"""Wipe color across display a pixel at a time."""
|
||||||
|
for i in range(strip.numPixels()):
|
||||||
|
strip.setPixelColor(i, color)
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
|
||||||
|
def theaterChase(strip, color, wait_ms=50, iterations=10):
|
||||||
|
"""Movie theater light style chaser animation."""
|
||||||
|
for j in range(iterations):
|
||||||
|
for q in range(3):
|
||||||
|
for i in range(0, strip.numPixels(), 3):
|
||||||
|
strip.setPixelColor(i+q, color)
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
for i in range(0, strip.numPixels(), 3):
|
||||||
|
strip.setPixelColor(i+q, 0)
|
||||||
|
|
||||||
|
def wheel(pos):
|
||||||
|
"""Generate rainbow colors across 0-255 positions."""
|
||||||
|
if pos < 85:
|
||||||
|
return Color(pos * 3, 255 - pos * 3, 0)
|
||||||
|
elif pos < 170:
|
||||||
|
pos -= 85
|
||||||
|
return Color(255 - pos * 3, 0, pos * 3)
|
||||||
|
else:
|
||||||
|
pos -= 170
|
||||||
|
return Color(0, pos * 3, 255 - pos * 3)
|
||||||
|
|
||||||
|
def rainbow(strip, wait_ms=20, iterations=1):
|
||||||
|
"""Draw rainbow that fades across all pixels at once."""
|
||||||
|
for j in range(256*iterations):
|
||||||
|
for i in range(strip.numPixels()):
|
||||||
|
strip.setPixelColor(i, wheel((i+j) & 255))
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
|
||||||
|
def rainbowCycle(strip, wait_ms=20, iterations=5):
|
||||||
|
"""Draw rainbow that uniformly distributes itself across all pixels."""
|
||||||
|
for j in range(256*iterations):
|
||||||
|
for i in range(strip.numPixels()):
|
||||||
|
strip.setPixelColor(i, wheel((int(i * 256 / strip.numPixels()) + j) & 255))
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
|
||||||
|
def theaterChaseRainbow(strip, wait_ms=50):
|
||||||
|
"""Rainbow movie theater light style chaser animation."""
|
||||||
|
for j in range(256):
|
||||||
|
for q in range(3):
|
||||||
|
for i in range(0, strip.numPixels(), 3):
|
||||||
|
strip.setPixelColor(i+q, wheel((i+j) % 255))
|
||||||
|
strip.show()
|
||||||
|
time.sleep(wait_ms/1000.0)
|
||||||
|
for i in range(0, strip.numPixels(), 3):
|
||||||
|
strip.setPixelColor(i+q, 0)
|
||||||
|
|
||||||
|
# Main program logic follows:
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Process arguments
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Create NeoPixel object with appropriate configuration.
|
||||||
|
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
|
||||||
|
# Intialize the library (must be called once before other functions).
|
||||||
|
strip.begin()
|
||||||
|
|
||||||
|
print ('Press Ctrl-C to quit.')
|
||||||
|
if not args.clear:
|
||||||
|
print('Use "-c" argument to clear LEDs on exit')
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
print ('Color wipe animations.')
|
||||||
|
colorWipe(strip, Color(255, 0, 0)) # Red wipe
|
||||||
|
colorWipe(strip, Color(0, 255, 0)) # Blue wipe
|
||||||
|
colorWipe(strip, Color(0, 0, 255)) # Green wipe
|
||||||
|
print ('Theater chase animations.')
|
||||||
|
theaterChase(strip, Color(127, 127, 127)) # White theater chase
|
||||||
|
theaterChase(strip, Color(127, 0, 0)) # Red theater chase
|
||||||
|
theaterChase(strip, Color( 0, 0, 127)) # Blue theater chase
|
||||||
|
print ('Rainbow animations.')
|
||||||
|
rainbow(strip)
|
||||||
|
rainbowCycle(strip)
|
||||||
|
theaterChaseRainbow(strip)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
if args.clear:
|
||||||
|
colorWipe(strip, Color(0,0,0), 10)
|
@ -0,0 +1,332 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""Bootstrap setuptools installation
|
||||||
|
|
||||||
|
To use setuptools in your package's setup.py, include this
|
||||||
|
file in the same directory and add this to the top of your setup.py::
|
||||||
|
|
||||||
|
from ez_setup import use_setuptools
|
||||||
|
use_setuptools()
|
||||||
|
|
||||||
|
To require a specific version of setuptools, set a download
|
||||||
|
mirror, or use an alternate download directory, simply supply
|
||||||
|
the appropriate options to ``use_setuptools()``.
|
||||||
|
|
||||||
|
This file can also be run as a script to install or upgrade setuptools.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
|
import optparse
|
||||||
|
import subprocess
|
||||||
|
import platform
|
||||||
|
import textwrap
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
from distutils import log
|
||||||
|
|
||||||
|
try:
|
||||||
|
from urllib.request import urlopen
|
||||||
|
except ImportError:
|
||||||
|
from urllib2 import urlopen
|
||||||
|
|
||||||
|
try:
|
||||||
|
from site import USER_SITE
|
||||||
|
except ImportError:
|
||||||
|
USER_SITE = None
|
||||||
|
|
||||||
|
DEFAULT_VERSION = "5.7"
|
||||||
|
DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
|
||||||
|
|
||||||
|
def _python_cmd(*args):
|
||||||
|
"""
|
||||||
|
Return True if the command succeeded.
|
||||||
|
"""
|
||||||
|
args = (sys.executable,) + args
|
||||||
|
return subprocess.call(args) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def _install(archive_filename, install_args=()):
|
||||||
|
with archive_context(archive_filename):
|
||||||
|
# installing
|
||||||
|
log.warn('Installing Setuptools')
|
||||||
|
if not _python_cmd('setup.py', 'install', *install_args):
|
||||||
|
log.warn('Something went wrong during the installation.')
|
||||||
|
log.warn('See the error message above.')
|
||||||
|
# exitcode will be 2
|
||||||
|
return 2
|
||||||
|
|
||||||
|
|
||||||
|
def _build_egg(egg, archive_filename, to_dir):
|
||||||
|
with archive_context(archive_filename):
|
||||||
|
# building an egg
|
||||||
|
log.warn('Building a Setuptools egg in %s', to_dir)
|
||||||
|
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
|
||||||
|
# returning the result
|
||||||
|
log.warn(egg)
|
||||||
|
if not os.path.exists(egg):
|
||||||
|
raise IOError('Could not build the egg.')
|
||||||
|
|
||||||
|
|
||||||
|
class ContextualZipFile(zipfile.ZipFile):
|
||||||
|
"""
|
||||||
|
Supplement ZipFile class to support context manager for Python 2.6
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Construct a ZipFile or ContextualZipFile as appropriate
|
||||||
|
"""
|
||||||
|
if hasattr(zipfile.ZipFile, '__exit__'):
|
||||||
|
return zipfile.ZipFile(*args, **kwargs)
|
||||||
|
return super(ContextualZipFile, cls).__new__(cls)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def archive_context(filename):
|
||||||
|
# extracting the archive
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
log.warn('Extracting in %s', tmpdir)
|
||||||
|
old_wd = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir(tmpdir)
|
||||||
|
with ContextualZipFile(filename) as archive:
|
||||||
|
archive.extractall()
|
||||||
|
|
||||||
|
# going in the directory
|
||||||
|
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
||||||
|
os.chdir(subdir)
|
||||||
|
log.warn('Now working in %s', subdir)
|
||||||
|
yield
|
||||||
|
|
||||||
|
finally:
|
||||||
|
os.chdir(old_wd)
|
||||||
|
shutil.rmtree(tmpdir)
|
||||||
|
|
||||||
|
|
||||||
|
def _do_download(version, download_base, to_dir, download_delay):
|
||||||
|
egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg'
|
||||||
|
% (version, sys.version_info[0], sys.version_info[1]))
|
||||||
|
if not os.path.exists(egg):
|
||||||
|
archive = download_setuptools(version, download_base,
|
||||||
|
to_dir, download_delay)
|
||||||
|
_build_egg(egg, archive, to_dir)
|
||||||
|
sys.path.insert(0, egg)
|
||||||
|
|
||||||
|
# Remove previously-imported pkg_resources if present (see
|
||||||
|
# https://bitbucket.org/pypa/setuptools/pull-request/7/ for details).
|
||||||
|
if 'pkg_resources' in sys.modules:
|
||||||
|
del sys.modules['pkg_resources']
|
||||||
|
|
||||||
|
import setuptools
|
||||||
|
setuptools.bootstrap_install_from = egg
|
||||||
|
|
||||||
|
|
||||||
|
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||||
|
to_dir=os.curdir, download_delay=15):
|
||||||
|
to_dir = os.path.abspath(to_dir)
|
||||||
|
rep_modules = 'pkg_resources', 'setuptools'
|
||||||
|
imported = set(sys.modules).intersection(rep_modules)
|
||||||
|
try:
|
||||||
|
import pkg_resources
|
||||||
|
except ImportError:
|
||||||
|
return _do_download(version, download_base, to_dir, download_delay)
|
||||||
|
try:
|
||||||
|
pkg_resources.require("setuptools>=" + version)
|
||||||
|
return
|
||||||
|
except pkg_resources.DistributionNotFound:
|
||||||
|
return _do_download(version, download_base, to_dir, download_delay)
|
||||||
|
except pkg_resources.VersionConflict as VC_err:
|
||||||
|
if imported:
|
||||||
|
msg = textwrap.dedent("""
|
||||||
|
The required version of setuptools (>={version}) is not available,
|
||||||
|
and can't be installed while this script is running. Please
|
||||||
|
install a more recent version first, using
|
||||||
|
'easy_install -U setuptools'.
|
||||||
|
|
||||||
|
(Currently using {VC_err.args[0]!r})
|
||||||
|
""").format(VC_err=VC_err, version=version)
|
||||||
|
sys.stderr.write(msg)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
# otherwise, reload ok
|
||||||
|
del pkg_resources, sys.modules['pkg_resources']
|
||||||
|
return _do_download(version, download_base, to_dir, download_delay)
|
||||||
|
|
||||||
|
def _clean_check(cmd, target):
|
||||||
|
"""
|
||||||
|
Run the command to download target. If the command fails, clean up before
|
||||||
|
re-raising the error.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
if os.access(target, os.F_OK):
|
||||||
|
os.unlink(target)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def download_file_powershell(url, target):
|
||||||
|
"""
|
||||||
|
Download the file at url to target using Powershell (which will validate
|
||||||
|
trust). Raise an exception if the command cannot complete.
|
||||||
|
"""
|
||||||
|
target = os.path.abspath(target)
|
||||||
|
ps_cmd = (
|
||||||
|
"[System.Net.WebRequest]::DefaultWebProxy.Credentials = "
|
||||||
|
"[System.Net.CredentialCache]::DefaultCredentials; "
|
||||||
|
"(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)"
|
||||||
|
% vars()
|
||||||
|
)
|
||||||
|
cmd = [
|
||||||
|
'powershell',
|
||||||
|
'-Command',
|
||||||
|
ps_cmd,
|
||||||
|
]
|
||||||
|
_clean_check(cmd, target)
|
||||||
|
|
||||||
|
def has_powershell():
|
||||||
|
if platform.system() != 'Windows':
|
||||||
|
return False
|
||||||
|
cmd = ['powershell', '-Command', 'echo test']
|
||||||
|
with open(os.path.devnull, 'wb') as devnull:
|
||||||
|
try:
|
||||||
|
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
download_file_powershell.viable = has_powershell
|
||||||
|
|
||||||
|
def download_file_curl(url, target):
|
||||||
|
cmd = ['curl', '-L', url, '--silent', '--output', target]
|
||||||
|
_clean_check(cmd, target)
|
||||||
|
|
||||||
|
def has_curl():
|
||||||
|
cmd = ['curl', '--version']
|
||||||
|
with open(os.path.devnull, 'wb') as devnull:
|
||||||
|
try:
|
||||||
|
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
download_file_curl.viable = has_curl
|
||||||
|
|
||||||
|
def download_file_wget(url, target):
|
||||||
|
cmd = ['wget', url, '--quiet', '--output-document', target]
|
||||||
|
_clean_check(cmd, target)
|
||||||
|
|
||||||
|
def has_wget():
|
||||||
|
cmd = ['wget', '--version']
|
||||||
|
with open(os.path.devnull, 'wb') as devnull:
|
||||||
|
try:
|
||||||
|
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
download_file_wget.viable = has_wget
|
||||||
|
|
||||||
|
def download_file_insecure(url, target):
|
||||||
|
"""
|
||||||
|
Use Python to download the file, even though it cannot authenticate the
|
||||||
|
connection.
|
||||||
|
"""
|
||||||
|
src = urlopen(url)
|
||||||
|
try:
|
||||||
|
# Read all the data in one block.
|
||||||
|
data = src.read()
|
||||||
|
finally:
|
||||||
|
src.close()
|
||||||
|
|
||||||
|
# Write all the data in one block to avoid creating a partial file.
|
||||||
|
with open(target, "wb") as dst:
|
||||||
|
dst.write(data)
|
||||||
|
|
||||||
|
download_file_insecure.viable = lambda: True
|
||||||
|
|
||||||
|
def get_best_downloader():
|
||||||
|
downloaders = (
|
||||||
|
download_file_powershell,
|
||||||
|
download_file_curl,
|
||||||
|
download_file_wget,
|
||||||
|
download_file_insecure,
|
||||||
|
)
|
||||||
|
viable_downloaders = (dl for dl in downloaders if dl.viable())
|
||||||
|
return next(viable_downloaders, None)
|
||||||
|
|
||||||
|
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||||
|
to_dir=os.curdir, delay=15, downloader_factory=get_best_downloader):
|
||||||
|
"""
|
||||||
|
Download setuptools from a specified location and return its filename
|
||||||
|
|
||||||
|
`version` should be a valid setuptools version number that is available
|
||||||
|
as an sdist for download under the `download_base` URL (which should end
|
||||||
|
with a '/'). `to_dir` is the directory where the egg will be downloaded.
|
||||||
|
`delay` is the number of seconds to pause before an actual download
|
||||||
|
attempt.
|
||||||
|
|
||||||
|
``downloader_factory`` should be a function taking no arguments and
|
||||||
|
returning a function for downloading a URL to a target.
|
||||||
|
"""
|
||||||
|
# making sure we use the absolute path
|
||||||
|
to_dir = os.path.abspath(to_dir)
|
||||||
|
zip_name = "setuptools-%s.zip" % version
|
||||||
|
url = download_base + zip_name
|
||||||
|
saveto = os.path.join(to_dir, zip_name)
|
||||||
|
if not os.path.exists(saveto): # Avoid repeated downloads
|
||||||
|
log.warn("Downloading %s", url)
|
||||||
|
downloader = downloader_factory()
|
||||||
|
downloader(url, saveto)
|
||||||
|
return os.path.realpath(saveto)
|
||||||
|
|
||||||
|
def _build_install_args(options):
|
||||||
|
"""
|
||||||
|
Build the arguments to 'python setup.py install' on the setuptools package
|
||||||
|
"""
|
||||||
|
return ['--user'] if options.user_install else []
|
||||||
|
|
||||||
|
def _parse_args():
|
||||||
|
"""
|
||||||
|
Parse the command line for options
|
||||||
|
"""
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
parser.add_option(
|
||||||
|
'--user', dest='user_install', action='store_true', default=False,
|
||||||
|
help='install in user site package (requires Python 2.6 or later)')
|
||||||
|
parser.add_option(
|
||||||
|
'--download-base', dest='download_base', metavar="URL",
|
||||||
|
default=DEFAULT_URL,
|
||||||
|
help='alternative URL from where to download the setuptools package')
|
||||||
|
parser.add_option(
|
||||||
|
'--insecure', dest='downloader_factory', action='store_const',
|
||||||
|
const=lambda: download_file_insecure, default=get_best_downloader,
|
||||||
|
help='Use internal, non-validating downloader'
|
||||||
|
)
|
||||||
|
parser.add_option(
|
||||||
|
'--version', help="Specify which version to download",
|
||||||
|
default=DEFAULT_VERSION,
|
||||||
|
)
|
||||||
|
options, args = parser.parse_args()
|
||||||
|
# positional arguments are ignored
|
||||||
|
return options
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Install or upgrade setuptools and EasyInstall"""
|
||||||
|
options = _parse_args()
|
||||||
|
archive = download_setuptools(
|
||||||
|
version=options.version,
|
||||||
|
download_base=options.download_base,
|
||||||
|
downloader_factory=options.downloader_factory,
|
||||||
|
)
|
||||||
|
return _install(archive, _build_install_args(options))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
@ -0,0 +1,494 @@
|
|||||||
|
0,63,408
|
||||||
|
1,57,397
|
||||||
|
2,55,387
|
||||||
|
3,50,374
|
||||||
|
4,44,356
|
||||||
|
5,41,343
|
||||||
|
6,42,330
|
||||||
|
7,42,320
|
||||||
|
8,41,308
|
||||||
|
9,41,298
|
||||||
|
10,42,286
|
||||||
|
11,41,273
|
||||||
|
12,41,264
|
||||||
|
13,41,253
|
||||||
|
14,41,239
|
||||||
|
15,41,230
|
||||||
|
16,40,219
|
||||||
|
17,40,209
|
||||||
|
18,43,192
|
||||||
|
19,49,176
|
||||||
|
20,52,164
|
||||||
|
21,57,151
|
||||||
|
22,61,143
|
||||||
|
23,64,141
|
||||||
|
24,76,136
|
||||||
|
25,89,132
|
||||||
|
26,102,128
|
||||||
|
27,115,126
|
||||||
|
28,126,126
|
||||||
|
29,137,126
|
||||||
|
30,148,126
|
||||||
|
31,159,126
|
||||||
|
32,170,128
|
||||||
|
33,182,129
|
||||||
|
34,193,128
|
||||||
|
35,203,128
|
||||||
|
36,214,128
|
||||||
|
37,226,128
|
||||||
|
38,236,129
|
||||||
|
39,249,128
|
||||||
|
40,259,126
|
||||||
|
41,272,125
|
||||||
|
42,287,128
|
||||||
|
43,299,131
|
||||||
|
44,312,135
|
||||||
|
45,323,137
|
||||||
|
46,333,141
|
||||||
|
47,334,148
|
||||||
|
48,335,164
|
||||||
|
49,336,177
|
||||||
|
50,336,190
|
||||||
|
51,334,205
|
||||||
|
52,334,209
|
||||||
|
53,324,211
|
||||||
|
54,316,213
|
||||||
|
55,305,216
|
||||||
|
56,292,219
|
||||||
|
57,279,220
|
||||||
|
58,264,221
|
||||||
|
59,251,220
|
||||||
|
60,241,221
|
||||||
|
61,230,221
|
||||||
|
62,219,221
|
||||||
|
63,207,221
|
||||||
|
64,199,221
|
||||||
|
65,193,221
|
||||||
|
66,187,222
|
||||||
|
67,181,222
|
||||||
|
68,180,222
|
||||||
|
69,180,223
|
||||||
|
70,179,224
|
||||||
|
71,180,224
|
||||||
|
72,185,224
|
||||||
|
73,192,224
|
||||||
|
74,199,223
|
||||||
|
75,206,224
|
||||||
|
76,218,224
|
||||||
|
77,228,224
|
||||||
|
78,244,226
|
||||||
|
79,260,230
|
||||||
|
80,272,233
|
||||||
|
81,283,235
|
||||||
|
82,293,237
|
||||||
|
83,304,238
|
||||||
|
84,305,243
|
||||||
|
85,305,253
|
||||||
|
86,305,267
|
||||||
|
87,305,282
|
||||||
|
88,309,293
|
||||||
|
89,301,300
|
||||||
|
90,293,301
|
||||||
|
91,284,302
|
||||||
|
92,270,306
|
||||||
|
93,257,310
|
||||||
|
94,241,315
|
||||||
|
95,229,316
|
||||||
|
96,217,315
|
||||||
|
97,206,316
|
||||||
|
98,199,316
|
||||||
|
99,192,316
|
||||||
|
100,187,316
|
||||||
|
101,181,316
|
||||||
|
102,183,317
|
||||||
|
103,182,318
|
||||||
|
104,182,319
|
||||||
|
105,186,319
|
||||||
|
106,189,319
|
||||||
|
107,197,319
|
||||||
|
108,203,319
|
||||||
|
109,211,319
|
||||||
|
110,223,319
|
||||||
|
111,234,319
|
||||||
|
112,244,318
|
||||||
|
113,255,318
|
||||||
|
114,269,318
|
||||||
|
115,280,317
|
||||||
|
116,296,318
|
||||||
|
117,307,320
|
||||||
|
118,321,322
|
||||||
|
119,330,325
|
||||||
|
120,339,329
|
||||||
|
121,345,335
|
||||||
|
122,348,346
|
||||||
|
123,349,362
|
||||||
|
124,349,376
|
||||||
|
125,349,391
|
||||||
|
126,344,401
|
||||||
|
127,334,405
|
||||||
|
128,322,408
|
||||||
|
129,310,412
|
||||||
|
130,295,416
|
||||||
|
131,280,419
|
||||||
|
132,270,420
|
||||||
|
133,259,419
|
||||||
|
134,248,420
|
||||||
|
135,238,421
|
||||||
|
136,227,419
|
||||||
|
137,215,419
|
||||||
|
138,205,419
|
||||||
|
139,193,419
|
||||||
|
140,182,419
|
||||||
|
141,171,419
|
||||||
|
142,160,419
|
||||||
|
143,149,419
|
||||||
|
144,138,420
|
||||||
|
145,127,420
|
||||||
|
146,115,420
|
||||||
|
147,103,419
|
||||||
|
148,86,416
|
||||||
|
149,73,414
|
||||||
|
150,391,397
|
||||||
|
151,388,389
|
||||||
|
152,382,374
|
||||||
|
153,378,360
|
||||||
|
154,375,348
|
||||||
|
155,374,336
|
||||||
|
156,374,324
|
||||||
|
157,374,313
|
||||||
|
158,374,302
|
||||||
|
159,373,291
|
||||||
|
160,373,279
|
||||||
|
161,373,267
|
||||||
|
162,372,256
|
||||||
|
163,372,243
|
||||||
|
164,372,234
|
||||||
|
165,372,222
|
||||||
|
166,371,212
|
||||||
|
167,371,201
|
||||||
|
168,374,185
|
||||||
|
169,378,170
|
||||||
|
170,382,156
|
||||||
|
171,385,145
|
||||||
|
172,391,135
|
||||||
|
173,402,132
|
||||||
|
174,417,128
|
||||||
|
175,434,125
|
||||||
|
176,454,127
|
||||||
|
177,467,129
|
||||||
|
178,479,133
|
||||||
|
179,490,137
|
||||||
|
180,499,142
|
||||||
|
181,502,154
|
||||||
|
182,506,166
|
||||||
|
183,508,178
|
||||||
|
184,511,192
|
||||||
|
185,511,204
|
||||||
|
186,512,216
|
||||||
|
187,512,227
|
||||||
|
188,513,239
|
||||||
|
189,513,249
|
||||||
|
190,511,263
|
||||||
|
191,513,273
|
||||||
|
192,513,281
|
||||||
|
193,514,288
|
||||||
|
194,514,294
|
||||||
|
195,514,300
|
||||||
|
196,513,305
|
||||||
|
197,519,306
|
||||||
|
198,526,305
|
||||||
|
199,533,305
|
||||||
|
200,540,305
|
||||||
|
201,550,305
|
||||||
|
202,561,304
|
||||||
|
203,573,305
|
||||||
|
204,583,305
|
||||||
|
205,596,306
|
||||||
|
206,613,310
|
||||||
|
207,624,312
|
||||||
|
208,636,315
|
||||||
|
209,647,318
|
||||||
|
210,655,322
|
||||||
|
211,658,334
|
||||||
|
212,658,347
|
||||||
|
213,659,362
|
||||||
|
214,657,378
|
||||||
|
215,656,393
|
||||||
|
216,645,399
|
||||||
|
217,633,404
|
||||||
|
218,622,408
|
||||||
|
219,606,412
|
||||||
|
220,591,415
|
||||||
|
221,580,416
|
||||||
|
222,571,416
|
||||||
|
223,559,417
|
||||||
|
224,548,417
|
||||||
|
225,537,417
|
||||||
|
226,524,417
|
||||||
|
227,514,417
|
||||||
|
228,502,417
|
||||||
|
229,491,418
|
||||||
|
230,480,418
|
||||||
|
231,470,417
|
||||||
|
232,459,417
|
||||||
|
233,448,417
|
||||||
|
234,434,415
|
||||||
|
235,420,412
|
||||||
|
236,405,407
|
||||||
|
237,685,392
|
||||||
|
238,686,380
|
||||||
|
239,686,369
|
||||||
|
240,686,354
|
||||||
|
241,689,339
|
||||||
|
242,693,326
|
||||||
|
243,696,316
|
||||||
|
244,701,305
|
||||||
|
245,706,295
|
||||||
|
246,710,285
|
||||||
|
247,714,275
|
||||||
|
248,718,264
|
||||||
|
249,723,253
|
||||||
|
250,727,243
|
||||||
|
251,732,232
|
||||||
|
252,736,223
|
||||||
|
253,741,211
|
||||||
|
254,745,202
|
||||||
|
255,749,191
|
||||||
|
256,754,181
|
||||||
|
257,760,169
|
||||||
|
258,768,157
|
||||||
|
259,776,145
|
||||||
|
260,783,135
|
||||||
|
261,795,128
|
||||||
|
262,804,125
|
||||||
|
263,817,122
|
||||||
|
264,832,119
|
||||||
|
265,844,117
|
||||||
|
266,855,115
|
||||||
|
267,869,116
|
||||||
|
268,885,118
|
||||||
|
269,898,120
|
||||||
|
270,912,123
|
||||||
|
271,922,125
|
||||||
|
272,935,136
|
||||||
|
273,942,145
|
||||||
|
274,951,158
|
||||||
|
275,958,170
|
||||||
|
276,964,182
|
||||||
|
277,969,193
|
||||||
|
278,973,203
|
||||||
|
279,978,214
|
||||||
|
280,982,224
|
||||||
|
281,987,236
|
||||||
|
282,991,246
|
||||||
|
283,996,257
|
||||||
|
284,1000,267
|
||||||
|
285,1004,276
|
||||||
|
286,1009,288
|
||||||
|
287,1013,298
|
||||||
|
288,1018,309
|
||||||
|
289,1022,320
|
||||||
|
290,1026,331
|
||||||
|
291,1028,348
|
||||||
|
292,1029,363
|
||||||
|
293,1030,376
|
||||||
|
294,1030,389
|
||||||
|
295,1028,399
|
||||||
|
296,1018,401
|
||||||
|
297,1006,404
|
||||||
|
298,991,408
|
||||||
|
299,977,414
|
||||||
|
300,959,414
|
||||||
|
301,946,412
|
||||||
|
302,933,411
|
||||||
|
303,920,409
|
||||||
|
304,913,405
|
||||||
|
305,907,400
|
||||||
|
306,898,394
|
||||||
|
307,888,393
|
||||||
|
308,879,392
|
||||||
|
309,871,391
|
||||||
|
310,862,390
|
||||||
|
311,852,391
|
||||||
|
312,843,392
|
||||||
|
313,835,393
|
||||||
|
314,825,394
|
||||||
|
315,814,395
|
||||||
|
316,805,398
|
||||||
|
317,801,403
|
||||||
|
318,791,412
|
||||||
|
319,783,410
|
||||||
|
320,770,412
|
||||||
|
321,757,414
|
||||||
|
322,742,415
|
||||||
|
323,723,409
|
||||||
|
324,711,405
|
||||||
|
325,699,403
|
||||||
|
326,688,399
|
||||||
|
327,852,285
|
||||||
|
328,855,280
|
||||||
|
329,855,277
|
||||||
|
330,855,275
|
||||||
|
331,854,273
|
||||||
|
332,855,268
|
||||||
|
333,855,263
|
||||||
|
334,856,255
|
||||||
|
335,857,255
|
||||||
|
336,857,260
|
||||||
|
337,858,267
|
||||||
|
338,858,273
|
||||||
|
339,858,275
|
||||||
|
340,857,277
|
||||||
|
341,857,279
|
||||||
|
342,859,284
|
||||||
|
343,859,287
|
||||||
|
344,857,286
|
||||||
|
345,856,286
|
||||||
|
346,856,286
|
||||||
|
347,855,286
|
||||||
|
348,853,288
|
||||||
|
349,1069,389
|
||||||
|
350,1065,376
|
||||||
|
351,1062,363
|
||||||
|
352,1059,348
|
||||||
|
353,1057,335
|
||||||
|
354,1057,323
|
||||||
|
355,1057,311
|
||||||
|
356,1058,299
|
||||||
|
357,1058,288
|
||||||
|
358,1058,277
|
||||||
|
359,1057,267
|
||||||
|
360,1058,252
|
||||||
|
361,1058,242
|
||||||
|
362,1059,232
|
||||||
|
363,1058,224
|
||||||
|
364,1058,207
|
||||||
|
365,1058,197
|
||||||
|
366,1059,184
|
||||||
|
367,1061,171
|
||||||
|
368,1064,158
|
||||||
|
369,1068,144
|
||||||
|
370,1071,131
|
||||||
|
371,1079,124
|
||||||
|
372,1090,121
|
||||||
|
373,1103,117
|
||||||
|
374,1114,114
|
||||||
|
375,1131,110
|
||||||
|
376,1146,108
|
||||||
|
377,1158,107
|
||||||
|
378,1169,108
|
||||||
|
379,1182,108
|
||||||
|
380,1194,109
|
||||||
|
381,1206,109
|
||||||
|
382,1218,110
|
||||||
|
383,1230,110
|
||||||
|
384,1239,112
|
||||||
|
385,1253,112
|
||||||
|
386,1266,114
|
||||||
|
387,1277,111
|
||||||
|
388,1289,108
|
||||||
|
389,1302,108
|
||||||
|
390,1316,108
|
||||||
|
391,1329,109
|
||||||
|
392,1341,111
|
||||||
|
393,1355,115
|
||||||
|
394,1369,120
|
||||||
|
395,1383,128
|
||||||
|
396,1395,137
|
||||||
|
397,1403,148
|
||||||
|
398,1409,162
|
||||||
|
399,1413,177
|
||||||
|
400,1413,196
|
||||||
|
401,1413,212
|
||||||
|
402,1413,223
|
||||||
|
403,1411,231
|
||||||
|
404,1406,239
|
||||||
|
405,1402,245
|
||||||
|
406,1397,249
|
||||||
|
407,1403,252
|
||||||
|
408,1407,255
|
||||||
|
409,1412,261
|
||||||
|
410,1414,269
|
||||||
|
411,1416,279
|
||||||
|
412,1418,292
|
||||||
|
413,1420,309
|
||||||
|
414,1420,327
|
||||||
|
415,1416,348
|
||||||
|
416,1413,361
|
||||||
|
417,1407,372
|
||||||
|
418,1399,383
|
||||||
|
419,1388,393
|
||||||
|
420,1374,400
|
||||||
|
421,1361,405
|
||||||
|
422,1349,408
|
||||||
|
423,1334,411
|
||||||
|
424,1320,412
|
||||||
|
425,1308,413
|
||||||
|
426,1296,414
|
||||||
|
427,1283,414
|
||||||
|
428,1271,414
|
||||||
|
429,1259,414
|
||||||
|
430,1247,413
|
||||||
|
431,1234,413
|
||||||
|
432,1222,413
|
||||||
|
433,1211,413
|
||||||
|
434,1200,414
|
||||||
|
435,1188,413
|
||||||
|
436,1176,413
|
||||||
|
437,1164,413
|
||||||
|
438,1152,413
|
||||||
|
439,1140,413
|
||||||
|
440,1125,411
|
||||||
|
441,1109,407
|
||||||
|
442,1096,403
|
||||||
|
443,1083,399
|
||||||
|
444,1072,396
|
||||||
|
445,1205,307
|
||||||
|
446,1207,306
|
||||||
|
447,1207,304
|
||||||
|
448,1206,303
|
||||||
|
449,1205,302
|
||||||
|
450,1210,300
|
||||||
|
451,1215,300
|
||||||
|
452,1221,301
|
||||||
|
453,1229,302
|
||||||
|
454,1237,300
|
||||||
|
455,1247,300
|
||||||
|
456,1255,302
|
||||||
|
457,1260,302
|
||||||
|
458,1265,303
|
||||||
|
459,1268,303
|
||||||
|
460,1270,305
|
||||||
|
461,1269,306
|
||||||
|
462,1266,307
|
||||||
|
463,1261,307
|
||||||
|
464,1254,307
|
||||||
|
465,1246,307
|
||||||
|
466,1237,307
|
||||||
|
467,1228,307
|
||||||
|
468,1223,307
|
||||||
|
469,1217,307
|
||||||
|
470,1210,307
|
||||||
|
471,1206,211
|
||||||
|
472,1207,209
|
||||||
|
473,1207,207
|
||||||
|
474,1207,206
|
||||||
|
475,1212,206
|
||||||
|
476,1218,206
|
||||||
|
477,1224,207
|
||||||
|
478,1231,207
|
||||||
|
479,1238,206
|
||||||
|
480,1245,206
|
||||||
|
481,1251,206
|
||||||
|
482,1256,207
|
||||||
|
483,1261,207
|
||||||
|
484,1264,208
|
||||||
|
485,1263,209
|
||||||
|
486,1259,209
|
||||||
|
487,1253,214
|
||||||
|
488,1247,213
|
||||||
|
489,1239,212
|
||||||
|
490,1231,210
|
||||||
|
491,1224,211
|
||||||
|
492,1217,214
|
||||||
|
493,1212,214
|
@ -0,0 +1,151 @@
|
|||||||
|
# Adafruit NeoPixel library port to the rpi_ws281x library.
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com), Jeremy Garff (jer@jers.net)
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
import _rpi_ws281x as ws
|
||||||
|
|
||||||
|
|
||||||
|
def Color(red, green, blue, white = 0):
|
||||||
|
"""Convert the provided red, green, blue color to a 24-bit color value.
|
||||||
|
Each color component should be a value 0-255 where 0 is the lowest intensity
|
||||||
|
and 255 is the highest intensity.
|
||||||
|
"""
|
||||||
|
return (white << 24) | (red << 16)| (green << 8) | blue
|
||||||
|
|
||||||
|
|
||||||
|
class _LED_Data(object):
|
||||||
|
"""Wrapper class which makes a SWIG LED color data array look and feel like
|
||||||
|
a Python list of integers.
|
||||||
|
"""
|
||||||
|
def __init__(self, channel, size):
|
||||||
|
self.size = size
|
||||||
|
self.channel = channel
|
||||||
|
|
||||||
|
def __getitem__(self, pos):
|
||||||
|
"""Return the 24-bit RGB color value at the provided position or slice
|
||||||
|
of positions.
|
||||||
|
"""
|
||||||
|
# Handle if a slice of positions are passed in by grabbing all the values
|
||||||
|
# and returning them in a list.
|
||||||
|
if isinstance(pos, slice):
|
||||||
|
return [ws.ws2811_led_get(self.channel, n) for n in xrange(*pos.indices(self.size))]
|
||||||
|
# Else assume the passed in value is a number to the position.
|
||||||
|
else:
|
||||||
|
return ws.ws2811_led_get(self.channel, pos)
|
||||||
|
|
||||||
|
def __setitem__(self, pos, value):
|
||||||
|
"""Set the 24-bit RGB color value at the provided position or slice of
|
||||||
|
positions.
|
||||||
|
"""
|
||||||
|
# Handle if a slice of positions are passed in by setting the appropriate
|
||||||
|
# LED data values to the provided values.
|
||||||
|
if isinstance(pos, slice):
|
||||||
|
index = 0
|
||||||
|
for n in xrange(*pos.indices(self.size)):
|
||||||
|
ws.ws2811_led_set(self.channel, n, value[index])
|
||||||
|
index += 1
|
||||||
|
# Else assume the passed in value is a number to the position.
|
||||||
|
else:
|
||||||
|
return ws.ws2811_led_set(self.channel, pos, value)
|
||||||
|
|
||||||
|
|
||||||
|
class Adafruit_NeoPixel(object):
|
||||||
|
def __init__(self, num, pin, freq_hz=800000, dma=10, invert=False,
|
||||||
|
brightness=255, channel=0, strip_type=ws.WS2811_STRIP_RGB):
|
||||||
|
"""Class to represent a NeoPixel/WS281x LED display. Num should be the
|
||||||
|
number of pixels in the display, and pin should be the GPIO pin connected
|
||||||
|
to the display signal line (must be a PWM pin like 18!). Optional
|
||||||
|
parameters are freq, the frequency of the display signal in hertz (default
|
||||||
|
800khz), dma, the DMA channel to use (default 10), invert, a boolean
|
||||||
|
specifying if the signal line should be inverted (default False), and
|
||||||
|
channel, the PWM channel to use (defaults to 0).
|
||||||
|
"""
|
||||||
|
# Create ws2811_t structure and fill in parameters.
|
||||||
|
self._leds = ws.new_ws2811_t()
|
||||||
|
|
||||||
|
# Initialize the channels to zero
|
||||||
|
for channum in range(2):
|
||||||
|
chan = ws.ws2811_channel_get(self._leds, channum)
|
||||||
|
ws.ws2811_channel_t_count_set(chan, 0)
|
||||||
|
ws.ws2811_channel_t_gpionum_set(chan, 0)
|
||||||
|
ws.ws2811_channel_t_invert_set(chan, 0)
|
||||||
|
ws.ws2811_channel_t_brightness_set(chan, 0)
|
||||||
|
|
||||||
|
# Initialize the channel in use
|
||||||
|
self._channel = ws.ws2811_channel_get(self._leds, channel)
|
||||||
|
ws.ws2811_channel_t_count_set(self._channel, num)
|
||||||
|
ws.ws2811_channel_t_gpionum_set(self._channel, pin)
|
||||||
|
ws.ws2811_channel_t_invert_set(self._channel, 0 if not invert else 1)
|
||||||
|
ws.ws2811_channel_t_brightness_set(self._channel, brightness)
|
||||||
|
ws.ws2811_channel_t_strip_type_set(self._channel, strip_type)
|
||||||
|
|
||||||
|
# Initialize the controller
|
||||||
|
ws.ws2811_t_freq_set(self._leds, freq_hz)
|
||||||
|
ws.ws2811_t_dmanum_set(self._leds, dma)
|
||||||
|
|
||||||
|
# Grab the led data array.
|
||||||
|
self._led_data = _LED_Data(self._channel, num)
|
||||||
|
|
||||||
|
# Substitute for __del__, traps an exit condition and cleans up properly
|
||||||
|
atexit.register(self._cleanup)
|
||||||
|
|
||||||
|
def _cleanup(self):
|
||||||
|
# Clean up memory used by the library when not needed anymore.
|
||||||
|
if self._leds is not None:
|
||||||
|
ws.delete_ws2811_t(self._leds)
|
||||||
|
self._leds = None
|
||||||
|
self._channel = None
|
||||||
|
|
||||||
|
def begin(self):
|
||||||
|
"""Initialize library, must be called once before other functions are
|
||||||
|
called.
|
||||||
|
"""
|
||||||
|
resp = ws.ws2811_init(self._leds)
|
||||||
|
if resp != ws.WS2811_SUCCESS:
|
||||||
|
message = ws.ws2811_get_return_t_str(resp)
|
||||||
|
raise RuntimeError('ws2811_init failed with code {0} ({1})'.format(resp, message))
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
"""Update the display with the data from the LED buffer."""
|
||||||
|
resp = ws.ws2811_render(self._leds)
|
||||||
|
if resp != ws.WS2811_SUCCESS:
|
||||||
|
message = ws.ws2811_get_return_t_str(resp)
|
||||||
|
raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, message))
|
||||||
|
|
||||||
|
def setPixelColor(self, n, color):
|
||||||
|
"""Set LED at position n to the provided 24-bit color value (in RGB order).
|
||||||
|
"""
|
||||||
|
self._led_data[n] = color
|
||||||
|
|
||||||
|
def setPixelColorRGB(self, n, red, green, blue, white = 0):
|
||||||
|
"""Set LED at position n to the provided red, green, and blue color.
|
||||||
|
Each color component should be a value from 0 to 255 (where 0 is the
|
||||||
|
lowest intensity and 255 is the highest intensity).
|
||||||
|
"""
|
||||||
|
self.setPixelColor(n, Color(red, green, blue, white))
|
||||||
|
|
||||||
|
def setBrightness(self, brightness):
|
||||||
|
"""Scale each LED in the buffer by the provided brightness. A brightness
|
||||||
|
of 0 is the darkest and 255 is the brightest.
|
||||||
|
"""
|
||||||
|
ws.ws2811_channel_t_brightness_set(self._channel, brightness)
|
||||||
|
|
||||||
|
def getBrightness(self):
|
||||||
|
"""Get the brightness value for each LED in the buffer. A brightness
|
||||||
|
of 0 is the darkest and 255 is the brightest.
|
||||||
|
"""
|
||||||
|
return ws.ws2811_channel_t_brightness_get(self._channel)
|
||||||
|
|
||||||
|
def getPixels(self):
|
||||||
|
"""Return an object which allows access to the LED display data as if
|
||||||
|
it were a sequence of 24-bit RGB values.
|
||||||
|
"""
|
||||||
|
return self._led_data
|
||||||
|
|
||||||
|
def numPixels(self):
|
||||||
|
"""Return the number of pixels in the display."""
|
||||||
|
return ws.ws2811_channel_t_count_get(self._channel)
|
||||||
|
|
||||||
|
def getPixelColor(self, n):
|
||||||
|
"""Get the 24-bit RGB color value for the LED at position n."""
|
||||||
|
return self._led_data[n]
|
@ -0,0 +1,26 @@
|
|||||||
|
For overclocing needs, the pulse times MEASURED on the sign were:
|
||||||
|
|
||||||
|
0:
|
||||||
|
high: 294ns
|
||||||
|
low: 954ns
|
||||||
|
|
||||||
|
1:
|
||||||
|
high: 626ns
|
||||||
|
low: 618ns
|
||||||
|
|
||||||
|
|
||||||
|
The HIGH pulse times are always the same, the LOW pulse times are shortened by increasing frequency
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Current speed 800Khz
|
||||||
|
|
||||||
|
494 LED theoretical maximum framerate:
|
||||||
|
1/((494*32)/800000 + 80e-6) = 50.4Hz :(
|
||||||
|
|
||||||
|
925KHz is still fully in spec of the LEDs and provides:
|
||||||
|
58.2Hz
|
||||||
|
|
||||||
|
955KHz is only slightly out of spec and proviced a smooth
|
||||||
|
60.1fps
|
||||||
|
|
@ -0,0 +1,48 @@
|
|||||||
|
// SWIG interface file to define rpi_ws281x library python wrapper.
|
||||||
|
// Author: Tony DiCola (tony@tonydicola.com), Jeremy Garff (jer@jers.net)
|
||||||
|
|
||||||
|
// Define module name rpi_ws281x. This will actually be imported under
|
||||||
|
// the name _rpi_ws281x following the SWIG & Python conventions.
|
||||||
|
%module rpi_ws281x
|
||||||
|
|
||||||
|
// Include standard SWIG types & array support for support of uint32_t
|
||||||
|
// parameters and arrays.
|
||||||
|
%include "stdint.i"
|
||||||
|
%include "carrays.i"
|
||||||
|
|
||||||
|
// Declare functions which will be exported as anything in the ws2811.h header.
|
||||||
|
%{
|
||||||
|
#include "../ws2811.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
// Process ws2811.h header and export all included functions.
|
||||||
|
%include "../ws2811.h"
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
uint32_t ws2811_led_get(ws2811_channel_t *channel, int lednum)
|
||||||
|
{
|
||||||
|
if (lednum >= channel->count)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel->leds[lednum];
|
||||||
|
}
|
||||||
|
|
||||||
|
int ws2811_led_set(ws2811_channel_t *channel, int lednum, uint32_t color)
|
||||||
|
{
|
||||||
|
if (lednum >= channel->count)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel->leds[lednum] = color;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ws2811_channel_t *ws2811_channel_get(ws2811_t *ws, int channelnum)
|
||||||
|
{
|
||||||
|
return &ws->channel[channelnum];
|
||||||
|
}
|
||||||
|
%}
|
@ -0,0 +1,18 @@
|
|||||||
|
# Python wrapper for the rpi_ws281x library.
|
||||||
|
# Author: Tony DiCola (tony@tonydicola.com)
|
||||||
|
from ez_setup import use_setuptools
|
||||||
|
use_setuptools()
|
||||||
|
from setuptools import setup, find_packages, Extension
|
||||||
|
|
||||||
|
setup(name = 'rpi_ws281x',
|
||||||
|
version = '1.0.0',
|
||||||
|
author = 'Jeremy Garff',
|
||||||
|
author_email = 'jer@jers.net',
|
||||||
|
description = 'Userspace Raspberry Pi PWM library for WS281X LEDs.',
|
||||||
|
license = 'MIT',
|
||||||
|
url = 'https://github.com/jgarff/rpi_ws281x/',
|
||||||
|
py_modules = ['neopixel'],
|
||||||
|
ext_modules = [Extension('_rpi_ws281x',
|
||||||
|
sources=['rpi_ws281x.i'],
|
||||||
|
library_dirs=['../.'],
|
||||||
|
libraries=['ws2811', 'rt'])])
|
@ -0,0 +1,466 @@
|
|||||||
|
/*
|
||||||
|
* rpihw.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <byteswap.h>
|
||||||
|
|
||||||
|
#include "rpihw.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define LINE_WIDTH_MAX 80
|
||||||
|
#define HW_VER_STRING "Revision"
|
||||||
|
|
||||||
|
#define PERIPH_BASE_RPI 0x20000000
|
||||||
|
#define PERIPH_BASE_RPI2 0x3f000000
|
||||||
|
#define PERIPH_BASE_RPI4 0xfe000000
|
||||||
|
|
||||||
|
#define VIDEOCORE_BASE_RPI 0x40000000
|
||||||
|
#define VIDEOCORE_BASE_RPI2 0xc0000000
|
||||||
|
|
||||||
|
#define RPI_MANUFACTURER_MASK (0xf << 16)
|
||||||
|
#define RPI_WARRANTY_MASK (0x3 << 24)
|
||||||
|
|
||||||
|
static const rpi_hw_t rpi_hw_info[] = {
|
||||||
|
//
|
||||||
|
// Raspberry Pi 4
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0xA03111,
|
||||||
|
.type = RPI_HWVER_TYPE_PI4,
|
||||||
|
.periph_base = PERIPH_BASE_RPI4,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 4 Model B - 1GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0xB03111,
|
||||||
|
.type = RPI_HWVER_TYPE_PI4,
|
||||||
|
.periph_base = PERIPH_BASE_RPI4,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 4 Model B - 2GB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0xC03111,
|
||||||
|
.type = RPI_HWVER_TYPE_PI4,
|
||||||
|
.periph_base = PERIPH_BASE_RPI4,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 4 Model B - 4GB"
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// Model B Rev 1.0
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0x02,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x03,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B",
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Model B Rev 2.0
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0x04,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x05,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x06,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B",
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Model A
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0x07,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model A",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x08,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model A",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x09,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model A",
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Model B
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0x0d,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x0e,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x0f,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B",
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Model B+
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0x10,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B+",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x13,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B+",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x900032,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model B+",
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Compute Module
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0x11,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Compute Module 1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x14,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Compute Module 1",
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pi Zero
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0x900092,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Pi Zero v1.2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x900093,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Pi Zero v1.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x920093,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Pi Zero v1.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x9200c1,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Pi Zero W v1.1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x9000c1,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Pi Zero W v1.1",
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Model A+
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0x12,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model A+",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x15,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model A+",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x900021,
|
||||||
|
.type = RPI_HWVER_TYPE_PI1,
|
||||||
|
.periph_base = PERIPH_BASE_RPI,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI,
|
||||||
|
.desc = "Model A+",
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pi 2 Model B
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0xa01041,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0xa01040,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0xa21041,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 2",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// Pi 2 with BCM2837
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0xa22042,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 2",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// Pi 3 Model B
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0xa020d3,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 3 B+",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0xa02082,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0xa02083,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0xa22082,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0xa22083,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Pi 3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.hwver = 0x9020e0,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Model 3 A+",
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pi Compute Module 3
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0xa020a0,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Compute Module 3/L3",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// Pi Compute Module 3+
|
||||||
|
//
|
||||||
|
{
|
||||||
|
.hwver = 0xa02100,
|
||||||
|
.type = RPI_HWVER_TYPE_PI2,
|
||||||
|
.periph_base = PERIPH_BASE_RPI2,
|
||||||
|
.videocore_base = VIDEOCORE_BASE_RPI2,
|
||||||
|
.desc = "Compute Module 3+",
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const rpi_hw_t *rpi_hw_detect(void)
|
||||||
|
{
|
||||||
|
const rpi_hw_t *result = NULL;
|
||||||
|
uint32_t rev;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
// On ARM64, read revision from /proc/device-tree as it is not shown in
|
||||||
|
// /proc/cpuinfo
|
||||||
|
FILE *f = fopen("/proc/device-tree/system/linux,revision", "r");
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
size_t read = fread(&rev, sizeof(uint32_t), 1, f);
|
||||||
|
if (read != sizeof(uint32_t))
|
||||||
|
goto done;
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
rev = bswap_32(rev); // linux,revision appears to be in big endian
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i = 0; i < (sizeof(rpi_hw_info) / sizeof(rpi_hw_info[0])); i++)
|
||||||
|
{
|
||||||
|
uint32_t hwver = rpi_hw_info[i].hwver;
|
||||||
|
if (rev == hwver)
|
||||||
|
{
|
||||||
|
result = &rpi_hw_info[i];
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
FILE *f = fopen("/proc/cpuinfo", "r");
|
||||||
|
char line[LINE_WIDTH_MAX];
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(line, LINE_WIDTH_MAX - 1, f))
|
||||||
|
{
|
||||||
|
if (strstr(line, HW_VER_STRING))
|
||||||
|
{
|
||||||
|
char *substr;
|
||||||
|
|
||||||
|
substr = strstr(line, ": ");
|
||||||
|
if (!substr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
rev = strtoul(&substr[1], NULL, 16); // Base 16
|
||||||
|
if (errno)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (sizeof(rpi_hw_info) / sizeof(rpi_hw_info[0])); i++)
|
||||||
|
{
|
||||||
|
uint32_t hwver = rpi_hw_info[i].hwver;
|
||||||
|
|
||||||
|
// Take out warranty and manufacturer bits
|
||||||
|
hwver &= ~(RPI_WARRANTY_MASK | RPI_MANUFACTURER_MASK);
|
||||||
|
rev &= ~(RPI_WARRANTY_MASK | RPI_MANUFACTURER_MASK);
|
||||||
|
|
||||||
|
if (rev == hwver)
|
||||||
|
{
|
||||||
|
result = &rpi_hw_info[i];
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
done:
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* rpihw.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __RPIHW_H__
|
||||||
|
#define __RPIHW_H__
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t type;
|
||||||
|
#define RPI_HWVER_TYPE_UNKNOWN 0
|
||||||
|
#define RPI_HWVER_TYPE_PI1 1
|
||||||
|
#define RPI_HWVER_TYPE_PI2 2
|
||||||
|
#define RPI_HWVER_TYPE_PI4 3
|
||||||
|
uint32_t hwver;
|
||||||
|
uint32_t periph_base;
|
||||||
|
uint32_t videocore_base;
|
||||||
|
char *desc;
|
||||||
|
} rpi_hw_t;
|
||||||
|
|
||||||
|
|
||||||
|
const rpi_hw_t *rpi_hw_detect(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __RPIHW_H__ */
|
@ -0,0 +1,71 @@
|
|||||||
|
#
|
||||||
|
# SConstruct
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 Jeremy Garff <jer @ jers.net>
|
||||||
|
#
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
# provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
# conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
# of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
# provided with the distribution.
|
||||||
|
# 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
# or promote products derived from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
import SCons, os
|
||||||
|
|
||||||
|
def version_flags(env):
|
||||||
|
if not env['V']:
|
||||||
|
env['VERSIONCOMSTR'] = 'Version ${TARGET}'
|
||||||
|
|
||||||
|
def version_builders(env):
|
||||||
|
def generate_version_header(target, source, env):
|
||||||
|
headername = os.path.basename(target[0].abspath)
|
||||||
|
headerdef = headername.replace('.', '_').replace('-', '_').upper()
|
||||||
|
|
||||||
|
try:
|
||||||
|
version = open(source[0].abspath, 'r').readline().strip().split('.')
|
||||||
|
except:
|
||||||
|
version = [ '0', '0', '0' ]
|
||||||
|
|
||||||
|
f = open(headername, 'w')
|
||||||
|
f.write('/* Auto Generated Header built by version.py - DO NOT MODIFY */\n')
|
||||||
|
f.write('\n')
|
||||||
|
f.write('#ifndef __%s__\n' % (headerdef))
|
||||||
|
f.write('#define __%s__\n' % (headerdef))
|
||||||
|
f.write('\n')
|
||||||
|
f.write('#define VERSION_MAJOR %s\n' % version[0])
|
||||||
|
f.write('#define VERSION_MINOR %s\n' % version[1])
|
||||||
|
f.write('#define VERSION_MICRO %s\n' % version[2])
|
||||||
|
f.write('\n')
|
||||||
|
f.write('#endif /* __%s__ */\n' % (headerdef))
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
env.Append(BUILDERS = {
|
||||||
|
'Version' : SCons.Builder.Builder(
|
||||||
|
action = SCons.Action.Action(generate_version_header, '${VERSIONCOMSTR}'),
|
||||||
|
suffix = '.h',
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
def exists(env):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def generate(env, **kwargs):
|
||||||
|
[f(env) for f in (version_flags, version_builders)]
|
||||||
|
|
||||||
|
|
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* ws2811.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Garff <jer @ jers.net>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||||
|
* provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
* 3. Neither the name of the owner nor the names of its contributors may be used to endorse
|
||||||
|
* or promote products derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||||
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __WS2811_H__
|
||||||
|
#define __WS2811_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "rpihw.h"
|
||||||
|
#include "pwm.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define WS2811_TARGET_FREQ 800000 // Can go as low as 400000
|
||||||
|
|
||||||
|
// 4 color R, G, B and W ordering
|
||||||
|
#define SK6812_STRIP_RGBW 0x18100800
|
||||||
|
#define SK6812_STRIP_RBGW 0x18100008
|
||||||
|
#define SK6812_STRIP_GRBW 0x18081000
|
||||||
|
#define SK6812_STRIP_GBRW 0x18080010
|
||||||
|
#define SK6812_STRIP_BRGW 0x18001008
|
||||||
|
#define SK6812_STRIP_BGRW 0x18000810
|
||||||
|
#define SK6812_SHIFT_WMASK 0xf0000000
|
||||||
|
|
||||||
|
// 3 color R, G and B ordering
|
||||||
|
#define WS2811_STRIP_RGB 0x00100800
|
||||||
|
#define WS2811_STRIP_RBG 0x00100008
|
||||||
|
#define WS2811_STRIP_GRB 0x00081000
|
||||||
|
#define WS2811_STRIP_GBR 0x00080010
|
||||||
|
#define WS2811_STRIP_BRG 0x00001008
|
||||||
|
#define WS2811_STRIP_BGR 0x00000810
|
||||||
|
|
||||||
|
// predefined fixed LED types
|
||||||
|
#define WS2812_STRIP WS2811_STRIP_GRB
|
||||||
|
#define SK6812_STRIP WS2811_STRIP_GRB
|
||||||
|
#define SK6812W_STRIP SK6812_STRIP_GRBW
|
||||||
|
|
||||||
|
struct ws2811_device;
|
||||||
|
|
||||||
|
typedef uint32_t ws2811_led_t; //< 0xWWRRGGBB
|
||||||
|
typedef struct ws2811_channel_t
|
||||||
|
{
|
||||||
|
int gpionum; //< GPIO Pin with PWM alternate function, 0 if unused
|
||||||
|
int invert; //< Invert output signal
|
||||||
|
int count; //< Number of LEDs, 0 if channel is unused
|
||||||
|
int strip_type; //< Strip color layout -- one of WS2811_STRIP_xxx constants
|
||||||
|
ws2811_led_t *leds; //< LED buffers, allocated by driver based on count
|
||||||
|
uint8_t brightness; //< Brightness value between 0 and 255
|
||||||
|
uint8_t wshift; //< White shift value
|
||||||
|
uint8_t rshift; //< Red shift value
|
||||||
|
uint8_t gshift; //< Green shift value
|
||||||
|
uint8_t bshift; //< Blue shift value
|
||||||
|
uint8_t *gamma; //< Gamma correction table
|
||||||
|
} ws2811_channel_t;
|
||||||
|
|
||||||
|
typedef struct ws2811_t
|
||||||
|
{
|
||||||
|
uint64_t render_wait_time; //< time in µs before the next render can run
|
||||||
|
struct ws2811_device *device; //< Private data for driver use
|
||||||
|
const rpi_hw_t *rpi_hw; //< RPI Hardware Information
|
||||||
|
uint32_t freq; //< Required output frequency
|
||||||
|
int dmanum; //< DMA number _not_ already in use
|
||||||
|
ws2811_channel_t channel[RPI_PWM_CHANNELS];
|
||||||
|
} ws2811_t;
|
||||||
|
|
||||||
|
#define WS2811_RETURN_STATES(X) \
|
||||||
|
X(0, WS2811_SUCCESS, "Success"), \
|
||||||
|
X(-1, WS2811_ERROR_GENERIC, "Generic failure"), \
|
||||||
|
X(-2, WS2811_ERROR_OUT_OF_MEMORY, "Out of memory"), \
|
||||||
|
X(-3, WS2811_ERROR_HW_NOT_SUPPORTED, "Hardware revision is not supported"), \
|
||||||
|
X(-4, WS2811_ERROR_MEM_LOCK, "Memory lock failed"), \
|
||||||
|
X(-5, WS2811_ERROR_MMAP, "mmap() failed"), \
|
||||||
|
X(-6, WS2811_ERROR_MAP_REGISTERS, "Unable to map registers into userspace"), \
|
||||||
|
X(-7, WS2811_ERROR_GPIO_INIT, "Unable to initialize GPIO"), \
|
||||||
|
X(-8, WS2811_ERROR_PWM_SETUP, "Unable to initialize PWM"), \
|
||||||
|
X(-9, WS2811_ERROR_MAILBOX_DEVICE, "Failed to create mailbox device"), \
|
||||||
|
X(-10, WS2811_ERROR_DMA, "DMA error"), \
|
||||||
|
X(-11, WS2811_ERROR_ILLEGAL_GPIO, "Selected GPIO not possible"), \
|
||||||
|
X(-12, WS2811_ERROR_PCM_SETUP, "Unable to initialize PCM"), \
|
||||||
|
X(-13, WS2811_ERROR_SPI_SETUP, "Unable to initialize SPI"), \
|
||||||
|
X(-14, WS2811_ERROR_SPI_TRANSFER, "SPI transfer error") \
|
||||||
|
|
||||||
|
#define WS2811_RETURN_STATES_ENUM(state, name, str) name = state
|
||||||
|
#define WS2811_RETURN_STATES_STRING(state, name, str) str
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WS2811_RETURN_STATES(WS2811_RETURN_STATES_ENUM),
|
||||||
|
|
||||||
|
WS2811_RETURN_STATE_COUNT
|
||||||
|
} ws2811_return_t;
|
||||||
|
|
||||||
|
ws2811_return_t ws2811_init(ws2811_t *ws2811); //< Initialize buffers/hardware
|
||||||
|
void ws2811_fini(ws2811_t *ws2811); //< Tear it all down
|
||||||
|
ws2811_return_t ws2811_render(ws2811_t *ws2811); //< Send LEDs off to hardware
|
||||||
|
ws2811_return_t ws2811_wait(ws2811_t *ws2811); //< Wait for DMA completion
|
||||||
|
const char * ws2811_get_return_t_str(const ws2811_return_t state); //< Get string representation of the given return state
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __WS2811_H__ */
|
Loading…
Reference in new issue