first commit

This commit is contained in:
pandacraft 2025-03-21 16:04:17 +01:00
commit a5a0434432
1126 changed files with 439481 additions and 0 deletions

49
Script/README.md Normal file
View file

@ -0,0 +1,49 @@
## Installing
You need internet access for the following step(s).
The quickest way for installing the GrovePi is to enter the following command:
```
curl -kL dexterindustries.com/update_grovepi | bash
```
By default, the GrovePi package is installed system-wide, [script_tools](https://github.com/DexterInd/script_tools) and [RFR_Tools](https://github.com/DexterInd/RFR_Tools) are updated each time the script is ran.
An example using options appended to the command can be:
```
curl -kL dexterindustries.com/update_grovepi | bash -s -- --user-local --no-update-aptget --no-dependencies
```
## Command Options
The options that can be appended to this command are:
* `--no-update-aptget` - to skip using `sudo apt-get update` before installing dependencies. For this to be useful, `--no-dependencies` has to be not used. Applies to RFR_Tools and the GrovePi.
* `--bypass-rfrtools` - skips installing RFR_Tools completely.
* `--bypass-python-rfrtools` - skips installing/updating the python package for [RFR_Tools](https://github.com/DexterInd/RFR_Tools).
* `--bypass-gui-installation` - skips installing the GUI packages/dependencies from [RFR_Tools](https://github.com/DexterInd/RFR_Tools).
* `--no-dependencies` - skip installing any dependencies for the GrovePi. It's supposed to be used on each consecutive update after the initial install has gone through.
* `--user-local` - install the python package for the GrovePi in the home directory of the user. This doesn't require any special read/write permissions: the actual command used is (`python setup.py install --force --user`).
* `--env-local` - install the python package for the GrovePi within the given environment without elevated privileges: the actual command used is (`python setup.py install --force`).
* `--system-wide` - install the python package for the GrovePi within the sytem-wide environment with `sudo`: the actual command used is (`sudo python setup.py install --force`).
Important to remember is that `--user-local`, `--env-local` and `--system-wide` options are all mutually-exclusive - they cannot be used together.
As a last thing, different versions of it can be pulled by appending a corresponding branch name or tag.
## Minimal Installation
Now, if you only want the absolute minimum in order to get going with the GrovePi, you can run this command:
```bash
curl -kL dexterindustries.com/update_grovepi | bash -s -- --bypass-gui-installation
```
This will only get you installed the GrovePi dependencies and nothing else. You still can use options such as `--user-local` or `--env-local` if you are working with a different kind of environment. Keep in mind that `--system-wide` is selected by default.
## Subsequent Updates
If the GrovePi has been installed either by using the full command or the one for the minimal installation, this means you have all the packages installed already and all dependencies put in. Therefore, on subsequent installation, you can skip installing any dependency and instead just reinstall the python package of the GrovePi. To do this, you can run this command:
```bash
curl -kL dexterindustries.com/update_grovepi | bash -s -- --bypass-rfrtools --no-dependencies
```
Or if this is too complex, you can always stick to the command meant for the full installation or the minimal one.

12
Script/grove.pth Normal file
View file

@ -0,0 +1,12 @@
/Software/Python/grove_i2c_adc
/Software/Python/grove_rgb_lcd
/Software/Python/grove_accelerometer_16g
/Software/Python/grove_barometer_sensors/barometric_sensor_bmp085
/Software/Python/grove_barometer_sensors/barometric_sensor_bmp180
/Software/Python/grove_i2c_digital_light_sensor
/Software/Python/grove_i2c_oled_128_64
/Software/Python/grove_i2c_sunlight_sensor
/Software/Python/grove_i2c_touch
/Software/Python/grove_ir_receiver
/Software/Python/grove_oled
/Software/Python/

View file

@ -0,0 +1,82 @@
i2c-tools CHANGES
-----------------
3.1.0 (2011-12-04)
decode-dimms: Decode module configuration type of DDR SDRAM
Decode refresh rate of DDR SDRAM
Add support for the at24 kernel driver
i2c-dev.h: Make value arrays const for block write functions
i2cset: Add support for SMBus and I2C block writes
Removed obsolete method to specify value mask
More stringent parameter validation
3.0.3 (2010-12-12)
Makefile: Let the environment set CC and CFLAGS
Integrate py-smbus into the build system
README: Point users to the linux-i2c mailing list
decode-dimms: Handle CRC of FB-DIMM and DDR3 SDRAM memory modules
Add support for DDR3 SDRAM
Fix decoding of SDR SDRAM bytes 12-14
Add side-by-side formatting option
Add merged cells formatting option
Try harder to decode the manufacturing date
Handle read errors on sysfs
Decode voltage interface level of DDR SDRAM
decode-xeon: Delete
eepromer: Fix array initialization overrun
i2cdetect: Drop legacy reference to ISA bus
i2cset: Add support for short writes with PEC
i2c-stub-from-dump: Use udev settle to speed up initialization
Unload i2c-stub automatically if needed
Add support for multiple dumps
tools: Properly handle /dev/i2c not being a directory
Increase limit on I2C bus number
3.0.2 (2008-11-29)
i2c-dev.h: Drop I2C_FUNC_SMBUS_*I2C_BLOCK_2 defines
decode-dimms: Add support for little-endian word hexdumps
Only export the ceil function from POSIX
decode-vaio: Remove history
i2cdetect: Support i2c bus passed by name
Shorten the usage message
i2cdump: Support i2c bus passed by name
Shorten the usage message
Restrict the chip address to 0x03-0x77
Split the functionality checking code into a separate function
Better error message on missing adapter functionality
i2cget: Support i2c bus passed by name
Shorten the usage message
Better error message on missing adapter functionality
i2cset: Support i2c bus passed by name
Shorten the usage message
Restrict the chip address to 0x03-0x77
Split the code into several functions for clarity
Add support for short writes (SMBus send byte)
Better error message on missing adapter functionality
Set the data value mask with -m
Make reading back the written value optional
i2c-stub-from-dump: Add support for partial dumps
Report if only garbage is found in dump file
Behave properly when i2c-stub is already loaded
Stop on i2cset error
3.0.1 (2008-04-04)
Drop the trailing .pl from all perl script names
decode-dimms: Fix DDR2 SDRAM module speed decoding
Update manufacturer IDs
Don't print anything by default if checksum fails
Decode all DDR2 SDRAM timing information
Add support for reading SPD data from hexdumps
Make command line parsing more robust
decode-vaio: Private data might not be readable by non-root users
Print the asset tag
Fix the timestamp decoding
i2cdump: Fix I2C block mode error code
Remove man page reference to hardware monitoring chips
Let the user specify a register range
i2cset: Final status messages go to stdout
Return success even when readback fails or doesn't match
i2c-stub-from-dump: New helper script to use with i2c-stub
3.0.0 (2007-10-14)
Initial release

View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View file

@ -0,0 +1,40 @@
# I2C tools for Linux
#
# Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
DESTDIR =
prefix = /usr/local
bindir = $(prefix)/bin
sbindir = $(prefix)/sbin
mandir = $(prefix)/share/man
man8dir = $(mandir)/man8
incdir = $(prefix)/include
INSTALL := install
INSTALL_DATA := $(INSTALL) -m 644
INSTALL_DIR := $(INSTALL) -m 755 -d
INSTALL_PROGRAM := $(INSTALL) -m 755
RM := rm -f
CC ?= gcc
CFLAGS ?= -O2
# When debugging, use the following instead
#CFLAGS := -O -g
CFLAGS += -Wall
KERNELVERSION := $(shell uname -r)
.PHONY: all strip clean install uninstall
all:
EXTRA :=
#EXTRA += py-smbus
SRCDIRS := include eeprom stub tools $(EXTRA)
include $(SRCDIRS:%=%/Module.mk)

View file

@ -0,0 +1,76 @@
I2C TOOLS FOR LINUX
===================
This package contains an heterogeneous set of I2C tools for the Linux kernel.
These tools were originally part of the lm-sensors project but were finally
split into their own package for convenience. They compile, run and have been
tested on GNU/Linux.
CONTENTS
--------
The various tools included in this package are grouped by category, each
category has its own sub-directory:
* eeprom
Perl scripts for decoding different types of EEPROMs (SPD, EDID...) These
scripts rely on the "eeprom" kernel driver. They are installed by default.
* eepromer
Tools for writing to EEPROMs. These tools rely on the "i2c-dev" kernel
driver. They are not installed by default.
* include
C/C++ header files for I2C and SMBus access over i2c-dev. Installed by
default.
* py-smbus
Python wrapper for SMBus access over i2c-dev. Not installed by default.
* stub
A helper script to use with the i2c-stub kernel driver. Installed by
default.
* tools
I2C device detection and register dump tools. These tools rely on the
"i2c-dev" kernel driver. They are installed by default.
INSTALLATION
------------
There's no configure script, so simply run "make" to build the tools, and
"make install" to install them. You also can use "make uninstall" to remove
all the files you installed. By default, files are installed in /usr/local
but you can change this behavior by editing the Makefile file and setting
prefix to wherever you want. You may change the C compiler and the
compilation flags as well.
Optionally, you can run "make strip" prior to "make install" if you want
smaller binaries. However, be aware that this will prevent any further
attempt to debug the programs.
If you wish to include sub-directories that are not enabled by default, then
just set them via the EXTRA make variable. For example, to build py-smbus,
do:
$ make EXTRA="py-smbus"
DOCUMENTATION
-------------
The main tools have manual pages, which are installed by "make install".
See these manual pages for command line interface details and tool specific
information.
The other tools come with simple text documentation, which isn't installed.
QUESTIONS AND BUG REPORTS
-------------------------
Please post your questions and bug reports to the linux-i2c mailing list:
linux-i2c@vger.kernel.org
For additional information about this list, see:
http://vger.kernel.org/vger-lists.html#linux-i2c

View file

@ -0,0 +1,29 @@
# EEPROM decoding scripts for the Linux eeprom driver
#
# Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
EEPROM_DIR := eeprom
EEPROM_TARGETS := decode-dimms decode-vaio ddcmon decode-edid
#
# Commands
#
install-eeprom: $(addprefix $(EEPROM_DIR)/,$(EEPROM_TARGETS))
$(INSTALL_DIR) $(DESTDIR)$(bindir)
for program in $(EEPROM_TARGETS) ; do \
$(INSTALL_PROGRAM) $(EEPROM_DIR)/$$program $(DESTDIR)$(bindir) ; done
uninstall-eeprom:
for program in $(EEPROM_TARGETS) ; do \
$(RM) $(DESTDIR)$(bindir)/$$program ; done
install: install-eeprom
uninstall: uninstall-eeprom

View file

@ -0,0 +1,18 @@
This directory contains scripts to decode the data exposed by the eeprom
Linux kernel driver.
* decode-dimms (perl script)
Decode the information found in memory module SPD EEPROMs. The SPD
data is read either from the running system or from dump files.
* decode-vaio (perl script)
Decode the information found in Sony Vaio laptop identification EEPROMs.
* ddcmon (perl script)
decode-edid (perl script)
Decode the information found in monitor EEPROMs. Both scripts require
an access to the DDC channel of the monitor. This is typically provided
by framebuffer drivers. decode-edid additionally requires parse-edid,
which is part of the read-edid package. ddcmon prints general
information, while decode-edid prints timing information for
inclusion into your X11 configuration file.

View file

@ -0,0 +1,567 @@
#!/usr/bin/perl -w
#
# Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
#
# Parts inspired from decode-edid.
# Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
#
# Parts inspired from the ddcmon driver and sensors' print_ddcmon function.
# Copyright (C) 1998-2004 Mark D. Studebaker
#
# Parts inspired from the fbmon driver (Linux 2.6.10).
# Copyright (C) 2002 James Simmons <jsimmons@users.sf.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
# Version 1.0 2005-01-04 Jean Delvare <khali@linux-fr.org>
#
# This script is a replacement for the now deprecated ddcmon kernel driver.
# Instead of having a dedicated driver, it is better to reuse the standard
# eeprom driver and implement the EDID-specific code in user-space.
#
# EDID (Extended Display Identification Data) is a VESA standard which
# allows storing (on manufacturer's side) and retrieving (on user's side)
# of configuration information about displays, such as manufacturer,
# serial number, physical dimensions and allowed horizontal and vertical
# refresh rates.
#
# Syntax: ddcmon [bus [address]]
# Address can be given in decimal or hexadecimal (with a 0x prefix).
# If no address is given, default is 0x50.
# Bus number must be given in decimal. If no bus number is given,
# try them all.
use strict;
use Fcntl qw(:DEFAULT :seek);
use vars qw(@standard_scales);
@standard_scales = ([1, 1], [3, 4], [4, 5], [16, 9]);
# Make sure the eeprom module is loaded.
# For non-modular kernels, we can't help.
if (-r '/proc/modules')
{
my $found = 0;
open(MODULES, '/proc/modules');
while (!$found && defined ($_ = <MODULES>))
{
$found++ if m/^eeprom\s+/;
}
close(MODULES);
unless ($found)
{
print STDERR
"This script requires the eeprom module to be loaded.\n";
exit 1;
}
}
# Only used for sysfs
sub rawread
{
my $filename = shift;
my $length = shift;
my $offset = shift || 0;
my $bytes = '';
sysopen(FH, $filename, O_RDONLY)
or die "Can't open $filename";
if ($offset)
{
sysseek(FH, $offset, SEEK_SET)
or die "Can't seek in $filename";
}
$offset = 0;
while ($length)
{
my $r = sysread(FH, $bytes, $length, $offset);
die "Can't read $filename"
unless defined($r);
die "Unexpected EOF in $filename"
unless $r;
$offset += $r;
$length -= $r;
}
close(FH);
return $bytes;
}
sub get_edid_sysfs
{
my ($bus, $addr) = @_;
my @bytes = unpack("C*", rawread("/sys/bus/i2c/devices/$bus-00$addr/eeprom", 128));
return \@bytes;
}
sub get_edid_procfs
{
my ($bus, $addr) = @_;
my @bytes;
for (my $i = 0 ; $i < 0x80; $i += 0x10)
{
my $filename = sprintf("/proc/sys/dev/sensors/eeprom-i2c-\%s-\%s/\%02x",
$bus, $addr, $i);
open(EEDATA, $filename)
or die "Can't read $filename";
push @bytes, split(/\s+/, <EEDATA>);
close(EEDATA);
}
return \@bytes;
}
sub print_line
{
my $label = shift;
my $pattern = shift;
printf("\%-24s$pattern\n", $label.':', @_);
}
sub extract_byte
{
my ($bytes, $offset) = @_;
return $bytes->[$offset];
}
sub extract_word
{
my ($bytes, $offset) = @_;
return ($bytes->[$offset]
| ($bytes->[$offset+1] << 8));
}
sub extract_manufacturer
{
my ($bytes, $offset) = @_;
my $i = ($bytes->[$offset+1] | ($bytes->[$offset] << 8));
return sprintf('%c%c%c',
(($i >> 10) & 0x1f) + ord('A') - 1,
(($i >> 5) & 0x1f) + ord('A') - 1,
($i & 0x1f) + ord('A') - 1);
}
sub extract_sesquiword
{
my ($bytes, $offset) = @_;
return ($bytes->[$offset]
| ($bytes->[$offset+1] << 8)
| ($bytes->[$offset+2] << 16));
}
sub extract_dword
{
my ($bytes, $offset) = @_;
return ($bytes->[$offset]
| ($bytes->[$offset+1] << 8)
| ($bytes->[$offset+2] << 16)
| ($bytes->[$offset+3] << 24));
}
sub extract_display_input
{
my ($bytes, $offset) = @_;
my @voltage = ('0.700V/0.300V', '0.714V/0.286V',
'1.000V/0.400V', '0.700V/0.000V');
return 'Digital'
if ($bytes->[$offset] & 0x80);
return 'Analog ('.$voltage[($bytes->[$offset] & 0x60) >> 5].')';
}
sub extract_dpms
{
my ($bytes, $offset) = @_;
my @supported;
push @supported, 'Active Off' if ($bytes->[$offset] & 0x20);
push @supported, 'Suspend' if ($bytes->[$offset] & 0x40);
push @supported, 'Standby' if ($bytes->[$offset] & 0x80);
return join(', ', @supported)
if (@supported);
return 'None supported';
}
sub extract_color_mode
{
my ($bytes, $offset) = @_;
my @mode = ('Monochrome', 'RGB Multicolor', 'Non-RGB Multicolor');
return $mode[($bytes->[$offset] >> 3) & 0x03];
}
sub good_signature
{
my $bytes = shift;
return $bytes->[0] == 0x00
&& $bytes->[1] == 0xff
&& $bytes->[2] == 0xff
&& $bytes->[3] == 0xff
&& $bytes->[4] == 0xff
&& $bytes->[5] == 0xff
&& $bytes->[6] == 0xff
&& $bytes->[7] == 0x00;
}
sub verify_checksum
{
my $bytes = shift;
my $cs;
for (my $i = 0, $cs = 0; $i < 0x80; $i++)
{
$cs += $bytes->[$i];
}
return (($cs & 0xff) == 0 ? 'OK' : 'Not OK');
}
sub add_timing
{
my ($timings, $new) = @_;
my $mode = sprintf('%ux%u@%u%s', $new->[0], $new->[1],
$new->[2], defined ($new->[3]) &&
$new->[3] eq 'interlaced' ? 'i' : '');
$timings->{$mode} = $new;
}
sub add_standard_timing
{
my ($timings, $byte0, $byte1) = @_;
# Unused slot
return if ($byte0 == $byte1)
&& ($byte0 == 0x01 || $byte0 == 0x00 || $byte0 == 0x20);
my $width = ($byte0 + 31) * 8;
my $height = $width * $standard_scales[$byte1 >> 6]->[0]
/ $standard_scales[$byte1 >> 6]->[1];
my $refresh = 60 + ($byte1 & 0x3f);
add_timing($timings, [$width, $height, $refresh]);
}
sub sort_timings
{
# First order by width
return -1 if $a->[0] < $b->[0];
return 1 if $a->[0] > $b->[0];
# Second by height
return -1 if $a->[1] < $b->[1];
return 1 if $a->[1] > $b->[1];
# Third by frequency
# Interlaced modes count for half their frequency
my $freq_a = $a->[2];
my $freq_b = $b->[2];
$freq_a /= 2 if defined $a->[3] && $a->[3] eq 'interlaced';
$freq_b /= 2 if defined $b->[3] && $b->[3] eq 'interlaced';
return -1 if $freq_a < $freq_b;
return 1 if $freq_a > $freq_b;
return 0;
}
sub print_timings
{
my ($bytes, $timings) = @_;
# Established Timings
my @established =
(
[720, 400, 70],
[720, 400, 88],
[640, 480, 60],
[640, 480, 67],
[640, 480, 72],
[640, 480, 75],
[800, 600, 56],
[800, 600, 60],
[800, 600, 72],
[800, 600, 75],
[832, 624, 75],
[1024, 768, 87, 'interlaced'],
[1024, 768, 60],
[1024, 768, 70],
[1024, 768, 75],
[1280, 1024, 75],
undef, undef, undef,
[1152, 870, 75],
);
my $temp = extract_sesquiword($bytes, 0x23);
for (my $i = 0; $i < 24; $i++)
{
next unless defined($established[$i]);
add_timing($timings, $established[$i])
if ($temp & (1 << $i));
}
# Standard Timings
for (my $i = 0x26; $i < 0x36; $i += 2)
{
add_standard_timing($timings, $bytes->[$i], $bytes->[$i+1]);
}
foreach my $v (sort sort_timings values(%{$timings}))
{
print_line("Timing", '%ux%u @ %u Hz%s',
$v->[0], $v->[1], $v->[2],
defined($v->[3]) ? ' ('.$v->[3].')' : '');
}
}
sub extract_string
{
my ($bytes, $offset) = @_;
my $string = '';
for (my $i = 5; $i < 18; $i++)
{
last if $bytes->[$offset+$i] == 0x0a
|| $bytes->[$offset+$i] == 0x00;
$string .= chr($bytes->[$offset+$i])
if ($bytes->[$offset+$i] >= 32
&& $bytes->[$offset+$i] < 127);
}
$string =~ s/\s+$//;
return $string;
}
# Some blocks contain different information:
# 0x00, 0x00, 0x00, 0xfa: Additional standard timings block
# 0x00, 0x00, 0x00, 0xfc: Monitor block
# 0x00, 0x00, 0x00, 0xfd: Limits block
# 0x00, 0x00, 0x00, 0xfe: Ascii block
# 0x00, 0x00, 0x00, 0xff: Serial block
# Return a reference to a hash containing all information.
sub extract_detailed_timings
{
my ($bytes) = @_;
my %info = ('timings' => {});
for (my $offset = 0x36; $offset < 0x7e; $offset += 18)
{
if ($bytes->[$offset] == 0x00
&& $bytes->[$offset+1] == 0x00
&& $bytes->[$offset+2] == 0x00
&& $bytes->[$offset+4] == 0x00)
{
if ($bytes->[$offset+3] == 0xfa)
{
for (my $i = $offset + 5; $i < $offset + 17; $i += 2)
{
add_standard_timing($info{'timings'},
$bytes->[$i],
$bytes->[$i+1]);
}
}
elsif ($bytes->[$offset+3] == 0xfc)
{
$info{'monitor'} .= extract_string($bytes, $offset);
}
elsif ($bytes->[$offset+3] == 0xfd)
{
$info{'limits'}{'vsync_min'} = $bytes->[$offset+5];
$info{'limits'}{'vsync_max'} = $bytes->[$offset+6];
$info{'limits'}{'hsync_min'} = $bytes->[$offset+7];
$info{'limits'}{'hsync_max'} = $bytes->[$offset+8];
$info{'limits'}{'clock_max'} = $bytes->[$offset+9];
}
elsif ($bytes->[$offset+3] == 0xfe)
{
$info{'ascii'} .= extract_string($bytes, $offset);
}
elsif ($bytes->[$offset+3] == 0xff)
{
$info{'serial'} .= extract_string($bytes, $offset);
}
next;
}
# Detailed Timing
my $width = $bytes->[$offset+2] + (($bytes->[$offset+4] & 0xf0) << 4);
my $height = $bytes->[$offset+5] + (($bytes->[$offset+7] & 0xf0) << 4);
my $clock = extract_word($bytes, $offset) * 10000;
my $hblank = $bytes->[$offset+3] + (($bytes->[$offset+4] & 0x0f) << 8);
my $vblank = $bytes->[$offset+6] + (($bytes->[$offset+7] & 0x0f) << 8);
my $area = ($width + $hblank) * ($height + $vblank);
next unless $area; # Should not happen, but...
my $refresh = ($clock + $area / 2) / $area; # Proper rounding
add_timing($info{'timings'}, [$width, $height, $refresh]);
}
return \%info;
}
sub print_edid
{
my ($bus, $address) = @_;
my $bytes;
if (-r "/sys/bus/i2c/devices/$bus-00$address/eeprom")
{
$bytes = get_edid_sysfs($bus, $address);
}
elsif (-r "/proc/sys/dev/sensors/eeprom-i2c-$bus-$address/00")
{
$bytes = get_edid_procfs($bus, $address);
}
return 1 unless defined $bytes;
return 2 unless good_signature($bytes);
print_line('Checksum', '%s', verify_checksum($bytes));
my $edid_version = extract_byte($bytes, 0x12);
my $edid_revision = extract_byte($bytes, 0x13);
print_line('EDID Version', '%u.%u', $edid_version,
$edid_revision);
if ($edid_version > 1 || $edid_revision > 2)
{
$standard_scales[0][0] = 16;
$standard_scales[0][1] = 10;
}
else
{
$standard_scales[0][0] = 1;
$standard_scales[0][1] = 1;
}
my $info = extract_detailed_timings($bytes);
print_line('Manufacturer ID', '%s', extract_manufacturer($bytes, 0x08));
print_line('Model Number', '0x%04X', extract_word($bytes, 0x0A));
print_line('Model Name', '%s', $info->{'monitor'})
if defined $info->{'monitor'};
if ($info->{'serial'})
{
print_line('Serial Number', '%s', $info->{'serial'})
}
elsif ((my $temp = extract_dword($bytes, 0x0C)))
{
print_line('Serial Number', '%u', $temp)
}
print_line('Manufacture Time', '%u-W%02u',
1990 + extract_byte($bytes, 0x11),
extract_byte($bytes, 0x10));
print_line('Display Input', '%s', extract_display_input($bytes, 0x14));
print_line('Monitor Size (cm)', '%ux%u', extract_byte($bytes, 0x15),
extract_byte($bytes, 0x16));
print_line('Gamma Factor', '%.2f',
1 + extract_byte($bytes, 0x17) / 100.0);
print_line('DPMS Modes', '%s', extract_dpms($bytes, 0x18));
print_line('Color Mode', '%s', extract_color_mode($bytes, 0x18))
if (($bytes->[0x18] & 0x18) != 0x18);
print_line('Additional Info', '%s', $info->{'ascii'})
if $info->{'ascii'};
if (defined($info->{'limits'}))
{
print_line('Vertical Sync (Hz)', '%u-%u',
$info->{'limits'}{'vsync_min'},
$info->{'limits'}{'vsync_max'});
print_line('Horizontal Sync (kHz)', '%u-%u',
$info->{'limits'}{'hsync_min'},
$info->{'limits'}{'hsync_max'});
print_line('Max Pixel Clock (MHz)', '%u',
$info->{'limits'}{'clock_max'} * 10)
unless $info->{'limits'}{'clock_max'} == 0xff;
}
print_timings($bytes, $info->{'timings'});
print("\n");
return 0;
}
# Get the address. Default to 0x50 if not given.
my $address;
if (defined($ARGV[1]))
{
$address = $ARGV[1];
# Convert to decimal, whatever the value.
$address = oct $address if $address =~ m/^0/;
# Convert to an hexadecimal string.
$address = sprintf '%02x', $address;
}
else
{
$address = '50';
}
if (defined($ARGV[0]))
{
my $error = print_edid($ARGV[0], $address);
if ($error == 1)
{
print STDERR
"No EEPROM found at 0x$address on bus $ARGV[0].\n";
exit 1;
}
elsif ($error == 2)
{
print STDERR
"EEPROM found at 0x$address on bus $ARGV[0], but is not an EDID EEPROM.\n";
exit 1;
}
}
# If no bus is given, try them all.
else
{
my $total = 0;
for (my $i = 0; $i < 16; $i++)
{
$total++ unless print_edid($i, $address);
}
unless ($total)
{
print STDERR
"No EDID EEPROM found.\n";
exit 1;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,225 @@
#!/usr/bin/perl -w
#
# Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
# Version 0.1 2003-07-17 Jean Delvare <khali@linux-fr.org>
# Version 0.2 2003-07-22 Jean Delvare <khali@linux-fr.org>
# Use print instead of syswrite.
# Version 0.3 2003-08-24 Jean Delvare <khali@linux-fr.org>
# Fix data block length (128 bytes instead of 256).
# Version 1.0 2004-02-08 Jean Delvare <khali@linux-fr.org>
# Added support for Linux 2.5/2.6 (i.e. sysfs).
# Version 1.1 2006-09-01 Jean Delvare <khali@linux-fr.org>
# Append /usr/sbin or /usr/local/sbin to $PATH if needed.
#
# EEPROM data decoding for EDID. EDID (Extended Display Identification
# Data) is a VESA standard which allows storing (on manufacturer's side)
# and retrieving (on user's side) of configuration information about
# displays, such as manufacturer, serial number, physical dimensions and
# allowed horizontal and vertical refresh rates.
#
# Using the eeprom kernel driver, you have two possibilities to
# make use of these data:
# 1* The ddcmon script.
# 2* This script.
# Both solutions will return a different kind of information. The first
# method will report user-interesting information, such as the model number
# or the year of manufacturing. The second method will report video-card-
# interesting information, such as video modes and refresh rates.
#
# Note that this script does almost nothing by itself. It simply converts
# what it finds in /proc to binary data to feed the parse-edid program.
# The parse-edid program was written by John Fremlin and is available at
# the following address:
# http://john.fremlin.de/programs/linux/read-edid/
use strict;
use Fcntl qw(:DEFAULT :seek);
use vars qw($bus $address);
use constant PROCFS => 1;
use constant SYSFS => 2;
# parse-edid will typically be installed in /usr/sbin or /usr/local/sbin
# even though regular users can run it
$ENV{PATH} .= ':/usr/local/sbin'
if $ENV{PATH} !~ m,(^|:)/usr/local/sbin/?(:|$),
&& -x '/usr/local/sbin/parse-edid';
$ENV{PATH} .= ':/usr/sbin'
if $ENV{PATH} !~ m,(^|:)/usr/sbin/?(:|$),
&& -x '/usr/sbin/parse-edid';
sub edid_valid_procfs
{
my ($bus, $addr) = @_;
open EEDATA, "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/00";
my $line = <EEDATA>;
close EEDATA;
return 1
if $line =~ m/^0 255 255 255 255 255 255 0 /;
return 0;
}
# Only used for sysfs
sub rawread
{
my ($filename, $length, $offset) = @_;
my $bytes = '';
sysopen(FH, $filename, O_RDONLY)
or die "Can't open $filename";
if ($offset)
{
sysseek(FH, $offset, SEEK_SET)
or die "Can't seek in $filename";
}
$offset = 0;
while ($length)
{
my $r = sysread(FH, $bytes, $length, $offset);
die "Can't read $filename"
unless defined($r);
die "Unexpected EOF in $filename"
unless $r;
$offset += $r;
$length -= $r;
}
close(FH);
return $bytes;
}
sub edid_valid_sysfs
{
my ($bus, $addr) = @_;
my $bytes = rawread("/sys/bus/i2c/devices/$bus-00$addr/eeprom", 8, 0);
return 1
if $bytes eq "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00";
return 0;
}
sub bus_detect
{
my $max = shift;
for (my $i=0; $i<$max; $i++)
{
if (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-50/00")
{
if (edid_valid_procfs($i, '50'))
{
print STDERR
"decode-edid: using bus $i (autodetected)\n";
return $i;
}
}
elsif (-r "/sys/bus/i2c/devices/$i-0050/eeprom")
{
if (edid_valid_sysfs($i, '50'))
{
print STDERR
"decode-edid: using bus $i (autodetected)\n";
return $i;
}
}
}
return; # default
}
sub edid_decode
{
my ($bus, $addr, $mode) = @_;
# Make sure it is an EDID EEPROM.
unless (($mode == PROCFS && edid_valid_procfs ($bus, $addr))
|| ($mode == SYSFS && edid_valid_sysfs ($bus, $addr)))
{
print STDERR
"decode-edid: not an EDID EEPROM at $bus-$addr\n";
return;
}
$SIG{__WARN__} = sub { };
open PIPE, "| parse-edid"
or die "Can't open parse-edid. Please install read-edid.\n";
delete $SIG{__WARN__};
binmode PIPE;
if ($mode == PROCFS)
{
for (my $i=0; $i<=0x70; $i+=0x10)
{
my $file = sprintf '%02x', $i;
my $output = '';
open EEDATA, "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/$file"
or die "Can't read /proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/$file";
while(<EEDATA>)
{
foreach my $item (split)
{
$output .= pack "C", $item;
}
}
close EEDATA;
print PIPE $output;
}
}
elsif ($mode == SYSFS)
{
print PIPE rawread("/sys/bus/i2c/devices/$bus-00$address/eeprom", 128, 0);
}
close PIPE;
}
# Get the address. Default to 0x50 if not given.
$address = $ARGV[1] || 0x50;
# Convert to decimal, whatever the value.
$address = oct $address if $address =~ m/^0/;
# Convert to an hexadecimal string.
$address = sprintf '%02x', $address;
# Get the bus. Try to autodetect if not given.
$bus = $ARGV[0] if defined $ARGV[0];
$bus = bus_detect(8) unless defined $bus;
if(defined $bus)
{
print STDERR
"decode-edid: decode-edid version 1.1\n";
if (-r "/proc/sys/dev/sensors/eeprom-i2c-$bus-$address")
{
edid_decode ($bus, $address, PROCFS);
exit 0;
}
elsif (-r "/sys/bus/i2c/devices/$bus-00$address")
{
edid_decode ($bus, $address, SYSFS);
exit 0;
}
}
print STDERR
"EDID EEPROM not found. Please make sure that the eeprom module is loaded.\n";
print STDERR
"Maybe your EDID EEPROM is on another bus. Try \"decode-edid ".($bus+1)."\".\n"
if defined $bus;

View file

@ -0,0 +1,237 @@
#!/usr/bin/perl -w
#
# Copyright (C) 2002-2008 Jean Delvare <khali@linux-fr.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
# EEPROM data decoding for Sony Vaio laptops.
#
# The eeprom driver must be loaded. For kernels older than 2.6.0, the
# eeprom driver can be found in the lm-sensors package.
#
# Please note that this is a guess-only work. Sony support refused to help
# me, so if someone can provide information, please contact me.
# My knowledge is summarized on this page:
# http://khali.linux-fr.org/vaio/eeprom.html
#
# It seems that if present, the EEPROM is always at 0x57.
#
# Models tested so far:
# PCG-F403 : No EEPROM
# PCG-F707 : No EEPROM
# PCG-GR114EK : OK
# PCG-GR114SK : OK
# PCG-GR214EP : OK
# PCG-GRT955MP : OK
# PCG-GRX316G : OK
# PCG-GRX570 : OK
# PCG-GRX600K : OK
# PCG-U1 : OK
# PCG-Z600LEK : No EEPROM
# PCG-Z600NE : No EEPROM
# VGN-S260 : OK
# VGN-S4M/S : OK
# VGN-TZ11MN/N : OK
#
# Thanks to Werner Heuser, Carsten Blume, Christian Gennerat, Joe Wreschnig,
# Xavier Roche, Sebastien Lefevre, Lars Heer, Steve Dobson, Kent Hunt,
# Timo Hoenig and others for their precious help.
use strict;
use Fcntl qw(:DEFAULT :seek);
use vars qw($sysfs $found);
use constant VERSION => "1.6";
use constant ONLYROOT => "Readable only by root";
sub print_item
{
my ($label,$value) = @_;
printf("\%16s : \%s\n",$label,$value);
}
# Abstract reads so that other functions don't have to care wether
# we need to use procfs or sysfs
sub read_eeprom_bytes
{
my ($bus, $addr, $offset, $length) = @_;
my $filename;
if ($sysfs)
{
$filename = "/sys/bus/i2c/devices/$bus-00$addr/eeprom";
sysopen(FH, $filename, O_RDONLY)
or die "Can't open $filename";
sysseek(FH, $offset, SEEK_SET)
or die "Can't seek in $filename";
my ($r, $bytes);
$bytes = '';
$offset = 0;
while($length)
{
$r = sysread(FH, $bytes, $length, $offset);
die "Can't read $filename"
unless defined($r);
die "Unexpected EOF in $filename"
unless $r;
$offset += $r;
$length -= $r;
}
close(FH);
return $bytes;
}
else
{
my $base = $offset & 0xf0;
$offset -= $base;
my $values = '';
my $remains = $length + $offset;
# Get all lines in a single string
while ($remains > 0)
{
$filename = "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/"
. sprintf('%02x', $base);
open(FH, $filename)
or die "Can't open $filename";
$values .= <FH>;
close(FH);
$remains -= 16;
$base += 16;
}
# Store the useful part in an array
my @bytes = split(/[ \n]/, $values);
@bytes = @bytes[$offset..$offset+$length-1];
# Back to a binary string
return pack('C*', @bytes);
}
}
sub decode_string
{
my ($bus, $addr, $offset, $length) = @_;
my $string = read_eeprom_bytes($bus, $addr, $offset, $length);
$string =~ s/\x00.*$//;
return($string);
}
sub decode_hexa
{
my ($bus, $addr, $offset, $length) = @_;
my @bytes = unpack('C*', read_eeprom_bytes($bus, $addr, $offset, $length));
my $string='';
for(my $i=0;$i<$length;$i++)
{
$string.=sprintf('%02X', shift(@bytes));
}
return($string);
}
sub decode_uuid
{
my ($bus,$addr,$base) = @_;
my @bytes = unpack('C16', read_eeprom_bytes($bus, $addr, $base, 16));
my $string='';
for(my $i=0;$i<16;$i++)
{
$string.=sprintf('%02x',shift(@bytes));
if(($i==3)||($i==5)||($i==7)||($i==9))
{
$string.='-';
}
}
if ($string eq '00000000-0000-0000-0000-000000000000')
{
return(ONLYROOT);
}
else
{
return($string);
}
}
sub vaio_decode
{
my ($bus,$addr) = @_;
my $name = decode_string($bus, $addr, 128, 32);
# Simple heuristic to skip false positives
return 0 unless $name =~ m/^[A-Z-]{4}/;
print_item('Machine Name', $name);
my $serial = decode_string($bus, $addr, 192, 32);
print_item('Serial Number', $serial ? $serial : ONLYROOT);
print_item('UUID', decode_uuid($bus, $addr, 16));
my $revision = decode_string($bus, $addr, 160, 10);
print_item(length($revision) > 2 ? 'Service Tag' : 'Revision',
$revision);
print_item('Asset Tag', decode_string($bus, $addr, 170, 4).
decode_hexa($bus, $addr, 174, 12));
print_item('OEM Data', decode_string($bus, $addr, 32, 16));
print_item('Timestamp', decode_string($bus, $addr, 224, 18));
return 1;
}
BEGIN
{
print("# Sony Vaio EEPROM Decoder version ".VERSION." by Jean Delvare\n\n");
}
END
{
print("\n");
}
for (my $i = 0, $found=0; $i <= 4 && !$found; $i++)
{
if (-r "/sys/bus/i2c/devices/$i-0057/eeprom")
{
$sysfs = 1;
$found += vaio_decode($i, '57');
}
elsif (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57")
{
if (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57/data0-15")
{
print("Deprecated old interface found. Please upgrade to lm_sensors 2.6.3 or greater.");
exit;
}
else
{
$sysfs = 0;
$found += vaio_decode($i, '57');
}
}
}
if (!$found)
{
print("Vaio EEPROM not found. Please make sure that the eeprom module is loaded.\n");
}

View file

@ -0,0 +1,182 @@
/***************************************************************************
copyright : (C) by 2002-2003 Stefano Barbato
email : stefano@codesink.org
$Id: 24cXX.c 4230 2006-11-10 09:22:12Z khali $
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include "24cXX.h"
static int i2c_write_1b(struct eeprom *e, __u8 buf)
{
int r;
// we must simulate a plain I2C byte write with SMBus functions
r = i2c_smbus_write_byte(e->fd, buf);
if(r < 0)
fprintf(stderr, "Error i2c_write_1b: %s\n", strerror(errno));
usleep(10);
return r;
}
static int i2c_write_2b(struct eeprom *e, __u8 buf[2])
{
int r;
// we must simulate a plain I2C byte write with SMBus functions
r = i2c_smbus_write_byte_data(e->fd, buf[0], buf[1]);
if(r < 0)
fprintf(stderr, "Error i2c_write_2b: %s\n", strerror(errno));
usleep(10);
return r;
}
static int i2c_write_3b(struct eeprom *e, __u8 buf[3])
{
int r;
// we must simulate a plain I2C byte write with SMBus functions
// the __u16 data field will be byte swapped by the SMBus protocol
r = i2c_smbus_write_word_data(e->fd, buf[0], buf[2] << 8 | buf[1]);
if(r < 0)
fprintf(stderr, "Error i2c_write_3b: %s\n", strerror(errno));
usleep(10);
return r;
}
#define CHECK_I2C_FUNC( var, label ) \
do { if(0 == (var & label)) { \
fprintf(stderr, "\nError: " \
#label " function is required. Program halted.\n\n"); \
exit(1); } \
} while(0);
int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom* e)
{
int fd, r;
unsigned long funcs;
e->fd = e->addr = 0;
e->dev = 0;
fd = open(dev_fqn, O_RDWR);
if(fd <= 0)
return -1;
// get funcs list
if((r = ioctl(fd, I2C_FUNCS, &funcs) < 0))
return r;
// check for req funcs
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE_DATA );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE_DATA );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_WORD_DATA );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_WORD_DATA );
// set working device
if( ( r = ioctl(fd, I2C_SLAVE, addr)) < 0)
return r;
e->fd = fd;
e->addr = addr;
e->dev = dev_fqn;
e->type = type;
return 0;
}
int eeprom_close(struct eeprom *e)
{
close(e->fd);
e->fd = -1;
e->dev = 0;
e->type = EEPROM_TYPE_UNKNOWN;
return 0;
}
#if 0
int eeprom_24c32_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
{
__u8 buf[3] = { (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
return i2c_write_3b(e, buf);
}
int eeprom_24c32_read_current_byte(struct eeprom* e)
{
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
return i2c_smbus_read_byte(e->fd);
}
int eeprom_24c32_read_byte(struct eeprom* e, __u16 mem_addr)
{
int r;
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
r = i2c_write_2b(e, buf);
if (r < 0)
return r;
r = i2c_smbus_read_byte(e->fd);
return r;
}
#endif
int eeprom_read_current_byte(struct eeprom* e)
{
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
return i2c_smbus_read_byte(e->fd);
}
int eeprom_read_byte(struct eeprom* e, __u16 mem_addr)
{
int r;
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
if(e->type == EEPROM_TYPE_8BIT_ADDR)
{
__u8 buf = mem_addr & 0x0ff;
r = i2c_write_1b(e, buf);
} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
r = i2c_write_2b(e, buf);
} else {
fprintf(stderr, "ERR: unknown eeprom type\n");
return -1;
}
if (r < 0)
return r;
r = i2c_smbus_read_byte(e->fd);
return r;
}
int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
{
if(e->type == EEPROM_TYPE_8BIT_ADDR) {
__u8 buf[2] = { mem_addr & 0x00ff, data };
return i2c_write_2b(e, buf);
} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
__u8 buf[3] =
{ (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
return i2c_write_3b(e, buf);
} else {
fprintf(stderr, "ERR: unknown eeprom type\n");
return -1;
}
}

View file

@ -0,0 +1,58 @@
/***************************************************************************
copyright : (C) by 2002-2003 Stefano Barbato
email : stefano@codesink.org
$Id: 24cXX.h 4495 2007-06-27 12:57:50Z khali $
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef _24CXX_H_
#define _24CXX_H_
#include <linux/i2c-dev.h>
#define EEPROM_TYPE_UNKNOWN 0
#define EEPROM_TYPE_8BIT_ADDR 1
#define EEPROM_TYPE_16BIT_ADDR 2
struct eeprom
{
char *dev; // device file i.e. /dev/i2c-N
int addr; // i2c address
int fd; // file descriptor
int type; // eeprom type
};
/*
* opens the eeprom device at [dev_fqn] (i.e. /dev/i2c-N) whose address is
* [addr] and set the eeprom_24c32 [e]
*/
int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom*);
/*
* closees the eeprom device [e]
*/
int eeprom_close(struct eeprom *e);
/*
* read and returns the eeprom byte at memory address [mem_addr]
* Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address)
*/
int eeprom_read_byte(struct eeprom* e, __u16 mem_addr);
/*
* read the current byte
* Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address)
*/
int eeprom_read_current_byte(struct eeprom *e);
/*
* writes [data] at memory address [mem_addr]
* Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address)
*/
int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data);
#endif

View file

@ -0,0 +1,14 @@
#eepromer Makefile
CFLAGS = -O2 -I../include -Wall
all: eepromer eeprom eeprog
eepromer: eepromer.o
eeprom: eeprom.o
eeprog: eeprog.o 24cXX.o
clean:
rm -rf *~ *.o eepromer eeprom eeprog

View file

@ -0,0 +1,31 @@
These programs are used to read and write eeproms.
Use eeprom for small eeproms with one-byte addresses:
24C01, 24C01A, 24C02, 24C04, 24C08, and 24C16
It works only on true i2c bus adapters.
See README.eeprom for details.
Use eepromer for large eeproms with two-byte addresses:
24C32, 24C64, 24C128, 24C256, and 24C512
It works only on true i2c bus adapters.
See README.eepromer for details.
Use eeprog for either small or large eeproms.
Use the -16 switch for large eeproms.
It works on both i2c and smbus bus adapters.
See README.eeprog for details.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! !
!!! These programs should only be used on external busses such as i2c-pport !
!!! unless you REALLY know what you are doing. !
!!! !
!!! Your computer probably contains eeproms for saving data vital to its !
!!! operation. If you are not careful you might overwrite this data with !
!!! this program and your computer may no longer boot! !
!!! !
!!! An example are the EEPROMS on your SDRAM DIMMs, your computer may no !
!!! longer detect the RAM module rendering it essentially USELESS! !
!!! !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

View file

@ -0,0 +1,12 @@
Important! See the README file for important warnings.
eeprog reads and writes 24Cxx EEPROMs connected to I2C serial bus.
It uses the SMBus protocol used by most of the recent chipsets. Don't forget to load
your i2c chipset and the i2c-dev drivers.
Use -16 switch for EEPROM larger then 24C16 (16 bit addressing mode).
Again, it's really important that you read the README file.
Type "make" to compile.

View file

@ -0,0 +1,85 @@
You can use this program to read/write to i2c-eeproms
like the popular 24C16, 24C08, 24C04,.. In contrast to eeprommer
which supports 24C256-type eeproms 24C16ss use 1-byte addresses!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! !
!!! This program should only be used on external busses such as i2c-pport. !
!!! !
!!! Your computer may contain i2c-eeproms for saving data vital to its !
!!! operation. If you are not careful you might overwrite this data with !
!!! this program and your computer may no longer boot! !
!!! !
!!! An example are the EEPROMS on your SDRAM DIMMs, your computer may no !
!!! longer detect the RAM module rendering it essentially USELESS! !
!!! !
!!! IBM Thinkpads are said to store their configuration data in a eeprom, !
!!! if you manage to overwrite this eeprom you will have to send your !
!!! computer to the manufacturer for a costly repair! !
!!! !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
It has several options:
-d devicenode
set this to the device-node of the i2c-bus
you want to use like /dev/i2c-0.
Use /dev/i2c-1 for the second bus, i2c-2 for the third...
The default /dev/i2c-0 should work most of the time.
-a address
set this to the device-address of your
eeprom. For a 24C16 the address is hardcoded to
0x50, which is -you guessed it- the default.
For a 24C08 and smaller types you can choose which
addresses they occupy by forcing the address-pins
of the chip to High or Low so here the address may differ.
-p number_of_pages
set this to the number of pages you want to read
from or write to the eeprom. The 24C16 maps it's
pages to consecutive addresses on the i2c-bus so
we will try to read 256 bytes from every i2c
address between 'address' (inclusive) and
'address + number_of_pages' (exclusive)...
A 24C16 has 8 pages so that's the default for this
parameter.
-f filename
read data from this file (when writing to eeprom) or
write data to this file (when reading from eeprom).
When reading a file that's smaller than the
eeprom's storage size we will pad the eeprom
with zeroes.
If no file is given we will just read the
eeprom (while in read-mode) and test it's presence
this way. In write-mode we will just write zeroes
to the eeprom.
-w When '-w' is present we will *write* to the eeprom.
If you do not specify '-w' we will read the contents
of the eeprom.
-y This flag will suppress the warning when you write to the
eeprom. You will not be required to enter 'yes' so be careful
when using this switch!
I wrote that program to clear a 24C16 eeprom that sit's in my crappy
satellite receiver because sometimes its Z80 processor likes to
write garbage to it and then crash....
No further testing besides writing a long series of "The quick brown
fox jumps over the lazy dog!" and reading it back has been done so
of course this comes without any warranty.
Chris <chris@hedonism.cx>

View file

@ -0,0 +1,27 @@
Simple program for storing data to I2C EEPROM.
!!!!!!!!!!!!!!!!!!!!!!!!Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
The EEPROM must be a large EEPROM which uses a 2-byte address
field (24C32 or larger). It will NOT WORK on small EEPROMs
(24C01 - 24C16) such as those used on SDRAM DIMMs.
Tested only on 24C256.
!!!!!!!!!!!!!!!!!!!!!!!!Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
This program is intended for use on eeproms using external busses such as
i2c-pport.
Do not use this on your SDRAM DIMM EEPROMS, it won't work!!!!!!!!!
Doing so will render your SDRAM USELESS and leave your system UNBOOTABLE!!!
!!!!!!!!!!!!!!!!!!!!!!!!Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Options:
-r read
-w write
-e erase
-p print "super block of EEPROM" (date and size stored data)
Daniel Smolik
marvin@sitour.cz

View file

@ -0,0 +1,283 @@
/***************************************************************************
copyright : (C) by 2002-2003 Stefano Barbato
email : stefano@codesink.org
$Id: eeprog.c 5122 2008-02-18 09:22:21Z khali $
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <getopt.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "24cXX.h"
#define VERSION "0.7.5"
#define ENV_DEV "EEPROG_DEV"
#define ENV_I2C_ADDR "EEPROG_I2C_ADDR"
int g_quiet;
#define usage_if(a) do { do_usage_if( a , __LINE__); } while(0);
void do_usage_if(int b, int line)
{
static const char *eeprog_usage =
"eeprog " VERSION ", a 24Cxx EEPROM reader/writer\n"
"Copyright (c) 2003 by Stefano Barbato - All rights reserved.\n"
"Usage: eeprog [-fqxdh] [-16|-8] [ -r addr[:count] | -w addr ] /dev/i2c-N i2c-address\n"
"\n"
" Address modes:\n"
" -8 Use 8bit address mode for 24c0x...24C16 [default]\n"
" -16 Use 16bit address mode for 24c32...24C256\n"
" Actions:\n"
" -r addr[:count] Read [count] (1 if omitted) bytes from [addr]\n"
" and print them to the standard output\n"
" -w addr Write input (stdin) at address [addr] of the EEPROM\n"
" -h Print this help\n"
" Options:\n"
" -x Set hex output mode\n"
" -d Dummy mode, display what *would* have been done\n"
" -f Disable warnings and don't ask confirmation\n"
" -q Quiet mode\n"
"\n"
"The following environment variables could be set instead of the command\n"
"line arguments:\n"
" EEPROG_DEV device name(/dev/i2c-N)\n"
" EEPROG_I2C_ADDR i2c-address\n"
"\n"
" Examples\n"
" 1- read 64 bytes from the EEPROM at address 0x54 on bus 0 starting\n"
" at address 123 (decimal)\n"
" eeprog /dev/i2c-0 0x54 -r 123:64\n"
" 2- prints the hex codes of the first 32 bytes read from bus 1\n"
" at address 0x22\n"
" eeprog /dev/i2c-1 0x51 -x -r 0x22:0x20\n"
" 3- write the current timestamp at address 0x200 of the EEPROM on\n"
" bus 0 at address 0x33\n"
" date | eeprog /dev/i2c-0 0x33 -w 0x200\n";
if(!b)
return;
fprintf(stderr, "%s\n[line %d]\n", eeprog_usage, line);
exit(1);
}
#define die_if(a, msg) do { do_die_if( a , msg, __LINE__); } while(0);
void do_die_if(int b, char* msg, int line)
{
if(!b)
return;
fprintf(stderr, "Error at line %d: %s\n", line, msg);
//fprintf(stderr, " sysmsg: %s\n", strerror(errno));
exit(1);
}
#define print_info(args...) do { if(!g_quiet) fprintf(stderr, args); } while(0);
void parse_arg(char *arg, int* paddr, int *psize)
{
char *end;
*paddr = strtoul(arg, &end, 0);
if(*end == ':')
*psize = strtoul(++end, 0, 0);
}
int confirm_action()
{
fprintf(stderr,
"\n"
"____________________________WARNING____________________________\n"
"Erroneously writing to a system EEPROM (like DIMM SPD modules)\n"
"can break your system. It will NOT boot anymore so you'll not\n"
"be able to fix it.\n"
"\n"
"Reading from 8bit EEPROMs (like that in your DIMM) without using\n"
"the -8 switch can also UNEXPECTEDLY write to them, so be sure to\n"
"use the -8 command param when required.\n"
"\n"
"Use -f to disable this warning message\n"
"\n"
"Press ENTER to continue or hit CTRL-C to exit\n"
"\n"
);
getchar();
return 1;
}
int read_from_eeprom(struct eeprom *e, int addr, int size, int hex)
{
int ch, i;
// hex print out
die_if((ch = eeprom_read_byte(e, addr)) < 0, "read error");
i = 1;
if(hex)
printf("\n %.4x| %.2x ", addr, ch);
else
putchar(ch);
while(--size)
{
die_if((ch = eeprom_read_current_byte(e)) < 0, "read error");
if(hex)
{
addr++;
if( (i % 16) == 0 )
printf("\n %.4x| ", addr);
else if( (i % 8) == 0 )
printf(" ");
i++;
printf("%.2x ", ch);
} else {
putchar(ch);
}
}
if(hex)
printf("\n\n");
fflush(stdout);
return 0;
}
int write_to_eeprom(struct eeprom *e, int addr)
{
int c;
while((c = getchar()) != EOF)
{
print_info(".");
fflush(stdout);
die_if(eeprom_write_byte(e, addr++, c), "write error");
}
print_info("\n\n");
return 0;
}
int main(int argc, char** argv)
{
struct eeprom e;
int ret, op, i2c_addr, memaddr, size, want_hex, dummy, force, sixteen;
char *device, *arg = 0, *i2c_addr_s;
struct stat st;
int eeprom_type = 0;
op = want_hex = dummy = force = sixteen = 0;
g_quiet = 0;
while((ret = getopt(argc, argv, "1:8fr:qhw:xd")) != -1)
{
switch(ret)
{
case '1':
usage_if(*optarg != '6' || strlen(optarg) != 1);
die_if(eeprom_type, "EEPROM type switch (-8 or -16) used twice");
eeprom_type = EEPROM_TYPE_16BIT_ADDR;
break;
case 'x':
want_hex++;
break;
case 'd':
dummy++;
break;
case '8':
die_if(eeprom_type, "EEPROM type switch (-8 or -16) used twice");
eeprom_type = EEPROM_TYPE_8BIT_ADDR;
break;
case 'f':
force++;
break;
case 'q':
g_quiet++;
break;
case 'h':
usage_if(1);
break;
default:
die_if(op != 0, "Both read and write requested");
arg = optarg;
op = ret;
}
}
if(!eeprom_type)
eeprom_type = EEPROM_TYPE_8BIT_ADDR; // default
usage_if(op == 0); // no switches
// set device and i2c_addr reading from cmdline or env
device = i2c_addr_s = 0;
switch(argc - optind)
{
case 0:
device = getenv(ENV_DEV);
i2c_addr_s = getenv(ENV_I2C_ADDR);
break;
case 1:
if(stat(argv[optind], &st) != -1)
{
device = argv[optind];
i2c_addr_s = getenv(ENV_I2C_ADDR);
} else {
device = getenv(ENV_DEV);
i2c_addr_s = argv[optind];
}
break;
case 2:
device = argv[optind++];
i2c_addr_s = argv[optind];
break;
default:
usage_if(1);
}
usage_if(!device || !i2c_addr_s);
i2c_addr = strtoul(i2c_addr_s, 0, 0);
print_info("eeprog %s, a 24Cxx EEPROM reader/writer\n", VERSION);
print_info("Copyright (c) 2003 by Stefano Barbato - All rights reserved.\n");
print_info(" Bus: %s, Address: 0x%x, Mode: %dbit\n",
device, i2c_addr,
(eeprom_type == EEPROM_TYPE_8BIT_ADDR ? 8 : 16) );
if(dummy)
{
fprintf(stderr, "Dummy mode selected, nothing done.\n");
return 0;
}
die_if(eeprom_open(device, i2c_addr, eeprom_type, &e) < 0,
"unable to open eeprom device file (check that the file exists and that it's readable)");
switch(op)
{
case 'r':
if(force == 0)
confirm_action();
size = 1; // default
parse_arg(arg, &memaddr, &size);
print_info(" Reading %d bytes from 0x%x\n", size, memaddr);
read_from_eeprom(&e, memaddr, size, want_hex);
break;
case 'w':
if(force == 0)
confirm_action();
parse_arg(arg, &memaddr, &size);
print_info(" Writing stdin starting at address 0x%x\n",
memaddr);
write_to_eeprom(&e, memaddr);
break;
default:
usage_if(1);
exit(1);
}
eeprom_close(&e);
return 0;
}

View file

@ -0,0 +1,297 @@
/*
This program is hereby placed into the public domain.
Of course the program is provided without warranty of any kind.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <linux/i2c-dev.h>
/*
this program can read 24C16 (and probably smaller ones, too)
I wrote it as a quick and dirty hack because my satellite receiver
hung again... so I had to reprogram the eeprom where is stores it's
settings.
*/
#define DEFAULT_I2C_BUS "/dev/i2c-0"
#define DEFAULT_EEPROM_ADDR 0x50 /* the 24C16 sits on i2c address 0x50 */
#define DEFAULT_NUM_PAGES 8 /* we default to a 24C16 eeprom which has 8 pages */
#define BYTES_PER_PAGE 256 /* one eeprom page is 256 byte */
#define MAX_BYTES 8 /* max number of bytes to write in one chunk */
/* ... note: 24C02 and 24C01 only allow 8 bytes to be written in one chunk. *
* if you are going to write 24C04,8,16 you can change this to 16 */
/* write len bytes (stored in buf) to eeprom at address addr, page-offset offset */
/* if len=0 (buf may be NULL in this case) you can reposition the eeprom's read-pointer */
/* return 0 on success, -1 on failure */
int eeprom_write(int fd,
unsigned int addr,
unsigned int offset,
unsigned char *buf,
unsigned char len
){
struct i2c_rdwr_ioctl_data msg_rdwr;
struct i2c_msg i2cmsg;
int i;
char _buf[MAX_BYTES + 1];
if(len>MAX_BYTES){
fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n");
return -1;
}
if(len+offset >256){
fprintf(stderr,"Sorry, len(%d)+offset(%d) > 256 (page boundary)\n",
len,offset);
return -1;
}
_buf[0]=offset; /* _buf[0] is the offset into the eeprom page! */
for(i=0;i<len;i++) /* copy buf[0..n] -> _buf[1..n+1] */
_buf[1+i]=buf[i];
msg_rdwr.msgs = &i2cmsg;
msg_rdwr.nmsgs = 1;
i2cmsg.addr = addr;
i2cmsg.flags = 0;
i2cmsg.len = 1+len;
i2cmsg.buf = _buf;
if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){
perror("ioctl()");
fprintf(stderr,"ioctl returned %d\n",i);
return -1;
}
if(len>0)
fprintf(stderr,"Wrote %d bytes to eeprom at 0x%02x, offset %08x\n",
len,addr,offset);
else
fprintf(stderr,"Positioned pointer in eeprom at 0x%02x to offset %08x\n",
addr,offset);
return 0;
}
/* read len bytes stored in eeprom at address addr, offset offset in array buf */
/* return -1 on error, 0 on success */
int eeprom_read(int fd,
unsigned int addr,
unsigned int offset,
unsigned char *buf,
unsigned char len
){
struct i2c_rdwr_ioctl_data msg_rdwr;
struct i2c_msg i2cmsg;
int i;
if(len>MAX_BYTES){
fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n");
return -1;
}
if(eeprom_write(fd,addr,offset,NULL,0)<0)
return -1;
msg_rdwr.msgs = &i2cmsg;
msg_rdwr.nmsgs = 1;
i2cmsg.addr = addr;
i2cmsg.flags = I2C_M_RD;
i2cmsg.len = len;
i2cmsg.buf = buf;
if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){
perror("ioctl()");
fprintf(stderr,"ioctl returned %d\n",i);
return -1;
}
fprintf(stderr,"Read %d bytes from eeprom at 0x%02x, offset %08x\n",
len,addr,offset);
return 0;
}
int main(int argc, char **argv){
int i,j;
/* filedescriptor and name of device */
int d;
char *dn=DEFAULT_I2C_BUS;
/* filedescriptor and name of data file */
int f=-1;
char *fn=NULL;
unsigned int addr=DEFAULT_EEPROM_ADDR;
int rwmode=0;
int pages=DEFAULT_NUM_PAGES;
int force=0; /* suppress warning on write! */
while((i=getopt(argc,argv,"d:a:p:wyf:h"))>=0){
switch(i){
case 'h':
fprintf(stderr,"%s [-d dev] [-a adr] [-p pgs] [-w] [-y] [-f file]\n",argv[0]);
fprintf(stderr,"\tdev: device, e.g. /dev/i2c-0 (def)\n");
fprintf(stderr,"\tadr: base address of eeprom, eg 0xA0 (def)\n");
fprintf(stderr,"\tpgs: number of pages to read, eg 8 (def)\n");
fprintf(stderr,"\t-w : write to eeprom (default is reading!)\n");
fprintf(stderr,"\t-y : suppress warning when writing (default is to warn!)\n");
fprintf(stderr,"\t-f file: copy eeprom contents to/from file\n");
fprintf(stderr,"\t (default for read is test only; for write is all zeros)\n");
fprintf(stderr,"Note on pages/addresses:\n");
fprintf(stderr,"\teeproms with more than 256 byte appear as if they\n");
fprintf(stderr,"\twere several eeproms with consecutive addresses on the bus\n");
fprintf(stderr,"\tso we might as well address several separate eeproms with\n");
fprintf(stderr,"\tincreasing addresses....\n\n");
exit(1);
break;
case 'd':
dn=optarg;
break;
case 'a':
if(sscanf(optarg,"0x%x",&addr)!=1){
fprintf(stderr,"Cannot parse '%s' as addrs., example: 0xa0\n",
optarg);
exit(1);
}
break;
case 'p':
if(sscanf(optarg,"%d",&pages)!=1){
fprintf(stderr,"Cannot parse '%s' as number of pages, example: 8\n",
optarg);
exit(1);
}
break;
case 'w':
rwmode++;
break;
case 'f':
fn=optarg;
break;
case 'y':
force++;
break;
}
}
fprintf(stderr,"base-address of eeproms : 0x%02x\n",addr);
fprintf(stderr,"number of pages to read : %d (0x%02x .. 0x%02x)\n",
pages,addr,addr+pages-1);
if(fn){
if(!rwmode) /* if we are reading, *WRITE* to file */
f=open(fn,O_WRONLY|O_CREAT,0666);
else /* if we are writing to eeprom, *READ* from file */
f=open(fn,O_RDONLY);
if(f<0){
fprintf(stderr,"Could not open data-file %s for reading or writing\n",fn);
perror(fn);
exit(1);
}
fprintf(stderr,"file opened for %7s : %s\n",rwmode?"reading":"writing",fn);
fprintf(stderr," on filedescriptor : %d\n",f);
}
if((d=open(dn,O_RDWR))<0){
fprintf(stderr,"Could not open i2c at %s\n",dn);
perror(dn);
exit(1);
}
fprintf(stderr,"i2c-devicenode is : %s\n",dn);
fprintf(stderr," on filedescriptor : %d\n\n",d);
/***
*** I'm not the one to blame of you screw your computer!
***/
if(rwmode && ! force){
unsigned char warnbuf[4];
fprintf(stderr,"**WARNING**\n");
fprintf(stderr," - \tYou have chosen to WRITE to this eeprom.\n");
fprintf(stderr,"\tMake sure that this tiny chip is *NOT* vital to the\n");
fprintf(stderr,"\toperation of your computer as you can easily corrupt\n");
fprintf(stderr,"\tthe configuration memory of your SDRAM-memory-module,\n");
fprintf(stderr,"\tyour IBM ThinkPad or whatnot...! Fixing these errors can be\n");
fprintf(stderr,"\ta time-consuming and very costly process!\n\n");
fprintf(stderr,"Things to consider:\n");
fprintf(stderr," - \tYou can have more than one i2c-bus, check in /proc/bus/i2c\n");
fprintf(stderr,"\tand specify the correct one with -d\n");
fprintf(stderr,"\tright now you have chosen to use '%s'\n",dn);
fprintf(stderr," - \tA eeprom can occupy several i2c-addresses (one per page)\n");
fprintf(stderr,"\tso please make sure that there is no vital eeprom in your computer\n");
fprintf(stderr,"\tsitting at addresses between 0x%02x and 0x%02x\n",addr,addr+pages-1);
fprintf(stderr,"Enter 'yes' to continue:");
fflush(stderr);
if(!fgets(warnbuf,sizeof(warnbuf),stdin)){
fprintf(stderr,"\nCould not read confirmation from stdin!\n");
exit(1);
}
if(strncmp(warnbuf,"yes",3)){
fprintf(stderr,"\n** ABORTING WRITE! **, you did not answer 'yes'\n");
exit(1);
}
}
for(i=0;i<pages;i++){
unsigned char buf[BYTES_PER_PAGE];
if(rwmode){
if(f>=0){
j=read(f,buf,sizeof(buf));
if(j<0){
fprintf(stderr,"Cannot read from file '%s'\n",fn);
perror(fn);
exit(1);
}
if(j!=sizeof(buf)){
fprintf(stderr,"File '%s' is too small, padding eeprom with zeroes\n",fn);
while(j<sizeof(buf))
buf[j++]=0;
}
} else {
for(j=0;j<sizeof(buf);j++)
buf[j]=0;
}
for(j=0;j<(BYTES_PER_PAGE/MAX_BYTES);j++)
if(eeprom_write(d,addr+i,j*MAX_BYTES,buf+(j*MAX_BYTES),MAX_BYTES)<0)
exit(1);
} else {
for(j=0;j<(BYTES_PER_PAGE/MAX_BYTES);j++)
if(eeprom_read(d,addr+i,j*MAX_BYTES,buf+(j*MAX_BYTES),MAX_BYTES)<0)
exit(1);
}
if(!rwmode && f>=0){
j=write(f,buf,sizeof(buf));
if(j!=sizeof(buf)){
fprintf(stderr,"Cannot write to file '%s'\n",fn);
perror(fn);
exit(1);
}
}
}
if(f>=0)
close(f);
close(d);
exit(0);
}

View file

@ -0,0 +1,721 @@
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <linux/i2c-dev.h>
#define MAX_BLK_SIZE 64
#define EEPROM_SIZE 32768
#define READ 1
#define WRITE 0
#define ERASE 2
#define PHEADER 3
#define VER "eepromer v 0.4 (c) Daniel Smolik 2001\n"
#define HEAD_SIZE sizeof(struct mini_inode)
#define START_ADDR 0
#define FORCE 1
/*
To disable startup warning #undef WARNINC
*/
#define WARNINC
int block_write(int file,int dev_addr,int eeprom_addr,unsigned char *buf,int lenght);int block_write(int file,int dev_addr,int eeprom_addr,unsigned char *buf,int lenght);
int block_read(int file,int dev_addr,int eeprom_addr,unsigned char *buf);
/* block_read read block 64 bytes length and returns actual length of data*/
void help(void);
int init(char *device,int addr);
int content_write(int file, int addr);
int content_read(int file, int addr);
int inode_write(int file, int dev_addr, int lenght);
int inode_read(int file, int dev_addr, void *p_inode);
void pheader(int file, int addr);
void erase(int file,int addr,int eeprom_size);
void made_address(int addr,unsigned char *buf);
void warn(void);
void bar(void);
static int stav=0;
static struct mini_inode {
time_t timestamp;
int data_len;
char data[56];
} m_ind,*p_ind;
void help(void)
{
FILE *fptr;
char s[100];
fprintf(stderr,"Syntax: eepromer [-r|-w|-e|-p] -f /dev/i2c-X ADDRESS \n\n");
fprintf(stderr," ADDRESS is address of i2c device eg. 0x51\n");
if((fptr = fopen("/proc/bus/i2c", "r"))) {
fprintf(stderr," Installed I2C busses:\n");
while(fgets(s, 100, fptr))
fprintf(stderr, " %s", s);
fclose(fptr);
}
}
int main(int argc, char *argv[]){
int i, file, addr;
int action; //in this variable will be (-r,-w,-e)
char device[45];
int force;
p_ind=&m_ind;
force=0;
for(i=1; i < argc;i++){
if(!strcmp("-r",argv[i])) {
action=READ;
break;
}
if(!strcmp("-e",argv[i])) {
action=ERASE;
break;
}
if(!strcmp("-w",argv[i])) {
action=WRITE;
break;
}
if(!strcmp("-p",argv[i])) {
action=PHEADER;
break;
}
if(!strcmp("-force",argv[i])) {
force=FORCE;
break;
}
if(!strcmp("-v",argv[i])) {
fprintf(stderr,VER);
exit(0);
break;
}
else {
fprintf(stderr,"Error: No action specified !\n");
help();
exit(1);
}
}
#ifdef WARNINC
if(force!=FORCE) warn();
#endif
if(argc < 5) {
fprintf(stderr,"Error: No i2c address specified !\n");
help();
exit(1);
}
for(i=1; i < argc;i++){
if(!strcmp("-f",argv[i])) {
strcpy(device,argv[i+1]);
break;
}
}
if(!strlen(device)) {
fprintf(stderr,"Error: No device specified !\n");
help();
exit(1);
}
if(! (addr=strtol(argv[4],NULL,16))) {
fprintf(stderr,"Error: Bad device address !\n");
help();
exit(1);
}
if(! (file=init(device,addr))){
fprintf(stderr,"Error: Init failed !\n");
exit(1);
}
switch(action){
case READ:
content_read(file,addr);
break;
case WRITE:
content_write(file,addr);
break;
case ERASE: erase(file,addr,EEPROM_SIZE);
break;
case PHEADER: pheader(file,addr);
break;
default:
fprintf(stderr,"Internal error!\n");
exit(1); break;
}
close(file);
exit(0);
}
/****************************************************************************/
/* Low level function */
/* */
/****************************************************************************/
int block_write(int file,int dev_addr,int eeprom_addr,unsigned char *buf,int lenght){
unsigned char buff[2];
struct i2c_msg msg[2];
struct i2c_ioctl_rdwr_data {
struct i2c_msg *msgs; /* ptr to array of simple messages */
int nmsgs; /* number of messages to exchange */
} msgst;
if ( lenght > (MAX_BLK_SIZE) ) {
fprintf(stderr,
"Error: Block too large:\n");
}
//bar();
made_address(eeprom_addr,buff);
msg[0].addr = dev_addr;
msg[0].flags = 0;
msg[0].len = 2;
msg[0].buf = buff;
msg[1].addr = dev_addr;
msg[1].flags = I2C_M_NOSTART;
msg[1].len = lenght;
msg[1].buf = buf;
msgst.msgs = msg;
msgst.nmsgs = 2;
if (ioctl(file,I2C_RDWR,&msgst) < 0){
fprintf(stderr,
"Error: Transaction failed: %s\n",
strerror(errno));
return 1;
}
return 0;
}
int block_read(int file,int dev_addr,int eeprom_addr,unsigned char *buf){
int ln;
char buff[2]; //={0x0,0x0};
struct i2c_msg msg[2];
struct i2c_ioctl_rdwr_data {
struct i2c_msg *msgs; /* ptr to array of simple messages */
int nmsgs; /* number of messages to exchange */
} msgst;
made_address(eeprom_addr,buff);
ln=0;
//bar();
msg[0].addr = dev_addr;
msg[0].flags = 0;
msg[0].len = 2;
msg[0].buf = buff;
msg[1].addr = dev_addr;
msg[1].flags = I2C_M_RD;
msg[1].len = MAX_BLK_SIZE;
msg[1].buf = buf;
msgst.msgs = msg;
msgst.nmsgs = 2;
if ((ln = ioctl(file, I2C_RDWR, &msgst)) < 0) {
fprintf(stderr,
"Error: Read error:%d\n",ln);
return ln;
}
return ln;
}
void made_address(int addr,unsigned char *buf){
int k;
//addr = addr & 0xFFFF; /*odstranim nepoterbne bity*/
k=addr;
buf[1]=(unsigned char) (k & 0xFF); //vyrobim druhy byte adresy
k=addr & 0xFF00 ;
buf[0]= ((unsigned char) (k >> 8)) & 0x7F;
return;
}
int init(char *device,int addr) {
int file;
unsigned long funcs;
if ((file = open(device,O_RDWR)) < 0) {
fprintf(stderr,"Error: Could not open file %s\n",
device);
return 0;
}
/* check adapter functionality */
if (ioctl(file,I2C_FUNCS,&funcs) < 0) {
fprintf(stderr,
"Error: Could not get the adapter functionality matrix: %s\n",
strerror(errno));
close(file);
return 0;
}
/* The I2C address */
if (ioctl(file,I2C_SLAVE,addr) < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
fprintf(stderr,
"Error: Cannot communicate with slave: %s\n",
strerror(errno));
close(file);
return 0;
}
return file;
}
int content_write(int file, int addr){
unsigned char buf[MAX_BLK_SIZE];
unsigned char pom;
int i, j, k, delka, addr_cnt;
delka=0;
addr_cnt=HEAD_SIZE;
k=0;
for(j=0;j<MAX_BLK_SIZE;j++)
buf[j]=0;
i=0;
for(;;) {
delka=fread(&pom,1,1,stdin);
if( delka > 0 ){
buf[i]=pom;
}
if(i==(MAX_BLK_SIZE-1) || (delka < 1)) {
if(block_write(file,addr,addr_cnt,buf,delka<1?i:(i+1)) !=0) {
fprintf(stderr,"Block write failed\n");
return 1;
}
//printf("i:%d\n",i);
addr_cnt=addr_cnt + i + (delka==1?1:0); //+i
for(j=0;j<MAX_BLK_SIZE;j++)
buf[j]=0;
i=0;
if(delka<1) {
//pisu EOF
if(inode_write(file,addr,(addr_cnt-HEAD_SIZE)) !=0) {
fprintf(stderr,"Inode write failed\n");
return 1;
}
break;
}
} else i++;
}
return 0;
}
int content_read(int file, int addr){
unsigned char buf[MAX_BLK_SIZE];
int i, j, k, delka;
delka=0;
k=0;
inode_read(file,addr,p_ind );
for(i=HEAD_SIZE;i<= (HEAD_SIZE + p_ind->data_len);i=i+MAX_BLK_SIZE ) {
if(block_read(file,addr,i,buf) !=0) {
fprintf(stderr,"Block read failed\n");
return 1;
}
if( (HEAD_SIZE + p_ind->data_len - i) < MAX_BLK_SIZE ) {
k= HEAD_SIZE + p_ind->data_len - i;
}else {
k=MAX_BLK_SIZE;
}
for(j=0;j<k ;j++){
putc(buf[j],stdout);
}
}
return 0;
}
void erase(int file, int addr,int eeprom_size){
unsigned char buf[MAX_BLK_SIZE];
int i, j, k, delka;
delka=0;
k=0;
for(j=0;j<MAX_BLK_SIZE;j++)
buf[j]=0;
for(i=0;i<eeprom_size;i=i+MAX_BLK_SIZE) {
if(block_write(file,addr,i,buf,MAX_BLK_SIZE) !=0) {
fprintf(stderr,"Block write failed\n");
return;
}
}
return;
}
void bar(void){
if( stav > 70 ) stav=0;
switch(stav) {
case 10: fwrite("\\",1,1,stderr);
fflush(stderr);
rewind(stderr);
break;
case 20: fwrite("|",1,1,stderr);
fflush(stderr);
rewind(stderr);
break;
case 30: fwrite("/",1,1,stderr);
fflush(stderr);
rewind(stderr);
break;
case 40: fwrite("-",1,1,stderr);
fflush(stderr);
rewind(stderr);
break;
case 50: fwrite("\\",1,1,stderr);
fflush(stderr);
rewind(stderr);
break;
case 60: fwrite("|",1,1,stderr);
fflush(stderr);
rewind(stderr);
break;
case 70: fwrite("/",1,1,stderr);
fflush(stderr);
rewind(stderr);
break;
}
stav++;
}
int inode_write(int file,int dev_addr,int lenght){
unsigned char buff[2];
struct i2c_msg msg[2];
struct i2c_ioctl_rdwr_data {
struct i2c_msg *msgs; /* ptr to array of simple messages */
int nmsgs; /* number of messages to exchange */
} msgst;
m_ind.timestamp=time(NULL);
m_ind.data_len=lenght;
//bar();
made_address(START_ADDR,buff);
msg[0].addr = dev_addr;
msg[0].flags = 0;
msg[0].len = 2;
msg[0].buf = buff;
msg[1].addr = dev_addr;
msg[1].flags = I2C_M_NOSTART;
msg[1].len = sizeof(struct mini_inode);
msg[1].buf = (char *) &m_ind;
msgst.msgs = msg;
msgst.nmsgs = 2;
if (ioctl(file,I2C_RDWR,&msgst) < 0){
fprintf(stderr,
"Error: Transaction failed: %s\n",
strerror(errno));
return 1;
}
return 0;
}
int inode_read(int file,int dev_addr,void *p_inode ){
#define POK 32
int ln;
char buff[2]; //={0x0,0x0};
struct i2c_msg msg[2];
struct i2c_ioctl_rdwr_data {
struct i2c_msg *msgs; /* ptr to array of simple messages */
int nmsgs; /* number of messages to exchange */
} msgst;
made_address(START_ADDR,buff);
ln=0;
//bar();
msg[0].addr = dev_addr;
msg[0].flags = 0;
msg[0].len = 2;
msg[0].buf = buff;
msg[1].addr = dev_addr;
msg[1].flags = I2C_M_RD;
msg[1].len = sizeof(struct mini_inode);
msg[1].buf = p_inode;
msgst.msgs = msg;
msgst.nmsgs = 2;
if ((ln = ioctl(file, I2C_RDWR, &msgst)) < 0) {
fprintf(stderr,
"Error: Read error:%d\n",ln);
return ln;
}
return ln;
}
void pheader(int file,int dev_addr){
struct tm *p_tm;
char time_buf[15],*p_buf;
p_buf=time_buf;
inode_read(file,dev_addr,p_ind );
p_tm=localtime(&p_ind->timestamp);
strftime(p_buf,sizeof(time_buf),"%Y%m%d%H%M%S",p_tm);
printf("LEN=%d,TIME=%s\n",p_ind->data_len,p_buf);
return;
}
#ifdef WARNINC
void warn(void)
{
fprintf(stderr,"\n\n!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!\n");
fprintf(stderr,"This program is intended for use on eeproms\nusing external busses such as i2c-pport.\n");
fprintf(stderr,"Do not use this on your SDRAM DIMM EEPROMS\nunless you REALLY REALLY know what you are\ndoing!!! Doing so will render your SDRAM\nUSELESS and leave your system UNBOOTABLE!!!\n");
fprintf(stderr,"To disable this warning use -force\n");
fprintf(stderr,"\n\nPress ENTER to continue or hit Control-C NOW !!!!\n\n\n");
getchar();
}
#endif

View file

@ -0,0 +1,29 @@
# Linux I2C header files
#
# Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
INCLUDE_DIR := include
INCLUDE_TARGETS := linux/i2c-dev.h
#
# Commands
#
install-include: $(addprefix $(INCLUDE_DIR)/,$(INCLUDE_TARGETS))
$(INSTALL_DIR) $(DESTDIR)$(incdir)/linux
for file in $(INCLUDE_TARGETS) ; do \
$(INSTALL_DATA) $(INCLUDE_DIR)/$$file $(DESTDIR)$(incdir)/$$file ; done
uninstall-include:
for file in $(INCLUDE_TARGETS) ; do \
$(RM) $(DESTDIR)$(incdir)/$$file ; done
install: install-include
uninstall: uninstall-include

View file

@ -0,0 +1,335 @@
/*
i2c-dev.h - i2c-bus driver, char device interface
Copyright (C) 1995-97 Simon G. Vogl
Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
/* $Id: i2c-dev.h 5894 2010-12-12 13:22:29Z khali $ */
#ifndef LIB_I2CDEV_H
#define LIB_I2CDEV_H
#include <linux/types.h>
#include <sys/ioctl.h>
/* -- i2c.h -- */
/*
* I2C Message - used for pure i2c transaction, also from /dev interface
*/
struct i2c_msg {
__u16 addr; /* slave address */
unsigned short flags;
#define I2C_M_TEN 0x10 /* we have a ten bit chip address */
#define I2C_M_RD 0x01
#define I2C_M_NOSTART 0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800
short len; /* msg length */
char *buf; /* pointer to msg data */
};
/* To determine what functionality is present */
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
#define I2C_FUNC_SMBUS_PEC 0x00000008
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK 0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
I2C_FUNC_SMBUS_WRITE_BYTE)
#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \
I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \
I2C_FUNC_SMBUS_WRITE_WORD_DATA)
#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
/* Old name, for compatibility */
#define I2C_FUNC_SMBUS_HWPEC_CALC I2C_FUNC_SMBUS_PEC
/*
* Data for SMBus Messages
*/
#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */
union i2c_smbus_data {
__u8 byte;
__u16 word;
__u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
/* and one more for PEC */
};
/* smbus_access read or write markers */
#define I2C_SMBUS_READ 1
#define I2C_SMBUS_WRITE 0
/* SMBus transaction types (size parameter in the above functions)
Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
#define I2C_SMBUS_QUICK 0
#define I2C_SMBUS_BYTE 1
#define I2C_SMBUS_BYTE_DATA 2
#define I2C_SMBUS_WORD_DATA 3
#define I2C_SMBUS_PROC_CALL 4
#define I2C_SMBUS_BLOCK_DATA 5
#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
#define I2C_SMBUS_I2C_BLOCK_DATA 8
/* ----- commands for the ioctl like i2c_command call:
* note that additional calls are defined in the algorithm and hw
* dependent layers - these can be listed here, or see the
* corresponding header files.
*/
/* -> bit-adapter specific ioctls */
#define I2C_RETRIES 0x0701 /* number of times a device address */
/* should be polled when not */
/* acknowledging */
#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */
/* this is for i2c-dev.c */
#define I2C_SLAVE 0x0703 /* Change slave address */
/* Attn.: Slave address is 7 or 10 bits */
#define I2C_SLAVE_FORCE 0x0706 /* Change slave address */
/* Attn.: Slave address is 7 or 10 bits */
/* This changes the address, even if it */
/* is already taken! */
#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */
#define I2C_FUNCS 0x0705 /* Get the adapter functionality */
#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/
#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */
#define I2C_SMBUS 0x0720 /* SMBus-level access */
/* -- i2c.h -- */
/* Note: 10-bit addresses are NOT supported! */
/* This is the structure as used in the I2C_SMBUS ioctl call */
struct i2c_smbus_ioctl_data {
char read_write;
__u8 command;
int size;
union i2c_smbus_data *data;
};
/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* pointers to i2c_msgs */
int nmsgs; /* number of i2c_msgs */
};
static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
int size, union i2c_smbus_data *data)
{
struct i2c_smbus_ioctl_data args;
args.read_write = read_write;
args.command = command;
args.size = size;
args.data = data;
return ioctl(file,I2C_SMBUS,&args);
}
static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
{
return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
}
static inline __s32 i2c_smbus_read_byte(int file)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
return -1;
else
return 0x0FF & data.byte;
}
static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
{
return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
I2C_SMBUS_BYTE,NULL);
}
static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
I2C_SMBUS_BYTE_DATA,&data))
return -1;
else
return 0x0FF & data.byte;
}
static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command,
__u8 value)
{
union i2c_smbus_data data;
data.byte = value;
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_BYTE_DATA, &data);
}
static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
I2C_SMBUS_WORD_DATA,&data))
return -1;
else
return 0x0FFFF & data.word;
}
static inline __s32 i2c_smbus_write_word_data(int file, __u8 command,
__u16 value)
{
union i2c_smbus_data data;
data.word = value;
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_WORD_DATA, &data);
}
static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
{
union i2c_smbus_data data;
data.word = value;
if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_PROC_CALL,&data))
return -1;
else
return 0x0FFFF & data.word;
}
/* Returns the number of read bytes */
static inline __s32 i2c_smbus_read_block_data(int file, __u8 command,
__u8 *values)
{
union i2c_smbus_data data;
int i;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
I2C_SMBUS_BLOCK_DATA,&data))
return -1;
else {
for (i = 1; i <= data.block[0]; i++)
values[i-1] = data.block[i];
return data.block[0];
}
}
static inline __s32 i2c_smbus_write_block_data(int file, __u8 command,
__u8 length, const __u8 *values)
{
union i2c_smbus_data data;
int i;
if (length > 32)
length = 32;
for (i = 1; i <= length; i++)
data.block[i] = values[i-1];
data.block[0] = length;
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_BLOCK_DATA, &data);
}
/* Returns the number of read bytes */
/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
ask for less than 32 bytes, your code will only work with kernels
2.6.23 and later. */
static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command,
__u8 length, __u8 *values)
{
union i2c_smbus_data data;
int i;
if (length > 32)
length = 32;
data.block[0] = length;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
I2C_SMBUS_I2C_BLOCK_DATA,&data))
return -1;
else {
for (i = 1; i <= data.block[0]; i++)
values[i-1] = data.block[i];
return data.block[0];
}
}
static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
__u8 length,
const __u8 *values)
{
union i2c_smbus_data data;
int i;
if (length > 32)
length = 32;
for (i = 1; i <= length; i++)
data.block[i] = values[i-1];
data.block[0] = length;
return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
}
/* Returns the number of read bytes */
static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,
__u8 length, __u8 *values)
{
union i2c_smbus_data data;
int i;
if (length > 32)
length = 32;
for (i = 1; i <= length; i++)
data.block[i] = values[i-1];
data.block[0] = length;
if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
I2C_SMBUS_BLOCK_PROC_CALL,&data))
return -1;
else {
for (i = 1; i <= data.block[0]; i++)
values[i-1] = data.block[i];
return data.block[0];
}
}
#endif /* LIB_I2CDEV_H */

View file

@ -0,0 +1,31 @@
# Python bindings for Linux SMBus access through i2c-dev
#
# Copyright (C) 2009 Mike Frysinger <vapier@gentoo.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
PY_SMBUS_DIR := py-smbus
PYTHON ?= python
DISTUTILS := \
cd $(PY_SMBUS_DIR) && \
CPPFLAGS="$(CPPFLAGS) -I../include" $(PYTHON) setup.py
all-python: $(INCLUDE_DIR)/linux/i2c-dev.h
$(DISTUTILS) build
clean-python:
$(DISTUTILS) clean
rm -rf py-smbus/build
install-python:
$(DISTUTILS) install
all: all-python
clean: clean-python
install: install-python

View file

@ -0,0 +1,26 @@
README: py-smbus
To build:
$ python setup.py build
On most GNU/Linux distributions, you'll need to install the python-devel
package for the build to succeed.
To install (will also build if necessary):
$ python setup.py install
For general build/install help:
$ python setup.py --help-commands
Frequently Answered Question:
Q: It's throwing exceptions, nothing works, what's wrong?
A1: You need write permissions to the i2c-dev devices. Try running as root.
A2: Addresses in Linux/I2C are the most-sig 7 bits, right-justified. E.g.
if your device uses address 0xc0 to write and 0xc1 to read, then use
address 0x60 with this module.
A3: Some other kernel driver has claimed that I2C address. Unload it first.

View file

@ -0,0 +1,14 @@
#!/usr/bin/env python
from distutils.core import setup, Extension
setup( name="smbus",
version="1.1",
description="Python bindings for Linux SMBus access through i2c-dev",
author="Mark M. Hoffman",
author_email="mhoffman@lightlink.com",
maintainer="Mark M. Hoffman",
maintainer_email="linux-i2c@vger.kernel.org",
license="GPLv2",
url="http://lm-sensors.org/",
ext_modules=[Extension("smbus", ["smbusmodule.c"])])

View file

@ -0,0 +1,730 @@
/*
* smbusmodule.c - Python bindings for Linux SMBus access through i2c-dev
* Copyright (C) 2005-2007 Mark M. Hoffman <mhoffman@xxxxxxxxxxxxx>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <Python.h>
#include "structmember.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
/*
** These are required to build this module against Linux older than 2.6.23.
*/
#ifndef I2C_SMBUS_I2C_BLOCK_BROKEN
#undef I2C_SMBUS_I2C_BLOCK_DATA
#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
#define I2C_SMBUS_I2C_BLOCK_DATA 8
#endif
/*yDoc_STRVAR(SMBus_module_doc,
"This module defines an object type that allows SMBus transactions\n"
"on hosts running the Linux kernel. The host kernel must have I2C\n"
"support, I2C device interface support, and a bus adapter driver.\n"
"All of these can be either built-in to the kernel, or loaded from\n"
"modules.\n"
"\n"
"Because the I2C device interface is opened R/W, users of this\n"
"module usually must have root permissions.\n");
*/
typedef struct {
PyObject_HEAD
int fd; /* open file descriptor: /dev/i2c-?, or -1 */
int addr; /* current client SMBus address */
int pec; /* !0 => Packet Error Codes enabled */
} SMBus;
static PyObject *
SMBus_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
SMBus *self;
if ((self = (SMBus *)type->tp_alloc(type, 0)) == NULL)
return NULL;
self->fd = -1;
self->addr = -1;
self->pec = 0;
return (PyObject *)self;
}
PyDoc_STRVAR(SMBus_close_doc,
"close()\n\n"
"Disconnects the object from the bus.\n");
static PyObject *
SMBus_close(SMBus *self)
{
if ((self->fd != -1) && (close(self->fd) == -1)) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
self->fd = -1;
self->addr = -1;
self->pec = 0;
Py_INCREF(Py_None);
return Py_None;
}
static void
SMBus_dealloc(SMBus *self)
{
PyObject *ref = SMBus_close(self);
Py_XDECREF(ref);
/*old python 2.7 declaration */
/*self->ob_type->tp_free((PyObject *)self);*/
Py_TYPE(self)->tp_free((PyObject*)self);
}
#define MAXPATH 16
PyDoc_STRVAR(SMBus_open_doc,
"open(bus)\n\n"
"Connects the object to the specified SMBus.\n");
static PyObject *
SMBus_open(SMBus *self, PyObject *args, PyObject *kwds)
{
int bus;
char path[MAXPATH];
static char *kwlist[] = {"bus", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:open", kwlist, &bus))
return NULL;
if (snprintf(path, MAXPATH, "/dev/i2c-%d", bus) >= MAXPATH) {
PyErr_SetString(PyExc_OverflowError,
"Bus number is invalid.");
return NULL;
}
if ((self->fd = open(path, O_RDWR, 0)) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static int
SMBus_init(SMBus *self, PyObject *args, PyObject *kwds)
{
int bus = -1;
static char *kwlist[] = {"bus", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:__init__",
kwlist, &bus))
return -1;
if (bus >= 0) {
SMBus_open(self, args, kwds);
if (PyErr_Occurred())
return -1;
}
return 0;
}
/*
* private helper function, 0 => success, !0 => error
*/
static int
SMBus_set_addr(SMBus *self, int addr)
{
int ret = 0;
if (self->addr != addr) {
ret = ioctl(self->fd, I2C_SLAVE, addr);
self->addr = addr;
}
return ret;
}
#define SMBus_SET_ADDR(self, addr) do { \
if (SMBus_set_addr(self, addr)) { \
PyErr_SetFromErrno(PyExc_IOError); \
return NULL; \
} \
} while(0)
PyDoc_STRVAR(SMBus_write_quick_doc,
"write_quick(addr)\n\n"
"Perform SMBus Quick transaction.\n");
static PyObject *
SMBus_write_quick(SMBus *self, PyObject *args)
{
int addr;
__s32 result;
if (!PyArg_ParseTuple(args, "i:write_quick", &addr))
return NULL;
SMBus_SET_ADDR(self, addr);
if ((result = i2c_smbus_write_quick(self->fd, I2C_SMBUS_WRITE))) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyDoc_STRVAR(SMBus_read_byte_doc,
"read_byte(addr) -> result\n\n"
"Perform SMBus Read Byte transaction.\n");
static PyObject *
SMBus_read_byte(SMBus *self, PyObject *args)
{
int addr;
__s32 result;
if (!PyArg_ParseTuple(args, "i:read_byte", &addr))
return NULL;
SMBus_SET_ADDR(self, addr);
if ((result = i2c_smbus_read_byte(self->fd)) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
return Py_BuildValue("l", (long)result);
}
PyDoc_STRVAR(SMBus_write_byte_doc,
"write_byte(addr, val)\n\n"
"Perform SMBus Write Byte transaction.\n");
static PyObject *
SMBus_write_byte(SMBus *self, PyObject *args)
{
int addr, val;
__s32 result;
if (!PyArg_ParseTuple(args, "ii:write_byte", &addr, &val))
return NULL;
SMBus_SET_ADDR(self, addr);
if ((result = i2c_smbus_write_byte(self->fd, (__u8)val)) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyDoc_STRVAR(SMBus_read_byte_data_doc,
"read_byte_data(addr, cmd) -> result\n\n"
"Perform SMBus Read Byte Data transaction.\n");
static PyObject *
SMBus_read_byte_data(SMBus *self, PyObject *args)
{
int addr, cmd;
__s32 result;
if (!PyArg_ParseTuple(args, "ii:read_byte_data", &addr, &cmd))
return NULL;
SMBus_SET_ADDR(self, addr);
if ((result = i2c_smbus_read_byte_data(self->fd, (__u8)cmd)) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
return Py_BuildValue("l", (long)result);
}
PyDoc_STRVAR(SMBus_write_byte_data_doc,
"write_byte_data(addr, cmd, val)\n\n"
"Perform SMBus Write Byte Data transaction.\n");
static PyObject *
SMBus_write_byte_data(SMBus *self, PyObject *args)
{
int addr, cmd, val;
__s32 result;
if (!PyArg_ParseTuple(args, "iii:write_byte_data", &addr, &cmd, &val))
return NULL;
SMBus_SET_ADDR(self, addr);
if ((result = i2c_smbus_write_byte_data(self->fd,
(__u8)cmd, (__u8)val)) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyDoc_STRVAR(SMBus_read_word_data_doc,
"read_word_data(addr, cmd) -> result\n\n"
"Perform SMBus Read Word Data transaction.\n");
static PyObject *
SMBus_read_word_data(SMBus *self, PyObject *args)
{
int addr, cmd;
__s32 result;
if (!PyArg_ParseTuple(args, "ii:read_word_data", &addr, &cmd))
return NULL;
SMBus_SET_ADDR(self, addr);
if ((result = i2c_smbus_read_word_data(self->fd, (__u8)cmd)) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
return Py_BuildValue("l", (long)result);
}
PyDoc_STRVAR(SMBus_write_word_data_doc,
"write_word_data(addr, cmd, val)\n\n"
"Perform SMBus Write Word Data transaction.\n");
static PyObject *
SMBus_write_word_data(SMBus *self, PyObject *args)
{
int addr, cmd, val;
__s32 result;
if (!PyArg_ParseTuple(args, "iii:write_word_data", &addr, &cmd, &val))
return NULL;
SMBus_SET_ADDR(self, addr);
if ((result = i2c_smbus_write_word_data(self->fd,
(__u8)cmd, (__u16)val)) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyDoc_STRVAR(SMBus_process_call_doc,
"process_call(addr, cmd, val)\n\n"
"Perform SMBus Process Call transaction.\n");
static PyObject *
SMBus_process_call(SMBus *self, PyObject *args)
{
int addr, cmd, val;
__s32 result;
if (!PyArg_ParseTuple(args, "iii:process_call", &addr, &cmd, &val))
return NULL;
SMBus_SET_ADDR(self, addr);
if ((result = i2c_smbus_process_call(self->fd,
(__u8)cmd, (__u16)val)) == -1) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/*
* private helper function; returns a new list of integers
*/
static PyObject *
SMBus_buf_to_list(__u8 const *buf, int len)
{
PyObject *list = PyList_New(len);
int ii;
if (list == NULL)
return NULL;
for (ii = 0; ii < len; ii++) {
PyObject *val = Py_BuildValue("l", (long)buf[ii]);
PyList_SET_ITEM(list, ii, val);
}
return list;
}
PyDoc_STRVAR(SMBus_read_block_data_doc,
"read_block_data(addr, cmd) -> results\n\n"
"Perform SMBus Read Block Data transaction.\n");
static PyObject *
SMBus_read_block_data(SMBus *self, PyObject *args)
{
int addr, cmd;
union i2c_smbus_data data;
if (!PyArg_ParseTuple(args, "ii:read_block_data", &addr, &cmd))
return NULL;
SMBus_SET_ADDR(self, addr);
/* save a bit of code by calling the access function directly */
if (i2c_smbus_access(self->fd, I2C_SMBUS_READ, (__u8)cmd,
I2C_SMBUS_BLOCK_DATA, &data)) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
/* first byte of the block contains (remaining) data length */
return SMBus_buf_to_list(&data.block[1], data.block[0]);
}
/*
* private helper function: convert an integer list to union i2c_smbus_data
*/
static int
SMBus_list_to_data(PyObject *list, union i2c_smbus_data *data)
{
static char *msg = "Third argument must be a list of at least one, "
"but not more than 32 integers";
int ii, len;
if (!PyList_Check(list)) {
PyErr_SetString(PyExc_TypeError, msg);
return 0; /* fail */
}
if ((len = PyList_GET_SIZE(list)) > 32) {
PyErr_SetString(PyExc_OverflowError, msg);
return 0; /* fail */
}
/* first byte is the length */
data->block[0] = (__u8)len;
for (ii = 0; ii < len; ii++) {
PyObject *val = PyList_GET_ITEM(list, ii);
if (!PyLong_Check(val)) {
PyErr_SetString(PyExc_TypeError, msg);
return 0; /* fail */
}
data->block[ii+1] = (__u8)PyLong_AS_LONG(val);
}
return 1; /* success */
}
PyDoc_STRVAR(SMBus_write_block_data_doc,
"write_block_data(addr, cmd, [vals])\n\n"
"Perform SMBus Write Block Data transaction.\n");
static PyObject *
SMBus_write_block_data(SMBus *self, PyObject *args)
{
int addr, cmd;
union i2c_smbus_data data;
if (!PyArg_ParseTuple(args, "iiO&:write_block_data", &addr, &cmd,
SMBus_list_to_data, &data))
return NULL;
SMBus_SET_ADDR(self, addr);
/* save a bit of code by calling the access function directly */
if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd,
I2C_SMBUS_BLOCK_DATA, &data)) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyDoc_STRVAR(SMBus_block_process_call_doc,
"block_process_call(addr, cmd, [vals]) -> results\n\n"
"Perform SMBus Block Process Call transaction.\n");
static PyObject *
SMBus_block_process_call(SMBus *self, PyObject *args)
{
int addr, cmd;
union i2c_smbus_data data;
if (!PyArg_ParseTuple(args, "iiO&:block_process_call", &addr, &cmd,
SMBus_list_to_data, &data))
return NULL;
SMBus_SET_ADDR(self, addr);
/* save a bit of code by calling the access function directly */
if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd,
I2C_SMBUS_BLOCK_PROC_CALL, &data)) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
/* first byte of the block contains (remaining) data length */
return SMBus_buf_to_list(&data.block[1], data.block[0]);
}
PyDoc_STRVAR(SMBus_read_i2c_block_data_doc,
"read_i2c_block_data(addr, cmd, len=32) -> results\n\n"
"Perform I2C Block Read transaction.\n");
static PyObject *
SMBus_read_i2c_block_data(SMBus *self, PyObject *args)
{
int addr, cmd, len=32;
union i2c_smbus_data data;
if (!PyArg_ParseTuple(args, "ii|i:read_i2c_block_data", &addr, &cmd,
&len))
return NULL;
SMBus_SET_ADDR(self, addr);
data.block[0] = len;
/* save a bit of code by calling the access function directly */
if (i2c_smbus_access(self->fd, I2C_SMBUS_READ, (__u8)cmd,
len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN:
I2C_SMBUS_I2C_BLOCK_DATA, &data)) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
/* first byte of the block contains (remaining) data length */
return SMBus_buf_to_list(&data.block[1], data.block[0]);
}
PyDoc_STRVAR(SMBus_write_i2c_block_data_doc,
"write_i2c_block_data(addr, cmd, [vals])\n\n"
"Perform I2C Block Write transaction.\n");
static PyObject *
SMBus_write_i2c_block_data(SMBus *self, PyObject *args)
{
int addr, cmd;
union i2c_smbus_data data;
if (!PyArg_ParseTuple(args, "iiO&:write_i2c_block_data", &addr, &cmd,
SMBus_list_to_data, &data))
return NULL;
SMBus_SET_ADDR(self, addr);
/* save a bit of code by calling the access function directly */
if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd,
I2C_SMBUS_I2C_BLOCK_BROKEN, &data)) {
PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyDoc_STRVAR(SMBus_type_doc,
"SMBus([bus]) -> SMBus\n\n"
"Return a new SMBus object that is (optionally) connected to the\n"
"specified I2C device interface.\n");
static PyMethodDef SMBus_methods[] = {
{"open", (PyCFunction)SMBus_open, METH_VARARGS | METH_KEYWORDS,
SMBus_open_doc},
{"close", (PyCFunction)SMBus_close, METH_NOARGS,
SMBus_close_doc},
{"write_quick", (PyCFunction)SMBus_write_quick, METH_VARARGS,
SMBus_write_quick_doc},
{"read_byte", (PyCFunction)SMBus_read_byte, METH_VARARGS,
SMBus_read_byte_doc},
{"write_byte", (PyCFunction)SMBus_write_byte, METH_VARARGS,
SMBus_write_byte_doc},
{"read_byte_data", (PyCFunction)SMBus_read_byte_data, METH_VARARGS,
SMBus_read_byte_data_doc},
{"write_byte_data", (PyCFunction)SMBus_write_byte_data, METH_VARARGS,
SMBus_write_byte_data_doc},
{"read_word_data", (PyCFunction)SMBus_read_word_data, METH_VARARGS,
SMBus_read_word_data_doc},
{"write_word_data", (PyCFunction)SMBus_write_word_data, METH_VARARGS,
SMBus_write_word_data_doc},
{"process_call", (PyCFunction)SMBus_process_call, METH_VARARGS,
SMBus_process_call_doc},
{"read_block_data", (PyCFunction)SMBus_read_block_data, METH_VARARGS,
SMBus_read_block_data_doc},
{"write_block_data", (PyCFunction)SMBus_write_block_data, METH_VARARGS,
SMBus_write_block_data_doc},
{"block_process_call", (PyCFunction)SMBus_block_process_call,
METH_VARARGS, SMBus_block_process_call_doc},
{"read_i2c_block_data", (PyCFunction)SMBus_read_i2c_block_data,
METH_VARARGS, SMBus_read_i2c_block_data_doc},
{"write_i2c_block_data", (PyCFunction)SMBus_write_i2c_block_data,
METH_VARARGS, SMBus_write_i2c_block_data_doc},
{NULL},
};
static PyObject *
SMBus_get_pec(SMBus *self, void *closure)
{
PyObject *result = self->pec ? Py_True : Py_False;
Py_INCREF(result);
return result;
}
static int
SMBus_set_pec(SMBus *self, PyObject *val, void *closure)
{
int pec;
pec = PyObject_IsTrue(val);
if (val == NULL) {
PyErr_SetString(PyExc_TypeError,
"Cannot delete attribute");
return -1;
}
else if (pec == -1) {
PyErr_SetString(PyExc_TypeError,
"The pec attribute must be a boolean.");
return -1;
}
if (self->pec != pec) {
if (ioctl(self->fd, I2C_PEC, pec)) {
PyErr_SetFromErrno(PyExc_IOError);
return -1;
}
self->pec = pec;
}
return 0;
}
static PyGetSetDef SMBus_getset[] = {
{"pec", (getter)SMBus_get_pec, (setter)SMBus_set_pec,
"True if Packet Error Codes (PEC) are enabled"},
{NULL},
};
/* old Python 2.7 declaration */
static PyTypeObject SMBus_type = {
/*tatic struct PyModuleDef SMBus_type = {*/
/* old Python 2.7 declaration */
/* PyObject_HEAD_INIT(NULL) */
/*0, ob_size */
PyVarObject_HEAD_INIT(NULL, 0)
"SMBus", /* tp_name */
sizeof(SMBus), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)SMBus_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
SMBus_type_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
SMBus_methods, /* tp_methods */
0, /* tp_members */
SMBus_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)SMBus_init, /* tp_init */
0, /* tp_alloc */
SMBus_new, /* tp_new */
};
/*static PyMethodDef SMBus_module_methods[] = {
{NULL}
};*/
static struct PyModuleDef SMBusModule = {
PyModuleDef_HEAD_INIT,
"SMBus", /* m_name */
"This module defines an object type that allows SMBus transactions\n"
"on hosts running the Linux kernel. The host kernel must have I2C\n"
"support, I2C device interface support, and a bus adapter driver.\n"
"All of these can be either built-in to the kernel, or loaded from\n"
"modules.\n"
"\n"
"Because the I2C device interface is opened R/W, users of this\n"
"module usually must have root permissions.\n", /* m_doc */
-1, /* m_size */
NULL, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
PyInit_smbus(void)
{
PyObject* m;
if (PyType_Ready(&SMBus_type) < 0)
return NULL;
/* old Python 2.7 declaration */
/*m = Py_InitModule3("smbus", SMBus_module_methods, SMBus_module_doc);*/
m = PyModule_Create(&SMBusModule);
if (m == NULL)
return NULL;
Py_INCREF(&SMBus_type);
PyModule_AddObject(m, "SMBus", (PyObject *)&SMBus_type);
return m;
}

View file

@ -0,0 +1,27 @@
# Helper for the Linux i2c-stub bus driver
#
# Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
STUB_DIR := stub
#
# Commands
#
install-stub: $(STUB_DIR)/i2c-stub-from-dump
$(INSTALL_DIR) $(DESTDIR)$(sbindir) $(DESTDIR)$(man8dir)
$(INSTALL_PROGRAM) $(STUB_DIR)/i2c-stub-from-dump $(DESTDIR)$(sbindir)
$(INSTALL_DATA) $(STUB_DIR)/i2c-stub-from-dump.8 $(DESTDIR)$(man8dir)
uninstall-stub:
$(RM) $(DESTDIR)$(sbindir)/i2c-stub-from-dump
$(RM) $(DESTDIR)$(man8dir)/i2c-stub-from-dump.8
install: install-stub
uninstall: uninstall-stub

View file

@ -0,0 +1,229 @@
#!/usr/bin/perl -w
#
# Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA
#
# This script feeds the i2c-stub driver with dump data from a real
# I2C or SMBus chip. This can be useful when writing a driver for
# a device you do not have access to, but of which you have a dump.
use strict;
use vars qw($bus_nr @addr $err);
# Kernel version detection code by Mark M. Hoffman,
# copied from sensors-detect.
use vars qw(@kernel_version);
sub initialize_kernel_version
{
`uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/;
@kernel_version = ($1, $2, $3, $4);
}
sub kernel_version_at_least
{
my ($vers, $plvl, $slvl) = @_;
return 1 if ($kernel_version[0] > $vers ||
($kernel_version[0] == $vers &&
($kernel_version[1] > $plvl ||
($kernel_version[1] == $plvl &&
($kernel_version[2] >= $slvl)))));
return 0;
}
# Find out the i2c bus number of i2c-stub
sub get_i2c_stub_bus_number
{
my $nr;
open(FH, "i2cdetect -l |") || die "Can't run i2cdetect";
while (<FH>) {
next unless m/^i2c-(\d+).*\tSMBus stub/;
$nr = $1;
last;
}
close(FH);
return $nr;
}
# Unload i2c-stub if we need an address it doesn't offer
sub check_chip_addr {
my $chip_addr_file = shift;
my @addr = @{shift()};
local $_;
open(CHIP_ADDR, $chip_addr_file) || return;
$_ = <CHIP_ADDR>;
chomp;
my %stub_addr = map { $_ => 1 } split ',';
close(CHIP_ADDR);
foreach my $addr (@addr) {
unless (exists $stub_addr{$addr}) {
print STDERR "Cycling i2c-stub to get the address we need\n";
system("/sbin/rmmod", "i2c-stub");
return;
}
}
}
# Load the required kernel drivers if needed
sub load_kernel_drivers
{
local $_;
my @addr = @{shift()};
my $nr;
# i2c-stub may be loaded without the address we want
check_chip_addr("/sys/module/i2c_stub/parameters/chip_addr", \@addr);
# Maybe everything is already loaded
$nr = get_i2c_stub_bus_number();
return $nr if defined $nr;
system("/sbin/modprobe", "i2c-dev") == 0 || exit 1;
if (kernel_version_at_least(2, 6, 19)) {
system("/sbin/modprobe", "i2c-stub",
"chip_addr=".join(',', @addr)) == 0 || exit 1;
} else {
system("/sbin/modprobe", "i2c-stub") == 0 || exit 1;
}
# udev may take some time to create the device node
if (!(-x "/sbin/udevadm" && system("/sbin/udevadm settle") == 0)
&& !(-x "/sbin/udevsettle" && system("/sbin/udevsettle") == 0)) {
sleep(1);
}
$nr = get_i2c_stub_bus_number();
if (!defined($nr)) {
print STDERR "Please load i2c-stub first\n";
exit 2;
}
return $nr;
}
sub process_dump
{
my ($addr, $dump) = @_;
my $err = 0;
my ($bytes, $words);
open(DUMP, $dump) || die "Can't open $dump: $!\n";
OUTER_LOOP:
while (<DUMP>) {
if (m/^([0-9a-f]0):(( [0-9a-fX]{2}){16})/) {
# Byte dump
my $offset = hex($1);
my @values = split(/ /, $2);
shift(@values);
for (my $i = 0; $i < 16 && (my $val = shift(@values)); $i++) {
next if $val =~ m/X/;
if (system("i2cset", "-y", $bus_nr, $addr,
sprintf("0x\%02x", $offset+$i),
"0x$val", "b")) {
$err = 3;
last OUTER_LOOP;
}
$bytes++;
}
} elsif (m/^([0-9a-f][08]):(( [0-9a-fX]{4}){8})/) {
# Word dump
my $offset = hex($1);
my @values = split(/ /, $2);
shift(@values);
for (my $i = 0; $i < 8 && (my $val = shift(@values)); $i++) {
next if $val =~ m/X/;
if (system("i2cset", "-y", $bus_nr, $addr,
sprintf("0x\%02x", $offset+$i),
"0x$val", "w")) {
$err = 3;
last OUTER_LOOP;
}
$words++;
}
}
}
close(DUMP);
if ($bytes) {
printf SAVEOUT "$bytes byte values written to \%d-\%04x\n",
$bus_nr, $addr;
}
if ($words) {
printf SAVEOUT "$words word values written to \%d-\%04x\n",
$bus_nr, $addr;
}
if (!$err && !$bytes && !$words) {
printf SAVEOUT "Only garbage found in dump file $dump\n";
$err = 1;
}
return $err;
}
if ($>) {
print "You must be root to use this script\n";
exit 1;
}
if (@ARGV < 2) {
print STDERR "Usage: i2c-stub-from-dump <addr>[,<addr>,...] <dump file> [<dump file> ...]\n";
exit 1;
}
# Check the parameters
@addr = split(/,/, shift @ARGV);
foreach (@addr) {
unless (m/^0x[0-7][0-9a-f]$/i) {
print STDERR "Invalid address $_\n";
exit 1;
}
$_ = oct $_;
}
if (@addr < @ARGV) {
print STDERR "Fewer addresses than dumps provided\n";
exit 4;
}
initialize_kernel_version();
if (@addr > 1 && !kernel_version_at_least(2, 6, 24)) {
print STDERR "Multiple addresses not supported by this kernel version\n";
exit 5;
}
$bus_nr = load_kernel_drivers(\@addr);
# We don't want to see the output of 256 i2cset
open(SAVEOUT, ">&STDOUT");
open(STDOUT, ">/dev/null");
foreach (@addr) {
if (!@ARGV) {
printf STDERR "Skipping \%d-\%04x, no dump file privided\n",
$bus_nr, $_;
next;
}
$err = process_dump($_, shift @ARGV);
last if $err;
}
close(STDOUT);
exit($err);

View file

@ -0,0 +1,52 @@
.TH I2C-STUB-FROM-DUMP 8 "March 2010"
.SH NAME
i2c-stub-from-dump \- feed i2c-stub with dump files
.SH SYNOPSIS
.B i2c-stub-from-dump
.IR address [, address ,...]
.IR dump-file " [" dump-file " ...]"
.SH DESCRIPTION
i2c-stub-from-dump is a small helper script for the i2c-stub kernel driver.
It lets you setup one or more fake I2C chips on the i2c-stub bus based on
dumps of the chips you want to emulate.
i2c-stub-from-dump requires i2cdetect and i2cset to be installed and
reachable through the user's PATH. The former is used to find out the i2c-stub
bus number, while the latter is used to write to the fake I2C chips.
.SH EXAMPLE
You have an I2C chip on system A. You would like to do some development on its
driver on system B. Here are the few steps you have to follow.
On system A, use i2cdump to capture a dump from the chip. Assuming that the
chip in question lives at address 0x4c on I2C bus 0, you would run:
i2cdump -y 0 0x4c b > chip.dump
Adjust the bus number and chip address for your case. i2cdetect can help
you find out their values. If the device uses word (16-bit) register
access instead of the traditional byte (8-bit) access, use mode \fBw\fR
instead of \fBb\fR.
Copy the dump file to system B.
On system B, run:
i2c-stub-from-dump 0x4c chip.dump
This will load the required i2c-dev and i2c-stub kernel drivers if needed,
then write all the register values to the emulated I2C chip at address 0x4c.
Again, adjust the address as needed.
.SH LIMITATIONS
There are some limitations to the kind of devices that can be handled:
.IP \(bu
Device must not have banks (as most Winbond devices do).
.SH SEE ALSO
i2cdump(8), i2cdetect(8), i2cset(8)
.SH AUTHOR
Jean Delvare

View file

@ -0,0 +1,87 @@
# I2C tools for Linux
#
# Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
TOOLS_DIR := tools
TOOLS_CFLAGS := -Wstrict-prototypes -Wshadow -Wpointer-arith -Wcast-qual \
-Wcast-align -Wwrite-strings -Wnested-externs -Winline \
-W -Wundef -Wmissing-prototypes -Iinclude
TOOLS_TARGETS := i2cdetect i2cdump i2cset i2cget
#
# Programs
#
$(TOOLS_DIR)/i2cdetect: $(TOOLS_DIR)/i2cdetect.o $(TOOLS_DIR)/i2cbusses.o
$(CC) $(LDFLAGS) -o $@ $^
$(TOOLS_DIR)/i2cdump: $(TOOLS_DIR)/i2cdump.o $(TOOLS_DIR)/i2cbusses.o $(TOOLS_DIR)/util.o
$(CC) $(LDFLAGS) -o $@ $^
$(TOOLS_DIR)/i2cset: $(TOOLS_DIR)/i2cset.o $(TOOLS_DIR)/i2cbusses.o $(TOOLS_DIR)/util.o
$(CC) $(LDFLAGS) -o $@ $^
$(TOOLS_DIR)/i2cget: $(TOOLS_DIR)/i2cget.o $(TOOLS_DIR)/i2cbusses.o $(TOOLS_DIR)/util.o
$(CC) $(LDFLAGS) -o $@ $^
#
# Objects
#
$(TOOLS_DIR)/i2cdetect.o: $(TOOLS_DIR)/i2cdetect.c $(TOOLS_DIR)/i2cbusses.h $(INCLUDE_DIR)/linux/i2c-dev.h
$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
$(TOOLS_DIR)/i2cdump.o: $(TOOLS_DIR)/i2cdump.c $(TOOLS_DIR)/i2cbusses.h $(TOOLS_DIR)/util.h $(INCLUDE_DIR)/linux/i2c-dev.h
$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
$(TOOLS_DIR)/i2cset.o: $(TOOLS_DIR)/i2cset.c $(TOOLS_DIR)/i2cbusses.h $(TOOLS_DIR)/util.h $(INCLUDE_DIR)/linux/i2c-dev.h
$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
$(TOOLS_DIR)/i2cget.o: $(TOOLS_DIR)/i2cget.c $(TOOLS_DIR)/i2cbusses.h $(TOOLS_DIR)/util.h $(INCLUDE_DIR)/linux/i2c-dev.h
$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
$(TOOLS_DIR)/i2cbusses.o: $(TOOLS_DIR)/i2cbusses.c $(TOOLS_DIR)/i2cbusses.h $(INCLUDE_DIR)/linux/i2c-dev.h
$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
$(TOOLS_DIR)/util.o: $(TOOLS_DIR)/util.c $(TOOLS_DIR)/util.h
$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
#
# Commands
#
all-tools: $(addprefix $(TOOLS_DIR)/,$(TOOLS_TARGETS))
strip-tools: $(addprefix $(TOOLS_DIR)/,$(TOOLS_TARGETS))
strip $(addprefix $(TOOLS_DIR)/,$(TOOLS_TARGETS))
clean-tools:
$(RM) $(addprefix $(TOOLS_DIR)/,*.o $(TOOLS_TARGETS))
install-tools: $(addprefix $(TOOLS_DIR)/,$(TOOLS_TARGETS))
$(INSTALL_DIR) $(DESTDIR)$(sbindir) $(DESTDIR)$(man8dir)
for program in $(TOOLS_TARGETS) ; do \
$(INSTALL_PROGRAM) $(TOOLS_DIR)/$$program $(DESTDIR)$(sbindir) ; \
$(INSTALL_DATA) $(TOOLS_DIR)/$$program.8 $(DESTDIR)$(man8dir) ; done
uninstall-tools:
for program in $(TOOLS_TARGETS) ; do \
$(RM) $(DESTDIR)$(sbindir)/$$program ; \
$(RM) $(DESTDIR)$(man8dir)/$$program.8 ; done
all: all-tools
strip: strip-tools
clean: clean-tools
install: install-tools
uninstall: uninstall-tools

View file

@ -0,0 +1,415 @@
/*
i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels.
Part of user-space programs to access for I2C
devices.
Copyright (c) 1999-2003 Frodo Looijaard <frodol@dds.nl> and
Mark D. Studebaker <mdsxyz123@yahoo.com>
Copyright (C) 2008-2010 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
/* For strdup and snprintf */
#define _BSD_SOURCE 1
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h> /* for NAME_MAX */
#include <string.h>
#include <strings.h> /* for strcasecmp() */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include "i2cbusses.h"
#include <linux/i2c-dev.h>
enum adt { adt_dummy, adt_isa, adt_i2c, adt_smbus, adt_unknown };
struct adap_type {
const char *funcs;
const char* algo;
};
static struct adap_type adap_types[5] = {
{ .funcs = "dummy",
.algo = "Dummy bus", },
{ .funcs = "isa",
.algo = "ISA bus", },
{ .funcs = "i2c",
.algo = "I2C adapter", },
{ .funcs = "smbus",
.algo = "SMBus adapter", },
{ .funcs = "unknown",
.algo = "N/A", },
};
static enum adt i2c_get_funcs(int i2cbus)
{
unsigned long funcs;
int file;
char filename[20];
enum adt ret;
file = open_i2c_dev(i2cbus, filename, sizeof(filename), 1);
if (file < 0)
return adt_unknown;
if (ioctl(file, I2C_FUNCS, &funcs) < 0)
ret = adt_unknown;
else if (funcs & I2C_FUNC_I2C)
ret = adt_i2c;
else if (funcs & (I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
ret = adt_smbus;
else
ret = adt_dummy;
close(file);
return ret;
}
/* Remove trailing spaces from a string
Return the new string length including the trailing NUL */
static int rtrim(char *s)
{
int i;
for (i = strlen(s) - 1; i >= 0 && (s[i] == ' ' || s[i] == '\n'); i--)
s[i] = '\0';
return i + 2;
}
void free_adapters(struct i2c_adap *adapters)
{
int i;
for (i = 0; adapters[i].name; i++)
free(adapters[i].name);
free(adapters);
}
/* We allocate space for the adapters in bunches. The last item is a
terminator, so here we start with room for 7 adapters, which should
be enough in most cases. If not, we allocate more later as needed. */
#define BUNCH 8
/* n must match the size of adapters at calling time */
static struct i2c_adap *more_adapters(struct i2c_adap *adapters, int n)
{
struct i2c_adap *new_adapters;
new_adapters = realloc(adapters, (n + BUNCH) * sizeof(struct i2c_adap));
if (!new_adapters) {
free_adapters(adapters);
return NULL;
}
memset(new_adapters + n, 0, BUNCH * sizeof(struct i2c_adap));
return new_adapters;
}
struct i2c_adap *gather_i2c_busses(void)
{
char s[120];
struct dirent *de, *dde;
DIR *dir, *ddir;
FILE *f;
char fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX];
int foundsysfs = 0;
int count=0;
struct i2c_adap *adapters;
adapters = calloc(BUNCH, sizeof(struct i2c_adap));
if (!adapters)
return NULL;
/* look in /proc/bus/i2c */
if ((f = fopen("/proc/bus/i2c", "r"))) {
while (fgets(s, 120, f)) {
char *algo, *name, *type, *all;
int len_algo, len_name, len_type;
int i2cbus;
algo = strrchr(s, '\t');
*(algo++) = '\0';
len_algo = rtrim(algo);
name = strrchr(s, '\t');
*(name++) = '\0';
len_name = rtrim(name);
type = strrchr(s, '\t');
*(type++) = '\0';
len_type = rtrim(type);
sscanf(s, "i2c-%d", &i2cbus);
if ((count + 1) % BUNCH == 0) {
/* We need more space */
adapters = more_adapters(adapters, count + 1);
if (!adapters)
return NULL;
}
all = malloc(len_name + len_type + len_algo);
if (all == NULL) {
free_adapters(adapters);
return NULL;
}
adapters[count].nr = i2cbus;
adapters[count].name = strcpy(all, name);
adapters[count].funcs = strcpy(all + len_name, type);
adapters[count].algo = strcpy(all + len_name + len_type,
algo);
count++;
}
fclose(f);
goto done;
}
/* look in sysfs */
/* First figure out where sysfs was mounted */
if ((f = fopen("/proc/mounts", "r")) == NULL) {
goto done;
}
while (fgets(n, NAME_MAX, f)) {
sscanf(n, "%*[^ ] %[^ ] %[^ ] %*s\n", sysfs, fstype);
if (strcasecmp(fstype, "sysfs") == 0) {
foundsysfs++;
break;
}
}
fclose(f);
if (! foundsysfs) {
goto done;
}
/* Bus numbers in i2c-adapter don't necessarily match those in
i2c-dev and what we really care about are the i2c-dev numbers.
Unfortunately the names are harder to get in i2c-dev */
strcat(sysfs, "/class/i2c-dev");
if(!(dir = opendir(sysfs)))
goto done;
/* go through the busses */
while ((de = readdir(dir)) != NULL) {
if (!strcmp(de->d_name, "."))
continue;
if (!strcmp(de->d_name, ".."))
continue;
/* this should work for kernels 2.6.5 or higher and */
/* is preferred because is unambiguous */
sprintf(n, "%s/%s/name", sysfs, de->d_name);
f = fopen(n, "r");
/* this seems to work for ISA */
if(f == NULL) {
sprintf(n, "%s/%s/device/name", sysfs, de->d_name);
f = fopen(n, "r");
}
/* non-ISA is much harder */
/* and this won't find the correct bus name if a driver
has more than one bus */
if(f == NULL) {
sprintf(n, "%s/%s/device", sysfs, de->d_name);
if(!(ddir = opendir(n)))
continue;
while ((dde = readdir(ddir)) != NULL) {
if (!strcmp(dde->d_name, "."))
continue;
if (!strcmp(dde->d_name, ".."))
continue;
if ((!strncmp(dde->d_name, "i2c-", 4))) {
sprintf(n, "%s/%s/device/%s/name",
sysfs, de->d_name, dde->d_name);
if((f = fopen(n, "r")))
goto found;
}
}
}
found:
if (f != NULL) {
int i2cbus;
enum adt type;
char *px;
px = fgets(s, 120, f);
fclose(f);
if (!px) {
fprintf(stderr, "%s: read error\n", n);
continue;
}
if ((px = strchr(s, '\n')) != NULL)
*px = 0;
if (!sscanf(de->d_name, "i2c-%d", &i2cbus))
continue;
if (!strncmp(s, "ISA ", 4)) {
type = adt_isa;
} else {
/* Attempt to probe for adapter capabilities */
type = i2c_get_funcs(i2cbus);
}
if ((count + 1) % BUNCH == 0) {
/* We need more space */
adapters = more_adapters(adapters, count + 1);
if (!adapters)
return NULL;
}
adapters[count].nr = i2cbus;
adapters[count].name = strdup(s);
if (adapters[count].name == NULL) {
free_adapters(adapters);
return NULL;
}
adapters[count].funcs = adap_types[type].funcs;
adapters[count].algo = adap_types[type].algo;
count++;
}
}
closedir(dir);
done:
return adapters;
}
static int lookup_i2c_bus_by_name(const char *bus_name)
{
struct i2c_adap *adapters;
int i, i2cbus = -1;
adapters = gather_i2c_busses();
if (adapters == NULL) {
fprintf(stderr, "Error: Out of memory!\n");
return -3;
}
/* Walk the list of i2c busses, looking for the one with the
right name */
for (i = 0; adapters[i].name; i++) {
if (strcmp(adapters[i].name, bus_name) == 0) {
if (i2cbus >= 0) {
fprintf(stderr,
"Error: I2C bus name is not unique!\n");
i2cbus = -4;
goto done;
}
i2cbus = adapters[i].nr;
}
}
if (i2cbus == -1)
fprintf(stderr, "Error: I2C bus name doesn't match any "
"bus present!\n");
done:
free_adapters(adapters);
return i2cbus;
}
/*
* Parse an I2CBUS command line argument and return the corresponding
* bus number, or a negative value if the bus is invalid.
*/
int lookup_i2c_bus(const char *i2cbus_arg)
{
unsigned long i2cbus;
char *end;
i2cbus = strtoul(i2cbus_arg, &end, 0);
if (*end || !*i2cbus_arg) {
/* Not a number, maybe a name? */
return lookup_i2c_bus_by_name(i2cbus_arg);
}
if (i2cbus > 0xFFFFF) {
fprintf(stderr, "Error: I2C bus out of range!\n");
return -2;
}
return i2cbus;
}
/*
* Parse a CHIP-ADDRESS command line argument and return the corresponding
* chip address, or a negative value if the address is invalid.
*/
int parse_i2c_address(const char *address_arg)
{
long address;
char *end;
address = strtol(address_arg, &end, 0);
if (*end || !*address_arg) {
fprintf(stderr, "Error: Chip address is not a number!\n");
return -1;
}
if (address < 0x03 || address > 0x77) {
fprintf(stderr, "Error: Chip address out of range "
"(0x03-0x77)!\n");
return -2;
}
return address;
}
int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet)
{
int file;
snprintf(filename, size, "/dev/i2c/%d", i2cbus);
filename[size - 1] = '\0';
file = open(filename, O_RDWR);
if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) {
sprintf(filename, "/dev/i2c-%d", i2cbus);
file = open(filename, O_RDWR);
}
if (file < 0 && !quiet) {
if (errno == ENOENT) {
fprintf(stderr, "Error: Could not open file "
"`/dev/i2c-%d' or `/dev/i2c/%d': %s\n",
i2cbus, i2cbus, strerror(ENOENT));
} else {
fprintf(stderr, "Error: Could not open file "
"`%s': %s\n", filename, strerror(errno));
if (errno == EACCES)
fprintf(stderr, "Run as root?\n");
}
}
return file;
}
int set_slave_addr(int file, int address, int force)
{
/* With force, let the user read from/write to the registers
even when a driver is also running */
if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) {
fprintf(stderr,
"Error: Could not set address to 0x%02x: %s\n",
address, strerror(errno));
return -errno;
}
return 0;
}

View file

@ -0,0 +1,44 @@
/*
i2cbusses.h - Part of the i2c-tools package
Copyright (C) 2004-2010 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
#ifndef _I2CBUSSES_H
#define _I2CBUSSES_H
#include <unistd.h>
struct i2c_adap {
int nr;
char *name;
const char *funcs;
const char *algo;
};
struct i2c_adap *gather_i2c_busses(void);
void free_adapters(struct i2c_adap *adapters);
int lookup_i2c_bus(const char *i2cbus_arg);
int parse_i2c_address(const char *address_arg);
int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet);
int set_slave_addr(int file, int address, int force);
#define MISSING_FUNC_FMT "Error: Adapter does not have %s capability\n"
#endif

View file

@ -0,0 +1,87 @@
.TH I2CDETECT 8 "April 2008"
.SH NAME
i2cdetect \- detect I2C chips
.SH SYNOPSIS
.B i2cdetect
.RI [ -y ]
.RI [ -a ]
.RI [ -q | -r ]
.I i2cbus
.RI [ "first last" ]
.br
.B i2cdetect
.I -F
.I i2cbus
.br
.B i2cdetect
.I -V
.br
.B i2cdetect
.I -l
.SH DESCRIPTION
i2cdetect is a userspace program to scan an I2C bus for devices. It
outputs a table with the list of detected devices on the specified bus.
\fIi2cbus\fR indicates the number or name of the I2C bus to be scanned, and
should correspond to one of the busses listed by \fIi2cdetect -l\fR.
The optional parameters \fIfirst\fR and \fIlast\fR restrict the scanning
range (default: from 0x03 to 0x77).
.PP
i2cdetect can also be used to query the functionalities of an I2C bus
(see option \fB-F\fP.)
.SH WARNING
This program can confuse your I2C bus, cause data loss and worse!
.SH INTERPRETING THE OUTPUT
Each cell in the output table will contain one of the following symbols:
.IP \(bu "\w'\(bu'u+1n"
"--". The address was probed but no chip answered.
.IP \(bu
"UU". Probing was skipped, because this address is currently in use by
a driver. This strongly suggests that there is a chip at this address.
.IP \(bu
An address number in hexadecimal, e.g. "2d" or "4e". A chip
was found at this address.
.SH OPTIONS
.TP
.B "\-y"
Disable interactive mode. By default, i2cdetect will wait for a confirmation
from the user before messing with the I2C bus. When this flag is used, it
will perform the operation directly. This is mainly meant to be used in
scripts.
.TP
.B "\-a"
Force scanning of non-regular addresses. Not recommended.
.TP
.B "\-q"
Use SMBus "quick write" commands for probing (by default, the command
used is the one believed to be the safest for each address).
Not recommended. This is known to corrupt the Atmel AT24RF08 EEPROM
found on many IBM Thinkpad laptops.
.TP
.B "\-r"
Use SMBus "read byte" commands for probing (by default, the command
used is the one believed to be the safest for each address).
Not recommended. This is known to lock SMBus on various write-only
chips (most notably clock chips at address 0x69).
.TP
.B "\-F"
Display the list of functionalities implemented by the adapter and exit.
.TP
.B "\-V"
Display the version and exit.
.TP
.B "\-l"
Output a list of installed busses.
.SH SEE ALSO
i2cdump(8), sensors-detect(8)
.SH AUTHOR
Frodo Looijaard, Mark D. Studebaker and Jean Delvare
This manual page was originally written by Aurelien Jarno
<aurel32@debian.org>, for the Debian GNU/Linux system.

View file

@ -0,0 +1,357 @@
/*
i2cdetect.c - a user-space program to scan for I2C devices
Copyright (C) 1999-2004 Frodo Looijaard <frodol@dds.nl>, and
Mark D. Studebaker <mdsxyz123@yahoo.com>
Copyright (C) 2004-2010 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include "i2cbusses.h"
#include "../version.h"
#define MODE_AUTO 0
#define MODE_QUICK 1
#define MODE_READ 2
#define MODE_FUNC 3
static void help(void)
{
fprintf(stderr,
"Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]\n"
" i2cdetect -F I2CBUS\n"
" i2cdetect -l\n"
" I2CBUS is an integer or an I2C bus name\n"
" If provided, FIRST and LAST limit the probing range.\n");
}
static int scan_i2c_bus(int file, int mode, int first, int last)
{
int i, j;
int res;
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n");
for (i = 0; i < 128; i += 16) {
printf("%02x: ", i);
for(j = 0; j < 16; j++) {
fflush(stdout);
/* Skip unwanted addresses */
if (i+j < first || i+j > last) {
printf(" ");
continue;
}
/* Set slave address */
if (ioctl(file, I2C_SLAVE, i+j) < 0) {
if (errno == EBUSY) {
printf("UU ");
continue;
} else {
fprintf(stderr, "Error: Could not set "
"address to 0x%02x: %s\n", i+j,
strerror(errno));
return -1;
}
}
/* Probe this address */
switch (mode) {
case MODE_QUICK:
/* This is known to corrupt the Atmel AT24RF08
EEPROM */
res = i2c_smbus_write_quick(file,
I2C_SMBUS_WRITE);
break;
case MODE_READ:
/* This is known to lock SMBus on various
write-only chips (mainly clock chips) */
res = i2c_smbus_read_byte(file);
break;
default:
if ((i+j >= 0x30 && i+j <= 0x37)
|| (i+j >= 0x50 && i+j <= 0x5F))
res = i2c_smbus_read_byte(file);
else
res = i2c_smbus_write_quick(file,
I2C_SMBUS_WRITE);
}
if (res < 0)
printf("-- ");
else
printf("%02x ", i+j);
}
printf("\n");
}
return 0;
}
struct func
{
long value;
const char* name;
};
static const struct func all_func[] = {
{ .value = I2C_FUNC_I2C,
.name = "I2C" },
{ .value = I2C_FUNC_SMBUS_QUICK,
.name = "SMBus Quick Command" },
{ .value = I2C_FUNC_SMBUS_WRITE_BYTE,
.name = "SMBus Send Byte" },
{ .value = I2C_FUNC_SMBUS_READ_BYTE,
.name = "SMBus Receive Byte" },
{ .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
.name = "SMBus Write Byte" },
{ .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
.name = "SMBus Read Byte" },
{ .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
.name = "SMBus Write Word" },
{ .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
.name = "SMBus Read Word" },
{ .value = I2C_FUNC_SMBUS_PROC_CALL,
.name = "SMBus Process Call" },
{ .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
.name = "SMBus Block Write" },
{ .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
.name = "SMBus Block Read" },
{ .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
.name = "SMBus Block Process Call" },
{ .value = I2C_FUNC_SMBUS_PEC,
.name = "SMBus PEC" },
{ .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
.name = "I2C Block Write" },
{ .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
.name = "I2C Block Read" },
{ .value = 0, .name = "" }
};
static void print_functionality(unsigned long funcs)
{
int i;
for (i = 0; all_func[i].value; i++) {
printf("%-32s %s\n", all_func[i].name,
(funcs & all_func[i].value) ? "yes" : "no");
}
}
/*
* Print the installed i2c busses. The format is those of Linux 2.4's
* /proc/bus/i2c for historical compatibility reasons.
*/
static void print_i2c_busses(void)
{
struct i2c_adap *adapters;
int count;
adapters = gather_i2c_busses();
if (adapters == NULL) {
fprintf(stderr, "Error: Out of memory!\n");
return;
}
for (count = 0; adapters[count].name; count++) {
printf("i2c-%d\t%-10s\t%-32s\t%s\n",
adapters[count].nr, adapters[count].funcs,
adapters[count].name, adapters[count].algo);
}
free_adapters(adapters);
}
int main(int argc, char *argv[])
{
char *end;
int i2cbus, file, res;
char filename[20];
unsigned long funcs;
int mode = MODE_AUTO;
int first = 0x03, last = 0x77;
int flags = 0;
int yes = 0, version = 0, list = 0;
/* handle (optional) flags first */
while (1+flags < argc && argv[1+flags][0] == '-') {
switch (argv[1+flags][1]) {
case 'V': version = 1; break;
case 'y': yes = 1; break;
case 'l': list = 1; break;
case 'F':
if (mode != MODE_AUTO && mode != MODE_FUNC) {
fprintf(stderr, "Error: Different modes "
"specified!\n");
exit(1);
}
mode = MODE_FUNC;
break;
case 'r':
if (mode == MODE_QUICK) {
fprintf(stderr, "Error: Different modes "
"specified!\n");
exit(1);
}
mode = MODE_READ;
break;
case 'q':
if (mode == MODE_READ) {
fprintf(stderr, "Error: Different modes "
"specified!\n");
exit(1);
}
mode = MODE_QUICK;
break;
case 'a':
first = 0x00;
last = 0x7F;
break;
default:
fprintf(stderr, "Error: Unsupported option "
"\"%s\"!\n", argv[1+flags]);
help();
exit(1);
}
flags++;
}
if (version) {
fprintf(stderr, "i2cdetect version %s\n", VERSION);
exit(0);
}
if (list) {
print_i2c_busses();
exit(0);
}
if (argc < flags + 2) {
fprintf(stderr, "Error: No i2c-bus specified!\n");
help();
exit(1);
}
i2cbus = lookup_i2c_bus(argv[flags+1]);
if (i2cbus < 0) {
help();
exit(1);
}
/* read address range if present */
if (argc == flags + 4 && mode != MODE_FUNC) {
int tmp;
tmp = strtol(argv[flags+2], &end, 0);
if (*end) {
fprintf(stderr, "Error: FIRST argment not a "
"number!\n");
help();
exit(1);
}
if (tmp < first || tmp > last) {
fprintf(stderr, "Error: FIRST argument out of range "
"(0x%02x-0x%02x)!\n", first, last);
help();
exit(1);
}
first = tmp;
tmp = strtol(argv[flags+3], &end, 0);
if (*end) {
fprintf(stderr, "Error: LAST argment not a "
"number!\n");
help();
exit(1);
}
if (tmp < first || tmp > last) {
fprintf(stderr, "Error: LAST argument out of range "
"(0x%02x-0x%02x)!\n", first, last);
help();
exit(1);
}
last = tmp;
} else if (argc != flags + 2) {
help();
exit(1);
}
file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
if (file < 0) {
exit(1);
}
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
fprintf(stderr, "Error: Could not get the adapter "
"functionality matrix: %s\n", strerror(errno));
close(file);
exit(1);
}
/* Special case, we only list the implemented functionalities */
if (mode == MODE_FUNC) {
close(file);
printf("Functionalities implemented by %s:\n", filename);
print_functionality(funcs);
exit(0);
}
if (mode != MODE_READ && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
fprintf(stderr, "Error: Can't use SMBus Quick Write command "
"on this bus\n");
close(file);
exit(1);
}
if (mode != MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
fprintf(stderr, "Error: Can't use SMBus Read Byte command "
"on this bus\n");
close(file);
exit(1);
}
if (!yes) {
char s[2];
fprintf(stderr, "WARNING! This program can confuse your I2C "
"bus, cause data loss and worse!\n");
fprintf(stderr, "I will probe file %s%s.\n", filename,
mode==MODE_QUICK?" using quick write commands":
mode==MODE_READ?" using read byte commands":"");
fprintf(stderr, "I will probe address range 0x%02x-0x%02x.\n",
first, last);
fprintf(stderr, "Continue? [Y/n] ");
fflush(stderr);
if (!fgets(s, 2, stdin)
|| (s[0] != '\n' && s[0] != 'y' && s[0] != 'Y')) {
fprintf(stderr, "Aborting on user request.\n");
exit(0);
}
}
res = scan_i2c_bus(file, mode, first, last);
close(file);
exit(res?1:0);
}

View file

@ -0,0 +1,84 @@
.TH I2CDUMP 8 "May 2008"
.SH NAME
i2cdump \- examine I2C registers
.SH SYNOPSIS
.B i2cdump
.RB [ -f ]
.RB [ "-r first-last" ]
.RB [ -y ]
.I i2cbus
.I address
.RI [ "mode " [ "bank " [ bankreg ]]]
.br
.B i2cdump
.B -V
.SH DESCRIPTION
i2cdump is a small helper program to examine registers
visible through the I2C bus.
.SH OPTIONS
.TP
.B -V
Display the version and exit.
.TP
.B -f
Force access to the device even if it is already busy. By default, i2cdump
will refuse to access a device which is already under the control of a
kernel driver. Using this flag is dangerous, it can seriously confuse the
kernel driver in question. It can also cause i2cdump to return invalid
results. So use at your own risk and only if you know what you're doing.
.TP
.B -r first-last
Limit the range of registers being accessed. This option is only available
with modes \fBb\fP, \fBw\fP, \fBc\fP and \fBW\fP. For mode \fBW\fP,
\fBfirst\fR must be even and \fBlast\fR must be odd.
.TP
.B -y
Disable interactive mode. By default, i2cdump will wait for a confirmation
from the user before messing with the I2C bus. When this flag is used, it
will perform the operation directly. This is mainly meant to be used in
scripts.
.PP
At least two options must be provided to i2cdump. \fIi2cbus\fR indicates the
number or name of the I2C bus to be scanned. This number should correspond to one
of the busses listed by \fIi2cdetect -l\fR. \fIaddress\fR indicates the
address to be scanned on that bus, and is an integer between 0x03 and 0x77.
.PP
The \fImode\fR parameter, if specified, is one of the letters \fBb\fP, \fBw\fP,
\fBs\fP, or \fBi\fP, corresponding to a read size of a single byte, a 16-bit
word, an SMBus block, an I2C block, respectively. The \fBc\fP mode is a
little different, it reads all bytes consecutively, and is useful for chips that
have an address auto-increment feature, such as EEPROMs. The \fBW\fP mode is
also special, it is similar to \fBw\fP except that a read command will only
be issued on even register addresses; this is again mainly useful for EEPROMs.
.PP
A \fBp\fP can also be appended to the \fImode\fR parameter (except for
\fBi\fP and \fBW\fP) to enable PEC. If the \fImode\fR parameter is omitted,
i2cdump defaults to byte access without PEC.
.PP
The \fIbank\fR and \fIbankreg\fR parameters are useful on the W83781D and
similar chips (at the time of writing, all Winbond and Asus chips).
\fIbank\fR is an integer between 0 and 7, and \fIbankreg\fR is an integer
between 0x00 and 0xFF (default value: 0x4E). The W83781D data sheet has more
information on bank selection.
.SH WARNING
i2cdump can be dangerous if used improperly. Most notably, the \fBc\fP mode
starts with WRITING a byte to the chip. On most chips it will be stored in the
address pointer register, which is OK, but some chips with a single register
or no (visible) register at all will most likely see this as a real WRITE,
resulting in possible misbehavior or corruption. Do not use i2cdump
on random addresses. Anyway, it is of little use unless you have good
knowledge of the chip you're working with and an idea of what you are looking
for.
.SH SEE ALSO
i2cset(8), i2cdetect(8), isadump(8)
.SH AUTHOR
Frodo Looijaard, Mark D. Studebaker and Jean Delvare
This manual page was originally written by David Z Maze <dmaze@debian.org> for
the Debian GNU/Linux system.

View file

@ -0,0 +1,487 @@
/*
i2cdump.c - a user-space program to dump I2C registers
Copyright (C) 2002-2003 Frodo Looijaard <frodol@dds.nl>, and
Mark D. Studebaker <mdsxyz123@yahoo.com>
Copyright (C) 2004-2010 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include "i2cbusses.h"
#include "util.h"
#include "../version.h"
static void help(void)
{
fprintf(stderr,
"Usage: i2cdump [-f] [-y] [-r first-last] I2CBUS ADDRESS [MODE [BANK [BANKREG]]]\n"
" I2CBUS is an integer or an I2C bus name\n"
" ADDRESS is an integer (0x03 - 0x77)\n"
" MODE is one of:\n"
" b (byte, default)\n"
" w (word)\n"
" W (word on even register addresses)\n"
" s (SMBus block)\n"
" i (I2C block)\n"
" c (consecutive byte)\n"
" Append p for SMBus PEC\n");
}
static int check_funcs(int file, int size, int pec)
{
unsigned long funcs;
/* check adapter functionality */
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
fprintf(stderr, "Error: Could not get the adapter "
"functionality matrix: %s\n", strerror(errno));
return -1;
}
switch(size) {
case I2C_SMBUS_BYTE:
if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus receive byte");
return -1;
}
if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
return -1;
}
break;
case I2C_SMBUS_BYTE_DATA:
if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus read byte");
return -1;
}
break;
case I2C_SMBUS_WORD_DATA:
if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus read word");
return -1;
}
break;
case I2C_SMBUS_BLOCK_DATA:
if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus block read");
return -1;
}
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
fprintf(stderr, MISSING_FUNC_FMT, "I2C block read");
return -1;
}
break;
}
if (pec
&& !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
fprintf(stderr, "Warning: Adapter does "
"not seem to support PEC\n");
}
return 0;
}
int main(int argc, char *argv[])
{
char *end;
int i, j, res, i2cbus, address, size, file;
int bank = 0, bankreg = 0x4E, old_bank = 0;
char filename[20];
int block[256], s_length = 0;
int pec = 0, even = 0;
int flags = 0;
int force = 0, yes = 0, version = 0;
const char *range = NULL;
int first = 0x00, last = 0xff;
/* handle (optional) flags first */
while (1+flags < argc && argv[1+flags][0] == '-') {
switch (argv[1+flags][1]) {
case 'V': version = 1; break;
case 'f': force = 1; break;
case 'r': range = argv[1+(++flags)]; break;
case 'y': yes = 1; break;
default:
fprintf(stderr, "Error: Unsupported option "
"\"%s\"!\n", argv[1+flags]);
help();
exit(1);
}
flags++;
}
if (version) {
fprintf(stderr, "i2cdump version %s\n", VERSION);
exit(0);
}
if (argc < flags + 2) {
fprintf(stderr, "Error: No i2c-bus specified!\n");
help();
exit(1);
}
i2cbus = lookup_i2c_bus(argv[flags+1]);
if (i2cbus < 0) {
help();
exit(1);
}
if (argc < flags + 3) {
fprintf(stderr, "Error: No address specified!\n");
help();
exit(1);
}
address = parse_i2c_address(argv[flags+2]);
if (address < 0) {
help();
exit(1);
}
if (argc < flags + 4) {
fprintf(stderr, "No size specified (using byte-data access)\n");
size = I2C_SMBUS_BYTE_DATA;
} else if (!strncmp(argv[flags+3], "b", 1)) {
size = I2C_SMBUS_BYTE_DATA;
pec = argv[flags+3][1] == 'p';
} else if (!strncmp(argv[flags+3], "w", 1)) {
size = I2C_SMBUS_WORD_DATA;
pec = argv[flags+3][1] == 'p';
} else if (!strncmp(argv[flags+3], "W", 1)) {
size = I2C_SMBUS_WORD_DATA;
even = 1;
} else if (!strncmp(argv[flags+3], "s", 1)) {
size = I2C_SMBUS_BLOCK_DATA;
pec = argv[flags+3][1] == 'p';
} else if (!strncmp(argv[flags+3], "c", 1)) {
size = I2C_SMBUS_BYTE;
pec = argv[flags+3][1] == 'p';
} else if (!strcmp(argv[flags+3], "i"))
size = I2C_SMBUS_I2C_BLOCK_DATA;
else {
fprintf(stderr, "Error: Invalid mode!\n");
help();
exit(1);
}
if (argc > flags + 4) {
bank = strtol(argv[flags+4], &end, 0);
if (*end || size == I2C_SMBUS_I2C_BLOCK_DATA) {
fprintf(stderr, "Error: Invalid bank number!\n");
help();
exit(1);
}
if ((size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_WORD_DATA)
&& (bank < 0 || bank > 15)) {
fprintf(stderr, "Error: bank out of range!\n");
help();
exit(1);
}
if (size == I2C_SMBUS_BLOCK_DATA
&& (bank < 0 || bank > 0xff)) {
fprintf(stderr, "Error: block command out of range!\n");
help();
exit(1);
}
if (argc > flags + 5) {
bankreg = strtol(argv[flags+5], &end, 0);
if (*end || size == I2C_SMBUS_BLOCK_DATA) {
fprintf(stderr, "Error: Invalid bank register "
"number!\n");
help();
exit(1);
}
if (bankreg < 0 || bankreg > 0xff) {
fprintf(stderr, "Error: bank out of range "
"(0-0xff)!\n");
help();
exit(1);
}
}
}
/* Parse optional range string */
if (range) {
char *dash;
first = strtol(range, &dash, 0);
if (dash == range || *dash != '-'
|| first < 0 || first > 0xff) {
fprintf(stderr, "Error: Invalid range parameter!\n");
exit(1);
}
last = strtol(++dash, &end, 0);
if (end == dash || *end != '\0'
|| last < first || last > 0xff) {
fprintf(stderr, "Error: Invalid range parameter!\n");
exit(1);
}
/* Check mode constraints */
switch (size) {
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
break;
case I2C_SMBUS_WORD_DATA:
if (!even || (!(first%2) && last%2))
break;
/* Fall through */
default:
fprintf(stderr,
"Error: Range parameter not compatible with selected mode!\n");
exit(1);
}
}
file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
if (file < 0
|| check_funcs(file, size, pec)
|| set_slave_addr(file, address, force))
exit(1);
if (pec) {
if (ioctl(file, I2C_PEC, 1) < 0) {
fprintf(stderr, "Error: Could not set PEC: %s\n",
strerror(errno));
exit(1);
}
}
if (!yes) {
fprintf(stderr, "WARNING! This program can confuse your I2C "
"bus, cause data loss and worse!\n");
fprintf(stderr, "I will probe file %s, address 0x%x, mode "
"%s\n", filename, address,
size == I2C_SMBUS_BLOCK_DATA ? "smbus block" :
size == I2C_SMBUS_I2C_BLOCK_DATA ? "i2c block" :
size == I2C_SMBUS_BYTE ? "byte consecutive read" :
size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
if (pec)
fprintf(stderr, "PEC checking enabled.\n");
if (even)
fprintf(stderr, "Only probing even register "
"addresses.\n");
if (bank) {
if (size == I2C_SMBUS_BLOCK_DATA)
fprintf(stderr, "Using command 0x%02x.\n",
bank);
else
fprintf(stderr, "Probing bank %d using bank "
"register 0x%02x.\n", bank, bankreg);
}
if (range) {
fprintf(stderr,
"Probe range limited to 0x%02x-0x%02x.\n",
first, last);
}
fprintf(stderr, "Continue? [Y/n] ");
fflush(stderr);
if (!user_ack(1)) {
fprintf(stderr, "Aborting on user request.\n");
exit(0);
}
}
/* See Winbond w83781d data sheet for bank details */
if (bank && size != I2C_SMBUS_BLOCK_DATA) {
res = i2c_smbus_read_byte_data(file, bankreg);
if (res >= 0) {
old_bank = res;
res = i2c_smbus_write_byte_data(file, bankreg,
bank | (old_bank & 0xf0));
}
if (res < 0) {
fprintf(stderr, "Error: Bank switching failed\n");
exit(1);
}
}
/* handle all but word data */
if (size != I2C_SMBUS_WORD_DATA || even) {
/* do the block transaction */
if (size == I2C_SMBUS_BLOCK_DATA
|| size == I2C_SMBUS_I2C_BLOCK_DATA) {
unsigned char cblock[288];
if (size == I2C_SMBUS_BLOCK_DATA) {
res = i2c_smbus_read_block_data(file, bank,
cblock);
/* Remember returned block length for a nicer
display later */
s_length = res;
} else {
for (res = 0; res < 256; res += i) {
i = i2c_smbus_read_i2c_block_data(file,
res, 32, cblock + res);
if (i <= 0) {
res = i;
break;
}
}
}
if (res <= 0) {
fprintf(stderr, "Error: Block read failed, "
"return code %d\n", res);
exit(1);
}
if (res >= 256)
res = 256;
for (i = 0; i < res; i++)
block[i] = cblock[i];
if (size != I2C_SMBUS_BLOCK_DATA)
for (i = res; i < 256; i++)
block[i] = -1;
}
if (size == I2C_SMBUS_BYTE) {
res = i2c_smbus_write_byte(file, first);
if(res != 0) {
fprintf(stderr, "Error: Write start address "
"failed, return code %d\n", res);
exit(1);
}
}
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
" 0123456789abcdef\n");
for (i = 0; i < 256; i+=16) {
if (size == I2C_SMBUS_BLOCK_DATA && i >= s_length)
break;
if (i/16 < first/16)
continue;
if (i/16 > last/16)
break;
printf("%02x: ", i);
for (j = 0; j < 16; j++) {
fflush(stdout);
/* Skip unwanted registers */
if (i+j < first || i+j > last) {
printf(" ");
if (size == I2C_SMBUS_WORD_DATA) {
printf(" ");
j++;
}
continue;
}
if (size == I2C_SMBUS_BYTE_DATA) {
block[i+j] = res =
i2c_smbus_read_byte_data(file, i+j);
} else if (size == I2C_SMBUS_WORD_DATA) {
res = i2c_smbus_read_word_data(file,
i+j);
if (res < 0) {
block[i+j] = res;
block[i+j+1] = res;
} else {
block[i+j] = res & 0xff;
block[i+j+1] = res >> 8;
}
} else if (size == I2C_SMBUS_BYTE) {
block[i+j] = res =
i2c_smbus_read_byte(file);
} else
res = block[i+j];
if (size == I2C_SMBUS_BLOCK_DATA
&& i+j >= s_length) {
printf(" ");
} else if (res < 0) {
printf("XX ");
if (size == I2C_SMBUS_WORD_DATA)
printf("XX ");
} else {
printf("%02x ", block[i+j]);
if (size == I2C_SMBUS_WORD_DATA)
printf("%02x ", block[i+j+1]);
}
if (size == I2C_SMBUS_WORD_DATA)
j++;
}
printf(" ");
for (j = 0; j < 16; j++) {
if (size == I2C_SMBUS_BLOCK_DATA
&& i+j >= s_length)
break;
/* Skip unwanted registers */
if (i+j < first || i+j > last) {
printf(" ");
continue;
}
res = block[i+j];
if (res < 0)
printf("X");
else
if ((res & 0xff) == 0x00
|| (res & 0xff) == 0xff)
printf(".");
else
if ((res & 0xff) < 32
|| (res & 0xff) >= 127)
printf("?");
else
printf("%c", res & 0xff);
}
printf("\n");
}
} else {
printf(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f\n");
for (i = 0; i < 256; i+=8) {
if (i/8 < first/8)
continue;
if (i/8 > last/8)
break;
printf("%02x: ", i);
for (j = 0; j < 8; j++) {
/* Skip unwanted registers */
if (i+j < first || i+j > last) {
printf(" ");
continue;
}
res = i2c_smbus_read_word_data(file, i+j);
if (res < 0)
printf("XXXX ");
else
printf("%04x ", res & 0xffff);
}
printf("\n");
}
}
if (bank && size != I2C_SMBUS_BLOCK_DATA) {
i2c_smbus_write_byte_data(file, bankreg, old_bank);
}
exit(0);
}

View file

@ -0,0 +1,68 @@
.TH I2CGET 8 "May 2008"
.SH "NAME"
i2cget \- read from I2C/SMBus chip registers
.SH SYNOPSIS
.B i2cget
.RB [ -f ]
.RB [ -y ]
.I i2cbus
.I chip-address
.RI [ "data-address " [ mode ]]
.br
.B i2cget
.B -V
.SH DESCRIPTION
i2cget is a small helper program to read registers visible through the I2C
bus (or SMBus).
.SH OPTIONS
.TP
.B -V
Display the version and exit.
.TP
.B -f
Force access to the device even if it is already busy. By default, i2cget
will refuse to access a device which is already under the control of a
kernel driver. Using this flag is dangerous, it can seriously confuse the
kernel driver in question. It can also cause i2cget to return an invalid
value. So use at your own risk and only if you know what you're doing.
.TP
.B -y
Disable interactive mode. By default, i2cget will wait for a confirmation
from the user before messing with the I2C bus. When this flag is used, it
will perform the operation directly. This is mainly meant to be used in
scripts. Use with caution.
.PP
There are two required options to i2cget. \fIi2cbus\fR indicates the number
or name of the I2C bus to be scanned. This number should correspond to one of
the busses listed by \fIi2cdetect -l\fR. \fIchip-address\fR specifies the
address of the chip on that bus, and is an integer between 0x03 and 0x77.
.PP
\fIdata-address\fR specifies the address on that chip to read from, and is
an integer between 0x00 and 0xFF. If omitted, the currently active register
will be read (if that makes sense for the considered chip).
.PP
The \fImode\fR parameter, if specified, is one of the letters \fBb\fP,
\fBw\fP or \fBc\fP, corresponding to a read byte data, a read word data or a
write byte/read byte transaction, respectively. A \fBp\fP can also be appended
to the \fImode\fR parameter to enable PEC. If the \fImode\fR parameter is omitted,
i2cget defaults to a read byte data transaction, unless \fIdata-address\fR is
also omitted, in which case the default (and only valid) transaction is a
single read byte.
.SH WARNING
i2cget can be extremely dangerous if used improperly. I2C and SMBus are designed
in such a way that an SMBus read transaction can be seen as a write transaction by
certain chips. This is particularly true if setting \fImode\fR to \fBcp\fP (write byte/read
byte with PEC). Be extremely careful using this program.
.SH SEE ALSO
i2cdump(8), i2cset(8)
.SH AUTHOR
Jean Delvare
This manual page was strongly inspired from those written by David Z Maze
for i2cset.

View file

@ -0,0 +1,256 @@
/*
i2cget.c - A user-space program to read an I2C register.
Copyright (C) 2005-2010 Jean Delvare <khali@linux-fr.org>
Based on i2cset.c:
Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
Mark D. Studebaker <mdsxyz123@yahoo.com>
Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include "i2cbusses.h"
#include "util.h"
#include "../version.h"
static void help(void) __attribute__ ((noreturn));
static void help(void)
{
fprintf(stderr,
"Usage: i2cget [-f] [-y] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]\n"
" I2CBUS is an integer or an I2C bus name\n"
" ADDRESS is an integer (0x03 - 0x77)\n"
" MODE is one of:\n"
" b (read byte data, default)\n"
" w (read word data)\n"
" c (write byte/read byte)\n"
" Append p for SMBus PEC\n");
exit(1);
}
static int check_funcs(int file, int size, int daddress, int pec)
{
unsigned long funcs;
/* check adapter functionality */
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
fprintf(stderr, "Error: Could not get the adapter "
"functionality matrix: %s\n", strerror(errno));
return -1;
}
switch (size) {
case I2C_SMBUS_BYTE:
if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus receive byte");
return -1;
}
if (daddress >= 0
&& !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
return -1;
}
break;
case I2C_SMBUS_BYTE_DATA:
if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus read byte");
return -1;
}
break;
case I2C_SMBUS_WORD_DATA:
if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus read word");
return -1;
}
break;
}
if (pec
&& !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
fprintf(stderr, "Warning: Adapter does "
"not seem to support PEC\n");
}
return 0;
}
static int confirm(const char *filename, int address, int size, int daddress,
int pec)
{
int dont = 0;
fprintf(stderr, "WARNING! This program can confuse your I2C "
"bus, cause data loss and worse!\n");
/* Don't let the user break his/her EEPROMs */
if (address >= 0x50 && address <= 0x57 && pec) {
fprintf(stderr, "STOP! EEPROMs are I2C devices, not "
"SMBus devices. Using PEC\non I2C devices may "
"result in unexpected results, such as\n"
"trashing the contents of EEPROMs. We can't "
"let you do that, sorry.\n");
return 0;
}
if (size == I2C_SMBUS_BYTE && daddress >= 0 && pec) {
fprintf(stderr, "WARNING! All I2C chips and some SMBus chips "
"will interpret a write\nbyte command with PEC as a"
"write byte data command, effectively writing a\n"
"value into a register!\n");
dont++;
}
fprintf(stderr, "I will read from device file %s, chip "
"address 0x%02x, ", filename, address);
if (daddress < 0)
fprintf(stderr, "current data\naddress");
else
fprintf(stderr, "data address\n0x%02x", daddress);
fprintf(stderr, ", using %s.\n",
size == I2C_SMBUS_BYTE ? (daddress < 0 ?
"read byte" : "write byte/read byte") :
size == I2C_SMBUS_BYTE_DATA ? "read byte data" :
"read word data");
if (pec)
fprintf(stderr, "PEC checking enabled.\n");
fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n");
fflush(stderr);
if (!user_ack(!dont)) {
fprintf(stderr, "Aborting on user request.\n");
return 0;
}
return 1;
}
int main(int argc, char *argv[])
{
char *end;
int res, i2cbus, address, size, file;
int daddress;
char filename[20];
int pec = 0;
int flags = 0;
int force = 0, yes = 0, version = 0;
/* handle (optional) flags first */
while (1+flags < argc && argv[1+flags][0] == '-') {
switch (argv[1+flags][1]) {
case 'V': version = 1; break;
case 'f': force = 1; break;
case 'y': yes = 1; break;
default:
fprintf(stderr, "Error: Unsupported option "
"\"%s\"!\n", argv[1+flags]);
help();
exit(1);
}
flags++;
}
if (version) {
fprintf(stderr, "i2cget version %s\n", VERSION);
exit(0);
}
if (argc < flags + 3)
help();
i2cbus = lookup_i2c_bus(argv[flags+1]);
if (i2cbus < 0)
help();
address = parse_i2c_address(argv[flags+2]);
if (address < 0)
help();
if (argc > flags + 3) {
size = I2C_SMBUS_BYTE_DATA;
daddress = strtol(argv[flags+3], &end, 0);
if (*end || daddress < 0 || daddress > 0xff) {
fprintf(stderr, "Error: Data address invalid!\n");
help();
}
} else {
size = I2C_SMBUS_BYTE;
daddress = -1;
}
if (argc > flags + 4) {
switch (argv[flags+4][0]) {
case 'b': size = I2C_SMBUS_BYTE_DATA; break;
case 'w': size = I2C_SMBUS_WORD_DATA; break;
case 'c': size = I2C_SMBUS_BYTE; break;
default:
fprintf(stderr, "Error: Invalid mode!\n");
help();
}
pec = argv[flags+4][1] == 'p';
}
file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
if (file < 0
|| check_funcs(file, size, daddress, pec)
|| set_slave_addr(file, address, force))
exit(1);
if (!yes && !confirm(filename, address, size, daddress, pec))
exit(0);
if (pec && ioctl(file, I2C_PEC, 1) < 0) {
fprintf(stderr, "Error: Could not set PEC: %s\n",
strerror(errno));
close(file);
exit(1);
}
switch (size) {
case I2C_SMBUS_BYTE:
if (daddress >= 0) {
res = i2c_smbus_write_byte(file, daddress);
if (res < 0)
fprintf(stderr, "Warning - write failed\n");
}
res = i2c_smbus_read_byte(file);
break;
case I2C_SMBUS_WORD_DATA:
res = i2c_smbus_read_word_data(file, daddress);
break;
default: /* I2C_SMBUS_BYTE_DATA */
res = i2c_smbus_read_byte_data(file, daddress);
}
close(file);
if (res < 0) {
fprintf(stderr, "Error: Read failed\n");
exit(2);
}
printf("0x%0*x\n", size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
exit(0);
}

View file

@ -0,0 +1,102 @@
.TH I2CSET 8 "November 2008"
.SH "NAME"
i2cset \- set I2C registers
.SH SYNOPSIS
.B i2cset
.RB [ -f ]
.RB [ -y ]
.RB [ "-m mask" ]
.RB [ -r ]
.I i2cbus
.I chip-address
.I data-address
.RI [ value ]
.RI ...
.RI [ mode ]
.br
.B i2cset
.B -V
.SH DESCRIPTION
i2cset is a small helper program to set registers visible through the I2C
bus.
.SH OPTIONS
.TP
.B -V
Display the version and exit.
.TP
.B -f
Force access to the device even if it is already busy. By default, i2cset
will refuse to access a device which is already under the control of a
kernel driver. Using this flag is dangerous, it can seriously confuse the
kernel driver in question. It can also cause i2cset to silently write to
the wrong register. So use at your own risk and only if you know what
you're doing.
.TP
.B -y
Disable interactive mode. By default, i2cset will wait for a confirmation
from the user before messing with the I2C bus. When this flag is used, it
will perform the operation directly. This is mainly meant to be used in
scripts.
.TP
.B -m mask
The \fImask\fR parameter, if specified, describes which bits of \fIvalue\fR
will be actually written to \fIdata-address\fR. Bits set to 1 in the mask
are taken from \fIvalue\fR, while bits set to 0 will be read from
\fIdata-address\fR and thus preserved by the operation. Please note that
this parameter assumes that the read and write operations for the specified
mode are symmetrical for the device you are accessing. This may or may not
be the case, as neither I2C nor SMBus guarantees this.
.TP
.B -r
Read back the value right after writing it, and compare the result with the
value written. This used to be the default behavior. The same limitations
apply as those of option \fB-m\fR.
.PP
There are three required options to i2cset. \fIi2cbus\fR indicates the number
or name of the I2C bus to be scanned. This number should correspond to one of
the busses listed by \fIi2cdetect -l\fR. \fIchip-address\fR specifies the
address of the chip on that bus, and is an integer between 0x03 and 0x77.
\fIdata-address\fR specifies the address on that chip to write to, and is an
integer between 0x00 and 0xFF.
.PP
The \fIvalue\fR parameter, if specified, is the value to write to that
location on the chip. If this parameter is omitted, then a short write is
issued. For most chips, it simply sets an internal pointer to the target
location, but doesn't actually write to that location. For a few chips
though, in particular simple ones with a single register, this short write
is an actual write. If the mode parameter is \fBs\fP or \fBi\fP, multiple
values can be specified.
.PP
The \fImode\fR parameter, if specified, is one of the letters \fBb\fP,
\fBw\fP, \fBs\fP, or \fBi\fP, corresponding to a write size of a single byte,
a 16-bit word, a SMBus block write, or an I2C block write, respectively.
For SMBus and I2C block writes, the write size is determined by the number
of \fIvalue\fR parameters.
Except for I2C block writes, a \fBp\fP can also be appended to the \fImode\fR
parameter to enable PEC.
If the \fImode\fR parameter is omitted, i2cset defaults to byte
mode without PEC. The \fIvalue\fR provided must be within range for the
specified data type (0x00-0xFF for byte and block writes, 0x0000-0xFFFF
for words).
Another possible mode is \fBc\fP, which doesn't write any value (so-called
short write). You usually don't have to specify this mode, as it is the
default when no value is provided, unless you also want to enable PEC.
.SH WARNING
i2cset can be extremely dangerous if used improperly. It can confuse your
I2C bus, cause data loss, or have more serious side effects. Writing to
a serial EEPROM on a memory DIMM (chip addresses between 0x50 and 0x57) may
DESTROY your memory, leaving your system unbootable! Be extremely careful
using this program.
.SH SEE ALSO
i2cdump(8), isaset(8)
.SH AUTHOR
Frodo Looijaard, Mark D. Studebaker and Jean Delvare
This manual page was originally written by David Z Maze <dmaze@debian.org> for
the Debian GNU/Linux system.

View file

@ -0,0 +1,430 @@
/*
i2cset.c - A user-space program to write an I2C register.
Copyright (C) 2001-2003 Frodo Looijaard <frodol@dds.nl>, and
Mark D. Studebaker <mdsxyz123@yahoo.com>
Copyright (C) 2004-2010 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include "i2cbusses.h"
#include "util.h"
#include "../version.h"
static void help(void) __attribute__ ((noreturn));
static void help(void)
{
fprintf(stderr,
"Usage: i2cset [-f] [-y] [-m MASK] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]\n"
" I2CBUS is an integer or an I2C bus name\n"
" ADDRESS is an integer (0x03 - 0x77)\n"
" MODE is one of:\n"
" c (byte, no value)\n"
" b (byte data, default)\n"
" w (word data)\n"
" i (I2C block data)\n"
" s (SMBus block data)\n"
" Append p for SMBus PEC\n");
exit(1);
}
static int check_funcs(int file, int size, int pec)
{
unsigned long funcs;
/* check adapter functionality */
if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
fprintf(stderr, "Error: Could not get the adapter "
"functionality matrix: %s\n", strerror(errno));
return -1;
}
switch (size) {
case I2C_SMBUS_BYTE:
if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
return -1;
}
break;
case I2C_SMBUS_BYTE_DATA:
if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus write byte");
return -1;
}
break;
case I2C_SMBUS_WORD_DATA:
if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus write word");
return -1;
}
break;
case I2C_SMBUS_BLOCK_DATA:
if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)) {
fprintf(stderr, MISSING_FUNC_FMT, "SMBus block write");
return -1;
}
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
fprintf(stderr, MISSING_FUNC_FMT, "I2C block write");
return -1;
}
break;
}
if (pec
&& !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
fprintf(stderr, "Warning: Adapter does "
"not seem to support PEC\n");
}
return 0;
}
static int confirm(const char *filename, int address, int size, int daddress,
int value, int vmask, const unsigned char *block, int len,
int pec)
{
int dont = 0;
fprintf(stderr, "WARNING! This program can confuse your I2C "
"bus, cause data loss and worse!\n");
if (address >= 0x50 && address <= 0x57) {
fprintf(stderr, "DANGEROUS! Writing to a serial "
"EEPROM on a memory DIMM\nmay render your "
"memory USELESS and make your system "
"UNBOOTABLE!\n");
dont++;
}
fprintf(stderr, "I will write to device file %s, chip address "
"0x%02x, data address\n0x%02x, ", filename, address, daddress);
if (size == I2C_SMBUS_BYTE)
fprintf(stderr, "no data.\n");
else if (size == I2C_SMBUS_BLOCK_DATA ||
size == I2C_SMBUS_I2C_BLOCK_DATA) {
int i;
fprintf(stderr, "data");
for (i = 0; i < len; i++)
fprintf(stderr, " 0x%02x", block[i]);
fprintf(stderr, ", mode %s.\n", size == I2C_SMBUS_BLOCK_DATA
? "smbus block" : "i2c block");
} else
fprintf(stderr, "data 0x%02x%s, mode %s.\n", value,
vmask ? " (masked)" : "",
size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
if (pec)
fprintf(stderr, "PEC checking enabled.\n");
fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n");
fflush(stderr);
if (!user_ack(!dont)) {
fprintf(stderr, "Aborting on user request.\n");
return 0;
}
return 1;
}
int main(int argc, char *argv[])
{
char *end;
const char *maskp = NULL;
int res, i2cbus, address, size, file;
int value, daddress, vmask = 0;
char filename[20];
int pec = 0;
int flags = 0;
int force = 0, yes = 0, version = 0, readback = 0;
unsigned char block[I2C_SMBUS_BLOCK_MAX];
int len;
/* handle (optional) flags first */
while (1+flags < argc && argv[1+flags][0] == '-') {
switch (argv[1+flags][1]) {
case 'V': version = 1; break;
case 'f': force = 1; break;
case 'y': yes = 1; break;
case 'm':
if (2+flags < argc)
maskp = argv[2+flags];
flags++;
break;
case 'r': readback = 1; break;
default:
fprintf(stderr, "Error: Unsupported option "
"\"%s\"!\n", argv[1+flags]);
help();
exit(1);
}
flags++;
}
if (version) {
fprintf(stderr, "i2cset version %s\n", VERSION);
exit(0);
}
if (argc < flags + 4)
help();
i2cbus = lookup_i2c_bus(argv[flags+1]);
if (i2cbus < 0)
help();
address = parse_i2c_address(argv[flags+2]);
if (address < 0)
help();
daddress = strtol(argv[flags+3], &end, 0);
if (*end || daddress < 0 || daddress > 0xff) {
fprintf(stderr, "Error: Data address invalid!\n");
help();
}
/* check for command/mode */
if (argc == flags + 4) {
/* Implicit "c" */
size = I2C_SMBUS_BYTE;
} else if (argc == flags + 5) {
/* "c", "cp", or implicit "b" */
if (!strcmp(argv[flags+4], "c")
|| !strcmp(argv[flags+4], "cp")) {
size = I2C_SMBUS_BYTE;
pec = argv[flags+4][1] == 'p';
} else {
size = I2C_SMBUS_BYTE_DATA;
}
} else {
/* All other commands */
if (strlen(argv[argc-1]) > 2
|| (strlen(argv[argc-1]) == 2 && argv[argc-1][1] != 'p')) {
fprintf(stderr, "Error: Invalid mode '%s'!\n", argv[argc-1]);
help();
}
switch (argv[argc-1][0]) {
case 'b': size = I2C_SMBUS_BYTE_DATA; break;
case 'w': size = I2C_SMBUS_WORD_DATA; break;
case 's': size = I2C_SMBUS_BLOCK_DATA; break;
case 'i': size = I2C_SMBUS_I2C_BLOCK_DATA; break;
default:
fprintf(stderr, "Error: Invalid mode '%s'!\n", argv[argc-1]);
help();
}
pec = argv[argc-1][1] == 'p';
if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_I2C_BLOCK_DATA) {
if (pec && size == I2C_SMBUS_I2C_BLOCK_DATA) {
fprintf(stderr, "Error: PEC not supported for I2C block writes!\n");
help();
}
if (maskp) {
fprintf(stderr, "Error: Mask not supported for block writes!\n");
help();
}
if (argc > (int)sizeof(block) + flags + 5) {
fprintf(stderr, "Error: Too many arguments!\n");
help();
}
} else if (argc != flags + 6) {
fprintf(stderr, "Error: Too many arguments!\n");
help();
}
}
len = 0; /* Must always initialize len since it is passed to confirm() */
/* read values from command line */
switch (size) {
case I2C_SMBUS_BYTE_DATA:
case I2C_SMBUS_WORD_DATA:
value = strtol(argv[flags+4], &end, 0);
if (*end || value < 0) {
fprintf(stderr, "Error: Data value invalid!\n");
help();
}
if ((size == I2C_SMBUS_BYTE_DATA && value > 0xff)
|| (size == I2C_SMBUS_WORD_DATA && value > 0xffff)) {
fprintf(stderr, "Error: Data value out of range!\n");
help();
}
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_I2C_BLOCK_DATA:
for (len = 0; len + flags + 5 < argc; len++) {
value = strtol(argv[flags + len + 4], &end, 0);
if (*end || value < 0) {
fprintf(stderr, "Error: Data value invalid!\n");
help();
}
if (value > 0xff) {
fprintf(stderr, "Error: Data value out of range!\n");
help();
}
block[len] = value;
}
value = -1;
break;
default:
value = -1;
break;
}
if (maskp) {
vmask = strtol(maskp, &end, 0);
if (*end || vmask == 0) {
fprintf(stderr, "Error: Data value mask invalid!\n");
help();
}
if (((size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA)
&& vmask > 0xff) || vmask > 0xffff) {
fprintf(stderr, "Error: Data value mask out of range!\n");
help();
}
}
file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
if (file < 0
|| check_funcs(file, size, pec)
|| set_slave_addr(file, address, force))
exit(1);
if (!yes && !confirm(filename, address, size, daddress,
value, vmask, block, len, pec))
exit(0);
if (vmask) {
int oldvalue;
switch (size) {
case I2C_SMBUS_BYTE:
oldvalue = i2c_smbus_read_byte(file);
break;
case I2C_SMBUS_WORD_DATA:
oldvalue = i2c_smbus_read_word_data(file, daddress);
break;
default:
oldvalue = i2c_smbus_read_byte_data(file, daddress);
}
if (oldvalue < 0) {
fprintf(stderr, "Error: Failed to read old value\n");
exit(1);
}
value = (value & vmask) | (oldvalue & ~vmask);
if (!yes) {
fprintf(stderr, "Old value 0x%0*x, write mask "
"0x%0*x: Will write 0x%0*x to register "
"0x%02x\n",
size == I2C_SMBUS_WORD_DATA ? 4 : 2, oldvalue,
size == I2C_SMBUS_WORD_DATA ? 4 : 2, vmask,
size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
daddress);
fprintf(stderr, "Continue? [Y/n] ");
fflush(stderr);
if (!user_ack(1)) {
fprintf(stderr, "Aborting on user request.\n");
exit(0);
}
}
}
if (pec && ioctl(file, I2C_PEC, 1) < 0) {
fprintf(stderr, "Error: Could not set PEC: %s\n",
strerror(errno));
close(file);
exit(1);
}
switch (size) {
case I2C_SMBUS_BYTE:
res = i2c_smbus_write_byte(file, daddress);
break;
case I2C_SMBUS_WORD_DATA:
res = i2c_smbus_write_word_data(file, daddress, value);
break;
case I2C_SMBUS_BLOCK_DATA:
res = i2c_smbus_write_block_data(file, daddress, len, block);
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
res = i2c_smbus_write_i2c_block_data(file, daddress, len, block);
break;
default: /* I2C_SMBUS_BYTE_DATA */
res = i2c_smbus_write_byte_data(file, daddress, value);
break;
}
if (res < 0) {
fprintf(stderr, "Error: Write failed\n");
close(file);
exit(1);
}
if (pec) {
if (ioctl(file, I2C_PEC, 0) < 0) {
fprintf(stderr, "Error: Could not clear PEC: %s\n",
strerror(errno));
close(file);
exit(1);
}
}
if (!readback) { /* We're done */
close(file);
exit(0);
}
switch (size) {
case I2C_SMBUS_BYTE:
res = i2c_smbus_read_byte(file);
value = daddress;
break;
case I2C_SMBUS_WORD_DATA:
res = i2c_smbus_read_word_data(file, daddress);
break;
default: /* I2C_SMBUS_BYTE_DATA */
res = i2c_smbus_read_byte_data(file, daddress);
}
close(file);
if (res < 0) {
printf("Warning - readback failed\n");
} else
if (res != value) {
printf("Warning - data mismatch - wrote "
"0x%0*x, read back 0x%0*x\n",
size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
} else {
printf("Value 0x%0*x written, readback matched\n",
size == I2C_SMBUS_WORD_DATA ? 4 : 2, value);
}
exit(0);
}

View file

@ -0,0 +1,58 @@
/*
util.c - helper functions
Copyright (C) 2006 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
#include <stdio.h>
#include "util.h"
/* Return 1 if we should continue, 0 if we should abort */
int user_ack(int def)
{
char s[2];
int ret;
if (!fgets(s, 2, stdin))
return 0; /* Nack by default */
switch (s[0]) {
case 'y':
case 'Y':
ret = 1;
break;
case 'n':
case 'N':
ret = 0;
break;
default:
ret = def;
}
/* Flush extra characters */
while (s[0] != '\n') {
int c = fgetc(stdin);
if (c == EOF) {
ret = 0;
break;
}
s[0] = c;
}
return ret;
}

View file

@ -0,0 +1,26 @@
/*
util - helper functions
Copyright (C) 2006 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA.
*/
#ifndef _UTIL_H
#define _UTIL_H
extern int user_ack(int def);
#endif /* _UTIL_H */

View file

@ -0,0 +1 @@
#define VERSION "3.1.0"

98
Script/install.sh Normal file
View file

@ -0,0 +1,98 @@
#! /bin/bash
PIHOME=/home/pi
DEXTERSCRIPT=$PIHOME/Dexter/lib/Dexter/script_tools
USER_ID=$(/usr/bin/id -u)
USER_NAME=$(/usr/bin/who am i | awk '{ print $1 }')
SCRIPT_PATH=$(/usr/bin/realpath $0)
DIR_PATH=$(/usr/bin/dirname ${SCRIPT_PATH} | sed 's/\/Script$//')
REPO_PATH=$(readlink -f $(dirname $0) | grep -E -o "^(.*?\\GrovePi)")
source $DEXTERSCRIPT/functions_library.sh
display_welcome_msg() {
echo "Special thanks to Joe Sanford at Tufts University. This script was derived from his work. Thank you Joe!"
}
check_root_user() {
if [[ $EUID -ne 0 ]]; then
feedback "FAIL! This script must be run as such: sudo ./install.sh"
exit 1
fi
}
compatible_with_pi4() {
BOARDVERSION=$(cat /proc/device-tree/model | awk '{ print $3 }')
BOOT_CONFIG="/boot/config.txt"
if [ "${BOARDVERSION}" -eq '4' ]; then
if grep -q "gpio=8=op,dh" ${BOOT_CONFIG}; then
echo "Pi4 already configured"
else
echo "gpio=8=op,dh" >> /boot/config.txt
fi
fi
}
install_spi_i2c() {
RASPI_BL="/etc/modprobe.d/raspi-blacklist.conf.bak"
MODS="i2c spi"
if [ -f ${RASPI_BL} ]; then
feedback "Removing blacklist from ${RASPI_BL} . . ."
for i in ${MODS}
do
MOD_NAME=$(echo $i | tr [a-z] [A-Z])
sudo sed -i -e "s/blacklist ${i}-bcm2708/#blacklist ${i}-bcm2708/g" ${RASPI_BL}
echo "${MOD_NAME} not present or removed from blacklist"
done
fi
#Adding in /etc/modules
feedback "Adding I2C-dev and SPI-dev in /etc/modules . . ."
if grep -q "i2c-dev" /etc/modules; then
echo "I2C-dev already present"
else
echo i2c-dev >> /etc/modules
echo "I2C-dev added"
fi
if grep -q "i2c-bcm2708" /etc/modules; then
echo "i2c-bcm2708 already present"
else
echo i2c-bcm2708 >> /etc/modules
echo "i2c-bcm2708 added"
fi
if grep -q "spi-dev" /etc/modules; then
echo "spi-dev already present"
else
echo spi-dev >> /etc/modules
echo "spi-dev added"
fi
feedback "Making I2C changes in /boot/config.txt . . ."
BOOT_CONFIG="/boot/config.txt"
DTPARAMS="i2c1 i2c_arm"
for i in ${DTPARAMS}
do
if grep -q "^dtparam=${i}=on$" ${BOOT_CONFIG}; then
echo "${i} already present"
else
echo "dtparam=${i}=on" >> /boot/config.txt
fi
done
sudo adduser ${USER_NAME} i2c
sudo chmod +x ${DIR_PATH}/Software/Scratch/GrovePi_Scratch_Scripts/*.sh
}
#install_avr() {
# feedback "Installing avrdude for the GrovePi"
# source $DEXTERSCRIPT/install_avrdude.sh
# create_avrdude_folder
# install_avrdude
# cd $ROBOT_DIR
# echo "done with AVRDUDE for the GrovePi"
#}
display_welcome_msg
check_root_user
compatible_with_pi4
install_spi_i2c
install_avr

112
Script/install_scratch.sh Normal file
View file

@ -0,0 +1,112 @@
echo "This script will install Scratch for GrovePi+ on a standard Stretch Raspbian"
PIHOME=/home/pi
RASPBIAN=$PIHOME/di_update/Raspbian_For_Robots
DEXTER=Dexter
ROBOT_FOLDER=GrovePi
LIB=lib
LIB_PATH=$PIHOME/$DEXTER/$LIB
DEXTERLIB_PATH=$LIB_PATH/$DEXTER
SCRATCH=Scratch_GUI
SCRATCH_PATH=$DEXTERLIB_PATH/$SCRATCH
RFR_TOOLS_PATH=$LIB_PATH/$DEXTER/RFR_Tools
# let's test for the presence of ~/Dexter/lib/Dexter as a sign that all tools are
# pre-installed
if [ ! -d "$DEXTERLIB_PATH" ]
then
echo "Installation issues. Please install GrovePi first."
echo "curl -kL dexterindustries.com/update_grovepi | bash"
exit 1
fi
if [ ! -d "$RFR_TOOLS_PATH" ]
then
echo "Installation issues. Please install GrovePi first."
echo "curl -kL dexterindustries.com/update_grovepi | bash"
exit 2
fi
if [ ! -d "$PIHOME/$DEXTER/$ROBOT_FOLDER" ]
then
echo "Installation issues. Please install GrovePi first."
echo "curl -kL dexterindustries.com/update_grovepi | bash"
exit 3
fi
source $DEXTERLIB_PATH/script_tools/functions_library.sh
# feedback "Installing some libraries"
# sudo apt-get install python-smbus python3-smbus
setup_modules_and_config(){
feedback "activating I2C"
sudo sed -i "/i2c-dev/d" /etc/modules
sudo echo "i2c-dev" >> /etc/modules
sudo sed -i "/dtparam=i2c_arm=on/d" /boot/config.txt
sudo echo "dtparam=i2c_arm=on" >> /boot/config.txt
}
install_scratchpy() {
# installing scratch_controller
pushd $LIB_PATH > /dev/null
delete_folder scratchpy
git clone --depth=1 https://github.com/DexterInd/scratchpy
cd scratchpy
sudo make install > /dev/null
popd > /dev/null
}
# Copy shortcut to desktop.
install_desktop_icons() {
feedback "Installing Scratch on the desktop"
if [ -f "/usr/bin/scratch" ]
then
echo "Installing support for Scratch 1.4"
echo $RFR_TOOLS_PATH/Scratch_GUI/Scratch_Start.desktop
sudo cp $RFR_TOOLS_PATH/Scratch_GUI/Scratch_Start.desktop /home/pi/Desktop/Scratch_Start.desktop
else
echo "scratch not found"
fi
if [ -f "/usr/bin/scratch2" ]
then
echo "Installing support for Scratch 2"
pushd $PIHOME/$DEXTER/$ROBOT_FOLDER/Software/Scratch/s2pifiles > /dev/null
sudo cp extensions.json /usr/lib/scratch2/scratch_extensions/extensions.json
sudo cp piGrovePiExtension.js /usr/lib/scratch2/scratch_extensions/piGrovePiExtension.js
sudo cp grovepi.html /usr/lib/scratch2/scratch_extensions/grovepi.html
sudo cp -u grovepi.png /usr/lib/scratch2/medialibrarythumbnails/grovepi.png
popd > /dev/null
sudo cp $PIHOME/$DEXTER/$ROBOT_FOLDER/Software/Scratch/Local_Scratch2_Start.desktop /home/pi/Desktop/Local_Scratch2_Start.desktop
fi
# Desktop shortcut permissions.
sudo chmod +x $PIHOME/Desktop/*.desktop
}
feedback "Installing Scratch Environment"
setup_modules_and_config
install_scratchpy
sudo rm -r $DEXTERLIB_PATH/$SCRATCH
mkdir -p $DEXTERLIB_PATH/$SCRATCH
cp -r $RFR_TOOLS_PATH/$SCRATCH $DEXTERLIB_PATH/
install_desktop_icons
# Make select_state, error_log, nohup.out readable and writable
sudo echo "GrovePi" >> $SCRATCH_PATH/selected_state
sudo touch $SCRATCH_PATH/error_log
sudo chmod 666 $SCRATCH_PATH/selected_state
sudo chmod 666 $SCRATCH_PATH/error_log
sudo cp $PIHOME/$DEXTER/$ROBOT_FOLDER/Software/Scratch/new.sb $PIHOME/$DEXTER/$LIB/$DEXTER/$SCRATCH/new.sb
# transferring Scratch examples into proper Scratch folder
sudo rm /usr/share/scratch/Projects/$ROBOT_FOLDER 2> /dev/null
sudo ln -s $PIHOME/$DEXTER/$ROBOT_FOLDER/Software/Scratch/Examples /usr/share/scratch/Projects/$ROBOT_FOLDER 2> /dev/null
feedback "You now have a Scratch icon on your desktop. Double clicking it will start Scratch with all the necessary configuration to control your GrovePi+"
feedback "Please note that you cannot use Scratch from the menu or double click on a Scratch file to control your robot."

View file

@ -0,0 +1,9 @@
## **Using Multiple GrovePi**
The instructions for using multiple GrovePi's can be found here: http://www.dexterindustries.com/GrovePi/engineering/using-multiple-grovepis-together/
### Getting Help
Need help? We [have a forum here where you can ask questions or make suggestions](http://www.google.com/url?q=http%3A%2F%2Fwww.dexterindustries.com%2FGrovePi%2Fprojects-for-the-raspberry-pi%2F&sa=D&sntz=1&usg=AFQjCNGoiMlC8E9az6mCY2piHsVCl984xg).
These files have been made available online through a [Creative Commons Attribution-ShareAlike 3.0](http://creativecommons.org/licenses/by-sa/3.0/) license.
See more at the [GrovePi Site](http://dexterindustries.com/GrovePi/)

View file

@ -0,0 +1,864 @@
:100000000C9463000C948B000C948B000C948B006C
:100010000C948B000C948B000C948B000C948B0034
:100020000C948B000C948B000C948B000C948B0024
:100030000C948B000C948B000C948B000C948B0014
:100040000C94D1130C948B000C94D3150C940F16B4
:100050000C948B000C948B000C948B000C948B00F4
:100060000C94C1100C948B000000000700020100EA
:100070000003040600000000000000000102040864
:100080001020408001020408102001020408102002
:10009000040404040404040402020202020203032E
:1000A00003030303000000002300260029000000D2
:1000B0000000250028002B0000000000240027007D
:1000C0002A00D00FC41611241FBECFEFD8E0DEBF28
:1000D000CDBF11E0A0E0B1E0ECE9F5E302C005908E
:1000E0000D92A035B107D9F713E0A0E5B1E001C04A
:1000F0001D92AF35B107E1F710E0C6ECD0E004C0C7
:100100002297FE010E945119C23CD107C9F70E94F3
:100110002A150C94CC1A0C940000CF93DF93EC01B9
:1001200060E088810E94D51284E190E00E947D14F5
:1001300061E088810E94D51284E190E0DF91CF9147
:100140000C947D140F931F93CF93DF93EC01062F34
:1001500018E007FF02C061E001C060E089810E94F1
:10016000D512CE010E948D00000F115091F7DF9142
:10017000CF911F910F910895EF92FF921F93CF930C
:10018000DF9300D0CDB7DEB77C01162F27FF02C06A
:1001900060EC01C060EE26FF606147FF686046FFCB
:1001A000646017FF626016FF6160C70129834A839C
:1001B0000E94A2002981622FC7010E94A2004A81E9
:1001C000642FC7010E94A200612FC7010F900F90FA
:1001D000DF91CF911F91FF90EF900C94A2007F923E
:1001E0008F929F92AF92BF92CF92DF92EF92FF9247
:1001F0000F931F93CF93DF93EC01162F942E822E33
:1002000060E00E94A20060E0CE010E94A20060E0D7
:10021000CE010E94A20060E0CE010E94A20083E015
:10022000189F7001112467018FEFC81AD80A57016F
:1002300082E0A80EB11C712C1FC071120FC0EB819F
:10024000FC81EE0DFF1D9082EB81FC81EC0DFD1D0C
:100250008082EB81FC81EA0DFB1D0083EB81FC8138
:1002600083E0789EE00DF11D11242281418160819F
:10027000CE010E94BC0073948A817816F0F260E08F
:10028000CE010E94A20060E0CE010E94A20060E0C8
:10029000CE010E94A20060E0CE01DF91CF911F91BC
:1002A0000F91FF90EF90DF90CF90BF90AF909F9015
:1002B0008F907F900C94A2000F931F93CF93DF93A6
:1002C000EC01862F688349832A8361E00E949D1296
:1002D00061E089810E949D128A8161E070E023E0E3
:1002E000829FC00111240E9455198B839C8310E0CA
:1002F00008C000E020E040E0612FCE010E94EF0046
:100300001F5F8A811817A8F3DF91CF911F910F917A
:100310000895FC018281089587EE91E00C94750F99
:10032000CF93DF93EC0168E670E087EE91E00E94E6
:10033000AE0F60E087EE91E00E94350F87EE91E00E
:100340000E94C30F47E050E068E670E087EE91E05E
:100350000E94A10F87EE91E00E94B30E382F3695D0
:10036000369536953E70232F220F220F230F8F7064
:100370009927280F288387EE91E00E94B30E282F3B
:1003800022952F708F7099273AE0239F800D1124BA
:10039000898387EE91E00E94B30E382F369536950B
:1003A00036953670232F220F220F230F8F70992737
:1003B000280F2A8387EE91E00E94B30E282F229502
:1003C0002F708F7099273AE0239F800D11248B8323
:1003D00087EE91E00E94B30E282F22952F708F7028
:1003E00099273AE0239F800D11248C8387EE91E0BA
:1003F0000E94B30E282F22952F708F7099273AE014
:10040000239F800D11248D8387EE91E00E94B30E0F
:10041000282F22952F708F7099273AE0239F800D07
:1004200011248E831F82DF91CF910895CF93DF93A4
:10043000EC01862F688319824A831B822C831E82DB
:100440001D8261E00E949D1261E08A81DF91CF915F
:100450000C949D121F93CF93DF93EC0160E08A818F
:100460000E94D5128AE090E00E947D1414E061E0C1
:100470008A810E94D51260E08A810E94D5121150B3
:10048000B1F7DF91CF911F910895FF920F931F93C2
:10049000CF93DF93EC018B0190E1F92E612F661F62
:1004A0006627661F8A810E94D51288810E940C13DC
:1004B00061E0892B09F060E088810E94D512000F6D
:1004C000111FFA9459F7DF91CF911F910F91FF906F
:1004D0000895EF92FF920F931F93CF93DF93EC0158
:1004E0007B01CB0193709E838D8360E070E0CE0131
:1004F0000E94450200E010E08C81882351F0C70182
:10050000002E02C0880F991F0A94E2F791FF0DC0D8
:1005100009C0C701002E02C0969587950A94E2F79C
:1005200080FF03C06FEF70E002C060E070E0CE01BA
:100530000E9445020F5F1F4F0A301105E9F660E087
:1005400070E0CE010E94450260E070E0CE010E94A2
:100550004502CE01DF91CF911F910F91FF90EF9057
:100560000C942A02662321F06B3018F06AE001C077
:1005700061E0262F215061E070E002C0660F771F16
:100580002A95E2F7FC01258136816227732776835D
:1005900065830C946902662321F06B3018F06AE0E1
:1005A00001C061E0562F5150FC012581368161E088
:1005B00070E002C0660F771F5A95E2F7442319F0E6
:1005C000622B732B04C06095709562237323FC012A
:1005D000768365830C9469026B3008F06AE02FEF34
:1005E0003FEF02C0220F331F6A95E2F72095309546
:1005F000FC0136832583B9010C946902FC016483F4
:10060000658176810C946902FC018581968108954B
:10061000FC0181E020813181232B09F480E00895E1
:10062000CF93DF93EC01862F6883498360E00E94BB
:100630009D1260E089810E949D1260E088810E9485
:10064000D51260E08981DF91CF910C94D51268308A
:1006500010F4685F01C06FE0FC016283089561E0FF
:10066000FC0181810E949D1282E390E00C947D1434
:10067000CF93DF93EC0161E089810E949D1282E3B8
:1006800090E00E947D1460E088810E949D1282E3C8
:1006900090E00E947D1460E089810E949D1282E3B7
:1006A00090E0DF91CF910C947D140F931F93CF9323
:1006B000DF93EC01062F18E061E088810E949D1213
:1006C00082E390E00E947D1400FF02C060E001C060
:1006D00061E089810E949D1282E390E00E947D1476
:1006E00060E088810E949D1282E390E00E947D1468
:1006F0000695115009F761E088810E949D1260E023
:1007000089810E949D1282E390E00E947D1460E046
:1007100088810E949D1282E390E00E947D1489816D
:100720000E940C13182F811104C061E089810E947E
:100730009D1282E390E00E947D1461E088810E9416
:100740009D1282E390E00E947D1481E0111101C0AE
:1007500080E0DF91CF911F910F910895CF92DF92AA
:10076000EF92FF920F931F93CF93DF9300D0CDB7FB
:10077000DEB76C01F62EE42E29837A830E942F03C4
:1007800060E4C6010E945503C6010E943803C601F9
:100790000E942F032981622F63706054C6010E945A
:1007A00055030F2D7A81172F06C0F80161918F0133
:1007B000C6010E945503802F8F198E15B0F3C60114
:1007C0000E943803C6010E942F03F601628160581F
:1007D000C6010E945503C6010F900F90DF91CF9183
:1007E0001F910F91FF90EF90DF90CF900C94380302
:1007F0004F925F926F927F928F929F92AF92BF9231
:10080000CF92DF92EF920F931F93CF93DF9300D09D
:1008100000D0CDB7DEB73C016B01322F202F8FE027
:10082000A82E81E0B82E88248394912C8C0E9D1ED6
:10083000F40101E01FE3D5015E904E905D01C60119
:10084000B2010E94DD186115710561F4411106C005
:10085000002321F08E2F8819833011F4108313C0E8
:10086000108211C0DB01AF70BB27A15FBE4F8C911E
:100870008083649DC001659D900D749D900D112431
:10088000C81AD90A00E0EE2039F08E2F881981307D
:1008900019F48081806880833196B7E0AB16B1E0AF
:1008A000BB0649F684E090E0831B9109BE016F5FAF
:1008B0007F4F680F791F432FC3010E94AE030F9033
:1008C0000F900F900F90DF91CF911F910F91EF90AC
:1008D000DF90CF90BF90AF909F908F907F906F9060
:1008E0005F904F9008956F70E62FF0E0E15FFE4F4C
:1008F00080810895FC0181E09081911101C080E028
:1009000008951F93CF93DF931F92CDB7DEB7162FB5
:1009100087EE91E049830E94750F6CE470E087EEEA
:1009200091E00E94AE0F612F87EE91E00E94350F9B
:100930004981642F87EE91E00E94350F87EE91E0A8
:100940000F90DF91CF911F910C94C30F462F67E05A
:100950000C948104462F68E00C948104CF93DF93BC
:10096000EC0160E00E94A60460E0CE010E94AA04AF
:1009700061E0CE01DF91CF910C94A6044F925F927B
:100980006F927F928F929F92AF92BF92CF92DF929F
:10099000EF92FF920F931F93CF93DF9300D01F929C
:1009A000CDB7DEB75B016A01790180E48B838A836E
:1009B00089830E941B142B013C010DC00E941B1453
:1009C0006419750986099709653F7140810591058C
:1009D00014F080E06EC087EE91E00E94AA0E181617
:1009E000190664F387EE91E00E94B30E43E050E0F5
:1009F0006CE470E087EE91E00E94A10F0E941B144E
:100A00002B013C018E010F5F1F4F48012DC0C80113
:100A1000881999090397D4F40E941B142B013C01F7
:100A200011C087EE91E00E94B30EF80180830E940E
:100A30001B146419750986099709633371058105CB
:100A400091053CF6F8018081803458F70E941B1410
:100A50000F5F1F4F6419750986099709653F71403B
:100A6000810591050CF0B5CF87EE91E00E94AA0EAA
:100A7000892B69F69981892F880F880F95FD8D5FE5
:100A800085958595F50180839A81892F880F880F38
:100A900095FD8D5F85958595F60180839B81892FD6
:100AA000880F880F95FD8D5F85958595F70180836B
:100AB00081E00F900F900F90DF91CF911F910F91D8
:100AC000FF90EF90DF90CF90BF90AF909F908F906E
:100AD0007F906F905F904F900895CF93DF93EC01DC
:100AE000862F6E834F83288791E09D8760E00E9468
:100AF0009D1261E08E810E94D51219861A861B868E
:100B00001C86DF91CF910895DF92EF92FF920F93B1
:100B10001F93CF93DF93EC0161E08E810E94D51289
:100B20006AEF70E080E090E00E9457140E941B146E
:100B300009851A852B853C85601771078207930705
:100B400020F419861A861B861C862D85211111C05A
:100B500009851A852B853C85DC01CB01801B910B17
:100B6000A20BB30B803D9740A105B10510F481E0C5
:100B700073C01D860E941B1469877A878B879C87A8
:100B80001C821B821A821982188261E08E810E9467
:100B90009D1260E08E810E94D51264E170E080E0D9
:100BA00090E00E945714F89461E08E810E94D51263
:100BB00088E290E00E947D1460E08E810E949D1288
:100BC000F12CD12C81E009C0E39481E090E00E94F7
:100BD0007D148FEFE81204C009C0E12C082F10E04B
:100BE0008E810E940C138017910771F38E810E94F1
:100BF0000C139FEFE916C9F023E02F1590F4F0FCD9
:100C000010C09D2D969596959695FE01E90FF11DC4
:100C10009081990F908328852E1510F49160908310
:100C2000D394F39495E5F912D8CF789427E22D1553
:100C300090F42C8130E04881898190E0840F911DEF
:100C40004A81840F911D4B81840F911D992728178C
:100C5000390709F48CCF80E0DF91CF911F910F917C
:100C6000FF90EF90DF900895EF92FF920F931F9304
:100C7000CF93DF93EC010E948405882391F18F814B
:100C80008B3029F070F18551823058F507C06881AA
:100C900070E080E090E00E94E1172DC0688170E074
:100CA00080E090E00E94E11720E030E040E853E46B
:100CB0000E946F187B018C01698170E080E090E0F8
:100CC0000E94E3179B01AC016E2D7F2D802F912F89
:100CD0000E94151720E030E040E251E40E947917AD
:100CE0000AC06FE171E084EB92E00E94F71460E0CB
:100CF00070E080EC9FE7DF91CF911F910F91FF9003
:100D0000EF900895CF92DF92EF92FF920F931F938F
:100D1000CF93DF938C01C62F0E948405882309F4AA
:100D200077C0F80187818B3039F008F471C08551A4
:100D3000823008F06DC01DC0F801628170E080E073
:100D400090E00E94E117B62FA72FF82FE92F462F2A
:100D5000572F682F792FCB01BA01CC2309F462C039
:100D600020E030E040E151E46B2F7A2F8F2F9E2F4F
:100D700037C0F801D2816D2F6F7770E080E090E08E
:100D80000E94E31720E030E040E853E40E946F182F
:100D90006B017C01F801638170E080E090E00E94CB
:100DA000E3179B01AC016C2D7D2D8E2D9F2D0E9494
:100DB000151720E030E040E251E40E947917472FF8
:100DC000382F292F862F942FA32FB22FBC01CD01AE
:100DD000D7FD9058CC2331F120E030E040E151E4E0
:100DE0000E946F1820E030E040EA50E40E9479173A
:100DF00020E030E040E052E40E941517472F382FE2
:100E0000292F862F942FA32FB22FBC01CD010AC00A
:100E10006FE171E084EB92E00E94F71460E070E013
:100E200080EC9FE7DF91CF911F910F91FF90EF90A2
:100E3000DF90CF900895CF93DF9322C087EE91E0AB
:100E40000E94AA0E049741F4109269011092680161
:100E500010926B0110926A01C0916A01D0916B01EE
:100E600087EE91E00E94B30EFE01EE0FFF1FE459E2
:100E7000FE4F918380832196D0936B01C0936A01CA
:100E800087EE91E00E94AA0E892BC1F6DF91CF91E7
:100E9000089580916C0190916D01019731F46091FA
:100EA000670187EE91E00E94350F80916C0190916F
:100EB0006D018330910529F08730910511F0C897B5
:100EC00041F443E050E06EE571E087EE91E00E946E
:100ED000070F80916C0190916D018830910511F0A0
:100EE000449741F444E050E06EE571E087EE91E014
:100EF0000E94070F80916C0190916D018E319105D8
:100F000011F0889741F449E050E06EE571E087EE1A
:100F100091E00C94070F089540E855E260E070E01E
:100F200084EB92E00E944A1663E070E087EE91E065
:100F30000E94920F6BE177E087EE91E00E94C60F6E
:100F400069E477E087EE91E00E94CB0F69E271E0FF
:100F500084EB92E00C941615AF92BF92CF92DF9281
:100F6000EF92FF920F931F93CF93DF93CDB7DEB72E
:100F70002C970FB6F894DEBF0FBECDBF80916A01EB
:100F800090916B01049709F0D4C68091680190910B
:100F90006901892B09F0CDC681E090E09093690149
:100FA0008093680180916C0190916D01019731F4FB
:100FB00080916E010E940C138093670180916C01F7
:100FC00090916D01029731F46091700180916E01F2
:100FD0000E94D51280916C0190916D010397A9F444
:100FE00080916E010E94F11190935D0180935C01EC
:100FF0009C0197FF02C021503F4F30935F0160E09A
:1010000071E00E94DD188093600180916C019091E5
:101010006D01049741F460917001709171018091AC
:101020006E010E94121280916C0190916D010597E2
:1010300031F46091700180916E010E949D12809147
:101040006C0190916D01079709F042C080916E018B
:1010500090916F01809352019093530161E00E943F
:101060009D1260E0809152010E94D51282E090E0D2
:101070000E947D1461E0809152010E94D51285E0AA
:1010800090E00E947D1460E0809152010E94D51290
:1010900060E0809152010E949D1220E432E44FE012
:1010A00050E061E0809152010E9435132AE330E064
:1010B00040E050E00E941319CA01B90120E031E07C
:1010C00040E050E00E94131920935F01609360019B
:1010D00080916C0190916D018830910539F481E027
:1010E00080935F0182E08093600121C0449709F5FD
:1010F00080915B01811107C086EE91E00E94AE04F1
:1011000081E080935B0129E531E048E551E067E546
:1011100071E086EE91E00E94BE04809157018093B9
:101120005F01809158018093600180915901809303
:10113000610180916C0190916D014E9769F58091EC
:101140005A01811107C08EED91E00E948C0181E06F
:1011500080935A018EED91E00E9490018091E00110
:1011600080935F018091DF01809360018091DE01B7
:10117000809361018091E301809362018091E2019B
:10118000809363019091E4019093640180936501E1
:101190008091E1018093660180916C0190916D01D5
:1011A000889709F059C08091700190917101009762
:1011B00019F426E04BE005C08130910549F426E0A2
:1011C00046E160916E0180ED91E00E946D0508C0DE
:1011D0008230910519F426E045E1F3CF0397D9F366
:1011E00060E080ED91E00E94820669877A878B87B4
:1011F0009C8780ED91E00E9434066D837E838F830F
:1012000098871092510110925001FE01399680E0AA
:1012100090E001962191DC01A25ABE4F2C938430BC
:101220009105BCF384E090E09093510180935001CC
:101230000196DC01A25ABE4FE5E0F0E0EC0FFD1F85
:10124000E80FF91F359720812C938830910584F39E
:10125000909351018093500180916C0190916D01A8
:10126000C297D9F480916E0190916F01482F21E0CF
:101270006091700170917101672B09F420E0642F77
:101280006F5FFC01329737E03E9FC0013F9F900D9A
:1012900011248A559E4F0E94160280916C019091F4
:1012A0006D01C39791F420916E0130916F0122502E
:1012B000310947E0429FC001439F900D11248A5598
:1012C0009E4F0E94080381116AC380916C01909126
:1012D0006D01C49791F420916E0130916F012250FD
:1012E000310917E0129FC001139F900D11248A55F8
:1012F0009E4F0E94080381116BC380916C019091F5
:101300006D01C59791F420916E0130916F012250CB
:10131000310947E0429FC001439F900D11248A5537
:101320009E4F0E940803811165C380916C019091CA
:101330006D01C69791F420916E0130916F0122509A
:10134000310917E0129FC001139F900D11248A5597
:101350009E4F0E940803811168C380916C01909197
:101360006D01C79791F420916E0130916F01225069
:10137000310917E0129FC001139F900D11248A5567
:101380009E4F0E940803811162C380916C0190916D
:101390006D01C89791F420916E0130916F01225038
:1013A000310917E0129FC001139F900D11248A5537
:1013B0009E4F0E940803811163C380916C0190913C
:1013C0006D018634910591F460916E0170916F0109
:1013D000462F4F5F9B0122503109C901880F991F89
:1013E000820F931F8C569E4F0E94100380916C01B8
:1013F00090916D018734910589F420916E013091AF
:101400006F0122503109C901880F991F820F931F64
:101410008C569E4F0E947A04811146C380916C01C4
:1014200090916D018834910589F420916E0130917D
:101430006F0122503109C901880F991F820F931F34
:101440008C569E4F0E947A04811140C380916C019A
:1014500090916D018934910589F420916E0130914C
:101460006F0122503109C901880F991F820F931F04
:101470008C569E4F0E947A04811145C380916C0165
:1014800090916D018A34910589F420916E0130911B
:101490006F0122503109C901880F991F820F931FD4
:1014A0008C569E4F0E947A0481114AC380916C0130
:1014B00090916D018B34910589F420916E013091EA
:1014C0006F0122503109C901880F991F820F931FA4
:1014D0008C569E4F0E947A0481115AC380916C01F0
:1014E00090916D018C34910589F420916E013091B9
:1014F0006F0122503109C901880F991F820F931F74
:101500008C569E4F0E947A0481115BC380916C01BE
:1015100090916D018D349105A9F520916E01309166
:101520006F0122503109C901880F991F820F931F43
:101530008C569E4F0E947A048111BBC323C0812F19
:101540000E94F111BC0120916E0130916F01225077
:101550003109C901880F991F820F931FE12C00E008
:1015600024E040E08C569E4F0E94F8036AEF70E042
:1015700080E090E00E9457142FEFC21AD20ACA14DA
:10158000DB04ECF280916C0190916D018E34910539
:1015900089F420916E0130916F0122503109C90107
:1015A000880F991F820F931F8C569E4F0E947A04BA
:1015B00081118CC380916C0190916D018F349105E4
:1015C00089F420916E0130916F0122503109C901D7
:1015D000880F991F820F931F8C569E4F0E947A048A
:1015E00081118EC380916C0190916D018A359105B6
:1015F00069F480916E018093540180917001809311
:101600005501809172018093560118C08B35910568
:10161000A9F460916E0170916F01462F4F5F9B019D
:101620002250310955E0529FC001539F900D112463
:10163000209170018A589E4F0E945C0180916C013C
:1016400090916D018C35910549F080916C019091DC
:101650006D018D35910509F0BDC048C060916E01E6
:1016600070916F01462F4F5F9B012250310955E069
:10167000529FC001539F900D1124209170018A58F0
:101680009E4F0E945C01009172011091730102FB58
:10169000DD24D0F8D19401FBCC24C0F8C1940170B2
:1016A0001127102F1195E12CF12CA5E0BA2E16C0B0
:1016B00060916E0170916F0162507109B69EC00118
:1016C000B79E900D1124012F2C2D4D2D6E2D8A5873
:1016D0009E4F0E94EF003FEFE31AF30A80917001E2
:1016E00090917101E816F9061CF3AFCF20917001BB
:1016F0003091710180916E0190916F01232BB1F4B3
:101700009C012250310945E0429FC001439F900D4A
:10171000112400915601209155014091540160918E
:1017200072018A589E4F0E94EF0054C09C012250C3
:10173000310945E0429FC001439F900D11248A5812
:101740009E4F0E948901E12CF12CC82ED12C15E06E
:101750003DC020917001309171012130310541F47B
:101760008091720190917301E816F906B1F42BC0D3
:101770002230310541F480917201909173018E15F0
:101780009F055CF420C023303105E9F4809172019B
:1017900090917301E816F906B4F020916E01309132
:1017A0006F0122503109129FC001139F900D112427
:1017B0000091560120915501409154016E2D8A5897
:1017C0009E4F0E94EF008FEFE81AF80AEC14FD0418
:1017D0000CF4BFCF80916C0190916D018E35910515
:1017E00049F080916C0190916D018F35910509F060
:1017F000A0C252C08091720190917301181619060F
:1018000034F081E090E09093730180937201209115
:101810006E0130916F012250310945E0429FC001B5
:10182000439F900D11248A589E4F0E948901E09099
:101830007001F0907101C82ED12C15E029C0809163
:101840007001909171019701281B390BC9016091BA
:101850007201709173010E94DD18892BB1F42091FF
:101860006E0130916F0122503109129FC001139F08
:10187000900D112400915601209155014091540181
:101880006E2D8A589E4F0E94EF003FEFE31AF30A35
:10189000EC14FD04A4F2A5CF20916E0130916F01EC
:1018A0002250310945E0429FC001439F900D112411
:1018B0008A589E4F0E9489012091720130917301D4
:1018C000232B59F133C080917001909171012091C7
:1018D0006E0130916F0122503109E816F90664F467
:1018E000129FC001139F900D112400915601209169
:1018F00055014091540108C0129FC001139F900DE3
:10190000112400E020E040E06E2D8A589E4F0E9496
:10191000EF008FEFE81AF80A05C0E12CF12CC82E71
:10192000D12C15E0EC14FD0474F203C2C82ED12CA6
:10193000760115E030C0809170019091710196019F
:10194000281B390B80916E0190916F01E216F3060E
:101950007CF09C0122503109129FC001139F900D11
:1019600011240091560120915501409154010BC062
:101970009C0122503109129FC001139F900D112428
:1019800000E020E040E06E2D8A589E4F0E94EF005C
:1019900021E0E21AF108E114F10469F6CAC161E03C
:1019A0008091700190917101892B09F460E0209180
:1019B0006E0130916F012250310947E0429FC00112
:1019C000439F900D11248A559E4F0E94FE027DCCAC
:1019D00020916E0130916F0122503109129FC00198
:1019E000139F900D1124609170018A559E4F0E94A3
:1019F000EC0283CC41E08091720190917301892BBC
:101A000009F440E020916E0130916F0122503109BC
:101A100057E0529FC001539F900D112460917001B7
:101A20008A559E4F0E94CB0280CC20916E0130914E
:101A30006F0122503109129FC001139F900D112494
:101A4000609170018A559E4F0E94B20286CC90919F
:101A5000720180E0609170017091710168277927AF
:101A600020916E0130916F0122503109129FC00107
:101A7000139F900D11248A559E4F0E94690285CCB8
:101A800020916E0130916F0122503109129FC001E7
:101A9000139F900D11248A559E4F0E94040380933A
:101AA0005F019093600189CC20916E0130916F01AC
:101AB00022503109C901880F991F820F931F60912D
:101AC00070018C569E4F0E942703A8CC9091720102
:101AD00080E06091700170917101682779272091F1
:101AE0006E0130916F0122503109C901880F991F91
:101AF000820F931FE12C00E024E040E08C569E4FC3
:101B00000E94F803A3CC9091720180E06091700173
:101B1000709171016827792720916E0130916F01D2
:101B200022503109C901880F991F820F931FE12CA0
:101B300000E024E041E08C569E4F0E94F8039ECCCA
:101B400020916E0130916F0122503109C901880F37
:101B5000991F820F931F609172018C569E4F0E94B5
:101B60007304898320916E0130916F0122503109F5
:101B7000C901880F991F820F931F2091700141E0C6
:101B8000BE016F5F7F4F8C569E4F0E94AE038ECC7E
:101B900080917201898320916E0130916F012250F2
:101BA0003109C901880F991F820F931F209170017D
:101BB00041E0BE016F5F7F4F8C569E4F0E94AE0387
:101BC0008DCC80917001909171010AE010E0B80114
:101BD0000E94DD1820916E0130916F012250310971
:101BE000C901880F991F820F931F8C569E4F0E9428
:101BF000730489838091700190917101B8010E94F2
:101C0000DD1820916E0130916F0122503109A90138
:101C1000440F551F420F531F682FCA018C569E4F09
:101C20000E94730480688A8380917201909173018D
:101C3000B8010E94DD1820916E0130916F01225091
:101C40003109C901880F991F820F931F8C569E4F2F
:101C50000E9473048B838091720190917301B8018B
:101C60000E94DD1820916E0130916F0122503109E0
:101C7000A901440F551F420F531F682FCA018C56EC
:101C80009E4F0E9473048C8320916E0130916F01EE
:101C900022503109C901880F991F820F931F20E03C
:101CA00044E0BE016F5F7F4F8C569E4F0E94AE0393
:101CB0002DCC10917001A0907201B0907301AA0C0C
:101CC000BB1CAA0CBB1CC12CD12C59CC8FEF898317
:101CD0008A838B838C8320916E0130916F01225017
:101CE0003109C901880F991F820F931F20E044E03A
:101CF000BE016F5F7F4F8C569E4F0E94AE035ACC41
:101D000019821A821B821C8220916E0130916F0110
:101D100022503109C901880F991F820F931F20E0BB
:101D200044E0BE016F5F7F4F8C569E4F0E94AE0312
:101D300059CC2C960FB6F894DEBF0FBECDBFDF9105
:101D4000CF911F910F91FF90EF90DF90CF90BF90B8
:101D5000AF90089520911B0230E080911C02281B57
:101D60003109C901089580911C0290911B028917C5
:101D700050F4E82FF0E0E35EFD4F208130E08F5F0C
:101D800080931C0202C02FEF3FEFC9010895E0913C
:101D90001C0280911B02E81730F4F0E0E35EFD4F77
:101DA000208130E002C02FEF3FEFC9010895089570
:101DB000E091F301F091F4013097E1F030911C02D1
:101DC00020911B023217B0F040E009C0DC01A20FE5
:101DD000B31F5C91D901A35EBD4F5C934F5F242F6D
:101DE00030E02617370794F310921C0260931B0211
:101DF000CB0109940895E091F501F091F601309737
:101E000029F01092F9011092F80109940895CF92E7
:101E1000DF92EF92FF920F931F93CF93DF937C019A
:101E2000CB018A012091F701222391F0EB016B0194
:101E3000C40ED51E09C06991D701ED91FC910190A6
:101E4000F081E02DC7010995CC15DD05A1F703C090
:101E5000642F0E948E10C801DF91CF911F910F91C6
:101E6000FF90EF90DF90CF900895CF93DF931F9274
:101E7000CDB7DEB769832091F7012223D1F02091FD
:101E8000F801203240F021E030E0FC01338322836E
:101E900020E030E015C08091F901E82FF0E0E65035
:101EA000FE4F998190838F5F8093F9018093F801B1
:101EB00005C061E0CE0101960E948E1021E030E065
:101EC000C9010F90DF91CF910895FC011382128216
:101ED00048EE53E060E070E0448355836683778387
:101EE00084E391E091838083089510921C02109204
:101EF0001B021092F9011092F8010C94D40FCF93A9
:101F0000DF93EC01862F0E94F20F8BEF9EE00E9480
:101F1000AC1088ED9EE00E94A710CE01DF91CF911A
:101F20000C94750F0C947F0F862F413208F040E21D
:101F30006DE172E00E94F60F10921C0280931B026A
:101F4000089521E00C94940F81E08093F701609351
:101F50001A021092F9011092F80108950C94A40F3E
:101F60000F93062F21E04091F8016AEF71E0809114
:101F70001A020E943B101092F9011092F80110927F
:101F8000F7010F91089561E00C94B00F7093F40184
:101F90006093F30108957093F6016093F50108953D
:101FA00087EE91E00C94650F1092460281E08093D9
:101FB00044021092430261E082E10E94D51261E086
:101FC00083E10E94D512E9EBF0E080818E7F80836F
:101FD00080818D7F808382E08093B80085E4809348
:101FE000BC000895880F8093BA000895413208F02C
:101FF0003FC0909146029111FCCF91E09093460230
:10200000209344022FEF20933D0210924202242F8E
:102010002150209341029093450290914502880FF0
:10202000892B8093450280914302813041F41092C4
:102030004302809145028093BB0085EC01C085EE90
:102040008093BC00809146028130E1F3809142028E
:10205000841710F44091420227E432E0FB01D901D9
:1020600002C08D9181938A2F821B8417D0F301C007
:1020700040E0842F08950F93413208F046C09091BC
:1020800046029111FCCF92E09093460200934402E5
:102090009FEF90933D021092420240934102FB0158
:1020A00067E472E0DB0102C091919D939A2F961B29
:1020B0009417D0F31092450290914502880F892B16
:1020C0008093450280914302813041F41092430293
:1020D000809145028093BB0085EC01C085EE809322
:1020E000BC00222321F0809146028230E1F38091EE
:1020F0003D028F3F61F080913D02803251F080912E
:102100003D02803341F483E007C081E005C080E0F8
:1021100003C082E001C084E00F910895613298F419
:1021200020914602243089F460933F02FC0187E647
:1021300092E0DC0102C021912D932A2F281B261743
:10214000D0F380E0089581E0089582E008959093AF
:10215000880280938702089590938A02809389026F
:10216000089585ED8093BC008091BC0084FDFCCF78
:1021700010924602089585EC8093BC0010924602AE
:1021800008951F920F920FB60F9211242F933F9331
:102190004F935F936F937F938F939F93AF93BF936F
:1021A000EF93FF938091B900887F803609F49FC038
:1021B00058F5883209F45BC090F4803109F452C0BC
:1021C00038F4882309F4F8C0883009F0F9C04AC00F
:1021D000883109F44CC0803209F0F2C05CC0803410
:1021E00009F46BC038F4803309F455C0883309F022
:1021F000E7C054C0803509F454C0883509F462C082
:10220000883409F0DDC0DAC0883909F4CBC0A8F4FD
:10221000883709F46CC038F4883609F468C0803710
:1022200009F0CEC064C0883809F4BCC0803909F414
:1022300064C0803809F0C4C060C0803B09F48AC023
:1022400038F4803A09F46BC0883A09F0B9C082C00A
:10225000803C09F4ABC0883C09F4A8C0883B09F075
:10226000AFC08DC0809145028093BB0012C0909199
:10227000420280914102981788F580914202E82F2E
:10228000F0E0E95BFD4F90819093BB008F5F8093FE
:10229000420285EC88C080933D0290C080933D024D
:1022A00056C0809142029091BB00E82FF0E0E95BBC
:1022B000FD4F90838F5F8093420290914202809104
:1022C00041026DC0809142029091BB00E82FF0E086
:1022D000E95BFD4F90838F5F8093420280914402BF
:1022E00081116CC081E08093430284EA60C083E086
:1022F0008093460210923E02CCCF80913E02803203
:1023000008F050C080913E029091BB00E82FF0E0B1
:10231000E557FD4F90838F5F80933E02BACF809147
:102320003E02803230F4E0913E02F0E0E557FD4F8E
:1023300010820E94B11060913E02E0918702F091FC
:10234000880270E08BE892E0099510923E020E94AC
:10235000BB1036C084E08093460210924002109277
:102360003F02E0918902F0918A02099580913F0233
:10237000811105C081E080933F0210926702809135
:102380004002E82FF0E0E959FD4F90819093BB00A7
:102390008F5F809340029091400280913F02981796
:1023A00008F477CF85E88093BC000AC085EC809361
:1023B000BC001092460204C010923D020E94B1106F
:1023C000FF91EF91BF91AF919F918F917F916F910D
:1023D0005F914F913F912F910F900FBE0F901F90E3
:1023E00018958E3008F08E5087702091060140E4D9
:1023F000249F90011124822B80937C0080917A008D
:10240000806480937A0080917A0086FDFCCF2091D1
:10241000780030917900932F80E0AC01422B9A0133
:10242000C90108951F93CF93DF93182FEB0161E04B
:102430000E949D12209711F460E004C0CF3FD105A7
:1024400039F461E0812FDF91CF911F910C94D51267
:10245000E12FF0E0E859FF4FE491E330B9F028F4C0
:10246000E13051F0E230B1F50CC0E63019F1E7305F
:1024700049F1E43079F514C084B5806884BDC7BDE6
:102480002EC084B5806284BDC8BD29C08091800003
:10249000806880938000D0938900C09388001FC01B
:1024A00080918000806280938000D0938B00C093E5
:1024B0008A0015C08091B00080688093B000C093FE
:1024C000B3000DC08091B00080628093B000C093D3
:1024D000B40005C0C038D1050CF0B3CFADCFDF914B
:1024E000CF911F910895833069F028F48130A1F0D5
:1024F000823011F514C08630B1F08730C1F08430DD
:10250000D9F404C0809180008F7703C0809180004F
:102510008F7D80938000089584B58F7702C084B545
:102520008F7D84BD08958091B0008F7703C0809126
:10253000B0008F7D8093B0000895CF93DF9390E03B
:10254000FC01E458FF4F4491FC01E057FF4F849198
:10255000882341F190E0880F991FFC01E854FF4F58
:1025600025913491D90182559F4FFC018591949119
:10257000C82FD92F9FB7F8948C91611106C0409550
:1025800084238C938881842308C0623041F4242FF3
:10259000209582238C938881842B888302C0842B8E
:1025A0008C939FBFDF91CF9108950F931F93CF938B
:1025B000DF931F92CDB7DEB7282F30E0F901E8593D
:1025C000FF4F8491F901E458FF4F1491F901E0574E
:1025D000FF4F04910023D1F0882321F069830E94EA
:1025E00073126981E02FF0E0EE0FFF1FE255FF4FFD
:1025F00085919491DC019FB7F8948C91611103C08F
:102600001095812301C0812B8C939FBF0F90DF9188
:10261000CF911F910F910895CF93DF93282F30E032
:10262000F901E859FF4F8491F901E458FF4FD49123
:10263000F901E057FF4FC491CC2389F081110E942A
:102640007312EC2FF0E0EE0FFF1FEC55FF4F85915A
:102650009491DC018C918D2321E030E011F420E095
:1026600030E0C901DF91CF9108958F929F92AF9290
:10267000BF92CF92DF92EF92FF920F931F93CF936F
:10268000DF9390E0FC01E458FF4FD491FC01E05748
:10269000FF4F7491611102C0C0E001C0CD2FDA017B
:1026A000C901880F991FAA1FBB1F54E0B695A795B3
:1026B000979587955A95D1F7672F70E0660F771F2A
:1026C0006C557F4F812C912C5401FB010591149185
:1026D00010C0C12CD12C7601C394C80CD91CEA1CA3
:1026E000FB1C88169906AA06BB0609F448C04601D9
:1026F0005701F801E081ED23EC1759F310C0C12C0C
:10270000D12C7601C394C80CD91CEA1CFB1C88167A
:102710009906AA06BB0699F14601570103C0FB01C1
:1027200005911491F801E081ED23EC13E8CF8819AD
:102730009909AA09BB0920E030E0A901FB016591D4
:10274000749109C0281739074A075B07C1F02F5F4A
:102750003F4F4F4F5F4FFB01E081ED23EC1791F3AB
:10276000A5E1B0E00E94D2188B019C01005F1F4FD1
:102770002F4F3F4F369527951795079503C000E0DB
:1027800010E09801B801C901DF91CF911F910F911D
:10279000FF90EF90DF90CF90BF90AF909F908F9081
:1027A00008951F920F920FB60F9211242F933F930B
:1027B0008F939F93AF93BF938091AB029091AC02A4
:1027C000A091AD02B091AE023091B302232F285EEA
:1027D0002D3720F40896A11DB11D05C0232F2556C5
:1027E0000996A11DB11D2093B3028093AB02909373
:1027F000AC02A093AD02B093AE028091AF02909173
:10280000B002A091B102B091B2020196A11DB11D1A
:102810008093AF029093B002A093B102B093B20242
:10282000BF91AF919F918F913F912F910F900FBECC
:102830000F901F9018950F931F938FB7F8940091E6
:10284000AB021091AC022091AD023091AE028FBF6D
:10285000B801C9011F910F9108950F931F939FB75E
:10286000F8940091AF021091B0022091B102309122
:10287000B20286B5A89B06C08F3F21F00F5F1F4FA5
:102880002F4F3F4F9FBF322F212F102F0027080FB0
:10289000111D211D311D45E0000F111F221F331F87
:1028A0004A95D1F7B801C9011F910F910895CF92B0
:1028B000DF92EF92FF92CF93DF936B017C010E9436
:1028C0002D14EB010EC00E942D146C1B7D0B683E75
:1028D000734038F081E0C81AD108E108F108C85106
:1028E000DC4FC114D104E104F10469F7DF91CF9109
:1028F000FF90EF90DF90CF900895019739F0019706
:1029000029F0880F991F01970197F1F7089578949E
:1029100084B5826084BD84B5816084BD85B58260E4
:1029200085BD85B5816085BDEEE6F0E08081816082
:102930008083E1E8F0E01082808182608083E0E8BB
:10294000F0E0808181608083E1EBF0E08081846051
:102950008083E0EBF0E0808181608083EAE7F0E053
:1029600080818460808380818260808380818160B7
:1029700080838081806880831092C1000895CF9207
:10298000DF92EF92FF920F931F93CF93DF936C012F
:10299000EB017A01E60EF71E00E010E00BC0699132
:1029A000D601ED91FC910190F081E02DC6010995D1
:1029B000080F191FCE15DF0591F7C801DF91CF91E0
:1029C0001F910F91FF90EF90DF90CF900895DB0162
:1029D0000D900020E9F7AD0141505109461B570BFE
:1029E000DC01ED91FC910280F381E02D09940C94BF
:1029F000E714DC01ED91FC910190F081E02D099448
:102A00000F931F93CF93DF93EC016DE00E94F914B5
:102A10008C016AE0CE010E94F9149C01200F311F45
:102A2000C901DF91CF911F910F9108950F931F93CB
:102A3000CF93DF93EC010E94E7148C01CE010E943A
:102A400000159801280F391FC901DF91CF911F91FF
:102A50000F9108950E9487140E948C07C6E0D6E16A
:102A60000E94AC072097E1F30E940616F9CFFC0103
:102A700084859585FC01E05CFF4F20813181FC015C
:102A8000EE5BFF4F80819181281B390B2F73332719
:102A9000C9010895FC0184859585FC01E05CFF4F28
:102AA00040815181FC01EE5BFF4F20813181421753
:102AB000530741F00190F081E02DE80FF91F2081CC
:102AC00030E002C02FEF3FEFC9010895FC0184857B
:102AD0009585FC01E05CFF4F40815181FC01EE5B7C
:102AE000FF4F208131814217530781F0A081B181CE
:102AF000A80FB91F8C91208131812F5F3F4F2F7319
:102B0000332731832083282F30E002C02FEF3FEF9F
:102B1000C9010895FC0186859785FC01E05CFF4FA3
:102B2000DC01AE5BBF4F408151812D913C911197EB
:102B300042175307C1F70895CF93DF93FC018685B1
:102B40009785DC01A05CBF4F2D913C9111972F5FC1
:102B50003F4F2F733327EC01CE5BDF4F4881598104
:102B600024173507D9F30D90BC91A02DA80FB91FDC
:102B70006C93A685B785A05CBF4F11963C932E93AE
:102B8000A689B7892C9181E090E0058C02C0880F5E
:102B9000991F0A94E2F7282B2C9381E090E0DF91B3
:102BA000CF91089508951F920F920FB60F9211249E
:102BB0002F933F934F938F939F93EF93FF93409166
:102BC000C600809157039091580301968F739927FF
:102BD0002091590330915A038217930759F0E091DD
:102BE0005703F0915803E95EFC4F408390935803DC
:102BF00080935703FF91EF919F918F914F913F9158
:102C00002F910F900FBE0F901F90189584EB92E0BC
:102C10000E943715892B11F00C94D21508951F923C
:102C20000F920FB60F9211242F933F938F939F9380
:102C3000EF93FF93209113033091140380911503B8
:102C4000909116032817390731F48091C1008F7DC8
:102C50008093C10014C0E0911503F0911603ED526A
:102C6000FD4F2081809115039091160301968F737B
:102C7000992790931603809315032093C600FF9124
:102C8000EF919F918F913F912F910F900FBE0F90D9
:102C90001F901895CF92DF92EF92FF92CF93DF9320
:102CA000EC016A017B01EC89FD8981E090E00E8CEA
:102CB00002C0880F991F0A94E2F7808360E271EAEC
:102CC00087E090E0A70196010E94F1182150310998
:102CD000410951095695479537952795211580E16A
:102CE000380798F0EC89FD89108260E970ED83E087
:102CF00090E0A70196010E94F11821503109410985
:102D000051095695479537952795E889F989308374
:102D1000EA89FB892083EE89FF89408181E090E088
:102D20009C010A8C02C0220F331F0A94E2F7422B47
:102D30004083EE89FF8940819C010B8C02C0220FE9
:102D4000331F0A94E2F7422B4083EE89FF894081CA
:102D50009C010C8C02C0220F331F0A94E2F7422B15
:102D60004083EE89FF8920810D8C02C0880F991F56
:102D70000A94E2F7809582238083DF91CF91FF90C0
:102D8000EF90DF90CF9008951092B7021092B602A4
:102D900088EE93E0A0E0B0E08093B8029093B9028F
:102DA000A093BA02B093BB0284E491E09093B50281
:102DB0008093B40287E193E09093C1028093C002B4
:102DC00083ED92E09093C3028093C20285EC90E081
:102DD0009093C5028093C40284EC90E09093C70264
:102DE0008093C60280EC90E09093C9028093C80261
:102DF00081EC90E09093CB028093CA0286EC90E045
:102E00009093CD028093CC0284E08093CE0283E045
:102E10008093CF0287E08093D00285E08093D10237
:102E200081E08093D20208955058BB27AA270ED084
:102E30001CC10DD130F012D120F031F49F3F11F4BC
:102E40001EF402C10EF4E095E7FBF8C0E92F1ED195
:102E500080F3BA17620773078407950718F071F4B7
:102E60009EF536C10EF4E0950B2EBA2FA02D0B0166
:102E7000B90190010C01CA01A0011124FF27591BBF
:102E800099F0593F50F4503E68F11A16F040A22FC5
:102E9000232F342F4427585FF3CF46953795279536
:102EA000A795F0405395C9F77EF41F16BA0B620B35
:102EB000730B840BBAF09150A1F0FF0FBB1F661F7C
:102EC000771F881FC2F70EC0BA0F621F731F841FBF
:102ED00048F4879577956795B795F7959E3F08F0E5
:102EE000B3CF9395880F08F09927EE0F97958795A4
:102EF00008950CD0BAC0B2D040F0A9D030F021F47F
:102F00005F3F19F09BC05111E4C09EC0BFD098F341
:102F10009923C9F35523B1F3951B550BBB27AA275A
:102F200062177307840738F09F5F5F4F220F331FCC
:102F3000441FAA1FA9F333D00E2E3AF0E0E830D098
:102F400091505040E695001CCAF729D0FE2F27D09B
:102F5000660F771F881FBB1F261737074807AB0769
:102F6000B0E809F0BB0B802DBF01FF2793585F4FDE
:102F70002AF09E3F510568F061C0ABC05F3FECF3A3
:102F8000983EDCF3869577956795B795F7959F5FA3
:102F9000C9F7880F911D9695879597F90895E1E0F7
:102FA000660F771F881FBB1F621773078407BA0756
:102FB00020F0621B730B840BBA0BEE1F88F7E095B1
:102FC0000895E89409C097FB3EF49095809570951C
:102FD00061957F4F8F4F9F4F9923A9F0F92F96E965
:102FE000BB279395F695879577956795B795F111DA
:102FF000F8CFFAF4BB0F11F460FF1BC06F5F7F4F77
:103000008F4F9F4F16C0882311F096E911C0772388
:1030100021F09EE8872F762F05C0662371F096E891
:10302000862F70E060E02AF09A95660F771F881F60
:10303000DAF7880F9695879597F9089597F99F671E
:1030400080E870E060E008959FEF80EC0895002430
:103050000A941616170618060906089500240A94FD
:1030600012161306140605060895092E0394000C83
:1030700011F4882352F0BB0F40F4BF2B11F460FF12
:1030800004C06F5F7F4F8F4F9F4F089557FD90583B
:10309000440F551F59F05F3F71F04795880F97FB1C
:1030A000991F61F09F3F79F08795089512161306D6
:1030B0001406551FF2CF4695F1DF08C01616170605
:1030C0001806991FF1CF869571056105089408953A
:1030D000E894BB2766277727CB0197F908950BD093
:1030E000C4CFB5DF28F0BADF18F0952309F0A6CFDA
:1030F000ABCF1124EECFCADFA0F3959FD1F3950F8C
:1031000050E0551F629FF001729FBB27F00DB11D6B
:10311000639FAA27F00DB11DAA1F649F6627B00DFB
:10312000A11D661F829F2227B00DA11D621F739FE4
:10313000B00DA11D621F839FA00D611D221F749FF2
:103140003327A00D611D231F849F600D211D822F39
:10315000762F6A2F11249F5750408AF0E1F0882380
:103160004AF0EE0FFF1FBB1F661F771F881F91508D
:103170005040A9F79E3F510570F060CFAACF5F3F46
:10318000ECF3983EDCF3869577956795B795F795C0
:10319000E7959F5FC1F7FE2B880F911D9695879548
:1031A00097F908950E942F19A59F900DB49F900D37
:1031B000A49F800D911D1124089597FB072E16F4EE
:1031C000009407D077FD09D00E943B1907FC05D079
:1031D0003EF4909581959F4F0895709561957F4F2E
:1031E0000895A1E21A2EAA1BBB1BFD010DC0AA1F48
:1031F000BB1FEE1FFF1FA217B307E407F50720F060
:10320000A21BB30BE40BF50B661F771F881F991FDA
:103210001A9469F760957095809590959B01AC0123
:10322000BD01CF010895052E97FB16F4009407D039
:1032300057FD0DD00E94F11807FC09D07EF490953F
:103240008095709561957F4F8F4F9F4F0895509552
:103250004095309521953F4F4F4F5F4F0895A29F66
:10326000B001B39FC001A39F01D0B29F700D811D1B
:103270001124911D0895AA1BBB1B51E107C0AA1F71
:10328000BB1FA617B70710F0A61BB70B881F991F07
:103290005A95A9F780959095BC01CD010895EE0F40
:1032A000FF1F0590F491E02D09940F931F93CF9386
:1032B000DF93689F8001699F100D789F100D112486
:1032C000C8010E947319C82FD92F209731F0A80187
:1032D00060E070E08C2F0E94AA1ACE01DF91CF919E
:1032E0001F910F9108950F931F93CF93DF93823017
:1032F000910510F482E090E0E0915D03F0915E03AF
:1033000020E030E0C0E0D0E023C040815181481788
:103310005907A8F04817590761F4828193812097D3
:1033200019F09B838A832EC090935E0380935D0384
:1033300029C02115310529F04217530710F0A901C2
:1033400002C0BE01DF0102811381EF019A01F80181
:103350003097D9F62115310509F1281B390B243096
:10336000310590F412968D919C911397611571051A
:1033700021F0FB019383828304C090935E038093CA
:103380005D03FD01329644C0FD01E20FF31F8193FE
:103390009193225031092D933C933AC020915B03C5
:1033A00030915C03232B41F4209102013091030101
:1033B00030935C0320935B03209100013091010165
:1033C0002115310541F42DB73EB7409104015091CC
:1033D0000501241B350BE0915B03F0915C03E217C0
:1033E000F307A0F42E1B3F0B2817390778F0AC0128
:1033F0004E5F5F4F2417350748F04E0F5F1F509305
:103400005C0340935B038193919302C0E0E0F0E0A2
:10341000CF01DF91CF911F910F910895EF92FF920D
:103420000F931F93CF93DF93009709F48EC0DC01B5
:10343000129713961C921E921297E0905D03F090E3
:103440005E03E114F10489F42D913C911197280F4A
:10345000391F80915B0390915C038217930789F574
:10346000B0935C03A0935B0370C0E70120E030E001
:1034700001C0EA01CA17DB0738F44A815B819E016B
:1034800041155105B1F722C0AC0142505109FA0172
:10349000D383C28300811181BC01600F711F6C173F
:1034A0007D0761F468817981600F711F6E5F7F4FC6
:1034B000718360836A817B81738362832115310507
:1034C00029F4B0935E03A0935D033FC0F901B38379
:1034D000A283E90149915991C40FD51FAC17BD07CB
:1034E00071F4DC019E918E91840F951F0296918359
:1034F000808312968D919C91139793838283A0E091
:10350000B0E002C0D7017C01F7018281938100976E
:10351000C9F7C701029620813181820F931F209144
:103520005B0330915C032817390779F4109729F46D
:1035300010925E0310925D0304C013961C921E92BB
:103540001297F0925C03E0925B03CDB7DEB7E6E042
:103550000C94BD1ADC0101C06D9341505040E0F75E
:1035600008952A88398848885F846E847D848C8495
:103570009B84AA84B984C884DF80EE80FD800C819E
:103580001B81AA81B981CE0FD11D0FB6F894DEBF81
:0C3590000FBECDBFED010895F894FFCFF1
:10359C0000005F0320000101000A006400E8033F03
:1035AC00065B4F666D7D077F6F777C395E79715254
:1035BC00656164206661696C005265616479210003
:1035CC0000000000350F070FAA0EB30EC70ED70E62
:1035DC00000000009C15BF14371566154A158A1596
:00000001FF

View file

@ -0,0 +1,864 @@
:100000000C9463000C948B000C948B000C948B006C
:100010000C948B000C948B000C948B000C948B0034
:100020000C948B000C948B000C948B000C948B0024
:100030000C948B000C948B000C948B000C948B0014
:100040000C94D1130C948B000C94D3150C940F16B4
:100050000C948B000C948B000C948B000C948B00F4
:100060000C94C1100C948B000000000700020100EA
:100070000003040600000000000000000102040864
:100080001020408001020408102001020408102002
:10009000040404040404040402020202020203032E
:1000A00003030303000000002300260029000000D2
:1000B0000000250028002B0000000000240027007D
:1000C0002A00D00FC41611241FBECFEFD8E0DEBF28
:1000D000CDBF11E0A0E0B1E0ECE9F5E302C005908E
:1000E0000D92A035B107D9F713E0A0E5B1E001C04A
:1000F0001D92AF35B107E1F710E0C6ECD0E004C0C7
:100100002297FE010E945119C23CD107C9F70E94F3
:100110002A150C94CC1A0C940000CF93DF93EC01B9
:1001200060E088810E94D51284E190E00E947D14F5
:1001300061E088810E94D51284E190E0DF91CF9147
:100140000C947D140F931F93CF93DF93EC01062F34
:1001500018E007FF02C061E001C060E089810E94F1
:10016000D512CE010E948D00000F115091F7DF9142
:10017000CF911F910F910895EF92FF921F93CF930C
:10018000DF9300D0CDB7DEB77C01162F27FF02C06A
:1001900060EC01C060EE26FF606147FF686046FFCB
:1001A000646017FF626016FF6160C70129834A839C
:1001B0000E94A2002981622FC7010E94A2004A81E9
:1001C000642FC7010E94A200612FC7010F900F90FA
:1001D000DF91CF911F91FF90EF900C94A2007F923E
:1001E0008F929F92AF92BF92CF92DF92EF92FF9247
:1001F0000F931F93CF93DF93EC01162F942E822E33
:1002000060E00E94A20060E0CE010E94A20060E0D7
:10021000CE010E94A20060E0CE010E94A20083E015
:10022000189F7001112467018FEFC81AD80A57016F
:1002300082E0A80EB11C712C1FC071120FC0EB819F
:10024000FC81EE0DFF1D9082EB81FC81EC0DFD1D0C
:100250008082EB81FC81EA0DFB1D0083EB81FC8138
:1002600083E0789EE00DF11D11242281418160819F
:10027000CE010E94BC0073948A817816F0F260E08F
:10028000CE010E94A20060E0CE010E94A20060E0C8
:10029000CE010E94A20060E0CE01DF91CF911F91BC
:1002A0000F91FF90EF90DF90CF90BF90AF909F9015
:1002B0008F907F900C94A2000F931F93CF93DF93A6
:1002C000EC01862F688349832A8361E00E949D1296
:1002D00061E089810E949D128A8161E070E023E0E3
:1002E000829FC00111240E9455198B839C8310E0CA
:1002F00008C000E020E040E0612FCE010E94EF0046
:100300001F5F8A811817A8F3DF91CF911F910F917A
:100310000895FC018281089587EE91E00C94750F99
:10032000CF93DF93EC0168E670E087EE91E00E94E6
:10033000AE0F60E087EE91E00E94350F87EE91E00E
:100340000E94C30F47E050E068E670E087EE91E05E
:100350000E94A10F87EE91E00E94B30E382F3695D0
:10036000369536953E70232F220F220F230F8F7064
:100370009927280F288387EE91E00E94B30E282F3B
:1003800022952F708F7099273AE0239F800D1124BA
:10039000898387EE91E00E94B30E382F369536950B
:1003A00036953670232F220F220F230F8F70992737
:1003B000280F2A8387EE91E00E94B30E282F229502
:1003C0002F708F7099273AE0239F800D11248B8323
:1003D00087EE91E00E94B30E282F22952F708F7028
:1003E00099273AE0239F800D11248C8387EE91E0BA
:1003F0000E94B30E282F22952F708F7099273AE014
:10040000239F800D11248D8387EE91E00E94B30E0F
:10041000282F22952F708F7099273AE0239F800D07
:1004200011248E831F82DF91CF910895CF93DF93A4
:10043000EC01862F688319824A831B822C831E82DB
:100440001D8261E00E949D1261E08A81DF91CF915F
:100450000C949D121F93CF93DF93EC0160E08A818F
:100460000E94D5128AE090E00E947D1414E061E0C1
:100470008A810E94D51260E08A810E94D5121150B3
:10048000B1F7DF91CF911F910895FF920F931F93C2
:10049000CF93DF93EC018B0190E1F92E612F661F62
:1004A0006627661F8A810E94D51288810E940C13DC
:1004B00061E0892B09F060E088810E94D512000F6D
:1004C000111FFA9459F7DF91CF911F910F91FF906F
:1004D0000895EF92FF920F931F93CF93DF93EC0158
:1004E0007B01CB0193709E838D8360E070E0CE0131
:1004F0000E94450200E010E08C81882351F0C70182
:10050000002E02C0880F991F0A94E2F791FF0DC0D8
:1005100009C0C701002E02C0969587950A94E2F79C
:1005200080FF03C06FEF70E002C060E070E0CE01BA
:100530000E9445020F5F1F4F0A301105E9F660E087
:1005400070E0CE010E94450260E070E0CE010E94A2
:100550004502CE01DF91CF911F910F91FF90EF9057
:100560000C942A02662321F06B3018F06AE001C077
:1005700061E0262F215061E070E002C0660F771F16
:100580002A95E2F7FC01258136816227732776835D
:1005900065830C946902662321F06B3018F06AE0E1
:1005A00001C061E0562F5150FC012581368161E088
:1005B00070E002C0660F771F5A95E2F7442319F0E6
:1005C000622B732B04C06095709562237323FC012A
:1005D000768365830C9469026B3008F06AE02FEF34
:1005E0003FEF02C0220F331F6A95E2F72095309546
:1005F000FC0136832583B9010C946902FC016483F4
:10060000658176810C946902FC018581968108954B
:10061000FC0181E020813181232B09F480E00895E1
:10062000CF93DF93EC01862F6883498360E00E94BB
:100630009D1260E089810E949D1260E088810E9485
:10064000D51260E08981DF91CF910C94D51268308A
:1006500010F4685F01C06FE0FC016283089561E0FF
:10066000FC0181810E949D1282E390E00C947D1434
:10067000CF93DF93EC0161E089810E949D1282E3B8
:1006800090E00E947D1460E088810E949D1282E3C8
:1006900090E00E947D1460E089810E949D1282E3B7
:1006A00090E0DF91CF910C947D140F931F93CF9323
:1006B000DF93EC01062F18E061E088810E949D1213
:1006C00082E390E00E947D1400FF02C060E001C060
:1006D00061E089810E949D1282E390E00E947D1476
:1006E00060E088810E949D1282E390E00E947D1468
:1006F0000695115009F761E088810E949D1260E023
:1007000089810E949D1282E390E00E947D1460E046
:1007100088810E949D1282E390E00E947D1489816D
:100720000E940C13182F811104C061E089810E947E
:100730009D1282E390E00E947D1461E088810E9416
:100740009D1282E390E00E947D1481E0111101C0AE
:1007500080E0DF91CF911F910F910895CF92DF92AA
:10076000EF92FF920F931F93CF93DF9300D0CDB7FB
:10077000DEB76C01F62EE42E29837A830E942F03C4
:1007800060E4C6010E945503C6010E943803C601F9
:100790000E942F032981622F63706054C6010E945A
:1007A00055030F2D7A81172F06C0F80161918F0133
:1007B000C6010E945503802F8F198E15B0F3C60114
:1007C0000E943803C6010E942F03F601628160581F
:1007D000C6010E945503C6010F900F90DF91CF9183
:1007E0001F910F91FF90EF90DF90CF900C94380302
:1007F0004F925F926F927F928F929F92AF92BF9231
:10080000CF92DF92EF920F931F93CF93DF9300D09D
:1008100000D0CDB7DEB73C016B01322F202F8FE027
:10082000A82E81E0B82E88248394912C8C0E9D1ED6
:10083000F40101E01FE3D5015E904E905D01C60119
:10084000B2010E94DD186115710561F4411106C005
:10085000002321F08E2F8819833011F4108313C0E8
:10086000108211C0DB01AF70BB27A15FBE4F8C911E
:100870008083649DC001659D900D749D900D112431
:10088000C81AD90A00E0EE2039F08E2F881981307D
:1008900019F48081806880833196B7E0AB16B1E0AF
:1008A000BB0649F684E090E0831B9109BE016F5FAF
:1008B0007F4F680F791F432FC3010E94AE030F9033
:1008C0000F900F900F90DF91CF911F910F91EF90AC
:1008D000DF90CF90BF90AF909F908F907F906F9060
:1008E0005F904F9008956F70E62FF0E0E15FFE4F4C
:1008F00080810895FC0181E09081911101C080E028
:1009000008951F93CF93DF931F92CDB7DEB7162FB5
:1009100087EE91E049830E94750F6CE470E087EEEA
:1009200091E00E94AE0F612F87EE91E00E94350F9B
:100930004981642F87EE91E00E94350F87EE91E0A8
:100940000F90DF91CF911F910C94C30F462F67E05A
:100950000C948104462F68E00C948104CF93DF93BC
:10096000EC0160E00E94A60460E0CE010E94AA04AF
:1009700061E0CE01DF91CF910C94A6044F925F927B
:100980006F927F928F929F92AF92BF92CF92DF929F
:10099000EF92FF920F931F93CF93DF9300D01F929C
:1009A000CDB7DEB75B016A01790180E48B838A836E
:1009B00089830E941B142B013C010DC00E941B1453
:1009C0006419750986099709653F7140810591058C
:1009D00014F080E06EC087EE91E00E94AA0E181617
:1009E000190664F387EE91E00E94B30E43E050E0F5
:1009F0006CE470E087EE91E00E94A10F0E941B144E
:100A00002B013C018E010F5F1F4F48012DC0C80113
:100A1000881999090397D4F40E941B142B013C01F7
:100A200011C087EE91E00E94B30EF80180830E940E
:100A30001B146419750986099709633371058105CB
:100A400091053CF6F8018081803458F70E941B1410
:100A50000F5F1F4F6419750986099709653F71403B
:100A6000810591050CF0B5CF87EE91E00E94AA0EAA
:100A7000892B69F69981892F880F880F95FD8D5FE5
:100A800085958595F50180839A81892F880F880F38
:100A900095FD8D5F85958595F60180839B81892FD6
:100AA000880F880F95FD8D5F85958595F70180836B
:100AB00081E00F900F900F90DF91CF911F910F91D8
:100AC000FF90EF90DF90CF90BF90AF909F908F906E
:100AD0007F906F905F904F900895CF93DF93EC01DC
:100AE000862F6E834F83288791E09D8760E00E9468
:100AF0009D1261E08E810E94D51219861A861B868E
:100B00001C86DF91CF910895DF92EF92FF920F93B1
:100B10001F93CF93DF93EC0161E08E810E94D51289
:100B20006AEF70E080E090E00E9457140E941B146E
:100B300009851A852B853C85601771078207930705
:100B400020F419861A861B861C862D85211111C05A
:100B500009851A852B853C85DC01CB01801B910B17
:100B6000A20BB30B803D9740A105B10510F481E0C5
:100B700073C01D860E941B1469877A878B879C87A8
:100B80001C821B821A821982188261E08E810E9467
:100B90009D1260E08E810E94D51264E170E080E0D9
:100BA00090E00E945714F89461E08E810E94D51263
:100BB00088E290E00E947D1460E08E810E949D1288
:100BC000F12CD12C81E009C0E39481E090E00E94F7
:100BD0007D148FEFE81204C009C0E12C082F10E04B
:100BE0008E810E940C138017910771F38E810E94F1
:100BF0000C139FEFE916C9F023E02F1590F4F0FCD9
:100C000010C09D2D969596959695FE01E90FF11DC4
:100C10009081990F908328852E1510F49160908310
:100C2000D394F39495E5F912D8CF789427E22D1553
:100C300090F42C8130E04881898190E0840F911DEF
:100C40004A81840F911D4B81840F911D992728178C
:100C5000390709F48CCF80E0DF91CF911F910F917C
:100C6000FF90EF90DF900895EF92FF920F931F9304
:100C7000CF93DF93EC010E948405882391F18F814B
:100C80008B3029F070F18551823058F507C06881AA
:100C900070E080E090E00E94E1172DC0688170E074
:100CA00080E090E00E94E11720E030E040E853E46B
:100CB0000E946F187B018C01698170E080E090E0F8
:100CC0000E94E3179B01AC016E2D7F2D802F912F89
:100CD0000E94151720E030E040E251E40E947917AD
:100CE0000AC06FE171E084EB92E00E94F71460E0CB
:100CF00070E080EC9FE7DF91CF911F910F91FF9003
:100D0000EF900895CF92DF92EF92FF920F931F938F
:100D1000CF93DF938C01C62F0E948405882309F4AA
:100D200077C0F80187818B3039F008F471C08551A4
:100D3000823008F06DC01DC0F801628170E080E073
:100D400090E00E94E117B62FA72FF82FE92F462F2A
:100D5000572F682F792FCB01BA01CC2309F462C039
:100D600020E030E040E151E46B2F7A2F8F2F9E2F4F
:100D700037C0F801D2816D2F6F7770E080E090E08E
:100D80000E94E31720E030E040E853E40E946F182F
:100D90006B017C01F801638170E080E090E00E94CB
:100DA000E3179B01AC016C2D7D2D8E2D9F2D0E9494
:100DB000151720E030E040E251E40E947917472FF8
:100DC000382F292F862F942FA32FB22FBC01CD01AE
:100DD000D7FD9058CC2331F120E030E040E151E4E0
:100DE0000E946F1820E030E040EA50E40E9479173A
:100DF00020E030E040E052E40E941517472F382FE2
:100E0000292F862F942FA32FB22FBC01CD010AC00A
:100E10006FE171E084EB92E00E94F71460E070E013
:100E200080EC9FE7DF91CF911F910F91FF90EF90A2
:100E3000DF90CF900895CF93DF9322C087EE91E0AB
:100E40000E94AA0E049741F4109269011092680161
:100E500010926B0110926A01C0916A01D0916B01EE
:100E600087EE91E00E94B30EFE01EE0FFF1FE459E2
:100E7000FE4F918380832196D0936B01C0936A01CA
:100E800087EE91E00E94AA0E892BC1F6DF91CF91E7
:100E9000089580916C0190916D01019731F46091FA
:100EA000670187EE91E00E94350F80916C0190916F
:100EB0006D018330910529F08730910511F0C897B5
:100EC00041F443E050E06EE571E087EE91E00E946E
:100ED000070F80916C0190916D018830910511F0A0
:100EE000449741F444E050E06EE571E087EE91E014
:100EF0000E94070F80916C0190916D018E319105D8
:100F000011F0889741F449E050E06EE571E087EE1A
:100F100091E00C94070F089540E855E260E070E01E
:100F200084EB92E00E944A1664E070E087EE91E064
:100F30000E94920F6BE177E087EE91E00E94C60F6E
:100F400069E477E087EE91E00E94CB0F69E271E0FF
:100F500084EB92E00C941615AF92BF92CF92DF9281
:100F6000EF92FF920F931F93CF93DF93CDB7DEB72E
:100F70002C970FB6F894DEBF0FBECDBF80916A01EB
:100F800090916B01049709F0D4C68091680190910B
:100F90006901892B09F0CDC681E090E09093690149
:100FA0008093680180916C0190916D01019731F4FB
:100FB00080916E010E940C138093670180916C01F7
:100FC00090916D01029731F46091700180916E01F2
:100FD0000E94D51280916C0190916D010397A9F444
:100FE00080916E010E94F11190935D0180935C01EC
:100FF0009C0197FF02C021503F4F30935F0160E09A
:1010000071E00E94DD188093600180916C019091E5
:101010006D01049741F460917001709171018091AC
:101020006E010E94121280916C0190916D010597E2
:1010300031F46091700180916E010E949D12809147
:101040006C0190916D01079709F042C080916E018B
:1010500090916F01809352019093530161E00E943F
:101060009D1260E0809152010E94D51282E090E0D2
:101070000E947D1461E0809152010E94D51285E0AA
:1010800090E00E947D1460E0809152010E94D51290
:1010900060E0809152010E949D1220E432E44FE012
:1010A00050E061E0809152010E9435132AE330E064
:1010B00040E050E00E941319CA01B90120E031E07C
:1010C00040E050E00E94131920935F01609360019B
:1010D00080916C0190916D018830910539F481E027
:1010E00080935F0182E08093600121C0449709F5FD
:1010F00080915B01811107C086EE91E00E94AE04F1
:1011000081E080935B0129E531E048E551E067E546
:1011100071E086EE91E00E94BE04809157018093B9
:101120005F01809158018093600180915901809303
:10113000610180916C0190916D014E9769F58091EC
:101140005A01811107C08EED91E00E948C0181E06F
:1011500080935A018EED91E00E9490018091E00110
:1011600080935F018091DF01809360018091DE01B7
:10117000809361018091E301809362018091E2019B
:10118000809363019091E4019093640180936501E1
:101190008091E1018093660180916C0190916D01D5
:1011A000889709F059C08091700190917101009762
:1011B00019F426E04BE005C08130910549F426E0A2
:1011C00046E160916E0180ED91E00E946D0508C0DE
:1011D0008230910519F426E045E1F3CF0397D9F366
:1011E00060E080ED91E00E94820669877A878B87B4
:1011F0009C8780ED91E00E9434066D837E838F830F
:1012000098871092510110925001FE01399680E0AA
:1012100090E001962191DC01A25ABE4F2C938430BC
:101220009105BCF384E090E09093510180935001CC
:101230000196DC01A25ABE4FE5E0F0E0EC0FFD1F85
:10124000E80FF91F359720812C938830910584F39E
:10125000909351018093500180916C0190916D01A8
:10126000C297D9F480916E0190916F01482F21E0CF
:101270006091700170917101672B09F420E0642F77
:101280006F5FFC01329737E03E9FC0013F9F900D9A
:1012900011248A559E4F0E94160280916C019091F4
:1012A0006D01C39791F420916E0130916F0122502E
:1012B000310947E0429FC001439F900D11248A5598
:1012C0009E4F0E94080381116AC380916C01909126
:1012D0006D01C49791F420916E0130916F012250FD
:1012E000310917E0129FC001139F900D11248A55F8
:1012F0009E4F0E94080381116BC380916C019091F5
:101300006D01C59791F420916E0130916F012250CB
:10131000310947E0429FC001439F900D11248A5537
:101320009E4F0E940803811165C380916C019091CA
:101330006D01C69791F420916E0130916F0122509A
:10134000310917E0129FC001139F900D11248A5597
:101350009E4F0E940803811168C380916C01909197
:101360006D01C79791F420916E0130916F01225069
:10137000310917E0129FC001139F900D11248A5567
:101380009E4F0E940803811162C380916C0190916D
:101390006D01C89791F420916E0130916F01225038
:1013A000310917E0129FC001139F900D11248A5537
:1013B0009E4F0E940803811163C380916C0190913C
:1013C0006D018634910591F460916E0170916F0109
:1013D000462F4F5F9B0122503109C901880F991F89
:1013E000820F931F8C569E4F0E94100380916C01B8
:1013F00090916D018734910589F420916E013091AF
:101400006F0122503109C901880F991F820F931F64
:101410008C569E4F0E947A04811146C380916C01C4
:1014200090916D018834910589F420916E0130917D
:101430006F0122503109C901880F991F820F931F34
:101440008C569E4F0E947A04811140C380916C019A
:1014500090916D018934910589F420916E0130914C
:101460006F0122503109C901880F991F820F931F04
:101470008C569E4F0E947A04811145C380916C0165
:1014800090916D018A34910589F420916E0130911B
:101490006F0122503109C901880F991F820F931FD4
:1014A0008C569E4F0E947A0481114AC380916C0130
:1014B00090916D018B34910589F420916E013091EA
:1014C0006F0122503109C901880F991F820F931FA4
:1014D0008C569E4F0E947A0481115AC380916C01F0
:1014E00090916D018C34910589F420916E013091B9
:1014F0006F0122503109C901880F991F820F931F74
:101500008C569E4F0E947A0481115BC380916C01BE
:1015100090916D018D349105A9F520916E01309166
:101520006F0122503109C901880F991F820F931F43
:101530008C569E4F0E947A048111BBC323C0812F19
:101540000E94F111BC0120916E0130916F01225077
:101550003109C901880F991F820F931FE12C00E008
:1015600024E040E08C569E4F0E94F8036AEF70E042
:1015700080E090E00E9457142FEFC21AD20ACA14DA
:10158000DB04ECF280916C0190916D018E34910539
:1015900089F420916E0130916F0122503109C90107
:1015A000880F991F820F931F8C569E4F0E947A04BA
:1015B00081118CC380916C0190916D018F349105E4
:1015C00089F420916E0130916F0122503109C901D7
:1015D000880F991F820F931F8C569E4F0E947A048A
:1015E00081118EC380916C0190916D018A359105B6
:1015F00069F480916E018093540180917001809311
:101600005501809172018093560118C08B35910568
:10161000A9F460916E0170916F01462F4F5F9B019D
:101620002250310955E0529FC001539F900D112463
:10163000209170018A589E4F0E945C0180916C013C
:1016400090916D018C35910549F080916C019091DC
:101650006D018D35910509F0BDC048C060916E01E6
:1016600070916F01462F4F5F9B012250310955E069
:10167000529FC001539F900D1124209170018A58F0
:101680009E4F0E945C01009172011091730102FB58
:10169000DD24D0F8D19401FBCC24C0F8C1940170B2
:1016A0001127102F1195E12CF12CA5E0BA2E16C0B0
:1016B00060916E0170916F0162507109B69EC00118
:1016C000B79E900D1124012F2C2D4D2D6E2D8A5873
:1016D0009E4F0E94EF003FEFE31AF30A80917001E2
:1016E00090917101E816F9061CF3AFCF20917001BB
:1016F0003091710180916E0190916F01232BB1F4B3
:101700009C012250310945E0429FC001439F900D4A
:10171000112400915601209155014091540160918E
:1017200072018A589E4F0E94EF0054C09C012250C3
:10173000310945E0429FC001439F900D11248A5812
:101740009E4F0E948901E12CF12CC82ED12C15E06E
:101750003DC020917001309171012130310541F47B
:101760008091720190917301E816F906B1F42BC0D3
:101770002230310541F480917201909173018E15F0
:101780009F055CF420C023303105E9F4809172019B
:1017900090917301E816F906B4F020916E01309132
:1017A0006F0122503109129FC001139F900D112427
:1017B0000091560120915501409154016E2D8A5897
:1017C0009E4F0E94EF008FEFE81AF80AEC14FD0418
:1017D0000CF4BFCF80916C0190916D018E35910515
:1017E00049F080916C0190916D018F35910509F060
:1017F000A0C252C08091720190917301181619060F
:1018000034F081E090E09093730180937201209115
:101810006E0130916F012250310945E0429FC001B5
:10182000439F900D11248A589E4F0E948901E09099
:101830007001F0907101C82ED12C15E029C0809163
:101840007001909171019701281B390BC9016091BA
:101850007201709173010E94DD18892BB1F42091FF
:101860006E0130916F0122503109129FC001139F08
:10187000900D112400915601209155014091540181
:101880006E2D8A589E4F0E94EF003FEFE31AF30A35
:10189000EC14FD04A4F2A5CF20916E0130916F01EC
:1018A0002250310945E0429FC001439F900D112411
:1018B0008A589E4F0E9489012091720130917301D4
:1018C000232B59F133C080917001909171012091C7
:1018D0006E0130916F0122503109E816F90664F467
:1018E000129FC001139F900D112400915601209169
:1018F00055014091540108C0129FC001139F900DE3
:10190000112400E020E040E06E2D8A589E4F0E9496
:10191000EF008FEFE81AF80A05C0E12CF12CC82E71
:10192000D12C15E0EC14FD0474F203C2C82ED12CA6
:10193000760115E030C0809170019091710196019F
:10194000281B390B80916E0190916F01E216F3060E
:101950007CF09C0122503109129FC001139F900D11
:1019600011240091560120915501409154010BC062
:101970009C0122503109129FC001139F900D112428
:1019800000E020E040E06E2D8A589E4F0E94EF005C
:1019900021E0E21AF108E114F10469F6CAC161E03C
:1019A0008091700190917101892B09F460E0209180
:1019B0006E0130916F012250310947E0429FC00112
:1019C000439F900D11248A559E4F0E94FE027DCCAC
:1019D00020916E0130916F0122503109129FC00198
:1019E000139F900D1124609170018A559E4F0E94A3
:1019F000EC0283CC41E08091720190917301892BBC
:101A000009F440E020916E0130916F0122503109BC
:101A100057E0529FC001539F900D112460917001B7
:101A20008A559E4F0E94CB0280CC20916E0130914E
:101A30006F0122503109129FC001139F900D112494
:101A4000609170018A559E4F0E94B20286CC90919F
:101A5000720180E0609170017091710168277927AF
:101A600020916E0130916F0122503109129FC00107
:101A7000139F900D11248A559E4F0E94690285CCB8
:101A800020916E0130916F0122503109129FC001E7
:101A9000139F900D11248A559E4F0E94040380933A
:101AA0005F019093600189CC20916E0130916F01AC
:101AB00022503109C901880F991F820F931F60912D
:101AC00070018C569E4F0E942703A8CC9091720102
:101AD00080E06091700170917101682779272091F1
:101AE0006E0130916F0122503109C901880F991F91
:101AF000820F931FE12C00E024E040E08C569E4FC3
:101B00000E94F803A3CC9091720180E06091700173
:101B1000709171016827792720916E0130916F01D2
:101B200022503109C901880F991F820F931FE12CA0
:101B300000E024E041E08C569E4F0E94F8039ECCCA
:101B400020916E0130916F0122503109C901880F37
:101B5000991F820F931F609172018C569E4F0E94B5
:101B60007304898320916E0130916F0122503109F5
:101B7000C901880F991F820F931F2091700141E0C6
:101B8000BE016F5F7F4F8C569E4F0E94AE038ECC7E
:101B900080917201898320916E0130916F012250F2
:101BA0003109C901880F991F820F931F209170017D
:101BB00041E0BE016F5F7F4F8C569E4F0E94AE0387
:101BC0008DCC80917001909171010AE010E0B80114
:101BD0000E94DD1820916E0130916F012250310971
:101BE000C901880F991F820F931F8C569E4F0E9428
:101BF000730489838091700190917101B8010E94F2
:101C0000DD1820916E0130916F0122503109A90138
:101C1000440F551F420F531F682FCA018C569E4F09
:101C20000E94730480688A8380917201909173018D
:101C3000B8010E94DD1820916E0130916F01225091
:101C40003109C901880F991F820F931F8C569E4F2F
:101C50000E9473048B838091720190917301B8018B
:101C60000E94DD1820916E0130916F0122503109E0
:101C7000A901440F551F420F531F682FCA018C56EC
:101C80009E4F0E9473048C8320916E0130916F01EE
:101C900022503109C901880F991F820F931F20E03C
:101CA00044E0BE016F5F7F4F8C569E4F0E94AE0393
:101CB0002DCC10917001A0907201B0907301AA0C0C
:101CC000BB1CAA0CBB1CC12CD12C59CC8FEF898317
:101CD0008A838B838C8320916E0130916F01225017
:101CE0003109C901880F991F820F931F20E044E03A
:101CF000BE016F5F7F4F8C569E4F0E94AE035ACC41
:101D000019821A821B821C8220916E0130916F0110
:101D100022503109C901880F991F820F931F20E0BB
:101D200044E0BE016F5F7F4F8C569E4F0E94AE0312
:101D300059CC2C960FB6F894DEBF0FBECDBFDF9105
:101D4000CF911F910F91FF90EF90DF90CF90BF90B8
:101D5000AF90089520911B0230E080911C02281B57
:101D60003109C901089580911C0290911B028917C5
:101D700050F4E82FF0E0E35EFD4F208130E08F5F0C
:101D800080931C0202C02FEF3FEFC9010895E0913C
:101D90001C0280911B02E81730F4F0E0E35EFD4F77
:101DA000208130E002C02FEF3FEFC9010895089570
:101DB000E091F301F091F4013097E1F030911C02D1
:101DC00020911B023217B0F040E009C0DC01A20FE5
:101DD000B31F5C91D901A35EBD4F5C934F5F242F6D
:101DE00030E02617370794F310921C0260931B0211
:101DF000CB0109940895E091F501F091F601309737
:101E000029F01092F9011092F80109940895CF92E7
:101E1000DF92EF92FF920F931F93CF93DF937C019A
:101E2000CB018A012091F701222391F0EB016B0194
:101E3000C40ED51E09C06991D701ED91FC910190A6
:101E4000F081E02DC7010995CC15DD05A1F703C090
:101E5000642F0E948E10C801DF91CF911F910F91C6
:101E6000FF90EF90DF90CF900895CF93DF931F9274
:101E7000CDB7DEB769832091F7012223D1F02091FD
:101E8000F801203240F021E030E0FC01338322836E
:101E900020E030E015C08091F901E82FF0E0E65035
:101EA000FE4F998190838F5F8093F9018093F801B1
:101EB00005C061E0CE0101960E948E1021E030E065
:101EC000C9010F90DF91CF910895FC011382128216
:101ED00048EE53E060E070E0448355836683778387
:101EE00084E391E091838083089510921C02109204
:101EF0001B021092F9011092F8010C94D40FCF93A9
:101F0000DF93EC01862F0E94F20F8BEF9EE00E9480
:101F1000AC1088ED9EE00E94A710CE01DF91CF911A
:101F20000C94750F0C947F0F862F413208F040E21D
:101F30006DE172E00E94F60F10921C0280931B026A
:101F4000089521E00C94940F81E08093F701609351
:101F50001A021092F9011092F80108950C94A40F3E
:101F60000F93062F21E04091F8016AEF71E0809114
:101F70001A020E943B101092F9011092F80110927F
:101F8000F7010F91089561E00C94B00F7093F40184
:101F90006093F30108957093F6016093F50108953D
:101FA00087EE91E00C94650F1092460281E08093D9
:101FB00044021092430261E082E10E94D51261E086
:101FC00083E10E94D512E9EBF0E080818E7F80836F
:101FD00080818D7F808382E08093B80085E4809348
:101FE000BC000895880F8093BA000895413208F02C
:101FF0003FC0909146029111FCCF91E09093460230
:10200000209344022FEF20933D0210924202242F8E
:102010002150209341029093450290914502880FF0
:10202000892B8093450280914302813041F41092C4
:102030004302809145028093BB0085EC01C085EE90
:102040008093BC00809146028130E1F3809142028E
:10205000841710F44091420227E432E0FB01D901D9
:1020600002C08D9181938A2F821B8417D0F301C007
:1020700040E0842F08950F93413208F046C09091BC
:1020800046029111FCCF92E09093460200934402E5
:102090009FEF90933D021092420240934102FB0158
:1020A00067E472E0DB0102C091919D939A2F961B29
:1020B0009417D0F31092450290914502880F892B16
:1020C0008093450280914302813041F41092430293
:1020D000809145028093BB0085EC01C085EE809322
:1020E000BC00222321F0809146028230E1F38091EE
:1020F0003D028F3F61F080913D02803251F080912E
:102100003D02803341F483E007C081E005C080E0F8
:1021100003C082E001C084E00F910895613298F419
:1021200020914602243089F460933F02FC0187E647
:1021300092E0DC0102C021912D932A2F281B261743
:10214000D0F380E0089581E0089582E008959093AF
:10215000880280938702089590938A02809389026F
:10216000089585ED8093BC008091BC0084FDFCCF78
:1021700010924602089585EC8093BC0010924602AE
:1021800008951F920F920FB60F9211242F933F9331
:102190004F935F936F937F938F939F93AF93BF936F
:1021A000EF93FF938091B900887F803609F49FC038
:1021B00058F5883209F45BC090F4803109F452C0BC
:1021C00038F4882309F4F8C0883009F0F9C04AC00F
:1021D000883109F44CC0803209F0F2C05CC0803410
:1021E00009F46BC038F4803309F455C0883309F022
:1021F000E7C054C0803509F454C0883509F462C082
:10220000883409F0DDC0DAC0883909F4CBC0A8F4FD
:10221000883709F46CC038F4883609F468C0803710
:1022200009F0CEC064C0883809F4BCC0803909F414
:1022300064C0803809F0C4C060C0803B09F48AC023
:1022400038F4803A09F46BC0883A09F0B9C082C00A
:10225000803C09F4ABC0883C09F4A8C0883B09F075
:10226000AFC08DC0809145028093BB0012C0909199
:10227000420280914102981788F580914202E82F2E
:10228000F0E0E95BFD4F90819093BB008F5F8093FE
:10229000420285EC88C080933D0290C080933D024D
:1022A00056C0809142029091BB00E82FF0E0E95BBC
:1022B000FD4F90838F5F8093420290914202809104
:1022C00041026DC0809142029091BB00E82FF0E086
:1022D000E95BFD4F90838F5F8093420280914402BF
:1022E00081116CC081E08093430284EA60C083E086
:1022F0008093460210923E02CCCF80913E02803203
:1023000008F050C080913E029091BB00E82FF0E0B1
:10231000E557FD4F90838F5F80933E02BACF809147
:102320003E02803230F4E0913E02F0E0E557FD4F8E
:1023300010820E94B11060913E02E0918702F091FC
:10234000880270E08BE892E0099510923E020E94AC
:10235000BB1036C084E08093460210924002109277
:102360003F02E0918902F0918A02099580913F0233
:10237000811105C081E080933F0210926702809135
:102380004002E82FF0E0E959FD4F90819093BB00A7
:102390008F5F809340029091400280913F02981796
:1023A00008F477CF85E88093BC000AC085EC809361
:1023B000BC001092460204C010923D020E94B1106F
:1023C000FF91EF91BF91AF919F918F917F916F910D
:1023D0005F914F913F912F910F900FBE0F901F90E3
:1023E00018958E3008F08E5087702091060140E4D9
:1023F000249F90011124822B80937C0080917A008D
:10240000806480937A0080917A0086FDFCCF2091D1
:10241000780030917900932F80E0AC01422B9A0133
:10242000C90108951F93CF93DF93182FEB0161E04B
:102430000E949D12209711F460E004C0CF3FD105A7
:1024400039F461E0812FDF91CF911F910C94D51267
:10245000E12FF0E0E859FF4FE491E330B9F028F4C0
:10246000E13051F0E230B1F50CC0E63019F1E7305F
:1024700049F1E43079F514C084B5806884BDC7BDE6
:102480002EC084B5806284BDC8BD29C08091800003
:10249000806880938000D0938900C09388001FC01B
:1024A00080918000806280938000D0938B00C093E5
:1024B0008A0015C08091B00080688093B000C093FE
:1024C000B3000DC08091B00080628093B000C093D3
:1024D000B40005C0C038D1050CF0B3CFADCFDF914B
:1024E000CF911F910895833069F028F48130A1F0D5
:1024F000823011F514C08630B1F08730C1F08430DD
:10250000D9F404C0809180008F7703C0809180004F
:102510008F7D80938000089584B58F7702C084B545
:102520008F7D84BD08958091B0008F7703C0809126
:10253000B0008F7D8093B0000895CF93DF9390E03B
:10254000FC01E458FF4F4491FC01E057FF4F849198
:10255000882341F190E0880F991FFC01E854FF4F58
:1025600025913491D90182559F4FFC018591949119
:10257000C82FD92F9FB7F8948C91611106C0409550
:1025800084238C938881842308C0623041F4242FF3
:10259000209582238C938881842B888302C0842B8E
:1025A0008C939FBFDF91CF9108950F931F93CF938B
:1025B000DF931F92CDB7DEB7282F30E0F901E8593D
:1025C000FF4F8491F901E458FF4F1491F901E0574E
:1025D000FF4F04910023D1F0882321F069830E94EA
:1025E00073126981E02FF0E0EE0FFF1FE255FF4FFD
:1025F00085919491DC019FB7F8948C91611103C08F
:102600001095812301C0812B8C939FBF0F90DF9188
:10261000CF911F910F910895CF93DF93282F30E032
:10262000F901E859FF4F8491F901E458FF4FD49123
:10263000F901E057FF4FC491CC2389F081110E942A
:102640007312EC2FF0E0EE0FFF1FEC55FF4F85915A
:102650009491DC018C918D2321E030E011F420E095
:1026600030E0C901DF91CF9108958F929F92AF9290
:10267000BF92CF92DF92EF92FF920F931F93CF936F
:10268000DF9390E0FC01E458FF4FD491FC01E05748
:10269000FF4F7491611102C0C0E001C0CD2FDA017B
:1026A000C901880F991FAA1FBB1F54E0B695A795B3
:1026B000979587955A95D1F7672F70E0660F771F2A
:1026C0006C557F4F812C912C5401FB010591149185
:1026D00010C0C12CD12C7601C394C80CD91CEA1CA3
:1026E000FB1C88169906AA06BB0609F448C04601D9
:1026F0005701F801E081ED23EC1759F310C0C12C0C
:10270000D12C7601C394C80CD91CEA1CFB1C88167A
:102710009906AA06BB0699F14601570103C0FB01C1
:1027200005911491F801E081ED23EC13E8CF8819AD
:102730009909AA09BB0920E030E0A901FB016591D4
:10274000749109C0281739074A075B07C1F02F5F4A
:102750003F4F4F4F5F4FFB01E081ED23EC1791F3AB
:10276000A5E1B0E00E94D2188B019C01005F1F4FD1
:102770002F4F3F4F369527951795079503C000E0DB
:1027800010E09801B801C901DF91CF911F910F911D
:10279000FF90EF90DF90CF90BF90AF909F908F9081
:1027A00008951F920F920FB60F9211242F933F930B
:1027B0008F939F93AF93BF938091AB029091AC02A4
:1027C000A091AD02B091AE023091B302232F285EEA
:1027D0002D3720F40896A11DB11D05C0232F2556C5
:1027E0000996A11DB11D2093B3028093AB02909373
:1027F000AC02A093AD02B093AE028091AF02909173
:10280000B002A091B102B091B2020196A11DB11D1A
:102810008093AF029093B002A093B102B093B20242
:10282000BF91AF919F918F913F912F910F900FBECC
:102830000F901F9018950F931F938FB7F8940091E6
:10284000AB021091AC022091AD023091AE028FBF6D
:10285000B801C9011F910F9108950F931F939FB75E
:10286000F8940091AF021091B0022091B102309122
:10287000B20286B5A89B06C08F3F21F00F5F1F4FA5
:102880002F4F3F4F9FBF322F212F102F0027080FB0
:10289000111D211D311D45E0000F111F221F331F87
:1028A0004A95D1F7B801C9011F910F910895CF92B0
:1028B000DF92EF92FF92CF93DF936B017C010E9436
:1028C0002D14EB010EC00E942D146C1B7D0B683E75
:1028D000734038F081E0C81AD108E108F108C85106
:1028E000DC4FC114D104E104F10469F7DF91CF9109
:1028F000FF90EF90DF90CF900895019739F0019706
:1029000029F0880F991F01970197F1F7089578949E
:1029100084B5826084BD84B5816084BD85B58260E4
:1029200085BD85B5816085BDEEE6F0E08081816082
:102930008083E1E8F0E01082808182608083E0E8BB
:10294000F0E0808181608083E1EBF0E08081846051
:102950008083E0EBF0E0808181608083EAE7F0E053
:1029600080818460808380818260808380818160B7
:1029700080838081806880831092C1000895CF9207
:10298000DF92EF92FF920F931F93CF93DF936C012F
:10299000EB017A01E60EF71E00E010E00BC0699132
:1029A000D601ED91FC910190F081E02DC6010995D1
:1029B000080F191FCE15DF0591F7C801DF91CF91E0
:1029C0001F910F91FF90EF90DF90CF900895DB0162
:1029D0000D900020E9F7AD0141505109461B570BFE
:1029E000DC01ED91FC910280F381E02D09940C94BF
:1029F000E714DC01ED91FC910190F081E02D099448
:102A00000F931F93CF93DF93EC016DE00E94F914B5
:102A10008C016AE0CE010E94F9149C01200F311F45
:102A2000C901DF91CF911F910F9108950F931F93CB
:102A3000CF93DF93EC010E94E7148C01CE010E943A
:102A400000159801280F391FC901DF91CF911F91FF
:102A50000F9108950E9487140E948C07C6E0D6E16A
:102A60000E94AC072097E1F30E940616F9CFFC0103
:102A700084859585FC01E05CFF4F20813181FC015C
:102A8000EE5BFF4F80819181281B390B2F73332719
:102A9000C9010895FC0184859585FC01E05CFF4F28
:102AA00040815181FC01EE5BFF4F20813181421753
:102AB000530741F00190F081E02DE80FF91F2081CC
:102AC00030E002C02FEF3FEFC9010895FC0184857B
:102AD0009585FC01E05CFF4F40815181FC01EE5B7C
:102AE000FF4F208131814217530781F0A081B181CE
:102AF000A80FB91F8C91208131812F5F3F4F2F7319
:102B0000332731832083282F30E002C02FEF3FEF9F
:102B1000C9010895FC0186859785FC01E05CFF4FA3
:102B2000DC01AE5BBF4F408151812D913C911197EB
:102B300042175307C1F70895CF93DF93FC018685B1
:102B40009785DC01A05CBF4F2D913C9111972F5FC1
:102B50003F4F2F733327EC01CE5BDF4F4881598104
:102B600024173507D9F30D90BC91A02DA80FB91FDC
:102B70006C93A685B785A05CBF4F11963C932E93AE
:102B8000A689B7892C9181E090E0058C02C0880F5E
:102B9000991F0A94E2F7282B2C9381E090E0DF91B3
:102BA000CF91089508951F920F920FB60F9211249E
:102BB0002F933F934F938F939F93EF93FF93409166
:102BC000C600809157039091580301968F739927FF
:102BD0002091590330915A038217930759F0E091DD
:102BE0005703F0915803E95EFC4F408390935803DC
:102BF00080935703FF91EF919F918F914F913F9158
:102C00002F910F900FBE0F901F90189584EB92E0BC
:102C10000E943715892B11F00C94D21508951F923C
:102C20000F920FB60F9211242F933F938F939F9380
:102C3000EF93FF93209113033091140380911503B8
:102C4000909116032817390731F48091C1008F7DC8
:102C50008093C10014C0E0911503F0911603ED526A
:102C6000FD4F2081809115039091160301968F737B
:102C7000992790931603809315032093C600FF9124
:102C8000EF919F918F913F912F910F900FBE0F90D9
:102C90001F901895CF92DF92EF92FF92CF93DF9320
:102CA000EC016A017B01EC89FD8981E090E00E8CEA
:102CB00002C0880F991F0A94E2F7808360E271EAEC
:102CC00087E090E0A70196010E94F1182150310998
:102CD000410951095695479537952795211580E16A
:102CE000380798F0EC89FD89108260E970ED83E087
:102CF00090E0A70196010E94F11821503109410985
:102D000051095695479537952795E889F989308374
:102D1000EA89FB892083EE89FF89408181E090E088
:102D20009C010A8C02C0220F331F0A94E2F7422B47
:102D30004083EE89FF8940819C010B8C02C0220FE9
:102D4000331F0A94E2F7422B4083EE89FF894081CA
:102D50009C010C8C02C0220F331F0A94E2F7422B15
:102D60004083EE89FF8920810D8C02C0880F991F56
:102D70000A94E2F7809582238083DF91CF91FF90C0
:102D8000EF90DF90CF9008951092B7021092B602A4
:102D900088EE93E0A0E0B0E08093B8029093B9028F
:102DA000A093BA02B093BB0284E491E09093B50281
:102DB0008093B40287E193E09093C1028093C002B4
:102DC00083ED92E09093C3028093C20285EC90E081
:102DD0009093C5028093C40284EC90E09093C70264
:102DE0008093C60280EC90E09093C9028093C80261
:102DF00081EC90E09093CB028093CA0286EC90E045
:102E00009093CD028093CC0284E08093CE0283E045
:102E10008093CF0287E08093D00285E08093D10237
:102E200081E08093D20208955058BB27AA270ED084
:102E30001CC10DD130F012D120F031F49F3F11F4BC
:102E40001EF402C10EF4E095E7FBF8C0E92F1ED195
:102E500080F3BA17620773078407950718F071F4B7
:102E60009EF536C10EF4E0950B2EBA2FA02D0B0166
:102E7000B90190010C01CA01A0011124FF27591BBF
:102E800099F0593F50F4503E68F11A16F040A22FC5
:102E9000232F342F4427585FF3CF46953795279536
:102EA000A795F0405395C9F77EF41F16BA0B620B35
:102EB000730B840BBAF09150A1F0FF0FBB1F661F7C
:102EC000771F881FC2F70EC0BA0F621F731F841FBF
:102ED00048F4879577956795B795F7959E3F08F0E5
:102EE000B3CF9395880F08F09927EE0F97958795A4
:102EF00008950CD0BAC0B2D040F0A9D030F021F47F
:102F00005F3F19F09BC05111E4C09EC0BFD098F341
:102F10009923C9F35523B1F3951B550BBB27AA275A
:102F200062177307840738F09F5F5F4F220F331FCC
:102F3000441FAA1FA9F333D00E2E3AF0E0E830D098
:102F400091505040E695001CCAF729D0FE2F27D09B
:102F5000660F771F881FBB1F261737074807AB0769
:102F6000B0E809F0BB0B802DBF01FF2793585F4FDE
:102F70002AF09E3F510568F061C0ABC05F3FECF3A3
:102F8000983EDCF3869577956795B795F7959F5FA3
:102F9000C9F7880F911D9695879597F90895E1E0F7
:102FA000660F771F881FBB1F621773078407BA0756
:102FB00020F0621B730B840BBA0BEE1F88F7E095B1
:102FC0000895E89409C097FB3EF49095809570951C
:102FD00061957F4F8F4F9F4F9923A9F0F92F96E965
:102FE000BB279395F695879577956795B795F111DA
:102FF000F8CFFAF4BB0F11F460FF1BC06F5F7F4F77
:103000008F4F9F4F16C0882311F096E911C0772388
:1030100021F09EE8872F762F05C0662371F096E891
:10302000862F70E060E02AF09A95660F771F881F60
:10303000DAF7880F9695879597F9089597F99F671E
:1030400080E870E060E008959FEF80EC0895002430
:103050000A941616170618060906089500240A94FD
:1030600012161306140605060895092E0394000C83
:1030700011F4882352F0BB0F40F4BF2B11F460FF12
:1030800004C06F5F7F4F8F4F9F4F089557FD90583B
:10309000440F551F59F05F3F71F04795880F97FB1C
:1030A000991F61F09F3F79F08795089512161306D6
:1030B0001406551FF2CF4695F1DF08C01616170605
:1030C0001806991FF1CF869571056105089408953A
:1030D000E894BB2766277727CB0197F908950BD093
:1030E000C4CFB5DF28F0BADF18F0952309F0A6CFDA
:1030F000ABCF1124EECFCADFA0F3959FD1F3950F8C
:1031000050E0551F629FF001729FBB27F00DB11D6B
:10311000639FAA27F00DB11DAA1F649F6627B00DFB
:10312000A11D661F829F2227B00DA11D621F739FE4
:10313000B00DA11D621F839FA00D611D221F749FF2
:103140003327A00D611D231F849F600D211D822F39
:10315000762F6A2F11249F5750408AF0E1F0882380
:103160004AF0EE0FFF1FBB1F661F771F881F91508D
:103170005040A9F79E3F510570F060CFAACF5F3F46
:10318000ECF3983EDCF3869577956795B795F795C0
:10319000E7959F5FC1F7FE2B880F911D9695879548
:1031A00097F908950E942F19A59F900DB49F900D37
:1031B000A49F800D911D1124089597FB072E16F4EE
:1031C000009407D077FD09D00E943B1907FC05D079
:1031D0003EF4909581959F4F0895709561957F4F2E
:1031E0000895A1E21A2EAA1BBB1BFD010DC0AA1F48
:1031F000BB1FEE1FFF1FA217B307E407F50720F060
:10320000A21BB30BE40BF50B661F771F881F991FDA
:103210001A9469F760957095809590959B01AC0123
:10322000BD01CF010895052E97FB16F4009407D039
:1032300057FD0DD00E94F11807FC09D07EF490953F
:103240008095709561957F4F8F4F9F4F0895509552
:103250004095309521953F4F4F4F5F4F0895A29F66
:10326000B001B39FC001A39F01D0B29F700D811D1B
:103270001124911D0895AA1BBB1B51E107C0AA1F71
:10328000BB1FA617B70710F0A61BB70B881F991F07
:103290005A95A9F780959095BC01CD010895EE0F40
:1032A000FF1F0590F491E02D09940F931F93CF9386
:1032B000DF93689F8001699F100D789F100D112486
:1032C000C8010E947319C82FD92F209731F0A80187
:1032D00060E070E08C2F0E94AA1ACE01DF91CF919E
:1032E0001F910F9108950F931F93CF93DF93823017
:1032F000910510F482E090E0E0915D03F0915E03AF
:1033000020E030E0C0E0D0E023C040815181481788
:103310005907A8F04817590761F4828193812097D3
:1033200019F09B838A832EC090935E0380935D0384
:1033300029C02115310529F04217530710F0A901C2
:1033400002C0BE01DF0102811381EF019A01F80181
:103350003097D9F62115310509F1281B390B243096
:10336000310590F412968D919C911397611571051A
:1033700021F0FB019383828304C090935E038093CA
:103380005D03FD01329644C0FD01E20FF31F8193FE
:103390009193225031092D933C933AC020915B03C5
:1033A00030915C03232B41F4209102013091030101
:1033B00030935C0320935B03209100013091010165
:1033C0002115310541F42DB73EB7409104015091CC
:1033D0000501241B350BE0915B03F0915C03E217C0
:1033E000F307A0F42E1B3F0B2817390778F0AC0128
:1033F0004E5F5F4F2417350748F04E0F5F1F509305
:103400005C0340935B038193919302C0E0E0F0E0A2
:10341000CF01DF91CF911F910F910895EF92FF920D
:103420000F931F93CF93DF93009709F48EC0DC01B5
:10343000129713961C921E921297E0905D03F090E3
:103440005E03E114F10489F42D913C911197280F4A
:10345000391F80915B0390915C038217930789F574
:10346000B0935C03A0935B0370C0E70120E030E001
:1034700001C0EA01CA17DB0738F44A815B819E016B
:1034800041155105B1F722C0AC0142505109FA0172
:10349000D383C28300811181BC01600F711F6C173F
:1034A0007D0761F468817981600F711F6E5F7F4FC6
:1034B000718360836A817B81738362832115310507
:1034C00029F4B0935E03A0935D033FC0F901B38379
:1034D000A283E90149915991C40FD51FAC17BD07CB
:1034E00071F4DC019E918E91840F951F0296918359
:1034F000808312968D919C91139793838283A0E091
:10350000B0E002C0D7017C01F7018281938100976E
:10351000C9F7C701029620813181820F931F209144
:103520005B0330915C032817390779F4109729F46D
:1035300010925E0310925D0304C013961C921E92BB
:103540001297F0925C03E0925B03CDB7DEB7E6E042
:103550000C94BD1ADC0101C06D9341505040E0F75E
:1035600008952A88398848885F846E847D848C8495
:103570009B84AA84B984C884DF80EE80FD800C819E
:103580001B81AA81B981CE0FD11D0FB6F894DEBF81
:0C3590000FBECDBFED010895F894FFCFF1
:10359C0000005F0320000101000A006400E8033F03
:1035AC00065B4F666D7D077F6F777C395E79715254
:1035BC00656164206661696C005265616479210003
:1035CC0000000000350F070FAA0EB30EC70ED70E62
:1035DC00000000009C15BF14371566154A158A1596
:00000001FF

View file

@ -0,0 +1,864 @@
:100000000C9463000C948B000C948B000C948B006C
:100010000C948B000C948B000C948B000C948B0034
:100020000C948B000C948B000C948B000C948B0024
:100030000C948B000C948B000C948B000C948B0014
:100040000C94D1130C948B000C94D3150C940F16B4
:100050000C948B000C948B000C948B000C948B00F4
:100060000C94C1100C948B000000000700020100EA
:100070000003040600000000000000000102040864
:100080001020408001020408102001020408102002
:10009000040404040404040402020202020203032E
:1000A00003030303000000002300260029000000D2
:1000B0000000250028002B0000000000240027007D
:1000C0002A00D00FC41611241FBECFEFD8E0DEBF28
:1000D000CDBF11E0A0E0B1E0ECE9F5E302C005908E
:1000E0000D92A035B107D9F713E0A0E5B1E001C04A
:1000F0001D92AF35B107E1F710E0C6ECD0E004C0C7
:100100002297FE010E945119C23CD107C9F70E94F3
:100110002A150C94CC1A0C940000CF93DF93EC01B9
:1001200060E088810E94D51284E190E00E947D14F5
:1001300061E088810E94D51284E190E0DF91CF9147
:100140000C947D140F931F93CF93DF93EC01062F34
:1001500018E007FF02C061E001C060E089810E94F1
:10016000D512CE010E948D00000F115091F7DF9142
:10017000CF911F910F910895EF92FF921F93CF930C
:10018000DF9300D0CDB7DEB77C01162F27FF02C06A
:1001900060EC01C060EE26FF606147FF686046FFCB
:1001A000646017FF626016FF6160C70129834A839C
:1001B0000E94A2002981622FC7010E94A2004A81E9
:1001C000642FC7010E94A200612FC7010F900F90FA
:1001D000DF91CF911F91FF90EF900C94A2007F923E
:1001E0008F929F92AF92BF92CF92DF92EF92FF9247
:1001F0000F931F93CF93DF93EC01162F942E822E33
:1002000060E00E94A20060E0CE010E94A20060E0D7
:10021000CE010E94A20060E0CE010E94A20083E015
:10022000189F7001112467018FEFC81AD80A57016F
:1002300082E0A80EB11C712C1FC071120FC0EB819F
:10024000FC81EE0DFF1D9082EB81FC81EC0DFD1D0C
:100250008082EB81FC81EA0DFB1D0083EB81FC8138
:1002600083E0789EE00DF11D11242281418160819F
:10027000CE010E94BC0073948A817816F0F260E08F
:10028000CE010E94A20060E0CE010E94A20060E0C8
:10029000CE010E94A20060E0CE01DF91CF911F91BC
:1002A0000F91FF90EF90DF90CF90BF90AF909F9015
:1002B0008F907F900C94A2000F931F93CF93DF93A6
:1002C000EC01862F688349832A8361E00E949D1296
:1002D00061E089810E949D128A8161E070E023E0E3
:1002E000829FC00111240E9455198B839C8310E0CA
:1002F00008C000E020E040E0612FCE010E94EF0046
:100300001F5F8A811817A8F3DF91CF911F910F917A
:100310000895FC018281089587EE91E00C94750F99
:10032000CF93DF93EC0168E670E087EE91E00E94E6
:10033000AE0F60E087EE91E00E94350F87EE91E00E
:100340000E94C30F47E050E068E670E087EE91E05E
:100350000E94A10F87EE91E00E94B30E382F3695D0
:10036000369536953E70232F220F220F230F8F7064
:100370009927280F288387EE91E00E94B30E282F3B
:1003800022952F708F7099273AE0239F800D1124BA
:10039000898387EE91E00E94B30E382F369536950B
:1003A00036953670232F220F220F230F8F70992737
:1003B000280F2A8387EE91E00E94B30E282F229502
:1003C0002F708F7099273AE0239F800D11248B8323
:1003D00087EE91E00E94B30E282F22952F708F7028
:1003E00099273AE0239F800D11248C8387EE91E0BA
:1003F0000E94B30E282F22952F708F7099273AE014
:10040000239F800D11248D8387EE91E00E94B30E0F
:10041000282F22952F708F7099273AE0239F800D07
:1004200011248E831F82DF91CF910895CF93DF93A4
:10043000EC01862F688319824A831B822C831E82DB
:100440001D8261E00E949D1261E08A81DF91CF915F
:100450000C949D121F93CF93DF93EC0160E08A818F
:100460000E94D5128AE090E00E947D1414E061E0C1
:100470008A810E94D51260E08A810E94D5121150B3
:10048000B1F7DF91CF911F910895FF920F931F93C2
:10049000CF93DF93EC018B0190E1F92E612F661F62
:1004A0006627661F8A810E94D51288810E940C13DC
:1004B00061E0892B09F060E088810E94D512000F6D
:1004C000111FFA9459F7DF91CF911F910F91FF906F
:1004D0000895EF92FF920F931F93CF93DF93EC0158
:1004E0007B01CB0193709E838D8360E070E0CE0131
:1004F0000E94450200E010E08C81882351F0C70182
:10050000002E02C0880F991F0A94E2F791FF0DC0D8
:1005100009C0C701002E02C0969587950A94E2F79C
:1005200080FF03C06FEF70E002C060E070E0CE01BA
:100530000E9445020F5F1F4F0A301105E9F660E087
:1005400070E0CE010E94450260E070E0CE010E94A2
:100550004502CE01DF91CF911F910F91FF90EF9057
:100560000C942A02662321F06B3018F06AE001C077
:1005700061E0262F215061E070E002C0660F771F16
:100580002A95E2F7FC01258136816227732776835D
:1005900065830C946902662321F06B3018F06AE0E1
:1005A00001C061E0562F5150FC012581368161E088
:1005B00070E002C0660F771F5A95E2F7442319F0E6
:1005C000622B732B04C06095709562237323FC012A
:1005D000768365830C9469026B3008F06AE02FEF34
:1005E0003FEF02C0220F331F6A95E2F72095309546
:1005F000FC0136832583B9010C946902FC016483F4
:10060000658176810C946902FC018581968108954B
:10061000FC0181E020813181232B09F480E00895E1
:10062000CF93DF93EC01862F6883498360E00E94BB
:100630009D1260E089810E949D1260E088810E9485
:10064000D51260E08981DF91CF910C94D51268308A
:1006500010F4685F01C06FE0FC016283089561E0FF
:10066000FC0181810E949D1282E390E00C947D1434
:10067000CF93DF93EC0161E089810E949D1282E3B8
:1006800090E00E947D1460E088810E949D1282E3C8
:1006900090E00E947D1460E089810E949D1282E3B7
:1006A00090E0DF91CF910C947D140F931F93CF9323
:1006B000DF93EC01062F18E061E088810E949D1213
:1006C00082E390E00E947D1400FF02C060E001C060
:1006D00061E089810E949D1282E390E00E947D1476
:1006E00060E088810E949D1282E390E00E947D1468
:1006F0000695115009F761E088810E949D1260E023
:1007000089810E949D1282E390E00E947D1460E046
:1007100088810E949D1282E390E00E947D1489816D
:100720000E940C13182F811104C061E089810E947E
:100730009D1282E390E00E947D1461E088810E9416
:100740009D1282E390E00E947D1481E0111101C0AE
:1007500080E0DF91CF911F910F910895CF92DF92AA
:10076000EF92FF920F931F93CF93DF9300D0CDB7FB
:10077000DEB76C01F62EE42E29837A830E942F03C4
:1007800060E4C6010E945503C6010E943803C601F9
:100790000E942F032981622F63706054C6010E945A
:1007A00055030F2D7A81172F06C0F80161918F0133
:1007B000C6010E945503802F8F198E15B0F3C60114
:1007C0000E943803C6010E942F03F601628160581F
:1007D000C6010E945503C6010F900F90DF91CF9183
:1007E0001F910F91FF90EF90DF90CF900C94380302
:1007F0004F925F926F927F928F929F92AF92BF9231
:10080000CF92DF92EF920F931F93CF93DF9300D09D
:1008100000D0CDB7DEB73C016B01322F202F8FE027
:10082000A82E81E0B82E88248394912C8C0E9D1ED6
:10083000F40101E01FE3D5015E904E905D01C60119
:10084000B2010E94DD186115710561F4411106C005
:10085000002321F08E2F8819833011F4108313C0E8
:10086000108211C0DB01AF70BB27A15FBE4F8C911E
:100870008083649DC001659D900D749D900D112431
:10088000C81AD90A00E0EE2039F08E2F881981307D
:1008900019F48081806880833196B7E0AB16B1E0AF
:1008A000BB0649F684E090E0831B9109BE016F5FAF
:1008B0007F4F680F791F432FC3010E94AE030F9033
:1008C0000F900F900F90DF91CF911F910F91EF90AC
:1008D000DF90CF90BF90AF909F908F907F906F9060
:1008E0005F904F9008956F70E62FF0E0E15FFE4F4C
:1008F00080810895FC0181E09081911101C080E028
:1009000008951F93CF93DF931F92CDB7DEB7162FB5
:1009100087EE91E049830E94750F6CE470E087EEEA
:1009200091E00E94AE0F612F87EE91E00E94350F9B
:100930004981642F87EE91E00E94350F87EE91E0A8
:100940000F90DF91CF911F910C94C30F462F67E05A
:100950000C948104462F68E00C948104CF93DF93BC
:10096000EC0160E00E94A60460E0CE010E94AA04AF
:1009700061E0CE01DF91CF910C94A6044F925F927B
:100980006F927F928F929F92AF92BF92CF92DF929F
:10099000EF92FF920F931F93CF93DF9300D01F929C
:1009A000CDB7DEB75B016A01790180E48B838A836E
:1009B00089830E941B142B013C010DC00E941B1453
:1009C0006419750986099709653F7140810591058C
:1009D00014F080E06EC087EE91E00E94AA0E181617
:1009E000190664F387EE91E00E94B30E43E050E0F5
:1009F0006CE470E087EE91E00E94A10F0E941B144E
:100A00002B013C018E010F5F1F4F48012DC0C80113
:100A1000881999090397D4F40E941B142B013C01F7
:100A200011C087EE91E00E94B30EF80180830E940E
:100A30001B146419750986099709633371058105CB
:100A400091053CF6F8018081803458F70E941B1410
:100A50000F5F1F4F6419750986099709653F71403B
:100A6000810591050CF0B5CF87EE91E00E94AA0EAA
:100A7000892B69F69981892F880F880F95FD8D5FE5
:100A800085958595F50180839A81892F880F880F38
:100A900095FD8D5F85958595F60180839B81892FD6
:100AA000880F880F95FD8D5F85958595F70180836B
:100AB00081E00F900F900F90DF91CF911F910F91D8
:100AC000FF90EF90DF90CF90BF90AF909F908F906E
:100AD0007F906F905F904F900895CF93DF93EC01DC
:100AE000862F6E834F83288791E09D8760E00E9468
:100AF0009D1261E08E810E94D51219861A861B868E
:100B00001C86DF91CF910895DF92EF92FF920F93B1
:100B10001F93CF93DF93EC0161E08E810E94D51289
:100B20006AEF70E080E090E00E9457140E941B146E
:100B300009851A852B853C85601771078207930705
:100B400020F419861A861B861C862D85211111C05A
:100B500009851A852B853C85DC01CB01801B910B17
:100B6000A20BB30B803D9740A105B10510F481E0C5
:100B700073C01D860E941B1469877A878B879C87A8
:100B80001C821B821A821982188261E08E810E9467
:100B90009D1260E08E810E94D51264E170E080E0D9
:100BA00090E00E945714F89461E08E810E94D51263
:100BB00088E290E00E947D1460E08E810E949D1288
:100BC000F12CD12C81E009C0E39481E090E00E94F7
:100BD0007D148FEFE81204C009C0E12C082F10E04B
:100BE0008E810E940C138017910771F38E810E94F1
:100BF0000C139FEFE916C9F023E02F1590F4F0FCD9
:100C000010C09D2D969596959695FE01E90FF11DC4
:100C10009081990F908328852E1510F49160908310
:100C2000D394F39495E5F912D8CF789427E22D1553
:100C300090F42C8130E04881898190E0840F911DEF
:100C40004A81840F911D4B81840F911D992728178C
:100C5000390709F48CCF80E0DF91CF911F910F917C
:100C6000FF90EF90DF900895EF92FF920F931F9304
:100C7000CF93DF93EC010E948405882391F18F814B
:100C80008B3029F070F18551823058F507C06881AA
:100C900070E080E090E00E94E1172DC0688170E074
:100CA00080E090E00E94E11720E030E040E853E46B
:100CB0000E946F187B018C01698170E080E090E0F8
:100CC0000E94E3179B01AC016E2D7F2D802F912F89
:100CD0000E94151720E030E040E251E40E947917AD
:100CE0000AC06FE171E084EB92E00E94F71460E0CB
:100CF00070E080EC9FE7DF91CF911F910F91FF9003
:100D0000EF900895CF92DF92EF92FF920F931F938F
:100D1000CF93DF938C01C62F0E948405882309F4AA
:100D200077C0F80187818B3039F008F471C08551A4
:100D3000823008F06DC01DC0F801628170E080E073
:100D400090E00E94E117B62FA72FF82FE92F462F2A
:100D5000572F682F792FCB01BA01CC2309F462C039
:100D600020E030E040E151E46B2F7A2F8F2F9E2F4F
:100D700037C0F801D2816D2F6F7770E080E090E08E
:100D80000E94E31720E030E040E853E40E946F182F
:100D90006B017C01F801638170E080E090E00E94CB
:100DA000E3179B01AC016C2D7D2D8E2D9F2D0E9494
:100DB000151720E030E040E251E40E947917472FF8
:100DC000382F292F862F942FA32FB22FBC01CD01AE
:100DD000D7FD9058CC2331F120E030E040E151E4E0
:100DE0000E946F1820E030E040EA50E40E9479173A
:100DF00020E030E040E052E40E941517472F382FE2
:100E0000292F862F942FA32FB22FBC01CD010AC00A
:100E10006FE171E084EB92E00E94F71460E070E013
:100E200080EC9FE7DF91CF911F910F91FF90EF90A2
:100E3000DF90CF900895CF93DF9322C087EE91E0AB
:100E40000E94AA0E049741F4109269011092680161
:100E500010926B0110926A01C0916A01D0916B01EE
:100E600087EE91E00E94B30EFE01EE0FFF1FE459E2
:100E7000FE4F918380832196D0936B01C0936A01CA
:100E800087EE91E00E94AA0E892BC1F6DF91CF91E7
:100E9000089580916C0190916D01019731F46091FA
:100EA000670187EE91E00E94350F80916C0190916F
:100EB0006D018330910529F08730910511F0C897B5
:100EC00041F443E050E06EE571E087EE91E00E946E
:100ED000070F80916C0190916D018830910511F0A0
:100EE000449741F444E050E06EE571E087EE91E014
:100EF0000E94070F80916C0190916D018E319105D8
:100F000011F0889741F449E050E06EE571E087EE1A
:100F100091E00C94070F089540E855E260E070E01E
:100F200084EB92E00E944A1665E070E087EE91E063
:100F30000E94920F6BE177E087EE91E00E94C60F6E
:100F400069E477E087EE91E00E94CB0F69E271E0FF
:100F500084EB92E00C941615AF92BF92CF92DF9281
:100F6000EF92FF920F931F93CF93DF93CDB7DEB72E
:100F70002C970FB6F894DEBF0FBECDBF80916A01EB
:100F800090916B01049709F0D4C68091680190910B
:100F90006901892B09F0CDC681E090E09093690149
:100FA0008093680180916C0190916D01019731F4FB
:100FB00080916E010E940C138093670180916C01F7
:100FC00090916D01029731F46091700180916E01F2
:100FD0000E94D51280916C0190916D010397A9F444
:100FE00080916E010E94F11190935D0180935C01EC
:100FF0009C0197FF02C021503F4F30935F0160E09A
:1010000071E00E94DD188093600180916C019091E5
:101010006D01049741F460917001709171018091AC
:101020006E010E94121280916C0190916D010597E2
:1010300031F46091700180916E010E949D12809147
:101040006C0190916D01079709F042C080916E018B
:1010500090916F01809352019093530161E00E943F
:101060009D1260E0809152010E94D51282E090E0D2
:101070000E947D1461E0809152010E94D51285E0AA
:1010800090E00E947D1460E0809152010E94D51290
:1010900060E0809152010E949D1220E432E44FE012
:1010A00050E061E0809152010E9435132AE330E064
:1010B00040E050E00E941319CA01B90120E031E07C
:1010C00040E050E00E94131920935F01609360019B
:1010D00080916C0190916D018830910539F481E027
:1010E00080935F0182E08093600121C0449709F5FD
:1010F00080915B01811107C086EE91E00E94AE04F1
:1011000081E080935B0129E531E048E551E067E546
:1011100071E086EE91E00E94BE04809157018093B9
:101120005F01809158018093600180915901809303
:10113000610180916C0190916D014E9769F58091EC
:101140005A01811107C08EED91E00E948C0181E06F
:1011500080935A018EED91E00E9490018091E00110
:1011600080935F018091DF01809360018091DE01B7
:10117000809361018091E301809362018091E2019B
:10118000809363019091E4019093640180936501E1
:101190008091E1018093660180916C0190916D01D5
:1011A000889709F059C08091700190917101009762
:1011B00019F426E04BE005C08130910549F426E0A2
:1011C00046E160916E0180ED91E00E946D0508C0DE
:1011D0008230910519F426E045E1F3CF0397D9F366
:1011E00060E080ED91E00E94820669877A878B87B4
:1011F0009C8780ED91E00E9434066D837E838F830F
:1012000098871092510110925001FE01399680E0AA
:1012100090E001962191DC01A25ABE4F2C938430BC
:101220009105BCF384E090E09093510180935001CC
:101230000196DC01A25ABE4FE5E0F0E0EC0FFD1F85
:10124000E80FF91F359720812C938830910584F39E
:10125000909351018093500180916C0190916D01A8
:10126000C297D9F480916E0190916F01482F21E0CF
:101270006091700170917101672B09F420E0642F77
:101280006F5FFC01329737E03E9FC0013F9F900D9A
:1012900011248A559E4F0E94160280916C019091F4
:1012A0006D01C39791F420916E0130916F0122502E
:1012B000310947E0429FC001439F900D11248A5598
:1012C0009E4F0E94080381116AC380916C01909126
:1012D0006D01C49791F420916E0130916F012250FD
:1012E000310917E0129FC001139F900D11248A55F8
:1012F0009E4F0E94080381116BC380916C019091F5
:101300006D01C59791F420916E0130916F012250CB
:10131000310947E0429FC001439F900D11248A5537
:101320009E4F0E940803811165C380916C019091CA
:101330006D01C69791F420916E0130916F0122509A
:10134000310917E0129FC001139F900D11248A5597
:101350009E4F0E940803811168C380916C01909197
:101360006D01C79791F420916E0130916F01225069
:10137000310917E0129FC001139F900D11248A5567
:101380009E4F0E940803811162C380916C0190916D
:101390006D01C89791F420916E0130916F01225038
:1013A000310917E0129FC001139F900D11248A5537
:1013B0009E4F0E940803811163C380916C0190913C
:1013C0006D018634910591F460916E0170916F0109
:1013D000462F4F5F9B0122503109C901880F991F89
:1013E000820F931F8C569E4F0E94100380916C01B8
:1013F00090916D018734910589F420916E013091AF
:101400006F0122503109C901880F991F820F931F64
:101410008C569E4F0E947A04811146C380916C01C4
:1014200090916D018834910589F420916E0130917D
:101430006F0122503109C901880F991F820F931F34
:101440008C569E4F0E947A04811140C380916C019A
:1014500090916D018934910589F420916E0130914C
:101460006F0122503109C901880F991F820F931F04
:101470008C569E4F0E947A04811145C380916C0165
:1014800090916D018A34910589F420916E0130911B
:101490006F0122503109C901880F991F820F931FD4
:1014A0008C569E4F0E947A0481114AC380916C0130
:1014B00090916D018B34910589F420916E013091EA
:1014C0006F0122503109C901880F991F820F931FA4
:1014D0008C569E4F0E947A0481115AC380916C01F0
:1014E00090916D018C34910589F420916E013091B9
:1014F0006F0122503109C901880F991F820F931F74
:101500008C569E4F0E947A0481115BC380916C01BE
:1015100090916D018D349105A9F520916E01309166
:101520006F0122503109C901880F991F820F931F43
:101530008C569E4F0E947A048111BBC323C0812F19
:101540000E94F111BC0120916E0130916F01225077
:101550003109C901880F991F820F931FE12C00E008
:1015600024E040E08C569E4F0E94F8036AEF70E042
:1015700080E090E00E9457142FEFC21AD20ACA14DA
:10158000DB04ECF280916C0190916D018E34910539
:1015900089F420916E0130916F0122503109C90107
:1015A000880F991F820F931F8C569E4F0E947A04BA
:1015B00081118CC380916C0190916D018F349105E4
:1015C00089F420916E0130916F0122503109C901D7
:1015D000880F991F820F931F8C569E4F0E947A048A
:1015E00081118EC380916C0190916D018A359105B6
:1015F00069F480916E018093540180917001809311
:101600005501809172018093560118C08B35910568
:10161000A9F460916E0170916F01462F4F5F9B019D
:101620002250310955E0529FC001539F900D112463
:10163000209170018A589E4F0E945C0180916C013C
:1016400090916D018C35910549F080916C019091DC
:101650006D018D35910509F0BDC048C060916E01E6
:1016600070916F01462F4F5F9B012250310955E069
:10167000529FC001539F900D1124209170018A58F0
:101680009E4F0E945C01009172011091730102FB58
:10169000DD24D0F8D19401FBCC24C0F8C1940170B2
:1016A0001127102F1195E12CF12CA5E0BA2E16C0B0
:1016B00060916E0170916F0162507109B69EC00118
:1016C000B79E900D1124012F2C2D4D2D6E2D8A5873
:1016D0009E4F0E94EF003FEFE31AF30A80917001E2
:1016E00090917101E816F9061CF3AFCF20917001BB
:1016F0003091710180916E0190916F01232BB1F4B3
:101700009C012250310945E0429FC001439F900D4A
:10171000112400915601209155014091540160918E
:1017200072018A589E4F0E94EF0054C09C012250C3
:10173000310945E0429FC001439F900D11248A5812
:101740009E4F0E948901E12CF12CC82ED12C15E06E
:101750003DC020917001309171012130310541F47B
:101760008091720190917301E816F906B1F42BC0D3
:101770002230310541F480917201909173018E15F0
:101780009F055CF420C023303105E9F4809172019B
:1017900090917301E816F906B4F020916E01309132
:1017A0006F0122503109129FC001139F900D112427
:1017B0000091560120915501409154016E2D8A5897
:1017C0009E4F0E94EF008FEFE81AF80AEC14FD0418
:1017D0000CF4BFCF80916C0190916D018E35910515
:1017E00049F080916C0190916D018F35910509F060
:1017F000A0C252C08091720190917301181619060F
:1018000034F081E090E09093730180937201209115
:101810006E0130916F012250310945E0429FC001B5
:10182000439F900D11248A589E4F0E948901E09099
:101830007001F0907101C82ED12C15E029C0809163
:101840007001909171019701281B390BC9016091BA
:101850007201709173010E94DD18892BB1F42091FF
:101860006E0130916F0122503109129FC001139F08
:10187000900D112400915601209155014091540181
:101880006E2D8A589E4F0E94EF003FEFE31AF30A35
:10189000EC14FD04A4F2A5CF20916E0130916F01EC
:1018A0002250310945E0429FC001439F900D112411
:1018B0008A589E4F0E9489012091720130917301D4
:1018C000232B59F133C080917001909171012091C7
:1018D0006E0130916F0122503109E816F90664F467
:1018E000129FC001139F900D112400915601209169
:1018F00055014091540108C0129FC001139F900DE3
:10190000112400E020E040E06E2D8A589E4F0E9496
:10191000EF008FEFE81AF80A05C0E12CF12CC82E71
:10192000D12C15E0EC14FD0474F203C2C82ED12CA6
:10193000760115E030C0809170019091710196019F
:10194000281B390B80916E0190916F01E216F3060E
:101950007CF09C0122503109129FC001139F900D11
:1019600011240091560120915501409154010BC062
:101970009C0122503109129FC001139F900D112428
:1019800000E020E040E06E2D8A589E4F0E94EF005C
:1019900021E0E21AF108E114F10469F6CAC161E03C
:1019A0008091700190917101892B09F460E0209180
:1019B0006E0130916F012250310947E0429FC00112
:1019C000439F900D11248A559E4F0E94FE027DCCAC
:1019D00020916E0130916F0122503109129FC00198
:1019E000139F900D1124609170018A559E4F0E94A3
:1019F000EC0283CC41E08091720190917301892BBC
:101A000009F440E020916E0130916F0122503109BC
:101A100057E0529FC001539F900D112460917001B7
:101A20008A559E4F0E94CB0280CC20916E0130914E
:101A30006F0122503109129FC001139F900D112494
:101A4000609170018A559E4F0E94B20286CC90919F
:101A5000720180E0609170017091710168277927AF
:101A600020916E0130916F0122503109129FC00107
:101A7000139F900D11248A559E4F0E94690285CCB8
:101A800020916E0130916F0122503109129FC001E7
:101A9000139F900D11248A559E4F0E94040380933A
:101AA0005F019093600189CC20916E0130916F01AC
:101AB00022503109C901880F991F820F931F60912D
:101AC00070018C569E4F0E942703A8CC9091720102
:101AD00080E06091700170917101682779272091F1
:101AE0006E0130916F0122503109C901880F991F91
:101AF000820F931FE12C00E024E040E08C569E4FC3
:101B00000E94F803A3CC9091720180E06091700173
:101B1000709171016827792720916E0130916F01D2
:101B200022503109C901880F991F820F931FE12CA0
:101B300000E024E041E08C569E4F0E94F8039ECCCA
:101B400020916E0130916F0122503109C901880F37
:101B5000991F820F931F609172018C569E4F0E94B5
:101B60007304898320916E0130916F0122503109F5
:101B7000C901880F991F820F931F2091700141E0C6
:101B8000BE016F5F7F4F8C569E4F0E94AE038ECC7E
:101B900080917201898320916E0130916F012250F2
:101BA0003109C901880F991F820F931F209170017D
:101BB00041E0BE016F5F7F4F8C569E4F0E94AE0387
:101BC0008DCC80917001909171010AE010E0B80114
:101BD0000E94DD1820916E0130916F012250310971
:101BE000C901880F991F820F931F8C569E4F0E9428
:101BF000730489838091700190917101B8010E94F2
:101C0000DD1820916E0130916F0122503109A90138
:101C1000440F551F420F531F682FCA018C569E4F09
:101C20000E94730480688A8380917201909173018D
:101C3000B8010E94DD1820916E0130916F01225091
:101C40003109C901880F991F820F931F8C569E4F2F
:101C50000E9473048B838091720190917301B8018B
:101C60000E94DD1820916E0130916F0122503109E0
:101C7000A901440F551F420F531F682FCA018C56EC
:101C80009E4F0E9473048C8320916E0130916F01EE
:101C900022503109C901880F991F820F931F20E03C
:101CA00044E0BE016F5F7F4F8C569E4F0E94AE0393
:101CB0002DCC10917001A0907201B0907301AA0C0C
:101CC000BB1CAA0CBB1CC12CD12C59CC8FEF898317
:101CD0008A838B838C8320916E0130916F01225017
:101CE0003109C901880F991F820F931F20E044E03A
:101CF000BE016F5F7F4F8C569E4F0E94AE035ACC41
:101D000019821A821B821C8220916E0130916F0110
:101D100022503109C901880F991F820F931F20E0BB
:101D200044E0BE016F5F7F4F8C569E4F0E94AE0312
:101D300059CC2C960FB6F894DEBF0FBECDBFDF9105
:101D4000CF911F910F91FF90EF90DF90CF90BF90B8
:101D5000AF90089520911B0230E080911C02281B57
:101D60003109C901089580911C0290911B028917C5
:101D700050F4E82FF0E0E35EFD4F208130E08F5F0C
:101D800080931C0202C02FEF3FEFC9010895E0913C
:101D90001C0280911B02E81730F4F0E0E35EFD4F77
:101DA000208130E002C02FEF3FEFC9010895089570
:101DB000E091F301F091F4013097E1F030911C02D1
:101DC00020911B023217B0F040E009C0DC01A20FE5
:101DD000B31F5C91D901A35EBD4F5C934F5F242F6D
:101DE00030E02617370794F310921C0260931B0211
:101DF000CB0109940895E091F501F091F601309737
:101E000029F01092F9011092F80109940895CF92E7
:101E1000DF92EF92FF920F931F93CF93DF937C019A
:101E2000CB018A012091F701222391F0EB016B0194
:101E3000C40ED51E09C06991D701ED91FC910190A6
:101E4000F081E02DC7010995CC15DD05A1F703C090
:101E5000642F0E948E10C801DF91CF911F910F91C6
:101E6000FF90EF90DF90CF900895CF93DF931F9274
:101E7000CDB7DEB769832091F7012223D1F02091FD
:101E8000F801203240F021E030E0FC01338322836E
:101E900020E030E015C08091F901E82FF0E0E65035
:101EA000FE4F998190838F5F8093F9018093F801B1
:101EB00005C061E0CE0101960E948E1021E030E065
:101EC000C9010F90DF91CF910895FC011382128216
:101ED00048EE53E060E070E0448355836683778387
:101EE00084E391E091838083089510921C02109204
:101EF0001B021092F9011092F8010C94D40FCF93A9
:101F0000DF93EC01862F0E94F20F8BEF9EE00E9480
:101F1000AC1088ED9EE00E94A710CE01DF91CF911A
:101F20000C94750F0C947F0F862F413208F040E21D
:101F30006DE172E00E94F60F10921C0280931B026A
:101F4000089521E00C94940F81E08093F701609351
:101F50001A021092F9011092F80108950C94A40F3E
:101F60000F93062F21E04091F8016AEF71E0809114
:101F70001A020E943B101092F9011092F80110927F
:101F8000F7010F91089561E00C94B00F7093F40184
:101F90006093F30108957093F6016093F50108953D
:101FA00087EE91E00C94650F1092460281E08093D9
:101FB00044021092430261E082E10E94D51261E086
:101FC00083E10E94D512E9EBF0E080818E7F80836F
:101FD00080818D7F808382E08093B80085E4809348
:101FE000BC000895880F8093BA000895413208F02C
:101FF0003FC0909146029111FCCF91E09093460230
:10200000209344022FEF20933D0210924202242F8E
:102010002150209341029093450290914502880FF0
:10202000892B8093450280914302813041F41092C4
:102030004302809145028093BB0085EC01C085EE90
:102040008093BC00809146028130E1F3809142028E
:10205000841710F44091420227E432E0FB01D901D9
:1020600002C08D9181938A2F821B8417D0F301C007
:1020700040E0842F08950F93413208F046C09091BC
:1020800046029111FCCF92E09093460200934402E5
:102090009FEF90933D021092420240934102FB0158
:1020A00067E472E0DB0102C091919D939A2F961B29
:1020B0009417D0F31092450290914502880F892B16
:1020C0008093450280914302813041F41092430293
:1020D000809145028093BB0085EC01C085EE809322
:1020E000BC00222321F0809146028230E1F38091EE
:1020F0003D028F3F61F080913D02803251F080912E
:102100003D02803341F483E007C081E005C080E0F8
:1021100003C082E001C084E00F910895613298F419
:1021200020914602243089F460933F02FC0187E647
:1021300092E0DC0102C021912D932A2F281B261743
:10214000D0F380E0089581E0089582E008959093AF
:10215000880280938702089590938A02809389026F
:10216000089585ED8093BC008091BC0084FDFCCF78
:1021700010924602089585EC8093BC0010924602AE
:1021800008951F920F920FB60F9211242F933F9331
:102190004F935F936F937F938F939F93AF93BF936F
:1021A000EF93FF938091B900887F803609F49FC038
:1021B00058F5883209F45BC090F4803109F452C0BC
:1021C00038F4882309F4F8C0883009F0F9C04AC00F
:1021D000883109F44CC0803209F0F2C05CC0803410
:1021E00009F46BC038F4803309F455C0883309F022
:1021F000E7C054C0803509F454C0883509F462C082
:10220000883409F0DDC0DAC0883909F4CBC0A8F4FD
:10221000883709F46CC038F4883609F468C0803710
:1022200009F0CEC064C0883809F4BCC0803909F414
:1022300064C0803809F0C4C060C0803B09F48AC023
:1022400038F4803A09F46BC0883A09F0B9C082C00A
:10225000803C09F4ABC0883C09F4A8C0883B09F075
:10226000AFC08DC0809145028093BB0012C0909199
:10227000420280914102981788F580914202E82F2E
:10228000F0E0E95BFD4F90819093BB008F5F8093FE
:10229000420285EC88C080933D0290C080933D024D
:1022A00056C0809142029091BB00E82FF0E0E95BBC
:1022B000FD4F90838F5F8093420290914202809104
:1022C00041026DC0809142029091BB00E82FF0E086
:1022D000E95BFD4F90838F5F8093420280914402BF
:1022E00081116CC081E08093430284EA60C083E086
:1022F0008093460210923E02CCCF80913E02803203
:1023000008F050C080913E029091BB00E82FF0E0B1
:10231000E557FD4F90838F5F80933E02BACF809147
:102320003E02803230F4E0913E02F0E0E557FD4F8E
:1023300010820E94B11060913E02E0918702F091FC
:10234000880270E08BE892E0099510923E020E94AC
:10235000BB1036C084E08093460210924002109277
:102360003F02E0918902F0918A02099580913F0233
:10237000811105C081E080933F0210926702809135
:102380004002E82FF0E0E959FD4F90819093BB00A7
:102390008F5F809340029091400280913F02981796
:1023A00008F477CF85E88093BC000AC085EC809361
:1023B000BC001092460204C010923D020E94B1106F
:1023C000FF91EF91BF91AF919F918F917F916F910D
:1023D0005F914F913F912F910F900FBE0F901F90E3
:1023E00018958E3008F08E5087702091060140E4D9
:1023F000249F90011124822B80937C0080917A008D
:10240000806480937A0080917A0086FDFCCF2091D1
:10241000780030917900932F80E0AC01422B9A0133
:10242000C90108951F93CF93DF93182FEB0161E04B
:102430000E949D12209711F460E004C0CF3FD105A7
:1024400039F461E0812FDF91CF911F910C94D51267
:10245000E12FF0E0E859FF4FE491E330B9F028F4C0
:10246000E13051F0E230B1F50CC0E63019F1E7305F
:1024700049F1E43079F514C084B5806884BDC7BDE6
:102480002EC084B5806284BDC8BD29C08091800003
:10249000806880938000D0938900C09388001FC01B
:1024A00080918000806280938000D0938B00C093E5
:1024B0008A0015C08091B00080688093B000C093FE
:1024C000B3000DC08091B00080628093B000C093D3
:1024D000B40005C0C038D1050CF0B3CFADCFDF914B
:1024E000CF911F910895833069F028F48130A1F0D5
:1024F000823011F514C08630B1F08730C1F08430DD
:10250000D9F404C0809180008F7703C0809180004F
:102510008F7D80938000089584B58F7702C084B545
:102520008F7D84BD08958091B0008F7703C0809126
:10253000B0008F7D8093B0000895CF93DF9390E03B
:10254000FC01E458FF4F4491FC01E057FF4F849198
:10255000882341F190E0880F991FFC01E854FF4F58
:1025600025913491D90182559F4FFC018591949119
:10257000C82FD92F9FB7F8948C91611106C0409550
:1025800084238C938881842308C0623041F4242FF3
:10259000209582238C938881842B888302C0842B8E
:1025A0008C939FBFDF91CF9108950F931F93CF938B
:1025B000DF931F92CDB7DEB7282F30E0F901E8593D
:1025C000FF4F8491F901E458FF4F1491F901E0574E
:1025D000FF4F04910023D1F0882321F069830E94EA
:1025E00073126981E02FF0E0EE0FFF1FE255FF4FFD
:1025F00085919491DC019FB7F8948C91611103C08F
:102600001095812301C0812B8C939FBF0F90DF9188
:10261000CF911F910F910895CF93DF93282F30E032
:10262000F901E859FF4F8491F901E458FF4FD49123
:10263000F901E057FF4FC491CC2389F081110E942A
:102640007312EC2FF0E0EE0FFF1FEC55FF4F85915A
:102650009491DC018C918D2321E030E011F420E095
:1026600030E0C901DF91CF9108958F929F92AF9290
:10267000BF92CF92DF92EF92FF920F931F93CF936F
:10268000DF9390E0FC01E458FF4FD491FC01E05748
:10269000FF4F7491611102C0C0E001C0CD2FDA017B
:1026A000C901880F991FAA1FBB1F54E0B695A795B3
:1026B000979587955A95D1F7672F70E0660F771F2A
:1026C0006C557F4F812C912C5401FB010591149185
:1026D00010C0C12CD12C7601C394C80CD91CEA1CA3
:1026E000FB1C88169906AA06BB0609F448C04601D9
:1026F0005701F801E081ED23EC1759F310C0C12C0C
:10270000D12C7601C394C80CD91CEA1CFB1C88167A
:102710009906AA06BB0699F14601570103C0FB01C1
:1027200005911491F801E081ED23EC13E8CF8819AD
:102730009909AA09BB0920E030E0A901FB016591D4
:10274000749109C0281739074A075B07C1F02F5F4A
:102750003F4F4F4F5F4FFB01E081ED23EC1791F3AB
:10276000A5E1B0E00E94D2188B019C01005F1F4FD1
:102770002F4F3F4F369527951795079503C000E0DB
:1027800010E09801B801C901DF91CF911F910F911D
:10279000FF90EF90DF90CF90BF90AF909F908F9081
:1027A00008951F920F920FB60F9211242F933F930B
:1027B0008F939F93AF93BF938091AB029091AC02A4
:1027C000A091AD02B091AE023091B302232F285EEA
:1027D0002D3720F40896A11DB11D05C0232F2556C5
:1027E0000996A11DB11D2093B3028093AB02909373
:1027F000AC02A093AD02B093AE028091AF02909173
:10280000B002A091B102B091B2020196A11DB11D1A
:102810008093AF029093B002A093B102B093B20242
:10282000BF91AF919F918F913F912F910F900FBECC
:102830000F901F9018950F931F938FB7F8940091E6
:10284000AB021091AC022091AD023091AE028FBF6D
:10285000B801C9011F910F9108950F931F939FB75E
:10286000F8940091AF021091B0022091B102309122
:10287000B20286B5A89B06C08F3F21F00F5F1F4FA5
:102880002F4F3F4F9FBF322F212F102F0027080FB0
:10289000111D211D311D45E0000F111F221F331F87
:1028A0004A95D1F7B801C9011F910F910895CF92B0
:1028B000DF92EF92FF92CF93DF936B017C010E9436
:1028C0002D14EB010EC00E942D146C1B7D0B683E75
:1028D000734038F081E0C81AD108E108F108C85106
:1028E000DC4FC114D104E104F10469F7DF91CF9109
:1028F000FF90EF90DF90CF900895019739F0019706
:1029000029F0880F991F01970197F1F7089578949E
:1029100084B5826084BD84B5816084BD85B58260E4
:1029200085BD85B5816085BDEEE6F0E08081816082
:102930008083E1E8F0E01082808182608083E0E8BB
:10294000F0E0808181608083E1EBF0E08081846051
:102950008083E0EBF0E0808181608083EAE7F0E053
:1029600080818460808380818260808380818160B7
:1029700080838081806880831092C1000895CF9207
:10298000DF92EF92FF920F931F93CF93DF936C012F
:10299000EB017A01E60EF71E00E010E00BC0699132
:1029A000D601ED91FC910190F081E02DC6010995D1
:1029B000080F191FCE15DF0591F7C801DF91CF91E0
:1029C0001F910F91FF90EF90DF90CF900895DB0162
:1029D0000D900020E9F7AD0141505109461B570BFE
:1029E000DC01ED91FC910280F381E02D09940C94BF
:1029F000E714DC01ED91FC910190F081E02D099448
:102A00000F931F93CF93DF93EC016DE00E94F914B5
:102A10008C016AE0CE010E94F9149C01200F311F45
:102A2000C901DF91CF911F910F9108950F931F93CB
:102A3000CF93DF93EC010E94E7148C01CE010E943A
:102A400000159801280F391FC901DF91CF911F91FF
:102A50000F9108950E9487140E948C07C6E0D6E16A
:102A60000E94AC072097E1F30E940616F9CFFC0103
:102A700084859585FC01E05CFF4F20813181FC015C
:102A8000EE5BFF4F80819181281B390B2F73332719
:102A9000C9010895FC0184859585FC01E05CFF4F28
:102AA00040815181FC01EE5BFF4F20813181421753
:102AB000530741F00190F081E02DE80FF91F2081CC
:102AC00030E002C02FEF3FEFC9010895FC0184857B
:102AD0009585FC01E05CFF4F40815181FC01EE5B7C
:102AE000FF4F208131814217530781F0A081B181CE
:102AF000A80FB91F8C91208131812F5F3F4F2F7319
:102B0000332731832083282F30E002C02FEF3FEF9F
:102B1000C9010895FC0186859785FC01E05CFF4FA3
:102B2000DC01AE5BBF4F408151812D913C911197EB
:102B300042175307C1F70895CF93DF93FC018685B1
:102B40009785DC01A05CBF4F2D913C9111972F5FC1
:102B50003F4F2F733327EC01CE5BDF4F4881598104
:102B600024173507D9F30D90BC91A02DA80FB91FDC
:102B70006C93A685B785A05CBF4F11963C932E93AE
:102B8000A689B7892C9181E090E0058C02C0880F5E
:102B9000991F0A94E2F7282B2C9381E090E0DF91B3
:102BA000CF91089508951F920F920FB60F9211249E
:102BB0002F933F934F938F939F93EF93FF93409166
:102BC000C600809157039091580301968F739927FF
:102BD0002091590330915A038217930759F0E091DD
:102BE0005703F0915803E95EFC4F408390935803DC
:102BF00080935703FF91EF919F918F914F913F9158
:102C00002F910F900FBE0F901F90189584EB92E0BC
:102C10000E943715892B11F00C94D21508951F923C
:102C20000F920FB60F9211242F933F938F939F9380
:102C3000EF93FF93209113033091140380911503B8
:102C4000909116032817390731F48091C1008F7DC8
:102C50008093C10014C0E0911503F0911603ED526A
:102C6000FD4F2081809115039091160301968F737B
:102C7000992790931603809315032093C600FF9124
:102C8000EF919F918F913F912F910F900FBE0F90D9
:102C90001F901895CF92DF92EF92FF92CF93DF9320
:102CA000EC016A017B01EC89FD8981E090E00E8CEA
:102CB00002C0880F991F0A94E2F7808360E271EAEC
:102CC00087E090E0A70196010E94F1182150310998
:102CD000410951095695479537952795211580E16A
:102CE000380798F0EC89FD89108260E970ED83E087
:102CF00090E0A70196010E94F11821503109410985
:102D000051095695479537952795E889F989308374
:102D1000EA89FB892083EE89FF89408181E090E088
:102D20009C010A8C02C0220F331F0A94E2F7422B47
:102D30004083EE89FF8940819C010B8C02C0220FE9
:102D4000331F0A94E2F7422B4083EE89FF894081CA
:102D50009C010C8C02C0220F331F0A94E2F7422B15
:102D60004083EE89FF8920810D8C02C0880F991F56
:102D70000A94E2F7809582238083DF91CF91FF90C0
:102D8000EF90DF90CF9008951092B7021092B602A4
:102D900088EE93E0A0E0B0E08093B8029093B9028F
:102DA000A093BA02B093BB0284E491E09093B50281
:102DB0008093B40287E193E09093C1028093C002B4
:102DC00083ED92E09093C3028093C20285EC90E081
:102DD0009093C5028093C40284EC90E09093C70264
:102DE0008093C60280EC90E09093C9028093C80261
:102DF00081EC90E09093CB028093CA0286EC90E045
:102E00009093CD028093CC0284E08093CE0283E045
:102E10008093CF0287E08093D00285E08093D10237
:102E200081E08093D20208955058BB27AA270ED084
:102E30001CC10DD130F012D120F031F49F3F11F4BC
:102E40001EF402C10EF4E095E7FBF8C0E92F1ED195
:102E500080F3BA17620773078407950718F071F4B7
:102E60009EF536C10EF4E0950B2EBA2FA02D0B0166
:102E7000B90190010C01CA01A0011124FF27591BBF
:102E800099F0593F50F4503E68F11A16F040A22FC5
:102E9000232F342F4427585FF3CF46953795279536
:102EA000A795F0405395C9F77EF41F16BA0B620B35
:102EB000730B840BBAF09150A1F0FF0FBB1F661F7C
:102EC000771F881FC2F70EC0BA0F621F731F841FBF
:102ED00048F4879577956795B795F7959E3F08F0E5
:102EE000B3CF9395880F08F09927EE0F97958795A4
:102EF00008950CD0BAC0B2D040F0A9D030F021F47F
:102F00005F3F19F09BC05111E4C09EC0BFD098F341
:102F10009923C9F35523B1F3951B550BBB27AA275A
:102F200062177307840738F09F5F5F4F220F331FCC
:102F3000441FAA1FA9F333D00E2E3AF0E0E830D098
:102F400091505040E695001CCAF729D0FE2F27D09B
:102F5000660F771F881FBB1F261737074807AB0769
:102F6000B0E809F0BB0B802DBF01FF2793585F4FDE
:102F70002AF09E3F510568F061C0ABC05F3FECF3A3
:102F8000983EDCF3869577956795B795F7959F5FA3
:102F9000C9F7880F911D9695879597F90895E1E0F7
:102FA000660F771F881FBB1F621773078407BA0756
:102FB00020F0621B730B840BBA0BEE1F88F7E095B1
:102FC0000895E89409C097FB3EF49095809570951C
:102FD00061957F4F8F4F9F4F9923A9F0F92F96E965
:102FE000BB279395F695879577956795B795F111DA
:102FF000F8CFFAF4BB0F11F460FF1BC06F5F7F4F77
:103000008F4F9F4F16C0882311F096E911C0772388
:1030100021F09EE8872F762F05C0662371F096E891
:10302000862F70E060E02AF09A95660F771F881F60
:10303000DAF7880F9695879597F9089597F99F671E
:1030400080E870E060E008959FEF80EC0895002430
:103050000A941616170618060906089500240A94FD
:1030600012161306140605060895092E0394000C83
:1030700011F4882352F0BB0F40F4BF2B11F460FF12
:1030800004C06F5F7F4F8F4F9F4F089557FD90583B
:10309000440F551F59F05F3F71F04795880F97FB1C
:1030A000991F61F09F3F79F08795089512161306D6
:1030B0001406551FF2CF4695F1DF08C01616170605
:1030C0001806991FF1CF869571056105089408953A
:1030D000E894BB2766277727CB0197F908950BD093
:1030E000C4CFB5DF28F0BADF18F0952309F0A6CFDA
:1030F000ABCF1124EECFCADFA0F3959FD1F3950F8C
:1031000050E0551F629FF001729FBB27F00DB11D6B
:10311000639FAA27F00DB11DAA1F649F6627B00DFB
:10312000A11D661F829F2227B00DA11D621F739FE4
:10313000B00DA11D621F839FA00D611D221F749FF2
:103140003327A00D611D231F849F600D211D822F39
:10315000762F6A2F11249F5750408AF0E1F0882380
:103160004AF0EE0FFF1FBB1F661F771F881F91508D
:103170005040A9F79E3F510570F060CFAACF5F3F46
:10318000ECF3983EDCF3869577956795B795F795C0
:10319000E7959F5FC1F7FE2B880F911D9695879548
:1031A00097F908950E942F19A59F900DB49F900D37
:1031B000A49F800D911D1124089597FB072E16F4EE
:1031C000009407D077FD09D00E943B1907FC05D079
:1031D0003EF4909581959F4F0895709561957F4F2E
:1031E0000895A1E21A2EAA1BBB1BFD010DC0AA1F48
:1031F000BB1FEE1FFF1FA217B307E407F50720F060
:10320000A21BB30BE40BF50B661F771F881F991FDA
:103210001A9469F760957095809590959B01AC0123
:10322000BD01CF010895052E97FB16F4009407D039
:1032300057FD0DD00E94F11807FC09D07EF490953F
:103240008095709561957F4F8F4F9F4F0895509552
:103250004095309521953F4F4F4F5F4F0895A29F66
:10326000B001B39FC001A39F01D0B29F700D811D1B
:103270001124911D0895AA1BBB1B51E107C0AA1F71
:10328000BB1FA617B70710F0A61BB70B881F991F07
:103290005A95A9F780959095BC01CD010895EE0F40
:1032A000FF1F0590F491E02D09940F931F93CF9386
:1032B000DF93689F8001699F100D789F100D112486
:1032C000C8010E947319C82FD92F209731F0A80187
:1032D00060E070E08C2F0E94AA1ACE01DF91CF919E
:1032E0001F910F9108950F931F93CF93DF93823017
:1032F000910510F482E090E0E0915D03F0915E03AF
:1033000020E030E0C0E0D0E023C040815181481788
:103310005907A8F04817590761F4828193812097D3
:1033200019F09B838A832EC090935E0380935D0384
:1033300029C02115310529F04217530710F0A901C2
:1033400002C0BE01DF0102811381EF019A01F80181
:103350003097D9F62115310509F1281B390B243096
:10336000310590F412968D919C911397611571051A
:1033700021F0FB019383828304C090935E038093CA
:103380005D03FD01329644C0FD01E20FF31F8193FE
:103390009193225031092D933C933AC020915B03C5
:1033A00030915C03232B41F4209102013091030101
:1033B00030935C0320935B03209100013091010165
:1033C0002115310541F42DB73EB7409104015091CC
:1033D0000501241B350BE0915B03F0915C03E217C0
:1033E000F307A0F42E1B3F0B2817390778F0AC0128
:1033F0004E5F5F4F2417350748F04E0F5F1F509305
:103400005C0340935B038193919302C0E0E0F0E0A2
:10341000CF01DF91CF911F910F910895EF92FF920D
:103420000F931F93CF93DF93009709F48EC0DC01B5
:10343000129713961C921E921297E0905D03F090E3
:103440005E03E114F10489F42D913C911197280F4A
:10345000391F80915B0390915C038217930789F574
:10346000B0935C03A0935B0370C0E70120E030E001
:1034700001C0EA01CA17DB0738F44A815B819E016B
:1034800041155105B1F722C0AC0142505109FA0172
:10349000D383C28300811181BC01600F711F6C173F
:1034A0007D0761F468817981600F711F6E5F7F4FC6
:1034B000718360836A817B81738362832115310507
:1034C00029F4B0935E03A0935D033FC0F901B38379
:1034D000A283E90149915991C40FD51FAC17BD07CB
:1034E00071F4DC019E918E91840F951F0296918359
:1034F000808312968D919C91139793838283A0E091
:10350000B0E002C0D7017C01F7018281938100976E
:10351000C9F7C701029620813181820F931F209144
:103520005B0330915C032817390779F4109729F46D
:1035300010925E0310925D0304C013961C921E92BB
:103540001297F0925C03E0925B03CDB7DEB7E6E042
:103550000C94BD1ADC0101C06D9341505040E0F75E
:1035600008952A88398848885F846E847D848C8495
:103570009B84AA84B984C884DF80EE80FD800C819E
:103580001B81AA81B981CE0FD11D0FB6F894DEBF81
:0C3590000FBECDBFED010895F894FFCFF1
:10359C0000005F0320000101000A006400E8033F03
:1035AC00065B4F666D7D077F6F777C395E79715254
:1035BC00656164206661696C005265616479210003
:1035CC0000000000350F070FAA0EB30EC70ED70E62
:1035DC00000000009C15BF14371566154A158A1596
:00000001FF

View file

@ -0,0 +1,864 @@
:100000000C9463000C948B000C948B000C948B006C
:100010000C948B000C948B000C948B000C948B0034
:100020000C948B000C948B000C948B000C948B0024
:100030000C948B000C948B000C948B000C948B0014
:100040000C94D1130C948B000C94D3150C940F16B4
:100050000C948B000C948B000C948B000C948B00F4
:100060000C94C1100C948B000000000700020100EA
:100070000003040600000000000000000102040864
:100080001020408001020408102001020408102002
:10009000040404040404040402020202020203032E
:1000A00003030303000000002300260029000000D2
:1000B0000000250028002B0000000000240027007D
:1000C0002A00D00FC41611241FBECFEFD8E0DEBF28
:1000D000CDBF11E0A0E0B1E0ECE9F5E302C005908E
:1000E0000D92A035B107D9F713E0A0E5B1E001C04A
:1000F0001D92AF35B107E1F710E0C6ECD0E004C0C7
:100100002297FE010E945119C23CD107C9F70E94F3
:100110002A150C94CC1A0C940000CF93DF93EC01B9
:1001200060E088810E94D51284E190E00E947D14F5
:1001300061E088810E94D51284E190E0DF91CF9147
:100140000C947D140F931F93CF93DF93EC01062F34
:1001500018E007FF02C061E001C060E089810E94F1
:10016000D512CE010E948D00000F115091F7DF9142
:10017000CF911F910F910895EF92FF921F93CF930C
:10018000DF9300D0CDB7DEB77C01162F27FF02C06A
:1001900060EC01C060EE26FF606147FF686046FFCB
:1001A000646017FF626016FF6160C70129834A839C
:1001B0000E94A2002981622FC7010E94A2004A81E9
:1001C000642FC7010E94A200612FC7010F900F90FA
:1001D000DF91CF911F91FF90EF900C94A2007F923E
:1001E0008F929F92AF92BF92CF92DF92EF92FF9247
:1001F0000F931F93CF93DF93EC01162F942E822E33
:1002000060E00E94A20060E0CE010E94A20060E0D7
:10021000CE010E94A20060E0CE010E94A20083E015
:10022000189F7001112467018FEFC81AD80A57016F
:1002300082E0A80EB11C712C1FC071120FC0EB819F
:10024000FC81EE0DFF1D9082EB81FC81EC0DFD1D0C
:100250008082EB81FC81EA0DFB1D0083EB81FC8138
:1002600083E0789EE00DF11D11242281418160819F
:10027000CE010E94BC0073948A817816F0F260E08F
:10028000CE010E94A20060E0CE010E94A20060E0C8
:10029000CE010E94A20060E0CE01DF91CF911F91BC
:1002A0000F91FF90EF90DF90CF90BF90AF909F9015
:1002B0008F907F900C94A2000F931F93CF93DF93A6
:1002C000EC01862F688349832A8361E00E949D1296
:1002D00061E089810E949D128A8161E070E023E0E3
:1002E000829FC00111240E9455198B839C8310E0CA
:1002F00008C000E020E040E0612FCE010E94EF0046
:100300001F5F8A811817A8F3DF91CF911F910F917A
:100310000895FC018281089587EE91E00C94750F99
:10032000CF93DF93EC0168E670E087EE91E00E94E6
:10033000AE0F60E087EE91E00E94350F87EE91E00E
:100340000E94C30F47E050E068E670E087EE91E05E
:100350000E94A10F87EE91E00E94B30E382F3695D0
:10036000369536953E70232F220F220F230F8F7064
:100370009927280F288387EE91E00E94B30E282F3B
:1003800022952F708F7099273AE0239F800D1124BA
:10039000898387EE91E00E94B30E382F369536950B
:1003A00036953670232F220F220F230F8F70992737
:1003B000280F2A8387EE91E00E94B30E282F229502
:1003C0002F708F7099273AE0239F800D11248B8323
:1003D00087EE91E00E94B30E282F22952F708F7028
:1003E00099273AE0239F800D11248C8387EE91E0BA
:1003F0000E94B30E282F22952F708F7099273AE014
:10040000239F800D11248D8387EE91E00E94B30E0F
:10041000282F22952F708F7099273AE0239F800D07
:1004200011248E831F82DF91CF910895CF93DF93A4
:10043000EC01862F688319824A831B822C831E82DB
:100440001D8261E00E949D1261E08A81DF91CF915F
:100450000C949D121F93CF93DF93EC0160E08A818F
:100460000E94D5128AE090E00E947D1414E061E0C1
:100470008A810E94D51260E08A810E94D5121150B3
:10048000B1F7DF91CF911F910895FF920F931F93C2
:10049000CF93DF93EC018B0190E1F92E612F661F62
:1004A0006627661F8A810E94D51288810E940C13DC
:1004B00061E0892B09F060E088810E94D512000F6D
:1004C000111FFA9459F7DF91CF911F910F91FF906F
:1004D0000895EF92FF920F931F93CF93DF93EC0158
:1004E0007B01CB0193709E838D8360E070E0CE0131
:1004F0000E94450200E010E08C81882351F0C70182
:10050000002E02C0880F991F0A94E2F791FF0DC0D8
:1005100009C0C701002E02C0969587950A94E2F79C
:1005200080FF03C06FEF70E002C060E070E0CE01BA
:100530000E9445020F5F1F4F0A301105E9F660E087
:1005400070E0CE010E94450260E070E0CE010E94A2
:100550004502CE01DF91CF911F910F91FF90EF9057
:100560000C942A02662321F06B3018F06AE001C077
:1005700061E0262F215061E070E002C0660F771F16
:100580002A95E2F7FC01258136816227732776835D
:1005900065830C946902662321F06B3018F06AE0E1
:1005A00001C061E0562F5150FC012581368161E088
:1005B00070E002C0660F771F5A95E2F7442319F0E6
:1005C000622B732B04C06095709562237323FC012A
:1005D000768365830C9469026B3008F06AE02FEF34
:1005E0003FEF02C0220F331F6A95E2F72095309546
:1005F000FC0136832583B9010C946902FC016483F4
:10060000658176810C946902FC018581968108954B
:10061000FC0181E020813181232B09F480E00895E1
:10062000CF93DF93EC01862F6883498360E00E94BB
:100630009D1260E089810E949D1260E088810E9485
:10064000D51260E08981DF91CF910C94D51268308A
:1006500010F4685F01C06FE0FC016283089561E0FF
:10066000FC0181810E949D1282E390E00C947D1434
:10067000CF93DF93EC0161E089810E949D1282E3B8
:1006800090E00E947D1460E088810E949D1282E3C8
:1006900090E00E947D1460E089810E949D1282E3B7
:1006A00090E0DF91CF910C947D140F931F93CF9323
:1006B000DF93EC01062F18E061E088810E949D1213
:1006C00082E390E00E947D1400FF02C060E001C060
:1006D00061E089810E949D1282E390E00E947D1476
:1006E00060E088810E949D1282E390E00E947D1468
:1006F0000695115009F761E088810E949D1260E023
:1007000089810E949D1282E390E00E947D1460E046
:1007100088810E949D1282E390E00E947D1489816D
:100720000E940C13182F811104C061E089810E947E
:100730009D1282E390E00E947D1461E088810E9416
:100740009D1282E390E00E947D1481E0111101C0AE
:1007500080E0DF91CF911F910F910895CF92DF92AA
:10076000EF92FF920F931F93CF93DF9300D0CDB7FB
:10077000DEB76C01F62EE42E29837A830E942F03C4
:1007800060E4C6010E945503C6010E943803C601F9
:100790000E942F032981622F63706054C6010E945A
:1007A00055030F2D7A81172F06C0F80161918F0133
:1007B000C6010E945503802F8F198E15B0F3C60114
:1007C0000E943803C6010E942F03F601628160581F
:1007D000C6010E945503C6010F900F90DF91CF9183
:1007E0001F910F91FF90EF90DF90CF900C94380302
:1007F0004F925F926F927F928F929F92AF92BF9231
:10080000CF92DF92EF920F931F93CF93DF9300D09D
:1008100000D0CDB7DEB73C016B01322F202F8FE027
:10082000A82E81E0B82E88248394912C8C0E9D1ED6
:10083000F40101E01FE3D5015E904E905D01C60119
:10084000B2010E94DD186115710561F4411106C005
:10085000002321F08E2F8819833011F4108313C0E8
:10086000108211C0DB01AF70BB27A15FBE4F8C911E
:100870008083649DC001659D900D749D900D112431
:10088000C81AD90A00E0EE2039F08E2F881981307D
:1008900019F48081806880833196B7E0AB16B1E0AF
:1008A000BB0649F684E090E0831B9109BE016F5FAF
:1008B0007F4F680F791F432FC3010E94AE030F9033
:1008C0000F900F900F90DF91CF911F910F91EF90AC
:1008D000DF90CF90BF90AF909F908F907F906F9060
:1008E0005F904F9008956F70E62FF0E0E15FFE4F4C
:1008F00080810895FC0181E09081911101C080E028
:1009000008951F93CF93DF931F92CDB7DEB7162FB5
:1009100087EE91E049830E94750F6CE470E087EEEA
:1009200091E00E94AE0F612F87EE91E00E94350F9B
:100930004981642F87EE91E00E94350F87EE91E0A8
:100940000F90DF91CF911F910C94C30F462F67E05A
:100950000C948104462F68E00C948104CF93DF93BC
:10096000EC0160E00E94A60460E0CE010E94AA04AF
:1009700061E0CE01DF91CF910C94A6044F925F927B
:100980006F927F928F929F92AF92BF92CF92DF929F
:10099000EF92FF920F931F93CF93DF9300D01F929C
:1009A000CDB7DEB75B016A01790180E48B838A836E
:1009B00089830E941B142B013C010DC00E941B1453
:1009C0006419750986099709653F7140810591058C
:1009D00014F080E06EC087EE91E00E94AA0E181617
:1009E000190664F387EE91E00E94B30E43E050E0F5
:1009F0006CE470E087EE91E00E94A10F0E941B144E
:100A00002B013C018E010F5F1F4F48012DC0C80113
:100A1000881999090397D4F40E941B142B013C01F7
:100A200011C087EE91E00E94B30EF80180830E940E
:100A30001B146419750986099709633371058105CB
:100A400091053CF6F8018081803458F70E941B1410
:100A50000F5F1F4F6419750986099709653F71403B
:100A6000810591050CF0B5CF87EE91E00E94AA0EAA
:100A7000892B69F69981892F880F880F95FD8D5FE5
:100A800085958595F50180839A81892F880F880F38
:100A900095FD8D5F85958595F60180839B81892FD6
:100AA000880F880F95FD8D5F85958595F70180836B
:100AB00081E00F900F900F90DF91CF911F910F91D8
:100AC000FF90EF90DF90CF90BF90AF909F908F906E
:100AD0007F906F905F904F900895CF93DF93EC01DC
:100AE000862F6E834F83288791E09D8760E00E9468
:100AF0009D1261E08E810E94D51219861A861B868E
:100B00001C86DF91CF910895DF92EF92FF920F93B1
:100B10001F93CF93DF93EC0161E08E810E94D51289
:100B20006AEF70E080E090E00E9457140E941B146E
:100B300009851A852B853C85601771078207930705
:100B400020F419861A861B861C862D85211111C05A
:100B500009851A852B853C85DC01CB01801B910B17
:100B6000A20BB30B803D9740A105B10510F481E0C5
:100B700073C01D860E941B1469877A878B879C87A8
:100B80001C821B821A821982188261E08E810E9467
:100B90009D1260E08E810E94D51264E170E080E0D9
:100BA00090E00E945714F89461E08E810E94D51263
:100BB00088E290E00E947D1460E08E810E949D1288
:100BC000F12CD12C81E009C0E39481E090E00E94F7
:100BD0007D148FEFE81204C009C0E12C082F10E04B
:100BE0008E810E940C138017910771F38E810E94F1
:100BF0000C139FEFE916C9F023E02F1590F4F0FCD9
:100C000010C09D2D969596959695FE01E90FF11DC4
:100C10009081990F908328852E1510F49160908310
:100C2000D394F39495E5F912D8CF789427E22D1553
:100C300090F42C8130E04881898190E0840F911DEF
:100C40004A81840F911D4B81840F911D992728178C
:100C5000390709F48CCF80E0DF91CF911F910F917C
:100C6000FF90EF90DF900895EF92FF920F931F9304
:100C7000CF93DF93EC010E948405882391F18F814B
:100C80008B3029F070F18551823058F507C06881AA
:100C900070E080E090E00E94E1172DC0688170E074
:100CA00080E090E00E94E11720E030E040E853E46B
:100CB0000E946F187B018C01698170E080E090E0F8
:100CC0000E94E3179B01AC016E2D7F2D802F912F89
:100CD0000E94151720E030E040E251E40E947917AD
:100CE0000AC06FE171E084EB92E00E94F71460E0CB
:100CF00070E080EC9FE7DF91CF911F910F91FF9003
:100D0000EF900895CF92DF92EF92FF920F931F938F
:100D1000CF93DF938C01C62F0E948405882309F4AA
:100D200077C0F80187818B3039F008F471C08551A4
:100D3000823008F06DC01DC0F801628170E080E073
:100D400090E00E94E117B62FA72FF82FE92F462F2A
:100D5000572F682F792FCB01BA01CC2309F462C039
:100D600020E030E040E151E46B2F7A2F8F2F9E2F4F
:100D700037C0F801D2816D2F6F7770E080E090E08E
:100D80000E94E31720E030E040E853E40E946F182F
:100D90006B017C01F801638170E080E090E00E94CB
:100DA000E3179B01AC016C2D7D2D8E2D9F2D0E9494
:100DB000151720E030E040E251E40E947917472FF8
:100DC000382F292F862F942FA32FB22FBC01CD01AE
:100DD000D7FD9058CC2331F120E030E040E151E4E0
:100DE0000E946F1820E030E040EA50E40E9479173A
:100DF00020E030E040E052E40E941517472F382FE2
:100E0000292F862F942FA32FB22FBC01CD010AC00A
:100E10006FE171E084EB92E00E94F71460E070E013
:100E200080EC9FE7DF91CF911F910F91FF90EF90A2
:100E3000DF90CF900895CF93DF9322C087EE91E0AB
:100E40000E94AA0E049741F4109269011092680161
:100E500010926B0110926A01C0916A01D0916B01EE
:100E600087EE91E00E94B30EFE01EE0FFF1FE459E2
:100E7000FE4F918380832196D0936B01C0936A01CA
:100E800087EE91E00E94AA0E892BC1F6DF91CF91E7
:100E9000089580916C0190916D01019731F46091FA
:100EA000670187EE91E00E94350F80916C0190916F
:100EB0006D018330910529F08730910511F0C897B5
:100EC00041F443E050E06EE571E087EE91E00E946E
:100ED000070F80916C0190916D018830910511F0A0
:100EE000449741F444E050E06EE571E087EE91E014
:100EF0000E94070F80916C0190916D018E319105D8
:100F000011F0889741F449E050E06EE571E087EE1A
:100F100091E00C94070F089540E855E260E070E01E
:100F200084EB92E00E944A1666E070E087EE91E062
:100F30000E94920F6BE177E087EE91E00E94C60F6E
:100F400069E477E087EE91E00E94CB0F69E271E0FF
:100F500084EB92E00C941615AF92BF92CF92DF9281
:100F6000EF92FF920F931F93CF93DF93CDB7DEB72E
:100F70002C970FB6F894DEBF0FBECDBF80916A01EB
:100F800090916B01049709F0D4C68091680190910B
:100F90006901892B09F0CDC681E090E09093690149
:100FA0008093680180916C0190916D01019731F4FB
:100FB00080916E010E940C138093670180916C01F7
:100FC00090916D01029731F46091700180916E01F2
:100FD0000E94D51280916C0190916D010397A9F444
:100FE00080916E010E94F11190935D0180935C01EC
:100FF0009C0197FF02C021503F4F30935F0160E09A
:1010000071E00E94DD188093600180916C019091E5
:101010006D01049741F460917001709171018091AC
:101020006E010E94121280916C0190916D010597E2
:1010300031F46091700180916E010E949D12809147
:101040006C0190916D01079709F042C080916E018B
:1010500090916F01809352019093530161E00E943F
:101060009D1260E0809152010E94D51282E090E0D2
:101070000E947D1461E0809152010E94D51285E0AA
:1010800090E00E947D1460E0809152010E94D51290
:1010900060E0809152010E949D1220E432E44FE012
:1010A00050E061E0809152010E9435132AE330E064
:1010B00040E050E00E941319CA01B90120E031E07C
:1010C00040E050E00E94131920935F01609360019B
:1010D00080916C0190916D018830910539F481E027
:1010E00080935F0182E08093600121C0449709F5FD
:1010F00080915B01811107C086EE91E00E94AE04F1
:1011000081E080935B0129E531E048E551E067E546
:1011100071E086EE91E00E94BE04809157018093B9
:101120005F01809158018093600180915901809303
:10113000610180916C0190916D014E9769F58091EC
:101140005A01811107C08EED91E00E948C0181E06F
:1011500080935A018EED91E00E9490018091E00110
:1011600080935F018091DF01809360018091DE01B7
:10117000809361018091E301809362018091E2019B
:10118000809363019091E4019093640180936501E1
:101190008091E1018093660180916C0190916D01D5
:1011A000889709F059C08091700190917101009762
:1011B00019F426E04BE005C08130910549F426E0A2
:1011C00046E160916E0180ED91E00E946D0508C0DE
:1011D0008230910519F426E045E1F3CF0397D9F366
:1011E00060E080ED91E00E94820669877A878B87B4
:1011F0009C8780ED91E00E9434066D837E838F830F
:1012000098871092510110925001FE01399680E0AA
:1012100090E001962191DC01A25ABE4F2C938430BC
:101220009105BCF384E090E09093510180935001CC
:101230000196DC01A25ABE4FE5E0F0E0EC0FFD1F85
:10124000E80FF91F359720812C938830910584F39E
:10125000909351018093500180916C0190916D01A8
:10126000C297D9F480916E0190916F01482F21E0CF
:101270006091700170917101672B09F420E0642F77
:101280006F5FFC01329737E03E9FC0013F9F900D9A
:1012900011248A559E4F0E94160280916C019091F4
:1012A0006D01C39791F420916E0130916F0122502E
:1012B000310947E0429FC001439F900D11248A5598
:1012C0009E4F0E94080381116AC380916C01909126
:1012D0006D01C49791F420916E0130916F012250FD
:1012E000310917E0129FC001139F900D11248A55F8
:1012F0009E4F0E94080381116BC380916C019091F5
:101300006D01C59791F420916E0130916F012250CB
:10131000310947E0429FC001439F900D11248A5537
:101320009E4F0E940803811165C380916C019091CA
:101330006D01C69791F420916E0130916F0122509A
:10134000310917E0129FC001139F900D11248A5597
:101350009E4F0E940803811168C380916C01909197
:101360006D01C79791F420916E0130916F01225069
:10137000310917E0129FC001139F900D11248A5567
:101380009E4F0E940803811162C380916C0190916D
:101390006D01C89791F420916E0130916F01225038
:1013A000310917E0129FC001139F900D11248A5537
:1013B0009E4F0E940803811163C380916C0190913C
:1013C0006D018634910591F460916E0170916F0109
:1013D000462F4F5F9B0122503109C901880F991F89
:1013E000820F931F8C569E4F0E94100380916C01B8
:1013F00090916D018734910589F420916E013091AF
:101400006F0122503109C901880F991F820F931F64
:101410008C569E4F0E947A04811146C380916C01C4
:1014200090916D018834910589F420916E0130917D
:101430006F0122503109C901880F991F820F931F34
:101440008C569E4F0E947A04811140C380916C019A
:1014500090916D018934910589F420916E0130914C
:101460006F0122503109C901880F991F820F931F04
:101470008C569E4F0E947A04811145C380916C0165
:1014800090916D018A34910589F420916E0130911B
:101490006F0122503109C901880F991F820F931FD4
:1014A0008C569E4F0E947A0481114AC380916C0130
:1014B00090916D018B34910589F420916E013091EA
:1014C0006F0122503109C901880F991F820F931FA4
:1014D0008C569E4F0E947A0481115AC380916C01F0
:1014E00090916D018C34910589F420916E013091B9
:1014F0006F0122503109C901880F991F820F931F74
:101500008C569E4F0E947A0481115BC380916C01BE
:1015100090916D018D349105A9F520916E01309166
:101520006F0122503109C901880F991F820F931F43
:101530008C569E4F0E947A048111BBC323C0812F19
:101540000E94F111BC0120916E0130916F01225077
:101550003109C901880F991F820F931FE12C00E008
:1015600024E040E08C569E4F0E94F8036AEF70E042
:1015700080E090E00E9457142FEFC21AD20ACA14DA
:10158000DB04ECF280916C0190916D018E34910539
:1015900089F420916E0130916F0122503109C90107
:1015A000880F991F820F931F8C569E4F0E947A04BA
:1015B00081118CC380916C0190916D018F349105E4
:1015C00089F420916E0130916F0122503109C901D7
:1015D000880F991F820F931F8C569E4F0E947A048A
:1015E00081118EC380916C0190916D018A359105B6
:1015F00069F480916E018093540180917001809311
:101600005501809172018093560118C08B35910568
:10161000A9F460916E0170916F01462F4F5F9B019D
:101620002250310955E0529FC001539F900D112463
:10163000209170018A589E4F0E945C0180916C013C
:1016400090916D018C35910549F080916C019091DC
:101650006D018D35910509F0BDC048C060916E01E6
:1016600070916F01462F4F5F9B012250310955E069
:10167000529FC001539F900D1124209170018A58F0
:101680009E4F0E945C01009172011091730102FB58
:10169000DD24D0F8D19401FBCC24C0F8C1940170B2
:1016A0001127102F1195E12CF12CA5E0BA2E16C0B0
:1016B00060916E0170916F0162507109B69EC00118
:1016C000B79E900D1124012F2C2D4D2D6E2D8A5873
:1016D0009E4F0E94EF003FEFE31AF30A80917001E2
:1016E00090917101E816F9061CF3AFCF20917001BB
:1016F0003091710180916E0190916F01232BB1F4B3
:101700009C012250310945E0429FC001439F900D4A
:10171000112400915601209155014091540160918E
:1017200072018A589E4F0E94EF0054C09C012250C3
:10173000310945E0429FC001439F900D11248A5812
:101740009E4F0E948901E12CF12CC82ED12C15E06E
:101750003DC020917001309171012130310541F47B
:101760008091720190917301E816F906B1F42BC0D3
:101770002230310541F480917201909173018E15F0
:101780009F055CF420C023303105E9F4809172019B
:1017900090917301E816F906B4F020916E01309132
:1017A0006F0122503109129FC001139F900D112427
:1017B0000091560120915501409154016E2D8A5897
:1017C0009E4F0E94EF008FEFE81AF80AEC14FD0418
:1017D0000CF4BFCF80916C0190916D018E35910515
:1017E00049F080916C0190916D018F35910509F060
:1017F000A0C252C08091720190917301181619060F
:1018000034F081E090E09093730180937201209115
:101810006E0130916F012250310945E0429FC001B5
:10182000439F900D11248A589E4F0E948901E09099
:101830007001F0907101C82ED12C15E029C0809163
:101840007001909171019701281B390BC9016091BA
:101850007201709173010E94DD18892BB1F42091FF
:101860006E0130916F0122503109129FC001139F08
:10187000900D112400915601209155014091540181
:101880006E2D8A589E4F0E94EF003FEFE31AF30A35
:10189000EC14FD04A4F2A5CF20916E0130916F01EC
:1018A0002250310945E0429FC001439F900D112411
:1018B0008A589E4F0E9489012091720130917301D4
:1018C000232B59F133C080917001909171012091C7
:1018D0006E0130916F0122503109E816F90664F467
:1018E000129FC001139F900D112400915601209169
:1018F00055014091540108C0129FC001139F900DE3
:10190000112400E020E040E06E2D8A589E4F0E9496
:10191000EF008FEFE81AF80A05C0E12CF12CC82E71
:10192000D12C15E0EC14FD0474F203C2C82ED12CA6
:10193000760115E030C0809170019091710196019F
:10194000281B390B80916E0190916F01E216F3060E
:101950007CF09C0122503109129FC001139F900D11
:1019600011240091560120915501409154010BC062
:101970009C0122503109129FC001139F900D112428
:1019800000E020E040E06E2D8A589E4F0E94EF005C
:1019900021E0E21AF108E114F10469F6CAC161E03C
:1019A0008091700190917101892B09F460E0209180
:1019B0006E0130916F012250310947E0429FC00112
:1019C000439F900D11248A559E4F0E94FE027DCCAC
:1019D00020916E0130916F0122503109129FC00198
:1019E000139F900D1124609170018A559E4F0E94A3
:1019F000EC0283CC41E08091720190917301892BBC
:101A000009F440E020916E0130916F0122503109BC
:101A100057E0529FC001539F900D112460917001B7
:101A20008A559E4F0E94CB0280CC20916E0130914E
:101A30006F0122503109129FC001139F900D112494
:101A4000609170018A559E4F0E94B20286CC90919F
:101A5000720180E0609170017091710168277927AF
:101A600020916E0130916F0122503109129FC00107
:101A7000139F900D11248A559E4F0E94690285CCB8
:101A800020916E0130916F0122503109129FC001E7
:101A9000139F900D11248A559E4F0E94040380933A
:101AA0005F019093600189CC20916E0130916F01AC
:101AB00022503109C901880F991F820F931F60912D
:101AC00070018C569E4F0E942703A8CC9091720102
:101AD00080E06091700170917101682779272091F1
:101AE0006E0130916F0122503109C901880F991F91
:101AF000820F931FE12C00E024E040E08C569E4FC3
:101B00000E94F803A3CC9091720180E06091700173
:101B1000709171016827792720916E0130916F01D2
:101B200022503109C901880F991F820F931FE12CA0
:101B300000E024E041E08C569E4F0E94F8039ECCCA
:101B400020916E0130916F0122503109C901880F37
:101B5000991F820F931F609172018C569E4F0E94B5
:101B60007304898320916E0130916F0122503109F5
:101B7000C901880F991F820F931F2091700141E0C6
:101B8000BE016F5F7F4F8C569E4F0E94AE038ECC7E
:101B900080917201898320916E0130916F012250F2
:101BA0003109C901880F991F820F931F209170017D
:101BB00041E0BE016F5F7F4F8C569E4F0E94AE0387
:101BC0008DCC80917001909171010AE010E0B80114
:101BD0000E94DD1820916E0130916F012250310971
:101BE000C901880F991F820F931F8C569E4F0E9428
:101BF000730489838091700190917101B8010E94F2
:101C0000DD1820916E0130916F0122503109A90138
:101C1000440F551F420F531F682FCA018C569E4F09
:101C20000E94730480688A8380917201909173018D
:101C3000B8010E94DD1820916E0130916F01225091
:101C40003109C901880F991F820F931F8C569E4F2F
:101C50000E9473048B838091720190917301B8018B
:101C60000E94DD1820916E0130916F0122503109E0
:101C7000A901440F551F420F531F682FCA018C56EC
:101C80009E4F0E9473048C8320916E0130916F01EE
:101C900022503109C901880F991F820F931F20E03C
:101CA00044E0BE016F5F7F4F8C569E4F0E94AE0393
:101CB0002DCC10917001A0907201B0907301AA0C0C
:101CC000BB1CAA0CBB1CC12CD12C59CC8FEF898317
:101CD0008A838B838C8320916E0130916F01225017
:101CE0003109C901880F991F820F931F20E044E03A
:101CF000BE016F5F7F4F8C569E4F0E94AE035ACC41
:101D000019821A821B821C8220916E0130916F0110
:101D100022503109C901880F991F820F931F20E0BB
:101D200044E0BE016F5F7F4F8C569E4F0E94AE0312
:101D300059CC2C960FB6F894DEBF0FBECDBFDF9105
:101D4000CF911F910F91FF90EF90DF90CF90BF90B8
:101D5000AF90089520911B0230E080911C02281B57
:101D60003109C901089580911C0290911B028917C5
:101D700050F4E82FF0E0E35EFD4F208130E08F5F0C
:101D800080931C0202C02FEF3FEFC9010895E0913C
:101D90001C0280911B02E81730F4F0E0E35EFD4F77
:101DA000208130E002C02FEF3FEFC9010895089570
:101DB000E091F301F091F4013097E1F030911C02D1
:101DC00020911B023217B0F040E009C0DC01A20FE5
:101DD000B31F5C91D901A35EBD4F5C934F5F242F6D
:101DE00030E02617370794F310921C0260931B0211
:101DF000CB0109940895E091F501F091F601309737
:101E000029F01092F9011092F80109940895CF92E7
:101E1000DF92EF92FF920F931F93CF93DF937C019A
:101E2000CB018A012091F701222391F0EB016B0194
:101E3000C40ED51E09C06991D701ED91FC910190A6
:101E4000F081E02DC7010995CC15DD05A1F703C090
:101E5000642F0E948E10C801DF91CF911F910F91C6
:101E6000FF90EF90DF90CF900895CF93DF931F9274
:101E7000CDB7DEB769832091F7012223D1F02091FD
:101E8000F801203240F021E030E0FC01338322836E
:101E900020E030E015C08091F901E82FF0E0E65035
:101EA000FE4F998190838F5F8093F9018093F801B1
:101EB00005C061E0CE0101960E948E1021E030E065
:101EC000C9010F90DF91CF910895FC011382128216
:101ED00048EE53E060E070E0448355836683778387
:101EE00084E391E091838083089510921C02109204
:101EF0001B021092F9011092F8010C94D40FCF93A9
:101F0000DF93EC01862F0E94F20F8BEF9EE00E9480
:101F1000AC1088ED9EE00E94A710CE01DF91CF911A
:101F20000C94750F0C947F0F862F413208F040E21D
:101F30006DE172E00E94F60F10921C0280931B026A
:101F4000089521E00C94940F81E08093F701609351
:101F50001A021092F9011092F80108950C94A40F3E
:101F60000F93062F21E04091F8016AEF71E0809114
:101F70001A020E943B101092F9011092F80110927F
:101F8000F7010F91089561E00C94B00F7093F40184
:101F90006093F30108957093F6016093F50108953D
:101FA00087EE91E00C94650F1092460281E08093D9
:101FB00044021092430261E082E10E94D51261E086
:101FC00083E10E94D512E9EBF0E080818E7F80836F
:101FD00080818D7F808382E08093B80085E4809348
:101FE000BC000895880F8093BA000895413208F02C
:101FF0003FC0909146029111FCCF91E09093460230
:10200000209344022FEF20933D0210924202242F8E
:102010002150209341029093450290914502880FF0
:10202000892B8093450280914302813041F41092C4
:102030004302809145028093BB0085EC01C085EE90
:102040008093BC00809146028130E1F3809142028E
:10205000841710F44091420227E432E0FB01D901D9
:1020600002C08D9181938A2F821B8417D0F301C007
:1020700040E0842F08950F93413208F046C09091BC
:1020800046029111FCCF92E09093460200934402E5
:102090009FEF90933D021092420240934102FB0158
:1020A00067E472E0DB0102C091919D939A2F961B29
:1020B0009417D0F31092450290914502880F892B16
:1020C0008093450280914302813041F41092430293
:1020D000809145028093BB0085EC01C085EE809322
:1020E000BC00222321F0809146028230E1F38091EE
:1020F0003D028F3F61F080913D02803251F080912E
:102100003D02803341F483E007C081E005C080E0F8
:1021100003C082E001C084E00F910895613298F419
:1021200020914602243089F460933F02FC0187E647
:1021300092E0DC0102C021912D932A2F281B261743
:10214000D0F380E0089581E0089582E008959093AF
:10215000880280938702089590938A02809389026F
:10216000089585ED8093BC008091BC0084FDFCCF78
:1021700010924602089585EC8093BC0010924602AE
:1021800008951F920F920FB60F9211242F933F9331
:102190004F935F936F937F938F939F93AF93BF936F
:1021A000EF93FF938091B900887F803609F49FC038
:1021B00058F5883209F45BC090F4803109F452C0BC
:1021C00038F4882309F4F8C0883009F0F9C04AC00F
:1021D000883109F44CC0803209F0F2C05CC0803410
:1021E00009F46BC038F4803309F455C0883309F022
:1021F000E7C054C0803509F454C0883509F462C082
:10220000883409F0DDC0DAC0883909F4CBC0A8F4FD
:10221000883709F46CC038F4883609F468C0803710
:1022200009F0CEC064C0883809F4BCC0803909F414
:1022300064C0803809F0C4C060C0803B09F48AC023
:1022400038F4803A09F46BC0883A09F0B9C082C00A
:10225000803C09F4ABC0883C09F4A8C0883B09F075
:10226000AFC08DC0809145028093BB0012C0909199
:10227000420280914102981788F580914202E82F2E
:10228000F0E0E95BFD4F90819093BB008F5F8093FE
:10229000420285EC88C080933D0290C080933D024D
:1022A00056C0809142029091BB00E82FF0E0E95BBC
:1022B000FD4F90838F5F8093420290914202809104
:1022C00041026DC0809142029091BB00E82FF0E086
:1022D000E95BFD4F90838F5F8093420280914402BF
:1022E00081116CC081E08093430284EA60C083E086
:1022F0008093460210923E02CCCF80913E02803203
:1023000008F050C080913E029091BB00E82FF0E0B1
:10231000E557FD4F90838F5F80933E02BACF809147
:102320003E02803230F4E0913E02F0E0E557FD4F8E
:1023300010820E94B11060913E02E0918702F091FC
:10234000880270E08BE892E0099510923E020E94AC
:10235000BB1036C084E08093460210924002109277
:102360003F02E0918902F0918A02099580913F0233
:10237000811105C081E080933F0210926702809135
:102380004002E82FF0E0E959FD4F90819093BB00A7
:102390008F5F809340029091400280913F02981796
:1023A00008F477CF85E88093BC000AC085EC809361
:1023B000BC001092460204C010923D020E94B1106F
:1023C000FF91EF91BF91AF919F918F917F916F910D
:1023D0005F914F913F912F910F900FBE0F901F90E3
:1023E00018958E3008F08E5087702091060140E4D9
:1023F000249F90011124822B80937C0080917A008D
:10240000806480937A0080917A0086FDFCCF2091D1
:10241000780030917900932F80E0AC01422B9A0133
:10242000C90108951F93CF93DF93182FEB0161E04B
:102430000E949D12209711F460E004C0CF3FD105A7
:1024400039F461E0812FDF91CF911F910C94D51267
:10245000E12FF0E0E859FF4FE491E330B9F028F4C0
:10246000E13051F0E230B1F50CC0E63019F1E7305F
:1024700049F1E43079F514C084B5806884BDC7BDE6
:102480002EC084B5806284BDC8BD29C08091800003
:10249000806880938000D0938900C09388001FC01B
:1024A00080918000806280938000D0938B00C093E5
:1024B0008A0015C08091B00080688093B000C093FE
:1024C000B3000DC08091B00080628093B000C093D3
:1024D000B40005C0C038D1050CF0B3CFADCFDF914B
:1024E000CF911F910895833069F028F48130A1F0D5
:1024F000823011F514C08630B1F08730C1F08430DD
:10250000D9F404C0809180008F7703C0809180004F
:102510008F7D80938000089584B58F7702C084B545
:102520008F7D84BD08958091B0008F7703C0809126
:10253000B0008F7D8093B0000895CF93DF9390E03B
:10254000FC01E458FF4F4491FC01E057FF4F849198
:10255000882341F190E0880F991FFC01E854FF4F58
:1025600025913491D90182559F4FFC018591949119
:10257000C82FD92F9FB7F8948C91611106C0409550
:1025800084238C938881842308C0623041F4242FF3
:10259000209582238C938881842B888302C0842B8E
:1025A0008C939FBFDF91CF9108950F931F93CF938B
:1025B000DF931F92CDB7DEB7282F30E0F901E8593D
:1025C000FF4F8491F901E458FF4F1491F901E0574E
:1025D000FF4F04910023D1F0882321F069830E94EA
:1025E00073126981E02FF0E0EE0FFF1FE255FF4FFD
:1025F00085919491DC019FB7F8948C91611103C08F
:102600001095812301C0812B8C939FBF0F90DF9188
:10261000CF911F910F910895CF93DF93282F30E032
:10262000F901E859FF4F8491F901E458FF4FD49123
:10263000F901E057FF4FC491CC2389F081110E942A
:102640007312EC2FF0E0EE0FFF1FEC55FF4F85915A
:102650009491DC018C918D2321E030E011F420E095
:1026600030E0C901DF91CF9108958F929F92AF9290
:10267000BF92CF92DF92EF92FF920F931F93CF936F
:10268000DF9390E0FC01E458FF4FD491FC01E05748
:10269000FF4F7491611102C0C0E001C0CD2FDA017B
:1026A000C901880F991FAA1FBB1F54E0B695A795B3
:1026B000979587955A95D1F7672F70E0660F771F2A
:1026C0006C557F4F812C912C5401FB010591149185
:1026D00010C0C12CD12C7601C394C80CD91CEA1CA3
:1026E000FB1C88169906AA06BB0609F448C04601D9
:1026F0005701F801E081ED23EC1759F310C0C12C0C
:10270000D12C7601C394C80CD91CEA1CFB1C88167A
:102710009906AA06BB0699F14601570103C0FB01C1
:1027200005911491F801E081ED23EC13E8CF8819AD
:102730009909AA09BB0920E030E0A901FB016591D4
:10274000749109C0281739074A075B07C1F02F5F4A
:102750003F4F4F4F5F4FFB01E081ED23EC1791F3AB
:10276000A5E1B0E00E94D2188B019C01005F1F4FD1
:102770002F4F3F4F369527951795079503C000E0DB
:1027800010E09801B801C901DF91CF911F910F911D
:10279000FF90EF90DF90CF90BF90AF909F908F9081
:1027A00008951F920F920FB60F9211242F933F930B
:1027B0008F939F93AF93BF938091AB029091AC02A4
:1027C000A091AD02B091AE023091B302232F285EEA
:1027D0002D3720F40896A11DB11D05C0232F2556C5
:1027E0000996A11DB11D2093B3028093AB02909373
:1027F000AC02A093AD02B093AE028091AF02909173
:10280000B002A091B102B091B2020196A11DB11D1A
:102810008093AF029093B002A093B102B093B20242
:10282000BF91AF919F918F913F912F910F900FBECC
:102830000F901F9018950F931F938FB7F8940091E6
:10284000AB021091AC022091AD023091AE028FBF6D
:10285000B801C9011F910F9108950F931F939FB75E
:10286000F8940091AF021091B0022091B102309122
:10287000B20286B5A89B06C08F3F21F00F5F1F4FA5
:102880002F4F3F4F9FBF322F212F102F0027080FB0
:10289000111D211D311D45E0000F111F221F331F87
:1028A0004A95D1F7B801C9011F910F910895CF92B0
:1028B000DF92EF92FF92CF93DF936B017C010E9436
:1028C0002D14EB010EC00E942D146C1B7D0B683E75
:1028D000734038F081E0C81AD108E108F108C85106
:1028E000DC4FC114D104E104F10469F7DF91CF9109
:1028F000FF90EF90DF90CF900895019739F0019706
:1029000029F0880F991F01970197F1F7089578949E
:1029100084B5826084BD84B5816084BD85B58260E4
:1029200085BD85B5816085BDEEE6F0E08081816082
:102930008083E1E8F0E01082808182608083E0E8BB
:10294000F0E0808181608083E1EBF0E08081846051
:102950008083E0EBF0E0808181608083EAE7F0E053
:1029600080818460808380818260808380818160B7
:1029700080838081806880831092C1000895CF9207
:10298000DF92EF92FF920F931F93CF93DF936C012F
:10299000EB017A01E60EF71E00E010E00BC0699132
:1029A000D601ED91FC910190F081E02DC6010995D1
:1029B000080F191FCE15DF0591F7C801DF91CF91E0
:1029C0001F910F91FF90EF90DF90CF900895DB0162
:1029D0000D900020E9F7AD0141505109461B570BFE
:1029E000DC01ED91FC910280F381E02D09940C94BF
:1029F000E714DC01ED91FC910190F081E02D099448
:102A00000F931F93CF93DF93EC016DE00E94F914B5
:102A10008C016AE0CE010E94F9149C01200F311F45
:102A2000C901DF91CF911F910F9108950F931F93CB
:102A3000CF93DF93EC010E94E7148C01CE010E943A
:102A400000159801280F391FC901DF91CF911F91FF
:102A50000F9108950E9487140E948C07C6E0D6E16A
:102A60000E94AC072097E1F30E940616F9CFFC0103
:102A700084859585FC01E05CFF4F20813181FC015C
:102A8000EE5BFF4F80819181281B390B2F73332719
:102A9000C9010895FC0184859585FC01E05CFF4F28
:102AA00040815181FC01EE5BFF4F20813181421753
:102AB000530741F00190F081E02DE80FF91F2081CC
:102AC00030E002C02FEF3FEFC9010895FC0184857B
:102AD0009585FC01E05CFF4F40815181FC01EE5B7C
:102AE000FF4F208131814217530781F0A081B181CE
:102AF000A80FB91F8C91208131812F5F3F4F2F7319
:102B0000332731832083282F30E002C02FEF3FEF9F
:102B1000C9010895FC0186859785FC01E05CFF4FA3
:102B2000DC01AE5BBF4F408151812D913C911197EB
:102B300042175307C1F70895CF93DF93FC018685B1
:102B40009785DC01A05CBF4F2D913C9111972F5FC1
:102B50003F4F2F733327EC01CE5BDF4F4881598104
:102B600024173507D9F30D90BC91A02DA80FB91FDC
:102B70006C93A685B785A05CBF4F11963C932E93AE
:102B8000A689B7892C9181E090E0058C02C0880F5E
:102B9000991F0A94E2F7282B2C9381E090E0DF91B3
:102BA000CF91089508951F920F920FB60F9211249E
:102BB0002F933F934F938F939F93EF93FF93409166
:102BC000C600809157039091580301968F739927FF
:102BD0002091590330915A038217930759F0E091DD
:102BE0005703F0915803E95EFC4F408390935803DC
:102BF00080935703FF91EF919F918F914F913F9158
:102C00002F910F900FBE0F901F90189584EB92E0BC
:102C10000E943715892B11F00C94D21508951F923C
:102C20000F920FB60F9211242F933F938F939F9380
:102C3000EF93FF93209113033091140380911503B8
:102C4000909116032817390731F48091C1008F7DC8
:102C50008093C10014C0E0911503F0911603ED526A
:102C6000FD4F2081809115039091160301968F737B
:102C7000992790931603809315032093C600FF9124
:102C8000EF919F918F913F912F910F900FBE0F90D9
:102C90001F901895CF92DF92EF92FF92CF93DF9320
:102CA000EC016A017B01EC89FD8981E090E00E8CEA
:102CB00002C0880F991F0A94E2F7808360E271EAEC
:102CC00087E090E0A70196010E94F1182150310998
:102CD000410951095695479537952795211580E16A
:102CE000380798F0EC89FD89108260E970ED83E087
:102CF00090E0A70196010E94F11821503109410985
:102D000051095695479537952795E889F989308374
:102D1000EA89FB892083EE89FF89408181E090E088
:102D20009C010A8C02C0220F331F0A94E2F7422B47
:102D30004083EE89FF8940819C010B8C02C0220FE9
:102D4000331F0A94E2F7422B4083EE89FF894081CA
:102D50009C010C8C02C0220F331F0A94E2F7422B15
:102D60004083EE89FF8920810D8C02C0880F991F56
:102D70000A94E2F7809582238083DF91CF91FF90C0
:102D8000EF90DF90CF9008951092B7021092B602A4
:102D900088EE93E0A0E0B0E08093B8029093B9028F
:102DA000A093BA02B093BB0284E491E09093B50281
:102DB0008093B40287E193E09093C1028093C002B4
:102DC00083ED92E09093C3028093C20285EC90E081
:102DD0009093C5028093C40284EC90E09093C70264
:102DE0008093C60280EC90E09093C9028093C80261
:102DF00081EC90E09093CB028093CA0286EC90E045
:102E00009093CD028093CC0284E08093CE0283E045
:102E10008093CF0287E08093D00285E08093D10237
:102E200081E08093D20208955058BB27AA270ED084
:102E30001CC10DD130F012D120F031F49F3F11F4BC
:102E40001EF402C10EF4E095E7FBF8C0E92F1ED195
:102E500080F3BA17620773078407950718F071F4B7
:102E60009EF536C10EF4E0950B2EBA2FA02D0B0166
:102E7000B90190010C01CA01A0011124FF27591BBF
:102E800099F0593F50F4503E68F11A16F040A22FC5
:102E9000232F342F4427585FF3CF46953795279536
:102EA000A795F0405395C9F77EF41F16BA0B620B35
:102EB000730B840BBAF09150A1F0FF0FBB1F661F7C
:102EC000771F881FC2F70EC0BA0F621F731F841FBF
:102ED00048F4879577956795B795F7959E3F08F0E5
:102EE000B3CF9395880F08F09927EE0F97958795A4
:102EF00008950CD0BAC0B2D040F0A9D030F021F47F
:102F00005F3F19F09BC05111E4C09EC0BFD098F341
:102F10009923C9F35523B1F3951B550BBB27AA275A
:102F200062177307840738F09F5F5F4F220F331FCC
:102F3000441FAA1FA9F333D00E2E3AF0E0E830D098
:102F400091505040E695001CCAF729D0FE2F27D09B
:102F5000660F771F881FBB1F261737074807AB0769
:102F6000B0E809F0BB0B802DBF01FF2793585F4FDE
:102F70002AF09E3F510568F061C0ABC05F3FECF3A3
:102F8000983EDCF3869577956795B795F7959F5FA3
:102F9000C9F7880F911D9695879597F90895E1E0F7
:102FA000660F771F881FBB1F621773078407BA0756
:102FB00020F0621B730B840BBA0BEE1F88F7E095B1
:102FC0000895E89409C097FB3EF49095809570951C
:102FD00061957F4F8F4F9F4F9923A9F0F92F96E965
:102FE000BB279395F695879577956795B795F111DA
:102FF000F8CFFAF4BB0F11F460FF1BC06F5F7F4F77
:103000008F4F9F4F16C0882311F096E911C0772388
:1030100021F09EE8872F762F05C0662371F096E891
:10302000862F70E060E02AF09A95660F771F881F60
:10303000DAF7880F9695879597F9089597F99F671E
:1030400080E870E060E008959FEF80EC0895002430
:103050000A941616170618060906089500240A94FD
:1030600012161306140605060895092E0394000C83
:1030700011F4882352F0BB0F40F4BF2B11F460FF12
:1030800004C06F5F7F4F8F4F9F4F089557FD90583B
:10309000440F551F59F05F3F71F04795880F97FB1C
:1030A000991F61F09F3F79F08795089512161306D6
:1030B0001406551FF2CF4695F1DF08C01616170605
:1030C0001806991FF1CF869571056105089408953A
:1030D000E894BB2766277727CB0197F908950BD093
:1030E000C4CFB5DF28F0BADF18F0952309F0A6CFDA
:1030F000ABCF1124EECFCADFA0F3959FD1F3950F8C
:1031000050E0551F629FF001729FBB27F00DB11D6B
:10311000639FAA27F00DB11DAA1F649F6627B00DFB
:10312000A11D661F829F2227B00DA11D621F739FE4
:10313000B00DA11D621F839FA00D611D221F749FF2
:103140003327A00D611D231F849F600D211D822F39
:10315000762F6A2F11249F5750408AF0E1F0882380
:103160004AF0EE0FFF1FBB1F661F771F881F91508D
:103170005040A9F79E3F510570F060CFAACF5F3F46
:10318000ECF3983EDCF3869577956795B795F795C0
:10319000E7959F5FC1F7FE2B880F911D9695879548
:1031A00097F908950E942F19A59F900DB49F900D37
:1031B000A49F800D911D1124089597FB072E16F4EE
:1031C000009407D077FD09D00E943B1907FC05D079
:1031D0003EF4909581959F4F0895709561957F4F2E
:1031E0000895A1E21A2EAA1BBB1BFD010DC0AA1F48
:1031F000BB1FEE1FFF1FA217B307E407F50720F060
:10320000A21BB30BE40BF50B661F771F881F991FDA
:103210001A9469F760957095809590959B01AC0123
:10322000BD01CF010895052E97FB16F4009407D039
:1032300057FD0DD00E94F11807FC09D07EF490953F
:103240008095709561957F4F8F4F9F4F0895509552
:103250004095309521953F4F4F4F5F4F0895A29F66
:10326000B001B39FC001A39F01D0B29F700D811D1B
:103270001124911D0895AA1BBB1B51E107C0AA1F71
:10328000BB1FA617B70710F0A61BB70B881F991F07
:103290005A95A9F780959095BC01CD010895EE0F40
:1032A000FF1F0590F491E02D09940F931F93CF9386
:1032B000DF93689F8001699F100D789F100D112486
:1032C000C8010E947319C82FD92F209731F0A80187
:1032D00060E070E08C2F0E94AA1ACE01DF91CF919E
:1032E0001F910F9108950F931F93CF93DF93823017
:1032F000910510F482E090E0E0915D03F0915E03AF
:1033000020E030E0C0E0D0E023C040815181481788
:103310005907A8F04817590761F4828193812097D3
:1033200019F09B838A832EC090935E0380935D0384
:1033300029C02115310529F04217530710F0A901C2
:1033400002C0BE01DF0102811381EF019A01F80181
:103350003097D9F62115310509F1281B390B243096
:10336000310590F412968D919C911397611571051A
:1033700021F0FB019383828304C090935E038093CA
:103380005D03FD01329644C0FD01E20FF31F8193FE
:103390009193225031092D933C933AC020915B03C5
:1033A00030915C03232B41F4209102013091030101
:1033B00030935C0320935B03209100013091010165
:1033C0002115310541F42DB73EB7409104015091CC
:1033D0000501241B350BE0915B03F0915C03E217C0
:1033E000F307A0F42E1B3F0B2817390778F0AC0128
:1033F0004E5F5F4F2417350748F04E0F5F1F509305
:103400005C0340935B038193919302C0E0E0F0E0A2
:10341000CF01DF91CF911F910F910895EF92FF920D
:103420000F931F93CF93DF93009709F48EC0DC01B5
:10343000129713961C921E921297E0905D03F090E3
:103440005E03E114F10489F42D913C911197280F4A
:10345000391F80915B0390915C038217930789F574
:10346000B0935C03A0935B0370C0E70120E030E001
:1034700001C0EA01CA17DB0738F44A815B819E016B
:1034800041155105B1F722C0AC0142505109FA0172
:10349000D383C28300811181BC01600F711F6C173F
:1034A0007D0761F468817981600F711F6E5F7F4FC6
:1034B000718360836A817B81738362832115310507
:1034C00029F4B0935E03A0935D033FC0F901B38379
:1034D000A283E90149915991C40FD51FAC17BD07CB
:1034E00071F4DC019E918E91840F951F0296918359
:1034F000808312968D919C91139793838283A0E091
:10350000B0E002C0D7017C01F7018281938100976E
:10351000C9F7C701029620813181820F931F209144
:103520005B0330915C032817390779F4109729F46D
:1035300010925E0310925D0304C013961C921E92BB
:103540001297F0925C03E0925B03CDB7DEB7E6E042
:103550000C94BD1ADC0101C06D9341505040E0F75E
:1035600008952A88398848885F846E847D848C8495
:103570009B84AA84B984C884DF80EE80FD800C819E
:103580001B81AA81B981CE0FD11D0FB6F894DEBF81
:0C3590000FBECDBFED010895F894FFCFF1
:10359C0000005F0320000101000A006400E8033F03
:1035AC00065B4F666D7D077F6F777C395E79715254
:1035BC00656164206661696C005265616479210003
:1035CC0000000000350F070FAA0EB30EC70ED70E62
:1035DC00000000009C15BF14371566154A158A1596
:00000001FF

View file

@ -0,0 +1,864 @@
:100000000C9463000C948B000C948B000C948B006C
:100010000C948B000C948B000C948B000C948B0034
:100020000C948B000C948B000C948B000C948B0024
:100030000C948B000C948B000C948B000C948B0014
:100040000C94D1130C948B000C94D3150C940F16B4
:100050000C948B000C948B000C948B000C948B00F4
:100060000C94C1100C948B000000000700020100EA
:100070000003040600000000000000000102040864
:100080001020408001020408102001020408102002
:10009000040404040404040402020202020203032E
:1000A00003030303000000002300260029000000D2
:1000B0000000250028002B0000000000240027007D
:1000C0002A00D00FC41611241FBECFEFD8E0DEBF28
:1000D000CDBF11E0A0E0B1E0ECE9F5E302C005908E
:1000E0000D92A035B107D9F713E0A0E5B1E001C04A
:1000F0001D92AF35B107E1F710E0C6ECD0E004C0C7
:100100002297FE010E945119C23CD107C9F70E94F3
:100110002A150C94CC1A0C940000CF93DF93EC01B9
:1001200060E088810E94D51284E190E00E947D14F5
:1001300061E088810E94D51284E190E0DF91CF9147
:100140000C947D140F931F93CF93DF93EC01062F34
:1001500018E007FF02C061E001C060E089810E94F1
:10016000D512CE010E948D00000F115091F7DF9142
:10017000CF911F910F910895EF92FF921F93CF930C
:10018000DF9300D0CDB7DEB77C01162F27FF02C06A
:1001900060EC01C060EE26FF606147FF686046FFCB
:1001A000646017FF626016FF6160C70129834A839C
:1001B0000E94A2002981622FC7010E94A2004A81E9
:1001C000642FC7010E94A200612FC7010F900F90FA
:1001D000DF91CF911F91FF90EF900C94A2007F923E
:1001E0008F929F92AF92BF92CF92DF92EF92FF9247
:1001F0000F931F93CF93DF93EC01162F942E822E33
:1002000060E00E94A20060E0CE010E94A20060E0D7
:10021000CE010E94A20060E0CE010E94A20083E015
:10022000189F7001112467018FEFC81AD80A57016F
:1002300082E0A80EB11C712C1FC071120FC0EB819F
:10024000FC81EE0DFF1D9082EB81FC81EC0DFD1D0C
:100250008082EB81FC81EA0DFB1D0083EB81FC8138
:1002600083E0789EE00DF11D11242281418160819F
:10027000CE010E94BC0073948A817816F0F260E08F
:10028000CE010E94A20060E0CE010E94A20060E0C8
:10029000CE010E94A20060E0CE01DF91CF911F91BC
:1002A0000F91FF90EF90DF90CF90BF90AF909F9015
:1002B0008F907F900C94A2000F931F93CF93DF93A6
:1002C000EC01862F688349832A8361E00E949D1296
:1002D00061E089810E949D128A8161E070E023E0E3
:1002E000829FC00111240E9455198B839C8310E0CA
:1002F00008C000E020E040E0612FCE010E94EF0046
:100300001F5F8A811817A8F3DF91CF911F910F917A
:100310000895FC018281089587EE91E00C94750F99
:10032000CF93DF93EC0168E670E087EE91E00E94E6
:10033000AE0F60E087EE91E00E94350F87EE91E00E
:100340000E94C30F47E050E068E670E087EE91E05E
:100350000E94A10F87EE91E00E94B30E382F3695D0
:10036000369536953E70232F220F220F230F8F7064
:100370009927280F288387EE91E00E94B30E282F3B
:1003800022952F708F7099273AE0239F800D1124BA
:10039000898387EE91E00E94B30E382F369536950B
:1003A00036953670232F220F220F230F8F70992737
:1003B000280F2A8387EE91E00E94B30E282F229502
:1003C0002F708F7099273AE0239F800D11248B8323
:1003D00087EE91E00E94B30E282F22952F708F7028
:1003E00099273AE0239F800D11248C8387EE91E0BA
:1003F0000E94B30E282F22952F708F7099273AE014
:10040000239F800D11248D8387EE91E00E94B30E0F
:10041000282F22952F708F7099273AE0239F800D07
:1004200011248E831F82DF91CF910895CF93DF93A4
:10043000EC01862F688319824A831B822C831E82DB
:100440001D8261E00E949D1261E08A81DF91CF915F
:100450000C949D121F93CF93DF93EC0160E08A818F
:100460000E94D5128AE090E00E947D1414E061E0C1
:100470008A810E94D51260E08A810E94D5121150B3
:10048000B1F7DF91CF911F910895FF920F931F93C2
:10049000CF93DF93EC018B0190E1F92E612F661F62
:1004A0006627661F8A810E94D51288810E940C13DC
:1004B00061E0892B09F060E088810E94D512000F6D
:1004C000111FFA9459F7DF91CF911F910F91FF906F
:1004D0000895EF92FF920F931F93CF93DF93EC0158
:1004E0007B01CB0193709E838D8360E070E0CE0131
:1004F0000E94450200E010E08C81882351F0C70182
:10050000002E02C0880F991F0A94E2F791FF0DC0D8
:1005100009C0C701002E02C0969587950A94E2F79C
:1005200080FF03C06FEF70E002C060E070E0CE01BA
:100530000E9445020F5F1F4F0A301105E9F660E087
:1005400070E0CE010E94450260E070E0CE010E94A2
:100550004502CE01DF91CF911F910F91FF90EF9057
:100560000C942A02662321F06B3018F06AE001C077
:1005700061E0262F215061E070E002C0660F771F16
:100580002A95E2F7FC01258136816227732776835D
:1005900065830C946902662321F06B3018F06AE0E1
:1005A00001C061E0562F5150FC012581368161E088
:1005B00070E002C0660F771F5A95E2F7442319F0E6
:1005C000622B732B04C06095709562237323FC012A
:1005D000768365830C9469026B3008F06AE02FEF34
:1005E0003FEF02C0220F331F6A95E2F72095309546
:1005F000FC0136832583B9010C946902FC016483F4
:10060000658176810C946902FC018581968108954B
:10061000FC0181E020813181232B09F480E00895E1
:10062000CF93DF93EC01862F6883498360E00E94BB
:100630009D1260E089810E949D1260E088810E9485
:10064000D51260E08981DF91CF910C94D51268308A
:1006500010F4685F01C06FE0FC016283089561E0FF
:10066000FC0181810E949D1282E390E00C947D1434
:10067000CF93DF93EC0161E089810E949D1282E3B8
:1006800090E00E947D1460E088810E949D1282E3C8
:1006900090E00E947D1460E089810E949D1282E3B7
:1006A00090E0DF91CF910C947D140F931F93CF9323
:1006B000DF93EC01062F18E061E088810E949D1213
:1006C00082E390E00E947D1400FF02C060E001C060
:1006D00061E089810E949D1282E390E00E947D1476
:1006E00060E088810E949D1282E390E00E947D1468
:1006F0000695115009F761E088810E949D1260E023
:1007000089810E949D1282E390E00E947D1460E046
:1007100088810E949D1282E390E00E947D1489816D
:100720000E940C13182F811104C061E089810E947E
:100730009D1282E390E00E947D1461E088810E9416
:100740009D1282E390E00E947D1481E0111101C0AE
:1007500080E0DF91CF911F910F910895CF92DF92AA
:10076000EF92FF920F931F93CF93DF9300D0CDB7FB
:10077000DEB76C01F62EE42E29837A830E942F03C4
:1007800060E4C6010E945503C6010E943803C601F9
:100790000E942F032981622F63706054C6010E945A
:1007A00055030F2D7A81172F06C0F80161918F0133
:1007B000C6010E945503802F8F198E15B0F3C60114
:1007C0000E943803C6010E942F03F601628160581F
:1007D000C6010E945503C6010F900F90DF91CF9183
:1007E0001F910F91FF90EF90DF90CF900C94380302
:1007F0004F925F926F927F928F929F92AF92BF9231
:10080000CF92DF92EF920F931F93CF93DF9300D09D
:1008100000D0CDB7DEB73C016B01322F202F8FE027
:10082000A82E81E0B82E88248394912C8C0E9D1ED6
:10083000F40101E01FE3D5015E904E905D01C60119
:10084000B2010E94DD186115710561F4411106C005
:10085000002321F08E2F8819833011F4108313C0E8
:10086000108211C0DB01AF70BB27A15FBE4F8C911E
:100870008083649DC001659D900D749D900D112431
:10088000C81AD90A00E0EE2039F08E2F881981307D
:1008900019F48081806880833196B7E0AB16B1E0AF
:1008A000BB0649F684E090E0831B9109BE016F5FAF
:1008B0007F4F680F791F432FC3010E94AE030F9033
:1008C0000F900F900F90DF91CF911F910F91EF90AC
:1008D000DF90CF90BF90AF909F908F907F906F9060
:1008E0005F904F9008956F70E62FF0E0E15FFE4F4C
:1008F00080810895FC0181E09081911101C080E028
:1009000008951F93CF93DF931F92CDB7DEB7162FB5
:1009100087EE91E049830E94750F6CE470E087EEEA
:1009200091E00E94AE0F612F87EE91E00E94350F9B
:100930004981642F87EE91E00E94350F87EE91E0A8
:100940000F90DF91CF911F910C94C30F462F67E05A
:100950000C948104462F68E00C948104CF93DF93BC
:10096000EC0160E00E94A60460E0CE010E94AA04AF
:1009700061E0CE01DF91CF910C94A6044F925F927B
:100980006F927F928F929F92AF92BF92CF92DF929F
:10099000EF92FF920F931F93CF93DF9300D01F929C
:1009A000CDB7DEB75B016A01790180E48B838A836E
:1009B00089830E941B142B013C010DC00E941B1453
:1009C0006419750986099709653F7140810591058C
:1009D00014F080E06EC087EE91E00E94AA0E181617
:1009E000190664F387EE91E00E94B30E43E050E0F5
:1009F0006CE470E087EE91E00E94A10F0E941B144E
:100A00002B013C018E010F5F1F4F48012DC0C80113
:100A1000881999090397D4F40E941B142B013C01F7
:100A200011C087EE91E00E94B30EF80180830E940E
:100A30001B146419750986099709633371058105CB
:100A400091053CF6F8018081803458F70E941B1410
:100A50000F5F1F4F6419750986099709653F71403B
:100A6000810591050CF0B5CF87EE91E00E94AA0EAA
:100A7000892B69F69981892F880F880F95FD8D5FE5
:100A800085958595F50180839A81892F880F880F38
:100A900095FD8D5F85958595F60180839B81892FD6
:100AA000880F880F95FD8D5F85958595F70180836B
:100AB00081E00F900F900F90DF91CF911F910F91D8
:100AC000FF90EF90DF90CF90BF90AF909F908F906E
:100AD0007F906F905F904F900895CF93DF93EC01DC
:100AE000862F6E834F83288791E09D8760E00E9468
:100AF0009D1261E08E810E94D51219861A861B868E
:100B00001C86DF91CF910895DF92EF92FF920F93B1
:100B10001F93CF93DF93EC0161E08E810E94D51289
:100B20006AEF70E080E090E00E9457140E941B146E
:100B300009851A852B853C85601771078207930705
:100B400020F419861A861B861C862D85211111C05A
:100B500009851A852B853C85DC01CB01801B910B17
:100B6000A20BB30B803D9740A105B10510F481E0C5
:100B700073C01D860E941B1469877A878B879C87A8
:100B80001C821B821A821982188261E08E810E9467
:100B90009D1260E08E810E94D51264E170E080E0D9
:100BA00090E00E945714F89461E08E810E94D51263
:100BB00088E290E00E947D1460E08E810E949D1288
:100BC000F12CD12C81E009C0E39481E090E00E94F7
:100BD0007D148FEFE81204C009C0E12C082F10E04B
:100BE0008E810E940C138017910771F38E810E94F1
:100BF0000C139FEFE916C9F023E02F1590F4F0FCD9
:100C000010C09D2D969596959695FE01E90FF11DC4
:100C10009081990F908328852E1510F49160908310
:100C2000D394F39495E5F912D8CF789427E22D1553
:100C300090F42C8130E04881898190E0840F911DEF
:100C40004A81840F911D4B81840F911D992728178C
:100C5000390709F48CCF80E0DF91CF911F910F917C
:100C6000FF90EF90DF900895EF92FF920F931F9304
:100C7000CF93DF93EC010E948405882391F18F814B
:100C80008B3029F070F18551823058F507C06881AA
:100C900070E080E090E00E94E1172DC0688170E074
:100CA00080E090E00E94E11720E030E040E853E46B
:100CB0000E946F187B018C01698170E080E090E0F8
:100CC0000E94E3179B01AC016E2D7F2D802F912F89
:100CD0000E94151720E030E040E251E40E947917AD
:100CE0000AC06FE171E084EB92E00E94F71460E0CB
:100CF00070E080EC9FE7DF91CF911F910F91FF9003
:100D0000EF900895CF92DF92EF92FF920F931F938F
:100D1000CF93DF938C01C62F0E948405882309F4AA
:100D200077C0F80187818B3039F008F471C08551A4
:100D3000823008F06DC01DC0F801628170E080E073
:100D400090E00E94E117B62FA72FF82FE92F462F2A
:100D5000572F682F792FCB01BA01CC2309F462C039
:100D600020E030E040E151E46B2F7A2F8F2F9E2F4F
:100D700037C0F801D2816D2F6F7770E080E090E08E
:100D80000E94E31720E030E040E853E40E946F182F
:100D90006B017C01F801638170E080E090E00E94CB
:100DA000E3179B01AC016C2D7D2D8E2D9F2D0E9494
:100DB000151720E030E040E251E40E947917472FF8
:100DC000382F292F862F942FA32FB22FBC01CD01AE
:100DD000D7FD9058CC2331F120E030E040E151E4E0
:100DE0000E946F1820E030E040EA50E40E9479173A
:100DF00020E030E040E052E40E941517472F382FE2
:100E0000292F862F942FA32FB22FBC01CD010AC00A
:100E10006FE171E084EB92E00E94F71460E070E013
:100E200080EC9FE7DF91CF911F910F91FF90EF90A2
:100E3000DF90CF900895CF93DF9322C087EE91E0AB
:100E40000E94AA0E049741F4109269011092680161
:100E500010926B0110926A01C0916A01D0916B01EE
:100E600087EE91E00E94B30EFE01EE0FFF1FE459E2
:100E7000FE4F918380832196D0936B01C0936A01CA
:100E800087EE91E00E94AA0E892BC1F6DF91CF91E7
:100E9000089580916C0190916D01019731F46091FA
:100EA000670187EE91E00E94350F80916C0190916F
:100EB0006D018330910529F08730910511F0C897B5
:100EC00041F443E050E06EE571E087EE91E00E946E
:100ED000070F80916C0190916D018830910511F0A0
:100EE000449741F444E050E06EE571E087EE91E014
:100EF0000E94070F80916C0190916D018E319105D8
:100F000011F0889741F449E050E06EE571E087EE1A
:100F100091E00C94070F089540E855E260E070E01E
:100F200084EB92E00E944A1667E070E087EE91E061
:100F30000E94920F6BE177E087EE91E00E94C60F6E
:100F400069E477E087EE91E00E94CB0F69E271E0FF
:100F500084EB92E00C941615AF92BF92CF92DF9281
:100F6000EF92FF920F931F93CF93DF93CDB7DEB72E
:100F70002C970FB6F894DEBF0FBECDBF80916A01EB
:100F800090916B01049709F0D4C68091680190910B
:100F90006901892B09F0CDC681E090E09093690149
:100FA0008093680180916C0190916D01019731F4FB
:100FB00080916E010E940C138093670180916C01F7
:100FC00090916D01029731F46091700180916E01F2
:100FD0000E94D51280916C0190916D010397A9F444
:100FE00080916E010E94F11190935D0180935C01EC
:100FF0009C0197FF02C021503F4F30935F0160E09A
:1010000071E00E94DD188093600180916C019091E5
:101010006D01049741F460917001709171018091AC
:101020006E010E94121280916C0190916D010597E2
:1010300031F46091700180916E010E949D12809147
:101040006C0190916D01079709F042C080916E018B
:1010500090916F01809352019093530161E00E943F
:101060009D1260E0809152010E94D51282E090E0D2
:101070000E947D1461E0809152010E94D51285E0AA
:1010800090E00E947D1460E0809152010E94D51290
:1010900060E0809152010E949D1220E432E44FE012
:1010A00050E061E0809152010E9435132AE330E064
:1010B00040E050E00E941319CA01B90120E031E07C
:1010C00040E050E00E94131920935F01609360019B
:1010D00080916C0190916D018830910539F481E027
:1010E00080935F0182E08093600121C0449709F5FD
:1010F00080915B01811107C086EE91E00E94AE04F1
:1011000081E080935B0129E531E048E551E067E546
:1011100071E086EE91E00E94BE04809157018093B9
:101120005F01809158018093600180915901809303
:10113000610180916C0190916D014E9769F58091EC
:101140005A01811107C08EED91E00E948C0181E06F
:1011500080935A018EED91E00E9490018091E00110
:1011600080935F018091DF01809360018091DE01B7
:10117000809361018091E301809362018091E2019B
:10118000809363019091E4019093640180936501E1
:101190008091E1018093660180916C0190916D01D5
:1011A000889709F059C08091700190917101009762
:1011B00019F426E04BE005C08130910549F426E0A2
:1011C00046E160916E0180ED91E00E946D0508C0DE
:1011D0008230910519F426E045E1F3CF0397D9F366
:1011E00060E080ED91E00E94820669877A878B87B4
:1011F0009C8780ED91E00E9434066D837E838F830F
:1012000098871092510110925001FE01399680E0AA
:1012100090E001962191DC01A25ABE4F2C938430BC
:101220009105BCF384E090E09093510180935001CC
:101230000196DC01A25ABE4FE5E0F0E0EC0FFD1F85
:10124000E80FF91F359720812C938830910584F39E
:10125000909351018093500180916C0190916D01A8
:10126000C297D9F480916E0190916F01482F21E0CF
:101270006091700170917101672B09F420E0642F77
:101280006F5FFC01329737E03E9FC0013F9F900D9A
:1012900011248A559E4F0E94160280916C019091F4
:1012A0006D01C39791F420916E0130916F0122502E
:1012B000310947E0429FC001439F900D11248A5598
:1012C0009E4F0E94080381116AC380916C01909126
:1012D0006D01C49791F420916E0130916F012250FD
:1012E000310917E0129FC001139F900D11248A55F8
:1012F0009E4F0E94080381116BC380916C019091F5
:101300006D01C59791F420916E0130916F012250CB
:10131000310947E0429FC001439F900D11248A5537
:101320009E4F0E940803811165C380916C019091CA
:101330006D01C69791F420916E0130916F0122509A
:10134000310917E0129FC001139F900D11248A5597
:101350009E4F0E940803811168C380916C01909197
:101360006D01C79791F420916E0130916F01225069
:10137000310917E0129FC001139F900D11248A5567
:101380009E4F0E940803811162C380916C0190916D
:101390006D01C89791F420916E0130916F01225038
:1013A000310917E0129FC001139F900D11248A5537
:1013B0009E4F0E940803811163C380916C0190913C
:1013C0006D018634910591F460916E0170916F0109
:1013D000462F4F5F9B0122503109C901880F991F89
:1013E000820F931F8C569E4F0E94100380916C01B8
:1013F00090916D018734910589F420916E013091AF
:101400006F0122503109C901880F991F820F931F64
:101410008C569E4F0E947A04811146C380916C01C4
:1014200090916D018834910589F420916E0130917D
:101430006F0122503109C901880F991F820F931F34
:101440008C569E4F0E947A04811140C380916C019A
:1014500090916D018934910589F420916E0130914C
:101460006F0122503109C901880F991F820F931F04
:101470008C569E4F0E947A04811145C380916C0165
:1014800090916D018A34910589F420916E0130911B
:101490006F0122503109C901880F991F820F931FD4
:1014A0008C569E4F0E947A0481114AC380916C0130
:1014B00090916D018B34910589F420916E013091EA
:1014C0006F0122503109C901880F991F820F931FA4
:1014D0008C569E4F0E947A0481115AC380916C01F0
:1014E00090916D018C34910589F420916E013091B9
:1014F0006F0122503109C901880F991F820F931F74
:101500008C569E4F0E947A0481115BC380916C01BE
:1015100090916D018D349105A9F520916E01309166
:101520006F0122503109C901880F991F820F931F43
:101530008C569E4F0E947A048111BBC323C0812F19
:101540000E94F111BC0120916E0130916F01225077
:101550003109C901880F991F820F931FE12C00E008
:1015600024E040E08C569E4F0E94F8036AEF70E042
:1015700080E090E00E9457142FEFC21AD20ACA14DA
:10158000DB04ECF280916C0190916D018E34910539
:1015900089F420916E0130916F0122503109C90107
:1015A000880F991F820F931F8C569E4F0E947A04BA
:1015B00081118CC380916C0190916D018F349105E4
:1015C00089F420916E0130916F0122503109C901D7
:1015D000880F991F820F931F8C569E4F0E947A048A
:1015E00081118EC380916C0190916D018A359105B6
:1015F00069F480916E018093540180917001809311
:101600005501809172018093560118C08B35910568
:10161000A9F460916E0170916F01462F4F5F9B019D
:101620002250310955E0529FC001539F900D112463
:10163000209170018A589E4F0E945C0180916C013C
:1016400090916D018C35910549F080916C019091DC
:101650006D018D35910509F0BDC048C060916E01E6
:1016600070916F01462F4F5F9B012250310955E069
:10167000529FC001539F900D1124209170018A58F0
:101680009E4F0E945C01009172011091730102FB58
:10169000DD24D0F8D19401FBCC24C0F8C1940170B2
:1016A0001127102F1195E12CF12CA5E0BA2E16C0B0
:1016B00060916E0170916F0162507109B69EC00118
:1016C000B79E900D1124012F2C2D4D2D6E2D8A5873
:1016D0009E4F0E94EF003FEFE31AF30A80917001E2
:1016E00090917101E816F9061CF3AFCF20917001BB
:1016F0003091710180916E0190916F01232BB1F4B3
:101700009C012250310945E0429FC001439F900D4A
:10171000112400915601209155014091540160918E
:1017200072018A589E4F0E94EF0054C09C012250C3
:10173000310945E0429FC001439F900D11248A5812
:101740009E4F0E948901E12CF12CC82ED12C15E06E
:101750003DC020917001309171012130310541F47B
:101760008091720190917301E816F906B1F42BC0D3
:101770002230310541F480917201909173018E15F0
:101780009F055CF420C023303105E9F4809172019B
:1017900090917301E816F906B4F020916E01309132
:1017A0006F0122503109129FC001139F900D112427
:1017B0000091560120915501409154016E2D8A5897
:1017C0009E4F0E94EF008FEFE81AF80AEC14FD0418
:1017D0000CF4BFCF80916C0190916D018E35910515
:1017E00049F080916C0190916D018F35910509F060
:1017F000A0C252C08091720190917301181619060F
:1018000034F081E090E09093730180937201209115
:101810006E0130916F012250310945E0429FC001B5
:10182000439F900D11248A589E4F0E948901E09099
:101830007001F0907101C82ED12C15E029C0809163
:101840007001909171019701281B390BC9016091BA
:101850007201709173010E94DD18892BB1F42091FF
:101860006E0130916F0122503109129FC001139F08
:10187000900D112400915601209155014091540181
:101880006E2D8A589E4F0E94EF003FEFE31AF30A35
:10189000EC14FD04A4F2A5CF20916E0130916F01EC
:1018A0002250310945E0429FC001439F900D112411
:1018B0008A589E4F0E9489012091720130917301D4
:1018C000232B59F133C080917001909171012091C7
:1018D0006E0130916F0122503109E816F90664F467
:1018E000129FC001139F900D112400915601209169
:1018F00055014091540108C0129FC001139F900DE3
:10190000112400E020E040E06E2D8A589E4F0E9496
:10191000EF008FEFE81AF80A05C0E12CF12CC82E71
:10192000D12C15E0EC14FD0474F203C2C82ED12CA6
:10193000760115E030C0809170019091710196019F
:10194000281B390B80916E0190916F01E216F3060E
:101950007CF09C0122503109129FC001139F900D11
:1019600011240091560120915501409154010BC062
:101970009C0122503109129FC001139F900D112428
:1019800000E020E040E06E2D8A589E4F0E94EF005C
:1019900021E0E21AF108E114F10469F6CAC161E03C
:1019A0008091700190917101892B09F460E0209180
:1019B0006E0130916F012250310947E0429FC00112
:1019C000439F900D11248A559E4F0E94FE027DCCAC
:1019D00020916E0130916F0122503109129FC00198
:1019E000139F900D1124609170018A559E4F0E94A3
:1019F000EC0283CC41E08091720190917301892BBC
:101A000009F440E020916E0130916F0122503109BC
:101A100057E0529FC001539F900D112460917001B7
:101A20008A559E4F0E94CB0280CC20916E0130914E
:101A30006F0122503109129FC001139F900D112494
:101A4000609170018A559E4F0E94B20286CC90919F
:101A5000720180E0609170017091710168277927AF
:101A600020916E0130916F0122503109129FC00107
:101A7000139F900D11248A559E4F0E94690285CCB8
:101A800020916E0130916F0122503109129FC001E7
:101A9000139F900D11248A559E4F0E94040380933A
:101AA0005F019093600189CC20916E0130916F01AC
:101AB00022503109C901880F991F820F931F60912D
:101AC00070018C569E4F0E942703A8CC9091720102
:101AD00080E06091700170917101682779272091F1
:101AE0006E0130916F0122503109C901880F991F91
:101AF000820F931FE12C00E024E040E08C569E4FC3
:101B00000E94F803A3CC9091720180E06091700173
:101B1000709171016827792720916E0130916F01D2
:101B200022503109C901880F991F820F931FE12CA0
:101B300000E024E041E08C569E4F0E94F8039ECCCA
:101B400020916E0130916F0122503109C901880F37
:101B5000991F820F931F609172018C569E4F0E94B5
:101B60007304898320916E0130916F0122503109F5
:101B7000C901880F991F820F931F2091700141E0C6
:101B8000BE016F5F7F4F8C569E4F0E94AE038ECC7E
:101B900080917201898320916E0130916F012250F2
:101BA0003109C901880F991F820F931F209170017D
:101BB00041E0BE016F5F7F4F8C569E4F0E94AE0387
:101BC0008DCC80917001909171010AE010E0B80114
:101BD0000E94DD1820916E0130916F012250310971
:101BE000C901880F991F820F931F8C569E4F0E9428
:101BF000730489838091700190917101B8010E94F2
:101C0000DD1820916E0130916F0122503109A90138
:101C1000440F551F420F531F682FCA018C569E4F09
:101C20000E94730480688A8380917201909173018D
:101C3000B8010E94DD1820916E0130916F01225091
:101C40003109C901880F991F820F931F8C569E4F2F
:101C50000E9473048B838091720190917301B8018B
:101C60000E94DD1820916E0130916F0122503109E0
:101C7000A901440F551F420F531F682FCA018C56EC
:101C80009E4F0E9473048C8320916E0130916F01EE
:101C900022503109C901880F991F820F931F20E03C
:101CA00044E0BE016F5F7F4F8C569E4F0E94AE0393
:101CB0002DCC10917001A0907201B0907301AA0C0C
:101CC000BB1CAA0CBB1CC12CD12C59CC8FEF898317
:101CD0008A838B838C8320916E0130916F01225017
:101CE0003109C901880F991F820F931F20E044E03A
:101CF000BE016F5F7F4F8C569E4F0E94AE035ACC41
:101D000019821A821B821C8220916E0130916F0110
:101D100022503109C901880F991F820F931F20E0BB
:101D200044E0BE016F5F7F4F8C569E4F0E94AE0312
:101D300059CC2C960FB6F894DEBF0FBECDBFDF9105
:101D4000CF911F910F91FF90EF90DF90CF90BF90B8
:101D5000AF90089520911B0230E080911C02281B57
:101D60003109C901089580911C0290911B028917C5
:101D700050F4E82FF0E0E35EFD4F208130E08F5F0C
:101D800080931C0202C02FEF3FEFC9010895E0913C
:101D90001C0280911B02E81730F4F0E0E35EFD4F77
:101DA000208130E002C02FEF3FEFC9010895089570
:101DB000E091F301F091F4013097E1F030911C02D1
:101DC00020911B023217B0F040E009C0DC01A20FE5
:101DD000B31F5C91D901A35EBD4F5C934F5F242F6D
:101DE00030E02617370794F310921C0260931B0211
:101DF000CB0109940895E091F501F091F601309737
:101E000029F01092F9011092F80109940895CF92E7
:101E1000DF92EF92FF920F931F93CF93DF937C019A
:101E2000CB018A012091F701222391F0EB016B0194
:101E3000C40ED51E09C06991D701ED91FC910190A6
:101E4000F081E02DC7010995CC15DD05A1F703C090
:101E5000642F0E948E10C801DF91CF911F910F91C6
:101E6000FF90EF90DF90CF900895CF93DF931F9274
:101E7000CDB7DEB769832091F7012223D1F02091FD
:101E8000F801203240F021E030E0FC01338322836E
:101E900020E030E015C08091F901E82FF0E0E65035
:101EA000FE4F998190838F5F8093F9018093F801B1
:101EB00005C061E0CE0101960E948E1021E030E065
:101EC000C9010F90DF91CF910895FC011382128216
:101ED00048EE53E060E070E0448355836683778387
:101EE00084E391E091838083089510921C02109204
:101EF0001B021092F9011092F8010C94D40FCF93A9
:101F0000DF93EC01862F0E94F20F8BEF9EE00E9480
:101F1000AC1088ED9EE00E94A710CE01DF91CF911A
:101F20000C94750F0C947F0F862F413208F040E21D
:101F30006DE172E00E94F60F10921C0280931B026A
:101F4000089521E00C94940F81E08093F701609351
:101F50001A021092F9011092F80108950C94A40F3E
:101F60000F93062F21E04091F8016AEF71E0809114
:101F70001A020E943B101092F9011092F80110927F
:101F8000F7010F91089561E00C94B00F7093F40184
:101F90006093F30108957093F6016093F50108953D
:101FA00087EE91E00C94650F1092460281E08093D9
:101FB00044021092430261E082E10E94D51261E086
:101FC00083E10E94D512E9EBF0E080818E7F80836F
:101FD00080818D7F808382E08093B80085E4809348
:101FE000BC000895880F8093BA000895413208F02C
:101FF0003FC0909146029111FCCF91E09093460230
:10200000209344022FEF20933D0210924202242F8E
:102010002150209341029093450290914502880FF0
:10202000892B8093450280914302813041F41092C4
:102030004302809145028093BB0085EC01C085EE90
:102040008093BC00809146028130E1F3809142028E
:10205000841710F44091420227E432E0FB01D901D9
:1020600002C08D9181938A2F821B8417D0F301C007
:1020700040E0842F08950F93413208F046C09091BC
:1020800046029111FCCF92E09093460200934402E5
:102090009FEF90933D021092420240934102FB0158
:1020A00067E472E0DB0102C091919D939A2F961B29
:1020B0009417D0F31092450290914502880F892B16
:1020C0008093450280914302813041F41092430293
:1020D000809145028093BB0085EC01C085EE809322
:1020E000BC00222321F0809146028230E1F38091EE
:1020F0003D028F3F61F080913D02803251F080912E
:102100003D02803341F483E007C081E005C080E0F8
:1021100003C082E001C084E00F910895613298F419
:1021200020914602243089F460933F02FC0187E647
:1021300092E0DC0102C021912D932A2F281B261743
:10214000D0F380E0089581E0089582E008959093AF
:10215000880280938702089590938A02809389026F
:10216000089585ED8093BC008091BC0084FDFCCF78
:1021700010924602089585EC8093BC0010924602AE
:1021800008951F920F920FB60F9211242F933F9331
:102190004F935F936F937F938F939F93AF93BF936F
:1021A000EF93FF938091B900887F803609F49FC038
:1021B00058F5883209F45BC090F4803109F452C0BC
:1021C00038F4882309F4F8C0883009F0F9C04AC00F
:1021D000883109F44CC0803209F0F2C05CC0803410
:1021E00009F46BC038F4803309F455C0883309F022
:1021F000E7C054C0803509F454C0883509F462C082
:10220000883409F0DDC0DAC0883909F4CBC0A8F4FD
:10221000883709F46CC038F4883609F468C0803710
:1022200009F0CEC064C0883809F4BCC0803909F414
:1022300064C0803809F0C4C060C0803B09F48AC023
:1022400038F4803A09F46BC0883A09F0B9C082C00A
:10225000803C09F4ABC0883C09F4A8C0883B09F075
:10226000AFC08DC0809145028093BB0012C0909199
:10227000420280914102981788F580914202E82F2E
:10228000F0E0E95BFD4F90819093BB008F5F8093FE
:10229000420285EC88C080933D0290C080933D024D
:1022A00056C0809142029091BB00E82FF0E0E95BBC
:1022B000FD4F90838F5F8093420290914202809104
:1022C00041026DC0809142029091BB00E82FF0E086
:1022D000E95BFD4F90838F5F8093420280914402BF
:1022E00081116CC081E08093430284EA60C083E086
:1022F0008093460210923E02CCCF80913E02803203
:1023000008F050C080913E029091BB00E82FF0E0B1
:10231000E557FD4F90838F5F80933E02BACF809147
:102320003E02803230F4E0913E02F0E0E557FD4F8E
:1023300010820E94B11060913E02E0918702F091FC
:10234000880270E08BE892E0099510923E020E94AC
:10235000BB1036C084E08093460210924002109277
:102360003F02E0918902F0918A02099580913F0233
:10237000811105C081E080933F0210926702809135
:102380004002E82FF0E0E959FD4F90819093BB00A7
:102390008F5F809340029091400280913F02981796
:1023A00008F477CF85E88093BC000AC085EC809361
:1023B000BC001092460204C010923D020E94B1106F
:1023C000FF91EF91BF91AF919F918F917F916F910D
:1023D0005F914F913F912F910F900FBE0F901F90E3
:1023E00018958E3008F08E5087702091060140E4D9
:1023F000249F90011124822B80937C0080917A008D
:10240000806480937A0080917A0086FDFCCF2091D1
:10241000780030917900932F80E0AC01422B9A0133
:10242000C90108951F93CF93DF93182FEB0161E04B
:102430000E949D12209711F460E004C0CF3FD105A7
:1024400039F461E0812FDF91CF911F910C94D51267
:10245000E12FF0E0E859FF4FE491E330B9F028F4C0
:10246000E13051F0E230B1F50CC0E63019F1E7305F
:1024700049F1E43079F514C084B5806884BDC7BDE6
:102480002EC084B5806284BDC8BD29C08091800003
:10249000806880938000D0938900C09388001FC01B
:1024A00080918000806280938000D0938B00C093E5
:1024B0008A0015C08091B00080688093B000C093FE
:1024C000B3000DC08091B00080628093B000C093D3
:1024D000B40005C0C038D1050CF0B3CFADCFDF914B
:1024E000CF911F910895833069F028F48130A1F0D5
:1024F000823011F514C08630B1F08730C1F08430DD
:10250000D9F404C0809180008F7703C0809180004F
:102510008F7D80938000089584B58F7702C084B545
:102520008F7D84BD08958091B0008F7703C0809126
:10253000B0008F7D8093B0000895CF93DF9390E03B
:10254000FC01E458FF4F4491FC01E057FF4F849198
:10255000882341F190E0880F991FFC01E854FF4F58
:1025600025913491D90182559F4FFC018591949119
:10257000C82FD92F9FB7F8948C91611106C0409550
:1025800084238C938881842308C0623041F4242FF3
:10259000209582238C938881842B888302C0842B8E
:1025A0008C939FBFDF91CF9108950F931F93CF938B
:1025B000DF931F92CDB7DEB7282F30E0F901E8593D
:1025C000FF4F8491F901E458FF4F1491F901E0574E
:1025D000FF4F04910023D1F0882321F069830E94EA
:1025E00073126981E02FF0E0EE0FFF1FE255FF4FFD
:1025F00085919491DC019FB7F8948C91611103C08F
:102600001095812301C0812B8C939FBF0F90DF9188
:10261000CF911F910F910895CF93DF93282F30E032
:10262000F901E859FF4F8491F901E458FF4FD49123
:10263000F901E057FF4FC491CC2389F081110E942A
:102640007312EC2FF0E0EE0FFF1FEC55FF4F85915A
:102650009491DC018C918D2321E030E011F420E095
:1026600030E0C901DF91CF9108958F929F92AF9290
:10267000BF92CF92DF92EF92FF920F931F93CF936F
:10268000DF9390E0FC01E458FF4FD491FC01E05748
:10269000FF4F7491611102C0C0E001C0CD2FDA017B
:1026A000C901880F991FAA1FBB1F54E0B695A795B3
:1026B000979587955A95D1F7672F70E0660F771F2A
:1026C0006C557F4F812C912C5401FB010591149185
:1026D00010C0C12CD12C7601C394C80CD91CEA1CA3
:1026E000FB1C88169906AA06BB0609F448C04601D9
:1026F0005701F801E081ED23EC1759F310C0C12C0C
:10270000D12C7601C394C80CD91CEA1CFB1C88167A
:102710009906AA06BB0699F14601570103C0FB01C1
:1027200005911491F801E081ED23EC13E8CF8819AD
:102730009909AA09BB0920E030E0A901FB016591D4
:10274000749109C0281739074A075B07C1F02F5F4A
:102750003F4F4F4F5F4FFB01E081ED23EC1791F3AB
:10276000A5E1B0E00E94D2188B019C01005F1F4FD1
:102770002F4F3F4F369527951795079503C000E0DB
:1027800010E09801B801C901DF91CF911F910F911D
:10279000FF90EF90DF90CF90BF90AF909F908F9081
:1027A00008951F920F920FB60F9211242F933F930B
:1027B0008F939F93AF93BF938091AB029091AC02A4
:1027C000A091AD02B091AE023091B302232F285EEA
:1027D0002D3720F40896A11DB11D05C0232F2556C5
:1027E0000996A11DB11D2093B3028093AB02909373
:1027F000AC02A093AD02B093AE028091AF02909173
:10280000B002A091B102B091B2020196A11DB11D1A
:102810008093AF029093B002A093B102B093B20242
:10282000BF91AF919F918F913F912F910F900FBECC
:102830000F901F9018950F931F938FB7F8940091E6
:10284000AB021091AC022091AD023091AE028FBF6D
:10285000B801C9011F910F9108950F931F939FB75E
:10286000F8940091AF021091B0022091B102309122
:10287000B20286B5A89B06C08F3F21F00F5F1F4FA5
:102880002F4F3F4F9FBF322F212F102F0027080FB0
:10289000111D211D311D45E0000F111F221F331F87
:1028A0004A95D1F7B801C9011F910F910895CF92B0
:1028B000DF92EF92FF92CF93DF936B017C010E9436
:1028C0002D14EB010EC00E942D146C1B7D0B683E75
:1028D000734038F081E0C81AD108E108F108C85106
:1028E000DC4FC114D104E104F10469F7DF91CF9109
:1028F000FF90EF90DF90CF900895019739F0019706
:1029000029F0880F991F01970197F1F7089578949E
:1029100084B5826084BD84B5816084BD85B58260E4
:1029200085BD85B5816085BDEEE6F0E08081816082
:102930008083E1E8F0E01082808182608083E0E8BB
:10294000F0E0808181608083E1EBF0E08081846051
:102950008083E0EBF0E0808181608083EAE7F0E053
:1029600080818460808380818260808380818160B7
:1029700080838081806880831092C1000895CF9207
:10298000DF92EF92FF920F931F93CF93DF936C012F
:10299000EB017A01E60EF71E00E010E00BC0699132
:1029A000D601ED91FC910190F081E02DC6010995D1
:1029B000080F191FCE15DF0591F7C801DF91CF91E0
:1029C0001F910F91FF90EF90DF90CF900895DB0162
:1029D0000D900020E9F7AD0141505109461B570BFE
:1029E000DC01ED91FC910280F381E02D09940C94BF
:1029F000E714DC01ED91FC910190F081E02D099448
:102A00000F931F93CF93DF93EC016DE00E94F914B5
:102A10008C016AE0CE010E94F9149C01200F311F45
:102A2000C901DF91CF911F910F9108950F931F93CB
:102A3000CF93DF93EC010E94E7148C01CE010E943A
:102A400000159801280F391FC901DF91CF911F91FF
:102A50000F9108950E9487140E948C07C6E0D6E16A
:102A60000E94AC072097E1F30E940616F9CFFC0103
:102A700084859585FC01E05CFF4F20813181FC015C
:102A8000EE5BFF4F80819181281B390B2F73332719
:102A9000C9010895FC0184859585FC01E05CFF4F28
:102AA00040815181FC01EE5BFF4F20813181421753
:102AB000530741F00190F081E02DE80FF91F2081CC
:102AC00030E002C02FEF3FEFC9010895FC0184857B
:102AD0009585FC01E05CFF4F40815181FC01EE5B7C
:102AE000FF4F208131814217530781F0A081B181CE
:102AF000A80FB91F8C91208131812F5F3F4F2F7319
:102B0000332731832083282F30E002C02FEF3FEF9F
:102B1000C9010895FC0186859785FC01E05CFF4FA3
:102B2000DC01AE5BBF4F408151812D913C911197EB
:102B300042175307C1F70895CF93DF93FC018685B1
:102B40009785DC01A05CBF4F2D913C9111972F5FC1
:102B50003F4F2F733327EC01CE5BDF4F4881598104
:102B600024173507D9F30D90BC91A02DA80FB91FDC
:102B70006C93A685B785A05CBF4F11963C932E93AE
:102B8000A689B7892C9181E090E0058C02C0880F5E
:102B9000991F0A94E2F7282B2C9381E090E0DF91B3
:102BA000CF91089508951F920F920FB60F9211249E
:102BB0002F933F934F938F939F93EF93FF93409166
:102BC000C600809157039091580301968F739927FF
:102BD0002091590330915A038217930759F0E091DD
:102BE0005703F0915803E95EFC4F408390935803DC
:102BF00080935703FF91EF919F918F914F913F9158
:102C00002F910F900FBE0F901F90189584EB92E0BC
:102C10000E943715892B11F00C94D21508951F923C
:102C20000F920FB60F9211242F933F938F939F9380
:102C3000EF93FF93209113033091140380911503B8
:102C4000909116032817390731F48091C1008F7DC8
:102C50008093C10014C0E0911503F0911603ED526A
:102C6000FD4F2081809115039091160301968F737B
:102C7000992790931603809315032093C600FF9124
:102C8000EF919F918F913F912F910F900FBE0F90D9
:102C90001F901895CF92DF92EF92FF92CF93DF9320
:102CA000EC016A017B01EC89FD8981E090E00E8CEA
:102CB00002C0880F991F0A94E2F7808360E271EAEC
:102CC00087E090E0A70196010E94F1182150310998
:102CD000410951095695479537952795211580E16A
:102CE000380798F0EC89FD89108260E970ED83E087
:102CF00090E0A70196010E94F11821503109410985
:102D000051095695479537952795E889F989308374
:102D1000EA89FB892083EE89FF89408181E090E088
:102D20009C010A8C02C0220F331F0A94E2F7422B47
:102D30004083EE89FF8940819C010B8C02C0220FE9
:102D4000331F0A94E2F7422B4083EE89FF894081CA
:102D50009C010C8C02C0220F331F0A94E2F7422B15
:102D60004083EE89FF8920810D8C02C0880F991F56
:102D70000A94E2F7809582238083DF91CF91FF90C0
:102D8000EF90DF90CF9008951092B7021092B602A4
:102D900088EE93E0A0E0B0E08093B8029093B9028F
:102DA000A093BA02B093BB0284E491E09093B50281
:102DB0008093B40287E193E09093C1028093C002B4
:102DC00083ED92E09093C3028093C20285EC90E081
:102DD0009093C5028093C40284EC90E09093C70264
:102DE0008093C60280EC90E09093C9028093C80261
:102DF00081EC90E09093CB028093CA0286EC90E045
:102E00009093CD028093CC0284E08093CE0283E045
:102E10008093CF0287E08093D00285E08093D10237
:102E200081E08093D20208955058BB27AA270ED084
:102E30001CC10DD130F012D120F031F49F3F11F4BC
:102E40001EF402C10EF4E095E7FBF8C0E92F1ED195
:102E500080F3BA17620773078407950718F071F4B7
:102E60009EF536C10EF4E0950B2EBA2FA02D0B0166
:102E7000B90190010C01CA01A0011124FF27591BBF
:102E800099F0593F50F4503E68F11A16F040A22FC5
:102E9000232F342F4427585FF3CF46953795279536
:102EA000A795F0405395C9F77EF41F16BA0B620B35
:102EB000730B840BBAF09150A1F0FF0FBB1F661F7C
:102EC000771F881FC2F70EC0BA0F621F731F841FBF
:102ED00048F4879577956795B795F7959E3F08F0E5
:102EE000B3CF9395880F08F09927EE0F97958795A4
:102EF00008950CD0BAC0B2D040F0A9D030F021F47F
:102F00005F3F19F09BC05111E4C09EC0BFD098F341
:102F10009923C9F35523B1F3951B550BBB27AA275A
:102F200062177307840738F09F5F5F4F220F331FCC
:102F3000441FAA1FA9F333D00E2E3AF0E0E830D098
:102F400091505040E695001CCAF729D0FE2F27D09B
:102F5000660F771F881FBB1F261737074807AB0769
:102F6000B0E809F0BB0B802DBF01FF2793585F4FDE
:102F70002AF09E3F510568F061C0ABC05F3FECF3A3
:102F8000983EDCF3869577956795B795F7959F5FA3
:102F9000C9F7880F911D9695879597F90895E1E0F7
:102FA000660F771F881FBB1F621773078407BA0756
:102FB00020F0621B730B840BBA0BEE1F88F7E095B1
:102FC0000895E89409C097FB3EF49095809570951C
:102FD00061957F4F8F4F9F4F9923A9F0F92F96E965
:102FE000BB279395F695879577956795B795F111DA
:102FF000F8CFFAF4BB0F11F460FF1BC06F5F7F4F77
:103000008F4F9F4F16C0882311F096E911C0772388
:1030100021F09EE8872F762F05C0662371F096E891
:10302000862F70E060E02AF09A95660F771F881F60
:10303000DAF7880F9695879597F9089597F99F671E
:1030400080E870E060E008959FEF80EC0895002430
:103050000A941616170618060906089500240A94FD
:1030600012161306140605060895092E0394000C83
:1030700011F4882352F0BB0F40F4BF2B11F460FF12
:1030800004C06F5F7F4F8F4F9F4F089557FD90583B
:10309000440F551F59F05F3F71F04795880F97FB1C
:1030A000991F61F09F3F79F08795089512161306D6
:1030B0001406551FF2CF4695F1DF08C01616170605
:1030C0001806991FF1CF869571056105089408953A
:1030D000E894BB2766277727CB0197F908950BD093
:1030E000C4CFB5DF28F0BADF18F0952309F0A6CFDA
:1030F000ABCF1124EECFCADFA0F3959FD1F3950F8C
:1031000050E0551F629FF001729FBB27F00DB11D6B
:10311000639FAA27F00DB11DAA1F649F6627B00DFB
:10312000A11D661F829F2227B00DA11D621F739FE4
:10313000B00DA11D621F839FA00D611D221F749FF2
:103140003327A00D611D231F849F600D211D822F39
:10315000762F6A2F11249F5750408AF0E1F0882380
:103160004AF0EE0FFF1FBB1F661F771F881F91508D
:103170005040A9F79E3F510570F060CFAACF5F3F46
:10318000ECF3983EDCF3869577956795B795F795C0
:10319000E7959F5FC1F7FE2B880F911D9695879548
:1031A00097F908950E942F19A59F900DB49F900D37
:1031B000A49F800D911D1124089597FB072E16F4EE
:1031C000009407D077FD09D00E943B1907FC05D079
:1031D0003EF4909581959F4F0895709561957F4F2E
:1031E0000895A1E21A2EAA1BBB1BFD010DC0AA1F48
:1031F000BB1FEE1FFF1FA217B307E407F50720F060
:10320000A21BB30BE40BF50B661F771F881F991FDA
:103210001A9469F760957095809590959B01AC0123
:10322000BD01CF010895052E97FB16F4009407D039
:1032300057FD0DD00E94F11807FC09D07EF490953F
:103240008095709561957F4F8F4F9F4F0895509552
:103250004095309521953F4F4F4F5F4F0895A29F66
:10326000B001B39FC001A39F01D0B29F700D811D1B
:103270001124911D0895AA1BBB1B51E107C0AA1F71
:10328000BB1FA617B70710F0A61BB70B881F991F07
:103290005A95A9F780959095BC01CD010895EE0F40
:1032A000FF1F0590F491E02D09940F931F93CF9386
:1032B000DF93689F8001699F100D789F100D112486
:1032C000C8010E947319C82FD92F209731F0A80187
:1032D00060E070E08C2F0E94AA1ACE01DF91CF919E
:1032E0001F910F9108950F931F93CF93DF93823017
:1032F000910510F482E090E0E0915D03F0915E03AF
:1033000020E030E0C0E0D0E023C040815181481788
:103310005907A8F04817590761F4828193812097D3
:1033200019F09B838A832EC090935E0380935D0384
:1033300029C02115310529F04217530710F0A901C2
:1033400002C0BE01DF0102811381EF019A01F80181
:103350003097D9F62115310509F1281B390B243096
:10336000310590F412968D919C911397611571051A
:1033700021F0FB019383828304C090935E038093CA
:103380005D03FD01329644C0FD01E20FF31F8193FE
:103390009193225031092D933C933AC020915B03C5
:1033A00030915C03232B41F4209102013091030101
:1033B00030935C0320935B03209100013091010165
:1033C0002115310541F42DB73EB7409104015091CC
:1033D0000501241B350BE0915B03F0915C03E217C0
:1033E000F307A0F42E1B3F0B2817390778F0AC0128
:1033F0004E5F5F4F2417350748F04E0F5F1F509305
:103400005C0340935B038193919302C0E0E0F0E0A2
:10341000CF01DF91CF911F910F910895EF92FF920D
:103420000F931F93CF93DF93009709F48EC0DC01B5
:10343000129713961C921E921297E0905D03F090E3
:103440005E03E114F10489F42D913C911197280F4A
:10345000391F80915B0390915C038217930789F574
:10346000B0935C03A0935B0370C0E70120E030E001
:1034700001C0EA01CA17DB0738F44A815B819E016B
:1034800041155105B1F722C0AC0142505109FA0172
:10349000D383C28300811181BC01600F711F6C173F
:1034A0007D0761F468817981600F711F6E5F7F4FC6
:1034B000718360836A817B81738362832115310507
:1034C00029F4B0935E03A0935D033FC0F901B38379
:1034D000A283E90149915991C40FD51FAC17BD07CB
:1034E00071F4DC019E918E91840F951F0296918359
:1034F000808312968D919C91139793838283A0E091
:10350000B0E002C0D7017C01F7018281938100976E
:10351000C9F7C701029620813181820F931F209144
:103520005B0330915C032817390779F4109729F46D
:1035300010925E0310925D0304C013961C921E92BB
:103540001297F0925C03E0925B03CDB7DEB7E6E042
:103550000C94BD1ADC0101C06D9341505040E0F75E
:1035600008952A88398848885F846E847D848C8495
:103570009B84AA84B984C884DF80EE80FD800C819E
:103580001B81AA81B981CE0FD11D0FB6F894DEBF81
:0C3590000FBECDBFED010895F894FFCFF1
:10359C0000005F0320000101000A006400E8033F03
:1035AC00065B4F666D7D077F6F777C395E79715254
:1035BC00656164206661696C005265616479210003
:1035CC0000000000350F070FAA0EB30EC70ED70E62
:1035DC00000000009C15BF14371566154A158A1596
:00000001FF

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x03
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x04
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x05
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x06
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x07
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x08
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x09
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x0a
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x0b
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,680 @@
#!/usr/bin/env python
#
# GrovePi Python library
# v1.4
#
# This file provides the basic functions for using the GrovePi
#
# The GrovePi connects the Raspberry Pi and Grove sensors. You can learn more about GrovePi here: http://www.dexterindustries.com/GrovePi
#
# Have a question about this example? Ask on the forums here: http://forum.dexterindustries.com/c/grovepi
#
'''
## License
The MIT License (MIT)
GrovePi for the Raspberry Pi: an open source platform for connecting Grove Sensors to the Raspberry Pi.
Copyright (C) 2017 Dexter Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
# Initial Date: 13 Feb 2014
# Last Updated: 11 Nov 2016
# http://www.dexterindustries.com/
# Author Date Comments
# Karan 13 Feb 2014 Initial Authoring
# 11 Nov 2016 I2C retries added for faster IO
# DHT function updated to look for nan's
# Nicole 16 Jan 2019 Bring to v1.4
import sys
import time
import math
import struct
import numpy
import di_i2c
def set_bus(bus):
global i2c
i2c = di_i2c.DI_I2C(bus = bus, address = address)
address = 0x0c
max_recv_size = 10
set_bus("RPI_1SW")
if sys.version_info<(3,0):
p_version = 2
else:
p_version = 3
# Earliest version of the firmware to work with
works_with_firmware = [
"1.4.0"
]
# interrupt operations
COUNT_CHANGES = 0
COUNT_LOW_DURATION = 1
# interrupt trigger mode
CHANGE = 1
FALLING = 2
RISING = 3
# This allows us to be more specific about which commands contain unused bytes
unused = 0
retries = 10
additional_waiting = 0
# Get firmware version
version_cmd = [8]
# No data is available from the GrovePi
data_not_available_cmd = [23]
# Command Format
# digitalRead() command format header
dRead_cmd = [1]
# digitalWrite() command format header
dWrite_cmd = [2]
# analogRead() command format header
aRead_cmd = [3]
# analogWrite() command format header
aWrite_cmd = [4]
# pinMode() command format header
pMode_cmd = [5]
# Ultrasonic read
uRead_cmd = [7]
# Accelerometer (+/- 1.5g) read
acc_xyz_cmd = [20]
# RTC get time
rtc_getTime_cmd = [30]
# DHT Pro sensor temperature
dht_temp_cmd = [40]
# Grove LED Bar commands
# Initialise
ledBarInit_cmd = [50]
# Set orientation
ledBarOrient_cmd = [51]
# Set level
ledBarLevel_cmd = [52]
# Set single LED
ledBarSetOne_cmd = [53]
# Toggle single LED
ledBarToggleOne_cmd = [54]
# Set all LEDs
ledBarSet_cmd = [55]
# Get current state
ledBarGet_cmd = [56]
# Grove 4 Digit Display commands
# Initialise
fourDigitInit_cmd = [70]
# Set brightness, not visible until next cmd
fourDigitBrightness_cmd = [71]
# Set numeric value without leading zeros
fourDigitValue_cmd = [72]
# Set numeric value with leading zeros
fourDigitValueZeros_cmd = [73]
# Set individual digit
fourDigitIndividualDigit_cmd = [74]
# Set individual leds of a segment
fourDigitIndividualLeds_cmd = [75]
# Set left and right values with colon
fourDigitScore_cmd = [76]
# Analog read for n seconds
fourDigitAnalogRead_cmd = [77]
# Entire display on
fourDigitAllOn_cmd = [78]
# Entire display off
fourDigitAllOff_cmd = [79]
# Grove Chainable RGB LED commands
# Store color for later use
storeColor_cmd = [90]
# Initialise
chainableRgbLedInit_cmd = [91]
# Initialise and test with a simple color
chainableRgbLedTest_cmd = [92]
# Set one or more leds to the stored color by pattern
chainableRgbLedSetPattern_cmd = [93]
# set one or more leds to the stored color by modulo
chainableRgbLedSetModulo_cmd = [94]
# sets leds similar to a bar graph, reversible
chainableRgbLedSetLevel_cmd = [95]
# Read the button from IR sensor
ir_read_cmd = [21]
# Set pin for the IR receiver
ir_recv_pin_cmd = [22]
# Check if there's data coming from the IR receiver
ir_read_isdata = [24]
# Interrupt-based devices
isr_set_cmd = [6]
isr_unset_cmd = [9]
isr_read_cmd = [10]
isr_clear_cmd = [11]
isr_active_cmd = [12]
# Grove Encoders
encoder_read_cmd = [13]
encoder_en_cmd = [14]
encoder_dis_cmd = [15]
# Dust, Encoder & Flow Sensor commands
# dust_sensor_read_cmd=[10]
# dust_sensor_en_cmd=[14]
# dust_sensor_dis_cmd=[15]
# dust_sensor_int_cmd=[9]
# dust_sensor_read_int_cmd=[6]
# flow_read_cmd=[12]
# flow_disable_cmd=[13]
# flow_en_cmd=[18]
# Function declarations of the various functions used for encoding and sending
# data from RPi to Arduino
# Write I2C block to the GrovePi
def write_i2c_block(block, custom_timing = None):
counter = 0
reg = block[0]
data = block[1:]
while counter < 3:
try:
i2c.write_reg_list(reg, data)
time.sleep(0.002 + additional_waiting)
return
except:
counter += 1
time.sleep(0.003)
continue
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
while data[0] != read_command_id[0]:
data = read_i2c_block(no_bytes + 1)
return data[1:]
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[0] * 256 + number[1]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[0] * 256 + number[1])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 8)
if p_version==2:
h=''
for element in (number[0:4]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[4:8]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[0:4])
h_val=bytearray(number[4:8])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
# Grove - Infrared Receiver - get the commands received from the Grove IR sensor
def ir_read_signal():
write_i2c_block(ir_read_cmd + [unused, unused, unused])
data_back = read_identified_i2c_block(ir_read_cmd, no_bytes = 7)
return (data_back[0],
data_back[1] + data_back[2] * 256,
data_back[3] + data_back[4] * 256 + data_back[5] * (256 ** 2) + data_back[6] * (256 ** 3))
# Grove - Infrared Receiver - set the pin on which the Grove IR sensor is connected
def ir_recv_pin(pin):
write_i2c_block(ir_recv_pin_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
# Grove - Infrared Receiver - check if there's any data that hasn't been read so far
def ir_is_data():
write_i2c_block(ir_read_isdata + 3 * [unused])
number = read_identified_i2c_block(ir_read_isdata, no_bytes = 1)
return number[0] != 0
# after a list of numerical values is provided
# the function returns a list with the outlier(or extreme) values removed
# make the std_factor_threshold bigger so that filtering becomes less strict
# and make the std_factor_threshold smaller to get the opposite
def statisticalNoiseReduction(values, std_factor_threshold = 2):
if len(values) == 0:
return []
mean = numpy.mean(values)
standard_deviation = numpy.std(values)
if standard_deviation == 0:
return values
filtered_values = [element for element in values if element > mean - std_factor_threshold * standard_deviation]
filtered_values = [element for element in filtered_values if element < mean + std_factor_threshold * standard_deviation]
return filtered_values
# Grove LED Bar - initialise
# orientation: (0 = red to green, 1 = green to red)
def ledBar_init(pin, orientation):
write_i2c_block(ledBarInit_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set orientation
# orientation: (0 = red to green, 1 = green to red)
def ledBar_orientation(pin, orientation):
write_i2c_block(ledBarOrient_cmd + [pin, orientation, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set level
# level: (0-10)
def ledBar_setLevel(pin, level):
write_i2c_block(ledBarLevel_cmd + [pin, level, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set single led
# led: which led (1-10)
# state: off or on (0-1)
def ledBar_setLed(pin, led, state):
write_i2c_block(ledBarSetOne_cmd + [pin, led, state])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - toggle single led
# led: which led (1-10)
def ledBar_toggleLed(pin, led):
write_i2c_block(ledBarToggleOne_cmd + [pin, led, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - set all leds
# state: (0-1023) or (0x00-0x3FF) or (0b0000000000-0b1111111111) or (int('0000000000',2)-int('1111111111',2))
def ledBar_setBits(pin, state):
byte1 = state & 255
byte2 = state >> 8
write_i2c_block(ledBarSet_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove LED Bar - get current state
# state: (0-1023) a bit for each of the 10 LEDs
def ledBar_getBits(pin):
write_i2c_block(ledBarGet_cmd + [pin, unused, unused])
block = read_identified_i2c_block(ledBarGet_cmd, no_bytes = 2)
return block[0] ^ (block[1] << 8)
# Grove 4 Digit Display - initialise
def fourDigit_init(pin):
write_i2c_block(fourDigitInit_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set numeric value with or without leading zeros
# value: (0-65535) or (0000-FFFF)
def fourDigit_number(pin, value, leading_zero):
# split the value into two bytes so we can render 0000-FFFF on the display
byte1 = value & 255
byte2 = value >> 8
# separate commands to overcome current 4 bytes per command limitation
if (leading_zero):
write_i2c_block(fourDigitValue_cmd + [pin, byte1, byte2])
else:
write_i2c_block(fourDigitValueZeros_cmd + [pin, byte1, byte2])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set brightness
# brightness: (0-7)
def fourDigit_brightness(pin, brightness):
# not actually visible until next command is executed
write_i2c_block(fourDigitBrightness_cmd + [pin, brightness, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set individual segment (0-9,A-F)
# segment: (0-3)
# value: (0-15) or (0-F)
def fourDigit_digit(pin, segment, value):
write_i2c_block(fourDigitIndividualDigit_cmd + [pin, segment, value])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set 7 individual leds of a segment
# segment: (0-3)
# leds: (0-255) or (0-0xFF) one bit per led, segment 2 is special, 8th bit is the colon
def fourDigit_segment(pin, segment, leds):
write_i2c_block(fourDigitIndividualLeds_cmd + [pin, segment, leds])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - set left and right values (0-99), with leading zeros and a colon
# left: (0-255) or (0-FF)
# right: (0-255) or (0-FF)
# colon will be lit
def fourDigit_score(pin, left, right):
write_i2c_block(fourDigitScore_cmd + [pin, left, right])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - display analogRead value for n seconds, 4 samples per second
# analog: analog pin to read
# duration: analog read for this many seconds
def fourDigit_monitor(pin, analog, duration):
write_i2c_block(fourDigitAnalogRead_cmd + [pin, analog, duration])
read_i2c_block(no_bytes = 1)
time.sleep(duration)
return 1
# Grove 4 Digit Display - turn entire display on (88:88)
def fourDigit_on(pin):
write_i2c_block(fourDigitAllOn_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove 4 Digit Display - turn entire display off
def fourDigit_off(pin):
write_i2c_block(fourDigitAllOff_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - store a color for later use
# red: 0-255
# green: 0-255
# blue: 0-255
def storeColor(red, green, blue):
write_i2c_block(storeColor_cmd + [red, green, blue])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise
# numLeds: how many leds do you have in the chain
def chainableRgbLed_init(pin, numLeds):
write_i2c_block(chainableRgbLedInit_cmd + [pin, numLeds, unused])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - initialise and test with a simple color
# numLeds: how many leds do you have in the chain
# testColor: (0-7) 3 bits in total - a bit for red, green and blue, eg. 0x04 == 0b100 (0bRGB) == rgb(255, 0, 0) == #FF0000 == red
# ie. 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 yellow, 7 white
def chainableRgbLed_test(pin, numLeds, testColor):
write_i2c_block(chainableRgbLedTest_cmd + [pin, numLeds, testColor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by pattern
# pattern: (0-3) 0 = this led only, 1 all leds except this led, 2 this led and all leds inwards, 3 this led and all leds outwards
# whichLed: index of led you wish to set counting outwards from the GrovePi, 0 = led closest to the GrovePi
def chainableRgbLed_pattern(pin, pattern, whichLed):
write_i2c_block(chainableRgbLedSetPattern_cmd + [pin, pattern, whichLed])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - set one or more leds to the stored color by modulo
# offset: index of led you wish to start at, 0 = led closest to the GrovePi, counting outwards
# divisor: when 1 (default) sets stored color on all leds >= offset, when 2 sets every 2nd led >= offset and so on
def chainableRgbLed_modulo(pin, offset, divisor):
write_i2c_block(chainableRgbLedSetModulo_cmd + [pin, offset, divisor])
read_i2c_block(no_bytes = 1)
return 1
# Grove Chainable RGB LED - sets leds similar to a bar graph, reversible
# level: (0-10) the number of leds you wish to set to the stored color
# reversible (0-1) when 0 counting outwards from GrovePi, 0 = led closest to the GrovePi, otherwise counting inwards
def chainableRgbLed_setLevel(pin, level, reverse):
write_i2c_block(chainableRgbLedSetLevel_cmd + [pin, level, reverse])
read_i2c_block(no_bytes = 1)
return 1
def set_pin_interrupt(pin, ftype, interrupt_mode, period):
'''
Attach an interrupt to a pin.
pin - D2-D8 pins
ftype - 0 for COUNT_CHANGES, 1 for COUNT_LOW_DURATION
interrupt_mode - 1 for CHANGE, 2 for FALLING, 3 for RISING
period - as measured in ms (max 65535 ms)
'''
period_high = period >> 8
period_low = period & 0xff
combined_params = (pin & 0x0f) + ((ftype & 0x03) << 4) + ((interrupt_mode & 0x03) << 6)
write_i2c_block(isr_set_cmd + [combined_params, period_high, period_low])
read_i2c_block(no_bytes = 1)
def unset_pin_interrupt(pin):
'''
Detach an interrupt from a pin.
pin - D2-D8 pins
'''
write_i2c_block(isr_unset_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def unset_all_interrupts():
'''
Detach all attached interrupts from all D2-D8 pins.
pin - D2-D8 pins
'''
write_i2c_block(isr_clear_cmd + 3 * [unused])
read_i2c_block(no_bytes = 1)
def is_interrupt_active(pin):
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[1] >> pin
return value != 0
def get_active_interrupts():
'''
Get list of attached interrupts for a given pin or all of them.
pin - D2-D8 pins; if it's 255 return the state of all pins
'''
pin = 255
write_i2c_block(isr_active_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_active_cmd, no_bytes = 2)
value = data[0] + (data[1] << 8)
active_interrupts = [i for i in range(2 * 8) if ((value >> i) & 0x01)]
return active_interrupts
def read_interrupt_state(pin):
'''
Read number of pulses/changes on given port that occurred within a time period.
pin - D2-D8 pins
'''
write_i2c_block(isr_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(isr_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def dust_sensor_en(pin = 2, period = 30000):
set_pin_interrupt(pin, ftype=COUNT_LOW_DURATION, interrupt_mode=CHANGE, period=period)
def dust_sensor_dis(pin = 2):
unset_pin_interrupt(pin)
def dust_sensor_read(pin = 2, period = 30000):
'''
By default, the sample rate is set to 1 at every 30 seconds and this
function was written only for that interval.
If you wish to use a different
interval, then use dust_sensor_read_more function. To set a
different interval, use set_dust_sensor_interval function.
'''
lpo = read_interrupt_state(pin)
percentage = 100.0 * lpo / period
concentration = 1.1 * percentage ** 3 - 3.8 * percentage ** 2 + 520 * percentage + 0.62
return lpo, percentage, concentration
def encoder_en(pin = 2, steps = 32):
write_i2c_block(encoder_en_cmd + [pin, steps, unused])
read_i2c_block(no_bytes = 1)
def encoder_dis(pin = 2):
write_i2c_block(encoder_dis_cmd + [pin, unused, unused])
read_i2c_block(no_bytes = 1)
def encoderRead(pin = 2):
write_i2c_block(encoder_read_cmd + [pin, unused, unused])
data = read_identified_i2c_block(encoder_read_cmd, no_bytes = 4)
value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24)
return value
def flowEnable(pin = 2, period = 2000):
set_pin_interrupt(pin, ftype=COUNT_CHANGES, interrupt_mode=RISING, period=period)
def flowDisable(pin = 2):
unset_pin_interrupt(pin)
def flowRead(pin = 2):
val = read_interrupt_state(pin)
return val
def main():
print("library supports this fw versions: " +
" ".join('{}'.format(k[1]) for k in enumerate(works_with_firmware)))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,26 @@
#!/usr/bin/env sh
echo "Current setup"
sudo i2cdetect -y 1
echo "What address would you like to use the GrovePi on? [3-9 a-c]"
read ADDRESS
# Check if the necessary files for the address exist.
if [ -e "grove_pi_v1_4_0_addr$ADDRESS.hex" ] && [ -e "setup$ADDRESS.py" ] && [ -e "grovepi$ADDRESS.py" ]; then
echo "Setting up GrovePi with Address $ADDRESS"
echo "BURNING FIRMWARE"
echo "..."
sudo avrdude -c gpio -p m328p -U flash:w:grove_pi_v1_4_0_addr"$ADDRESS".hex
echo "INSTALLING PYTHON LIBRARY"
sudo python setup"$ADDRESS".py install
sudo python3 setup"$ADDRESS".py install
echo "I2C DEVICES AVAILABLE"
sleep 1
sudo i2cdetect -y 1
exit 0
else
echo "The necessary files for this address do not exist."
exit 0
fi
# thanks to https://github.com/Mimry for the rewrite of this script. Much appreciated!

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepi3",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepi3'],
#install_requires=open('requirements.txt').readlines(),
)

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepi4",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepi4'],
#install_requires=open('requirements.txt').readlines(),
)

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepi5",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepi5'],
#install_requires=open('requirements.txt').readlines(),
)

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepi6",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepi6'],
#install_requires=open('requirements.txt').readlines(),
)

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepi7",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepi7'],
#install_requires=open('requirements.txt').readlines(),
)

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepi8",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepi8'],
#install_requires=open('requirements.txt').readlines(),
)

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepi9",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepi9'],
#install_requires=open('requirements.txt').readlines(),
)

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepia",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepia'],
#install_requires=open('requirements.txt').readlines(),
)

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepib",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepib'],
#install_requires=open('requirements.txt').readlines(),
)

View file

@ -0,0 +1,14 @@
#!/usr/bin/python
#
# These files have been made available online through a Creative Commons Attribution-ShareAlike 3.0 license.
# (http://creativecommons.org/licenses/by-sa/3.0/)
import setuptools
setuptools.setup(
name="grovepic",
description="Drivers and examples for using the GrovePi in Python",
author="Dexter Industries",
url="http://www.dexterindustries.com/GrovePi/",
py_modules=['grovepic'],
#install_requires=open('requirements.txt').readlines(),
)

296
Script/update_grovepi.sh Normal file
View file

@ -0,0 +1,296 @@
#! /bin/bash
# This script updates the the code repos on Raspbian for Robots.
################################################
######## Parsing Command Line Arguments ########
################################################
# definitions needed for standalone call
PIHOME=/home/pi
DEXTER=Dexter
DEXTER_PATH=$PIHOME/$DEXTER
RASPBIAN=$PIHOME/di_update/Raspbian_For_Robots
GROVEPI_DIR=$DEXTER_PATH/GrovePi
DEXTERSCRIPT=$DEXTER_PATH/lib/Dexter/script_tools
# the top-level module name of grovepi package
# used for detecting whether it's installed or not
REPO_PACKAGE=grovepi
# called way down bellow
check_if_run_with_pi() {
## if not running with the pi user then exit
if [ $(id -ur) -ne $(id -ur pi) ]; then
echo "GrovePi installer script must be run with \"pi\" user. Exiting."
exit 6
fi
}
# called way down below
parse_cmdline_arguments() {
# whether to install the dependencies or not (avrdude, apt-get, wiringpi, and so on)
installdependencies=true
updaterepo=true
install_rfrtools=true
install_pkg_rfrtools=true
install_rfrtools_gui=true
# the following 3 options are mutually exclusive
systemwide=true
userlocal=false
envlocal=false
usepython3exec=true
# the following option tells which branch has to be used
selectedbranch="master"
declare -ga rfrtools_options=("--system-wide")
# iterate through bash arguments
for i; do
case "$i" in
--no-dependencies)
installdependencies=false
;;
--no-update-aptget)
updaterepo=false
;;
--bypass-rfrtools)
install_rfrtools=false
;;
--bypass-python-rfrtools)
install_pkg_rfrtools=false
;;
--bypass-gui-installation)
install_rfrtools_gui=false
;;
--user-local)
userlocal=true
systemwide=false
declare -ga rfrtools_options=("--user-local")
;;
--env-local)
envlocal=true
systemwide=false
declare -ga rfrtools_options=("--env-local")
;;
--system-wide)
;;
develop|feature/*|hotfix/*|fix/*|DexterOS*|v*)
selectedbranch="$i"
;;
esac
done
# show some feedback on the console
if [ -f $DEXTERSCRIPT/functions_library.sh ]; then
source $DEXTERSCRIPT/functions_library.sh
# show some feedback for the GrovePi
if [[ quiet_mode -eq 0 ]]; then
echo " _____ _ ";
echo " | __ \ | | ";
echo " | | | | _____ _| |_ ___ _ __ ";
echo " | | | |/ _ \ \/ / __/ _ \ '__| ";
echo " | |__| | __/> <| || __/ | ";
echo " |_____/ \___/_/\_\\\__\___|_| _ ";
echo " |_ _| | | | | (_) ";
echo " | | _ __ __| |_ _ ___| |_ _ __ _ ___ ___ ";
echo " | | | '_ \ / _\ | | | / __| __| '__| |/ _ \/ __| ";
echo " _| |_| | | | (_| | |_| \__ \ |_| | | | __/\__ \ ";
echo " |_____|_| |_|\__,_|\__,_|___/\__|_| |_|\___||___/ ";
echo " ";
echo " ";
echo " _____ _____ _ "
echo " / ____| | __ (_) "
echo "| | __ _ __ _____ _____| |__) | "
echo "| | |_ | '__/ _ \ \ / / _ \ ___/ | "
echo "| |__| | | | (_) \ V / __/ | | | "
echo " \_____|_| \___/ \_/ \___|_| |_| "
echo " "
fi
feedback "Welcome to GrovePi Installer."
else
echo "Welcome to GrovePi Installer."
fi
echo "Updating GrovePi for $selectedbranch branch with the following options:"
([[ $installdependencies = "true" ]] && echo " --no-dependencies=false") || echo " --no-dependencies=true"
([[ $updaterepo = "true" ]] && echo " --no-update-aptget=false") || echo " --no-update-aptget=true"
([[ $install_rfrtools = "true" ]] && echo " --bypass-rfrtools=false") || echo " --bypass-rfrtools=true"
([[ $install_pkg_rfrtools = "true" ]] && echo " --bypass-python-rfrtools=false") || echo " --bypass-python-rfrtools=true"
([[ $install_rfrtools_gui = "true" ]] && echo " --bypass-gui-installation=false") || echo " --bypass-gui-installation=true"
echo " --user-local=$userlocal"
echo " --env-local=$envlocal"
echo " --system-wide=$systemwide"
# create rest of list of arguments for rfrtools call
rfrtools_options+=("$selectedbranch")
[[ $usepython3exec = "true" ]] && rfrtools_options+=("--use-python3-exe-too")
[[ $updaterepo = "true" ]] && rfrtools_options+=("--update-aptget")
[[ $installdependencies = "true" ]] && rfrtools_options+=("--install-deb-deps")
[[ $install_pkg_rfrtools = "true" ]] && rfrtools_options+=("--install-python-package")
[[ $install_rfrtools_gui = "true" ]] && rfrtools_options+=("--install-gui")
echo "Using \"$selectedbranch\" branch"
echo "Options used for RFR_Tools script: \"${rfrtools_options[@]}\""
}
################################################
######## Cloning GrovePi & RFR_Tools ##########
################################################
# called in <<install_rfrtools_repo>>
check_dependencies() {
command -v git >/dev/null 2>&1 || { echo "This script requires \"git\" but it's not installed. Error occurred with RFR_Tools installation." >&2; exit 1; }
command -v python >/dev/null 2>&1 || { echo "Executable \"python\" couldn't be found. Error occurred with RFR_Tools installation." >&2; exit 2; }
command -v pip >/dev/null 2>&1 || { echo "Executable \"pip\" couldn't be found. Error occurred with RFR_Tools installation." >&2; exit 3; }
if [[ $usepython3exec = "true" ]]; then
command -v python3 >/dev/null 2>&1 || { echo "Executable \"python3\" couldn't be found. Error occurred with RFR_Tools installation." >&2; exit 4; }
command -v pip3 >/dev/null 2>&1 || { echo "Executable \"pip3\" couldn't be found. Error occurred with RFR_Tools installation." >&2; exit 5; }
fi
if [[ ! -f $DEXTERSCRIPT/functions_library.sh ]]; then
echo "script_tools didn\'t get installed. Enable the installation of dependencies with RFR_Tools.'"
exit 8
fi
}
# called way down below
install_rfrtools_repo() {
# if rfrtools is not bypassed then install it
if [[ $install_rfrtools = "true" ]]; then
curl --silent -kL https://raw.githubusercontent.com/DexterInd/RFR_Tools/$selectedbranch/scripts/install_tools.sh > $PIHOME/.tmp_rfrtools.sh
echo "Installing RFR_Tools. This might take a while.."
bash $PIHOME/.tmp_rfrtools.sh ${rfrtools_options[@]} # > /dev/null
ret_val=$?
rm $PIHOME/.tmp_rfrtools.sh
if [[ $ret_val -ne 0 ]]; then
echo "RFR_Tools failed installing with exit code $ret_val. Exiting."
exit 7
fi
echo "Done installing RFR_Tool"
fi
# check if all deb packages have been installed with RFR_Tools
check_dependencies
source $DEXTERSCRIPT/functions_library.sh
}
# called way down bellow
clone_grovepi() {
# $DEXTER_PATH is still only available for the pi user
# shortly after this, we'll make it work for any user
sudo mkdir -p $DEXTER_PATH
sudo chown pi:pi -R $DEXTER_PATH
cd $DEXTER_PATH
# it's simpler and more reliable (for now) to just delete the repo and clone a new one
# otherwise, we'd have to deal with all the intricacies of git
sudo rm -rf $GROVEPI_DIR
git clone --quiet --depth=1 -b $selectedbranch https://github.com/DexterInd/GrovePi.git
cd $GROVEPI_DIR
}
################################################
######## Install Python Packages & Deps ########
################################################
# called by <<install_python_pkgs_and_dependencies>>
install_python_packages() {
[[ $systemwide = "true" ]] && sudo python setup.py install \
&& [[ $usepython3exec = "true" ]] && sudo python3 setup.py install
[[ $userlocal = "true" ]] && python setup.py install --user \
&& [[ $usepython3exec = "true" ]] && python3 setup.py install --user
[[ $envlocal = "true" ]] && python setup.py install \
&& [[ $usepython3exec = "true" ]] && python3 setup.py install
}
# called by <<install_python_pkgs_and_dependencies>>
remove_python_packages() {
# the 1st and only argument
# takes the name of the package that needs to removed
rm -f $PIHOME/.pypaths
# get absolute path to python package
# saves output to file because we want to have the syntax highlight working
# does this for both root and the current user because packages can be either system-wide or local
# later on the strings used with the python command can be put in just one string that gets used repeatedly
python -c "import pkgutil; import os; \
eggs_loader = pkgutil.find_loader('$1'); found = eggs_loader is not None; \
output = os.path.dirname(os.path.realpath(eggs_loader.get_filename('$1'))) if found else ''; print(output);" >> $PIHOME/.pypaths
sudo python -c "import pkgutil; import os; \
eggs_loader = pkgutil.find_loader('$1'); found = eggs_loader is not None; \
output = os.path.dirname(os.path.realpath(eggs_loader.get_filename('$1'))) if found else ''; print(output);" >> $PIHOME/.pypaths
if [[ $usepython3exec = "true" ]]; then
python3 -c "import pkgutil; import os; \
eggs_loader = pkgutil.find_loader('$1'); found = eggs_loader is not None; \
output = os.path.dirname(os.path.realpath(eggs_loader.get_filename('$1'))) if found else ''; print(output);" >> $PIHOME/.pypaths
sudo python3 -c "import pkgutil; import os; \
eggs_loader = pkgutil.find_loader('$1'); found = eggs_loader is not None; \
output = os.path.dirname(os.path.realpath(eggs_loader.get_filename('$1'))) if found else ''; print(output);" >> $PIHOME/.pypaths
fi
# removing eggs for $1 python package
# ideally, easy-install.pth needs to be adjusted too
# but pip seems to know how to handle missing packages, which is okay
while read path;
do
if [ ! -z "${path}" -a "${path}" != " " ]; then
echo "Removing ${path} egg"
sudo rm -f "${path}"
fi
done < $PIHOME/.pypaths
}
# called by <<install_python_pkgs_and_dependencies>>
install_deb_dependencies() {
feedback "Installing dependencies for the GrovePi"
# in order for nodejs to be installed, the repo for it
# needs to be in; this is all done in script_tools while doing an apt-get update
sudo apt-get install --no-install-recommends -y nodejs\
git libi2c-dev i2c-tools \
python-setuptools python-pip python-smbus python-dev python-serial python-rpi.gpio python-numpy python-scipy \
python3-setuptools python3-pip python3-smbus python3-dev python3-serial python3-rpi.gpio python3-numpy python3-scipy \
libncurses5
feedback "Dependencies for the GrovePi installed"
}
# called way down bellow
install_python_pkgs_and_dependencies() {
# installing dependencies if required
if [[ $installdependencies = "true" ]]; then
feedback "Installing GrovePi dependencies. This might take a while.."
install_deb_dependencies
pushd $GROVEPI_DIR/Script > /dev/null
sudo bash ./install.sh
popd > /dev/null
fi
# feedback "Removing \"$REPO_PACKAGE\" and \"$DHT_PACKAGE\" to make space for new ones"
feedback "Removing \"$REPO_PACKAGE\" to make space for the new one"
remove_python_packages "$REPO_PACKAGE"
# remove_python_packages "$DHT_PACKAGE"
# installing the package itself
pushd $GROVEPI_DIR/Software/Python > /dev/null
install_python_packages
popd > /dev/null
}
################################################
######## Aggregating all function calls ########
################################################
check_if_run_with_pi
parse_cmdline_arguments "$@"
install_rfrtools_repo
clone_grovepi
install_python_pkgs_and_dependencies
exit 0