platformio source, dokumentacija krmilnika

master
Jurij Podgoršek 2024-08-23 15:47:42 +02:00
parent 67b47c0918
commit b75a05a053
120 changed files with 87610 additions and 0 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@
.~lock*# .~lock*#
.*.swp .*.swp
node_modules node_modules
.pio
.venv

661
LICENSE 100644
View File

@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
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
them 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.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey 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;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero 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 that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
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.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
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.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
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
state 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 Affero General Public License as published by
the Free Software Foundation, either version 3 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

Binary file not shown.

5
flash.sh 100755
View File

@ -0,0 +1,5 @@
#!/bin/bash
source venv/bin/activate
pio run --target=upload

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 ElectronicCats
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.

View File

@ -0,0 +1,49 @@
# MPU6050 by Electronic Cats - Library for Arduino
<a href="https://github.com/ElectronicCats/mpu6050/wiki">
<img src="https://user-images.githubusercontent.com/107638696/241324971-43b8fe88-447d-4c2d-9296-4b3aaa50f4ce.png" height="400" />
</a>
<p>
<a href="https://github.com/ElectronicCats/mpu6050/wiki">
<img src="https://github.com/ElectronicCats/mpu6050/assets/139595394/62f14865-5e11-4c83-a044-f63a2ddbeb23" />
</a>
</p>
[![LibraryBuild](https://github.com/ElectronicCats/mpu6050/actions/workflows/LibraryBuild.yml/badge.svg)](https://github.com/ElectronicCats/mpu6050/actions/workflows/LibraryBuild.yml)
Arduino library for controlling MPU6050 module.
MPU6050 Combines a 3-axis gyroscope and a 3-axis accelerometer on the same silicon die together with
an onboard Digital Motion Processor(DMP) which processes complex 6-axis MotionFusion algorithms.
## Features of this version
- ### Supported Chipsets
- AVR
- SAM
- SAMD21
- ARM
- ESP32
- ESP8266
- RENESAS
#### Original Library
Based in the work of [jrowberg/i2cdevlib](https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050)
## Quick Installing
To install, use the [Arduino Library Manager](https://support.arduino.cc/hc/en-us/articles/5145457742236-Add-libraries-to-Arduino-IDE) and search for "MPU6050" and install the MPU6050 by Electronic Cats library.
## Maintainer
<a href="https://github.com/sponsors/ElectronicCats">
<p align="center">
<img src="https://electroniccats.com/wp-content/uploads/2020/07/Badge_GHS.png" height="104" />
</p>
</a>
Electronic Cats invests time and resources providing this open source design, please support Electronic Cats and open-source hardware by purchasing products from Electronic Cats!

View File

@ -0,0 +1,358 @@
// MPU6050 offset-finder, based on Jeff Rowberg's MPU6050_RAW
// 2016-10-19 by Robert R. Fenichel (bob@fenichel.net)
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class
// 10/7/2011 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2019-07-11 - added PID offset generation at begninning Generates first offsets
// - in @ 6 seconds and completes with 4 more sets @ 10 seconds
// - then continues with origional 2016 calibration code.
// 2016-11-25 - added delays to reduce sampling rate to ~200 Hz
// added temporizing printing during long computations
// 2016-10-25 - requires inequality (Low < Target, High > Target) during expansion
// dynamic speed change when closing in
// 2016-10-22 - cosmetic changes
// 2016-10-19 - initial release of IMU_Zero
// 2013-05-08 - added multiple output formats
// - added seamless Fastwire support
// 2011-10-07 - initial release of MPU6050_RAW
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2011 Jeff Rowberg
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.
If an MPU6050
* is an ideal member of its tribe,
* is properly warmed up,
* is at rest in a neutral position,
* is in a location where the pull of gravity is exactly 1g, and
* has been loaded with the best possible offsets,
then it will report 0 for all accelerations and displacements, except for
Z acceleration, for which it will report 16384 (that is, 2^14). Your device
probably won't do quite this well, but good offsets will all get the baseline
outputs close to these target values.
Put the MPU6050 on a flat and horizontal surface, and leave it operating for
5-10 minutes so its temperature gets stabilized.
Run this program. A "----- done -----" line will indicate that it has done its best.
With the current accuracy-related constants (NFast = 1000, NSlow = 10000), it will take
a few minutes to get there.
Along the way, it will generate a dozen or so lines of output, showing that for each
of the 6 desired offsets, it is
* first, trying to find two estimates, one too low and one too high, and
* then, closing in until the bracket can't be made smaller.
The line just above the "done" line will look something like
[567,567] --> [-1,2] [-2223,-2223] --> [0,1] [1131,1132] --> [16374,16404] [155,156] --> [-1,1] [-25,-24] --> [0,3] [5,6] --> [0,4]
As will have been shown in interspersed header lines, the six groups making up this
line describe the optimum offsets for the X acceleration, Y acceleration, Z acceleration,
X gyro, Y gyro, and Z gyro, respectively. In the sample shown just above, the trial showed
that +567 was the best offset for the X acceleration, -2223 was best for Y acceleration,
and so on.
The need for the delay between readings (usDelay) was brought to my attention by Nikolaus Doppelhammer.
===============================================
*/
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
//MPU6050 accelgyro(0x69); // <-- use for AD0 high
const char LBRACKET = '[';
const char RBRACKET = ']';
const char COMMA = ',';
const char BLANK = ' ';
const char PERIOD = '.';
const int iAx = 0;
const int iAy = 1;
const int iAz = 2;
const int iGx = 3;
const int iGy = 4;
const int iGz = 5;
const int usDelay = 3150; // empirical, to hold sampling to 200 Hz
const int NFast = 1000; // the bigger, the better (but slower)
const int NSlow = 10000; // ..
const int LinesBetweenHeaders = 5;
int LowValue[6];
int HighValue[6];
int Smoothed[6];
int LowOffset[6];
int HighOffset[6];
int Target[6];
int LinesOut;
int N;
void ForceHeader()
{ LinesOut = 99; }
void GetSmoothed()
{ int16_t RawValue[6];
int i;
long Sums[6];
for (i = iAx; i <= iGz; i++)
{ Sums[i] = 0; }
// unsigned long Start = micros();
for (i = 1; i <= N; i++)
{ // get sums
accelgyro.getMotion6(&RawValue[iAx], &RawValue[iAy], &RawValue[iAz],
&RawValue[iGx], &RawValue[iGy], &RawValue[iGz]);
if ((i % 500) == 0)
Serial.print(PERIOD);
delayMicroseconds(usDelay);
for (int j = iAx; j <= iGz; j++)
Sums[j] = Sums[j] + RawValue[j];
} // get sums
// unsigned long usForN = micros() - Start;
// Serial.print(" reading at ");
// Serial.print(1000000/((usForN+N/2)/N));
// Serial.println(" Hz");
for (i = iAx; i <= iGz; i++)
{ Smoothed[i] = (Sums[i] + N/2) / N ; }
} // GetSmoothed
void Initialize()
{
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(9600);
// initialize device
Serial.println("Initializing I2C devices...");
accelgyro.initialize();
// verify connection
Serial.println("Testing device connections...");
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
Serial.println("PID tuning Each Dot = 100 readings");
/*A tidbit on how PID (PI actually) tuning works.
When we change the offset in the MPU6050 we can get instant results. This allows us to use Proportional and
integral of the PID to discover the ideal offsets. Integral is the key to discovering these offsets, Integral
uses the error from set-point (set-point is zero), it takes a fraction of this error (error * ki) and adds it
to the integral value. Each reading narrows the error down to the desired offset. The greater the error from
set-point, the more we adjust the integral value. The proportional does its part by hiding the noise from the
integral math. The Derivative is not used because of the noise and because the sensor is stationary. With the
noise removed the integral value lands on a solid offset after just 600 readings. At the end of each set of 100
readings, the integral value is used for the actual offsets and the last proportional reading is ignored due to
the fact it reacts to any noise.
*/
accelgyro.CalibrateAccel(6);
accelgyro.CalibrateGyro(6);
Serial.println("\nat 600 Readings");
accelgyro.PrintActiveOffsets();
Serial.println();
accelgyro.CalibrateAccel(1);
accelgyro.CalibrateGyro(1);
Serial.println("700 Total Readings");
accelgyro.PrintActiveOffsets();
Serial.println();
accelgyro.CalibrateAccel(1);
accelgyro.CalibrateGyro(1);
Serial.println("800 Total Readings");
accelgyro.PrintActiveOffsets();
Serial.println();
accelgyro.CalibrateAccel(1);
accelgyro.CalibrateGyro(1);
Serial.println("900 Total Readings");
accelgyro.PrintActiveOffsets();
Serial.println();
accelgyro.CalibrateAccel(1);
accelgyro.CalibrateGyro(1);
Serial.println("1000 Total Readings");
accelgyro.PrintActiveOffsets();
Serial.println("\n\n Any of the above offsets will work nice \n\n Lets proof the PID tuning using another method:");
} // Initialize
void SetOffsets(int TheOffsets[6])
{ accelgyro.setXAccelOffset(TheOffsets [iAx]);
accelgyro.setYAccelOffset(TheOffsets [iAy]);
accelgyro.setZAccelOffset(TheOffsets [iAz]);
accelgyro.setXGyroOffset (TheOffsets [iGx]);
accelgyro.setYGyroOffset (TheOffsets [iGy]);
accelgyro.setZGyroOffset (TheOffsets [iGz]);
} // SetOffsets
void ShowProgress()
{ if (LinesOut >= LinesBetweenHeaders)
{ // show header
Serial.println("\tXAccel\t\t\tYAccel\t\t\t\tZAccel\t\t\tXGyro\t\t\tYGyro\t\t\tZGyro");
LinesOut = 0;
} // show header
Serial.print(BLANK);
for (int i = iAx; i <= iGz; i++)
{ Serial.print(LBRACKET);
Serial.print(LowOffset[i]),
Serial.print(COMMA);
Serial.print(HighOffset[i]);
Serial.print("] --> [");
Serial.print(LowValue[i]);
Serial.print(COMMA);
Serial.print(HighValue[i]);
if (i == iGz)
{ Serial.println(RBRACKET); }
else
{ Serial.print("]\t"); }
}
LinesOut++;
} // ShowProgress
void PullBracketsIn()
{ boolean AllBracketsNarrow;
boolean StillWorking;
int NewOffset[6];
Serial.println("\nclosing in:");
AllBracketsNarrow = false;
ForceHeader();
StillWorking = true;
while (StillWorking)
{ StillWorking = false;
if (AllBracketsNarrow && (N == NFast))
{ SetAveraging(NSlow); }
else
{ AllBracketsNarrow = true; }// tentative
for (int i = iAx; i <= iGz; i++)
{ if (HighOffset[i] <= (LowOffset[i]+1))
{ NewOffset[i] = LowOffset[i]; }
else
{ // binary search
StillWorking = true;
NewOffset[i] = (LowOffset[i] + HighOffset[i]) / 2;
if (HighOffset[i] > (LowOffset[i] + 10))
{ AllBracketsNarrow = false; }
} // binary search
}
SetOffsets(NewOffset);
GetSmoothed();
for (int i = iAx; i <= iGz; i++)
{ // closing in
if (Smoothed[i] > Target[i])
{ // use lower half
HighOffset[i] = NewOffset[i];
HighValue[i] = Smoothed[i];
} // use lower half
else
{ // use upper half
LowOffset[i] = NewOffset[i];
LowValue[i] = Smoothed[i];
} // use upper half
} // closing in
ShowProgress();
} // still working
} // PullBracketsIn
void PullBracketsOut()
{ boolean Done = false;
int NextLowOffset[6];
int NextHighOffset[6];
Serial.println("expanding:");
ForceHeader();
while (!Done)
{ Done = true;
SetOffsets(LowOffset);
GetSmoothed();
for (int i = iAx; i <= iGz; i++)
{ // got low values
LowValue[i] = Smoothed[i];
if (LowValue[i] >= Target[i])
{ Done = false;
NextLowOffset[i] = LowOffset[i] - 1000;
}
else
{ NextLowOffset[i] = LowOffset[i]; }
} // got low values
SetOffsets(HighOffset);
GetSmoothed();
for (int i = iAx; i <= iGz; i++)
{ // got high values
HighValue[i] = Smoothed[i];
if (HighValue[i] <= Target[i])
{ Done = false;
NextHighOffset[i] = HighOffset[i] + 1000;
}
else
{ NextHighOffset[i] = HighOffset[i]; }
} // got high values
ShowProgress();
for (int i = iAx; i <= iGz; i++)
{ LowOffset[i] = NextLowOffset[i]; // had to wait until ShowProgress done
HighOffset[i] = NextHighOffset[i]; // ..
}
} // keep going
} // PullBracketsOut
void SetAveraging(int NewN)
{ N = NewN;
Serial.print("averaging ");
Serial.print(N);
Serial.println(" readings each time");
} // SetAveraging
void setup()
{ Initialize();
for (int i = iAx; i <= iGz; i++)
{ // set targets and initial guesses
Target[i] = 0; // must fix for ZAccel
HighOffset[i] = 0;
LowOffset[i] = 0;
} // set targets and initial guesses
Target[iAz] = 16384;
SetAveraging(NFast);
PullBracketsOut();
PullBracketsIn();
Serial.println("-------------- done --------------");
} // setup
void loop()
{
} // loop

View File

@ -0,0 +1,20 @@
# BOARD_TAG = arduino:mbed_rp2040:pico
# BOARD_TAG = rp2040:rp2040:rpipico
BOARD_TAG = esp32:esp32:XIAO_ESP32C3
MONITOR_PORT = /dev/cu.usbmodem132401
ARDUINO_CLI_PATH := arduino-cli
compile:
$(ARDUINO_CLI_PATH) compile --fqbn $(BOARD_TAG) --export-binaries
upload:
@$(ARDUINO_CLI_PATH) upload -p $(MONITOR_PORT) --fqbn $(BOARD_TAG) --verbose
monitor:
@$(ARDUINO_CLI_PATH) monitor -p $(MONITOR_PORT) --config baudrate=9600
# screen $(MONITOR_PORT) 9600
clean:
@$(ARDUINO_CLI_PATH) cache clean
all: compile upload monitor

View File

@ -0,0 +1,134 @@
// This sample code shows how to use dmpSetFIFOPacketSize() so as not to waste time
// initializaing the MPU6050 when the MCU has been reset or powercycled but the MPU6050 has not.
// Instead we just need to set the FIFOPacketSize, since this is the only setting needed
// that was stored in the MCU RAM.
// This example code was written for the LGT8F328. In this example the LGT8F328 goes into
// a deep sleep for 1 second which erases its ram and thus causes the MCU to restart on wakeup.
// The code is based off a simplication of example code "MPU6050_DMP6".
// Code and comments related to demonstrating how to use dmpSetFIFOPacketSize() are preceded
// by a line of asterisks (***************************************************************).
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include <lgt_LowPower.h>
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
MPU6050 mpu;
// MPU control/status vars
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint8_t fifoBuffer[42]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorFloat gravity; // [x, y, z] gravity vector
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
uint32_t startTime;
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
Serial.println(F("Starting setup"));
// ***************************************************************
// if MotionDetectionDuration is not the default value (0) but is instead a value we have set previously (1)
// then we know that the mpu6050 has not been reset or powercycled only the MCU has been, so we don't need
// to waste time reininitializing the mpu6050. Instead we just have to set the MCU to know the packet size
// since this value was only retained previously in the MCU RAM:
if (mpu.getMotionDetectionDuration() == 1) {
Serial.println("Skipping MPU6050 initialization");
mpu.dmpSetFIFOPacketSize(42);
return;
}
// ***************************************************************
// if we got here then the MPU6050 has been power cycled or reset so we have to do a full initialization
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// Calibration Time: generate offsets and calibrate our MPU6050
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// ***************************************************************
// set MotionDetectionDuration to a value other than the default (0).
// Note that we could set any value other than default in the MPU6050
// and test for that instead of MotionDetectionDuration. We chose
// MotionDetectionDuration to set in this example only as an example
// of how to test for reset/powerup on the MPU6050.
mpu.setMotionDetectionDuration(1);
startTime = millis();
}
// ================================================================
// === MAIN PROGRAM LOOP ===
// ================================================================
void loop() {
if ((millis() - startTime) < 5000) { // show YPR values for 5 seconds
if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) { // Get the Latest packet
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
Serial.print("ypr\t");
Serial.print(ypr[0] * 180 / M_PI);
Serial.print("\t");
Serial.print(ypr[1] * 180 / M_PI);
Serial.print("\t");
Serial.println(ypr[2] * 180 / M_PI);
}
} else {
// ***************************************************************
// 5 seconds have passed
// put the MCU into a deep sleep for 1 second. All RAM is lost
// however the MPU6050 will continue to operate.
Serial.println("going to sleep for 1 Sec.");
delay(100); // give the MCU a chance to print the above message
LowPower.deepSleep2(SLEEP_1S);
}
}

View File

@ -0,0 +1,345 @@
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class using DMP (MotionApps v2.0)
// 6/21/2012 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2019-07-08 - Added Auto Calibration and offset generator
// - and altered FIFO retrieval sequence to avoid using blocking code
// 2016-04-18 - Eliminated a potential infinite loop
// 2013-05-08 - added seamless Fastwire support
// - added note about gyro calibration
// 2012-06-21 - added note about Arduino 1.0.1 + Leonardo compatibility error
// 2012-06-20 - improved FIFO overflow handling and simplified read process
// 2012-06-19 - completely rearranged DMP initialization code and simplification
// 2012-06-13 - pull gyro and accel data from FIFO packet instead of reading directly
// 2012-06-09 - fix broken FIFO read sequence and change interrupt detection to RISING
// 2012-06-05 - add gravity-compensated initial reference frame acceleration output
// - add 3D math helper file to DMP6 example sketch
// - add Euler output and Yaw/Pitch/Roll output formats
// 2012-06-04 - remove accel offset clearing for better results (thanks Sungon Lee)
// 2012-06-01 - fixed gyro sensitivity to be 2000 deg/sec instead of 250
// 2012-05-30 - basic DMP initialization working
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high
/* =========================================================================
NOTE: In addition to connection 3.3v, GND, SDA, and SCL, this sketch
depends on the MPU-6050's INT pin being connected to the Arduino's
external interrupt #0 pin. On the Arduino Uno and Mega 2560, this is
digital I/O pin 2.
* ========================================================================= */
/* =========================================================================
NOTE: Arduino v1.0.1 with the Leonardo board generates a compile error
when using Serial.write(buf, len). The Teapot output uses this method.
The solution requires a modification to the Arduino USBAPI.h file, which
is fortunately simple, but annoying. This will be fixed in the next IDE
release. For more info, see these links:
http://arduino.cc/forum/index.php/topic,109987.0.html
http://code.google.com/p/arduino/issues/detail?id=958
* ========================================================================= */
// uncomment "OUTPUT_READABLE_QUATERNION" if you want to see the actual
// quaternion components in a [w, x, y, z] format (not best for parsing
// on a remote host such as Processing or something though)
//#define OUTPUT_READABLE_QUATERNION
// uncomment "OUTPUT_READABLE_EULER" if you want to see Euler angles
// (in degrees) calculated from the quaternions coming from the FIFO.
// Note that Euler angles suffer from gimbal lock (for more info, see
// http://en.wikipedia.org/wiki/Gimbal_lock)
//#define OUTPUT_READABLE_EULER
// uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/
// pitch/roll angles (in degrees) calculated from the quaternions coming
// from the FIFO. Note this also requires gravity vector calculations.
// Also note that yaw/pitch/roll angles suffer from gimbal lock (for
// more info, see: http://en.wikipedia.org/wiki/Gimbal_lock)
#define OUTPUT_READABLE_YAWPITCHROLL
// uncomment "OUTPUT_READABLE_REALACCEL" if you want to see acceleration
// components with gravity removed. This acceleration reference frame is
// not compensated for orientation, so +X is always +X according to the
// sensor, just without the effects of gravity. If you want acceleration
// compensated for orientation, us OUTPUT_READABLE_WORLDACCEL instead.
//#define OUTPUT_READABLE_REALACCEL
// uncomment "OUTPUT_READABLE_WORLDACCEL" if you want to see acceleration
// components with gravity removed and adjusted for the world frame of
// reference (yaw is relative to initial orientation, since no magnetometer
// is present in this case). Could be quite handy in some cases.
//#define OUTPUT_READABLE_WORLDACCEL
// uncomment "OUTPUT_TEAPOT" if you want output that matches the
// format used for the InvenSense teapot demo
//#define OUTPUT_TEAPOT
#define INTERRUPT_PIN 2 // use pin 2 on Arduino Uno & most boards
#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize serial communication
// (115200 chosen because it is required for Teapot Demo output, but it's
// really up to you depending on your project)
Serial.begin(115200);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
// NOTE: 8MHz or slower host processors, like the Teensy @ 3.3V or Arduino
// Pro Mini running at 3.3V, cannot handle this baud rate reliably due to
// the baud timing being too misaligned with processor ticks. You must use
// 38400 or slower in these cases, or use some kind of external separate
// crystal solution for the UART timer.
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// wait for ready
Serial.println(F("\nSend any character to begin DMP programming and demo: "));
while (Serial.available() && Serial.read()); // empty buffer
while (!Serial.available()); // wait for data
while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// Calibration Time: generate offsets and calibrate our MPU6050
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
mpu.PrintActiveOffsets();
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
Serial.println(F(")..."));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// configure LED for output
pinMode(LED_PIN, OUTPUT);
}
// ================================================================
// === MAIN PROGRAM LOOP ===
// ================================================================
void loop() {
// if programming failed, don't try to do anything
if (!dmpReady) return;
// read a packet from FIFO
if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) { // Get the Latest packet
#ifdef OUTPUT_READABLE_QUATERNION
// display quaternion values in easy matrix form: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
Serial.print("quat\t");
Serial.print(q.w);
Serial.print("\t");
Serial.print(q.x);
Serial.print("\t");
Serial.print(q.y);
Serial.print("\t");
Serial.println(q.z);
#endif
#ifdef OUTPUT_READABLE_EULER
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetEuler(euler, &q);
Serial.print("euler\t");
Serial.print(euler[0] * 180/M_PI);
Serial.print("\t");
Serial.print(euler[1] * 180/M_PI);
Serial.print("\t");
Serial.println(euler[2] * 180/M_PI);
#endif
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
Serial.print("ypr\t");
Serial.print(ypr[0] * 180/M_PI);
Serial.print("\t");
Serial.print(ypr[1] * 180/M_PI);
Serial.print("\t");
Serial.println(ypr[2] * 180/M_PI);
#endif
#ifdef OUTPUT_READABLE_REALACCEL
// display real acceleration, adjusted to remove gravity
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
Serial.print("areal\t");
Serial.print(aaReal.x);
Serial.print("\t");
Serial.print(aaReal.y);
Serial.print("\t");
Serial.println(aaReal.z);
#endif
#ifdef OUTPUT_READABLE_WORLDACCEL
// display initial world-frame acceleration, adjusted to remove gravity
// and rotated based on known orientation from quaternion
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
Serial.print("aworld\t");
Serial.print(aaWorld.x);
Serial.print("\t");
Serial.print(aaWorld.y);
Serial.print("\t");
Serial.println(aaWorld.z);
#endif
#ifdef OUTPUT_TEAPOT
// display quaternion values in InvenSense Teapot demo format:
teapotPacket[2] = fifoBuffer[0];
teapotPacket[3] = fifoBuffer[1];
teapotPacket[4] = fifoBuffer[4];
teapotPacket[5] = fifoBuffer[5];
teapotPacket[6] = fifoBuffer[8];
teapotPacket[7] = fifoBuffer[9];
teapotPacket[8] = fifoBuffer[12];
teapotPacket[9] = fifoBuffer[13];
Serial.write(teapotPacket, 14);
teapotPacket[11]++; // packetCount, loops at 0xFF on purpose
#endif
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
}
}

View File

@ -0,0 +1,242 @@
// I2C device class (I2Cdev) demonstration Processing sketch for MPU6050 DMP output
// 6/20/2012 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2012-06-20 - initial release
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
import processing.serial.*;
import processing.opengl.*;
import toxi.geom.*;
import toxi.processing.*;
// NOTE: requires ToxicLibs to be installed in order to run properly.
// 1. Download from https://github.com/postspectacular/toxiclibs/releases
// 2. Extract into [userdir]/Processing/libraries
// (location may be different on Mac/Linux)
// 3. Run and bask in awesomeness
ToxiclibsSupport gfx;
Serial port; // The serial port
char[] teapotPacket = new char[14]; // InvenSense Teapot packet
int serialCount = 0; // current packet byte position
int synced = 0;
int interval = 0;
float[] q = new float[4];
Quaternion quat = new Quaternion(1, 0, 0, 0);
float[] gravity = new float[3];
float[] euler = new float[3];
float[] ypr = new float[3];
void setup() {
// 300px square viewport using OpenGL rendering
size(300, 300, OPENGL);
gfx = new ToxiclibsSupport(this);
// setup lights and antialiasing
lights();
smooth();
// display serial port list for debugging/clarity
println(Serial.list());
// get the first available port (use EITHER this OR the specific port code below)
String portName = Serial.list()[0];
// get a specific serial port (use EITHER this OR the first-available code above)
//String portName = "COM4";
// open the serial port
port = new Serial(this, portName, 115200);
// send single character to trigger DMP init/start
// (expected by MPU6050_DMP6 example Arduino sketch)
port.write('r');
}
void draw() {
if (millis() - interval > 1000) {
// resend single character to trigger DMP init/start
// in case the MPU is halted/reset while applet is running
port.write('r');
interval = millis();
}
// black background
background(0);
// translate everything to the middle of the viewport
pushMatrix();
translate(width / 2, height / 2);
// 3-step rotation from yaw/pitch/roll angles (gimbal lock!)
// ...and other weirdness I haven't figured out yet
//rotateY(-ypr[0]);
//rotateZ(-ypr[1]);
//rotateX(-ypr[2]);
// toxiclibs direct angle/axis rotation from quaternion (NO gimbal lock!)
// (axis order [1, 3, 2] and inversion [-1, +1, +1] is a consequence of
// different coordinate system orientation assumptions between Processing
// and InvenSense DMP)
float[] axis = quat.toAxisAngle();
rotate(axis[0], -axis[1], axis[3], axis[2]);
// draw main body in red
fill(255, 0, 0, 200);
box(10, 10, 200);
// draw front-facing tip in blue
fill(0, 0, 255, 200);
pushMatrix();
translate(0, 0, -120);
rotateX(PI/2);
drawCylinder(0, 20, 20, 8);
popMatrix();
// draw wings and tail fin in green
fill(0, 255, 0, 200);
beginShape(TRIANGLES);
vertex(-100, 2, 30); vertex(0, 2, -80); vertex(100, 2, 30); // wing top layer
vertex(-100, -2, 30); vertex(0, -2, -80); vertex(100, -2, 30); // wing bottom layer
vertex(-2, 0, 98); vertex(-2, -30, 98); vertex(-2, 0, 70); // tail left layer
vertex( 2, 0, 98); vertex( 2, -30, 98); vertex( 2, 0, 70); // tail right layer
endShape();
beginShape(QUADS);
vertex(-100, 2, 30); vertex(-100, -2, 30); vertex( 0, -2, -80); vertex( 0, 2, -80);
vertex( 100, 2, 30); vertex( 100, -2, 30); vertex( 0, -2, -80); vertex( 0, 2, -80);
vertex(-100, 2, 30); vertex(-100, -2, 30); vertex(100, -2, 30); vertex(100, 2, 30);
vertex(-2, 0, 98); vertex(2, 0, 98); vertex(2, -30, 98); vertex(-2, -30, 98);
vertex(-2, 0, 98); vertex(2, 0, 98); vertex(2, 0, 70); vertex(-2, 0, 70);
vertex(-2, -30, 98); vertex(2, -30, 98); vertex(2, 0, 70); vertex(-2, 0, 70);
endShape();
popMatrix();
}
void serialEvent(Serial port) {
interval = millis();
while (port.available() > 0) {
int ch = port.read();
if (synced == 0 && ch != '$') return; // initial synchronization - also used to resync/realign if needed
synced = 1;
print ((char)ch);
if ((serialCount == 1 && ch != 2)
|| (serialCount == 12 && ch != '\r')
|| (serialCount == 13 && ch != '\n')) {
serialCount = 0;
synced = 0;
return;
}
if (serialCount > 0 || ch == '$') {
teapotPacket[serialCount++] = (char)ch;
if (serialCount == 14) {
serialCount = 0; // restart packet byte position
// get quaternion from data packet
q[0] = ((teapotPacket[2] << 8) | teapotPacket[3]) / 16384.0f;
q[1] = ((teapotPacket[4] << 8) | teapotPacket[5]) / 16384.0f;
q[2] = ((teapotPacket[6] << 8) | teapotPacket[7]) / 16384.0f;
q[3] = ((teapotPacket[8] << 8) | teapotPacket[9]) / 16384.0f;
for (int i = 0; i < 4; i++) if (q[i] >= 2) q[i] = -4 + q[i];
// set our toxilibs quaternion to new data
quat.set(q[0], q[1], q[2], q[3]);
/*
// below calculations unnecessary for orientation only using toxilibs
// calculate gravity vector
gravity[0] = 2 * (q[1]*q[3] - q[0]*q[2]);
gravity[1] = 2 * (q[0]*q[1] + q[2]*q[3]);
gravity[2] = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];
// calculate Euler angles
euler[0] = atan2(2*q[1]*q[2] - 2*q[0]*q[3], 2*q[0]*q[0] + 2*q[1]*q[1] - 1);
euler[1] = -asin(2*q[1]*q[3] + 2*q[0]*q[2]);
euler[2] = atan2(2*q[2]*q[3] - 2*q[0]*q[1], 2*q[0]*q[0] + 2*q[3]*q[3] - 1);
// calculate yaw/pitch/roll angles
ypr[0] = atan2(2*q[1]*q[2] - 2*q[0]*q[3], 2*q[0]*q[0] + 2*q[1]*q[1] - 1);
ypr[1] = atan(gravity[0] / sqrt(gravity[1]*gravity[1] + gravity[2]*gravity[2]));
ypr[2] = atan(gravity[1] / sqrt(gravity[0]*gravity[0] + gravity[2]*gravity[2]));
// output various components for debugging
//println("q:\t" + round(q[0]*100.0f)/100.0f + "\t" + round(q[1]*100.0f)/100.0f + "\t" + round(q[2]*100.0f)/100.0f + "\t" + round(q[3]*100.0f)/100.0f);
//println("euler:\t" + euler[0]*180.0f/PI + "\t" + euler[1]*180.0f/PI + "\t" + euler[2]*180.0f/PI);
//println("ypr:\t" + ypr[0]*180.0f/PI + "\t" + ypr[1]*180.0f/PI + "\t" + ypr[2]*180.0f/PI);
*/
}
}
}
}
void drawCylinder(float topRadius, float bottomRadius, float tall, int sides) {
float angle = 0;
float angleIncrement = TWO_PI / sides;
beginShape(QUAD_STRIP);
for (int i = 0; i < sides + 1; ++i) {
vertex(topRadius*cos(angle), 0, topRadius*sin(angle));
vertex(bottomRadius*cos(angle), tall, bottomRadius*sin(angle));
angle += angleIncrement;
}
endShape();
// If it is not a cone, draw the circular top cap
if (topRadius != 0) {
angle = 0;
beginShape(TRIANGLE_FAN);
// Center point
vertex(0, 0, 0);
for (int i = 0; i < sides + 1; i++) {
vertex(topRadius * cos(angle), 0, topRadius * sin(angle));
angle += angleIncrement;
}
endShape();
}
// If it is not a cone, draw the circular bottom cap
if (bottomRadius != 0) {
angle = 0;
beginShape(TRIANGLE_FAN);
// Center point
vertex(0, tall, 0);
for (int i = 0; i < sides + 1; i++) {
vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle));
angle += angleIncrement;
}
endShape();
}
}

View File

@ -0,0 +1,377 @@
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
/* This driver reads quaternion data from the MPU6060 and sends
Open Sound Control messages.
GY-521 NodeMCU
MPU6050 devkit 1.0
board Lolin Description
======= ========== ====================================================
VCC VU (5V USB) Not available on all boards so use 3.3V if needed.
GND G Ground
SCL D1 (GPIO05) I2C clock
SDA D2 (GPIO04) I2C data
XDA not connected
XCL not connected
AD0 not connected
INT D8 (GPIO15) Interrupt pin
*/
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <DNSServer.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <OSCMessage.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high
/* =========================================================================
NOTE: In addition to connection 5/3.3v, GND, SDA, and SCL, this sketch
depends on the MPU-6050's INT pin being connected to the ESP8266 GPIO15
pin.
* ========================================================================= */
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
// uncomment "OUTPUT_READABLE_QUATERNION" if you want to see the actual
// quaternion components in a [w, x, y, z] format (not best for parsing
// on a remote host such as Processing or something though)
//#define OUTPUT_READABLE_QUATERNION
// uncomment "OUTPUT_READABLE_EULER" if you want to see Euler angles
// (in degrees) calculated from the quaternions coming from the FIFO.
// Note that Euler angles suffer from gimbal lock (for more info, see
// http://en.wikipedia.org/wiki/Gimbal_lock)
//#define OUTPUT_READABLE_EULER
// uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/
// pitch/roll angles (in degrees) calculated from the quaternions coming
// from the FIFO. Note this also requires gravity vector calculations.
// Also note that yaw/pitch/roll angles suffer from gimbal lock (for
// more info, see: http://en.wikipedia.org/wiki/Gimbal_lock)
//#define OUTPUT_READABLE_YAWPITCHROLL
// uncomment "OUTPUT_READABLE_REALACCEL" if you want to see acceleration
// components with gravity removed. This acceleration reference frame is
// not compensated for orientation, so +X is always +X according to the
// sensor, just without the effects of gravity. If you want acceleration
// compensated for orientation, us OUTPUT_READABLE_WORLDACCEL instead.
//#define OUTPUT_READABLE_REALACCEL
// uncomment "OUTPUT_READABLE_WORLDACCEL" if you want to see acceleration
// components with gravity removed and adjusted for the world frame of
// reference (yaw is relative to initial orientation, since no magnetometer
// is present in this case). Could be quite handy in some cases.
//#define OUTPUT_READABLE_WORLDACCEL
// uncomment "OUTPUT_TEAPOT_OSC" if you want output that matches the
// format used for the InvenSense teapot demo
#define OUTPUT_TEAPOT_OSC
#ifdef OUTPUT_READABLE_EULER
float euler[3]; // [psi, theta, phi] Euler angle container
#endif
#ifdef OUTPUT_READABLE_YAWPITCHROLL
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
#endif
#define INTERRUPT_PIN 15 // use pin 15 on ESP8266
const char DEVICE_NAME[] = "mpu6050";
WiFiUDP Udp; // A UDP instance to let us send and receive packets over UDP
const IPAddress outIp(192, 168, 1, 11); // remote IP to receive OSC
const unsigned int outPort = 9999; // remote port to receive OSC
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void ICACHE_RAM_ATTR dmpDataReady() {
mpuInterrupt = true;
}
void mpu_setup()
{
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
}
void setup(void)
{
Serial.begin(115200);
Serial.println(F("\nOrientation Sensor OSC output")); Serial.println();
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset saved settings
//wifiManager.resetSettings();
//fetches ssid and pass from eeprom and tries to connect
//if it does not connect it starts an access point with the specified name
//and goes into a blocking loop awaiting configuration
wifiManager.autoConnect(DEVICE_NAME);
Serial.print(F("WiFi connected! IP address: "));
Serial.println(WiFi.localIP());
mpu_setup();
}
void mpu_loop()
{
// if programming failed, don't try to do anything
if (!dmpReady) return;
// wait for MPU interrupt or extra packet(s) available
if (!mpuInterrupt && fifoCount < packetSize) return;
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
// reset so we can continue cleanly
mpu.resetFIFO();
Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
} else if (mpuIntStatus & 0x02) {
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
#ifdef OUTPUT_READABLE_QUATERNION
// display quaternion values in easy matrix form: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
Serial.print("quat\t");
Serial.print(q.w);
Serial.print("\t");
Serial.print(q.x);
Serial.print("\t");
Serial.print(q.y);
Serial.print("\t");
Serial.println(q.z);
#endif
#ifdef OUTPUT_TEAPOT_OSC
#ifndef OUTPUT_READABLE_QUATERNION
// display quaternion values in easy matrix form: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
#endif
// Send OSC message
OSCMessage msg("/imuquat");
msg.add((float)q.w);
msg.add((float)q.x);
msg.add((float)q.y);
msg.add((float)q.z);
Udp.beginPacket(outIp, outPort);
msg.send(Udp);
Udp.endPacket();
msg.empty();
#endif
#ifdef OUTPUT_READABLE_EULER
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetEuler(euler, &q);
Serial.print("euler\t");
Serial.print(euler[0] * 180/M_PI);
Serial.print("\t");
Serial.print(euler[1] * 180/M_PI);
Serial.print("\t");
Serial.println(euler[2] * 180/M_PI);
#endif
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
Serial.print("ypr\t");
Serial.print(ypr[0] * 180/M_PI);
Serial.print("\t");
Serial.print(ypr[1] * 180/M_PI);
Serial.print("\t");
Serial.println(ypr[2] * 180/M_PI);
#endif
#ifdef OUTPUT_READABLE_REALACCEL
// display real acceleration, adjusted to remove gravity
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
Serial.print("areal\t");
Serial.print(aaReal.x);
Serial.print("\t");
Serial.print(aaReal.y);
Serial.print("\t");
Serial.println(aaReal.z);
#endif
#ifdef OUTPUT_READABLE_WORLDACCEL
// display initial world-frame acceleration, adjusted to remove gravity
// and rotated based on known orientation from quaternion
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
Serial.print("aworld\t");
Serial.print(aaWorld.x);
Serial.print("\t");
Serial.print(aaWorld.y);
Serial.print("\t");
Serial.println(aaWorld.z);
#endif
}
}
/**************************************************************************/
/*
Arduino loop function, called once 'setup' is complete (your own code
should go here)
*/
/**************************************************************************/
void loop(void)
{
if (WiFi.status() != WL_CONNECTED) {
Serial.println();
Serial.println("*** Disconnected from AP so rebooting ***");
Serial.println();
#if defined(ESP8266)
ESP.reset();
#else
ESP.restart();
#endif
}
mpu_loop();
}

View File

@ -0,0 +1,187 @@
// I2C device class (I2Cdev) demonstration Processing sketch for MPU6050 DMP output
// 6/20/2012 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2012-06-20 - initial release
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
/**
* MPUOSCTeapot Processing demo for MPU6050 DMP modified for OSC
* https://gitub.com/jrowberg/i2cdevlib
* The original demo uses serial port I/O which has been replaced with
* OSC UDP messages in this sketch.
*
* The MPU6050 is connected to an ESP8266 with battery so it is completely
* wire free.
*
* Tested on Processing 3.3.5 running on Ubuntu Linux 14.04
*
* Dependencies installed using Library Manager
*
* Open Sound Control library
* oscP5 website at http://www.sojamo.de/oscP5
* ToxicLibs
* quaternion functions https://github.com/postspectacular/toxiclibs/
*/
// Install oscP5 using the IDE library manager.
// From the IDE menu bar, Sketch | Import Library | Add library.
// In the search box type "osc".
import oscP5.*;
import netP5.*;
// 1. Download from https://github.com/postspectacular/toxiclibs/releases
// 2. Extract into [userdir]/Processing/libraries
// (location may be different on Mac/Linux)
import toxi.geom.*;
import toxi.processing.*;
ToxiclibsSupport gfx;
Quaternion quat = new Quaternion(1, 0, 0, 0);
OscP5 oscP5;
void setup() {
// 300px square viewport using OpenGL rendering
size(300, 300, P3D);
gfx = new ToxiclibsSupport(this);
// setup lights and antialiasing
lights();
smooth();
/* start oscP5, listening for incoming messages at port 9999 */
oscP5 = new OscP5(this, 9999);
oscP5.plug(this, "imu", "/imuquat");
}
/* incoming osc message are forwarded to the oscEvent method. */
void oscEvent(OscMessage theOscMessage) {
/* print the address pattern and the typetag of the received OscMessage */
//print("### received an osc message.");
//print(" addrpattern: "+theOscMessage.addrPattern());
//println(" typetag: "+theOscMessage.typetag());
}
public void imu(float quant_w, float quant_x, float quant_y, float quant_z) {
//println(quant_w, quant_x, quant_y, quant_z);
quat.set(quant_w, quant_x, quant_y, quant_z);
}
void draw() {
// black background
background(0);
// translate everything to the middle of the viewport
pushMatrix();
translate(width / 2, height / 2);
// 3-step rotation from yaw/pitch/roll angles (gimbal lock!)
// ...and other weirdness I haven't figured out yet
//rotateY(-ypr[0]);
//rotateZ(-ypr[1]);
//rotateX(-ypr[2]);
// toxiclibs direct angle/axis rotation from quaternion (NO gimbal lock!)
// (axis order [1, 3, 2] and inversion [-1, +1, +1] is a consequence of
// different coordinate system orientation assumptions between Processing
// and InvenSense DMP)
float[] axis = quat.toAxisAngle();
rotate(axis[0], -axis[1], axis[3], axis[2]);
// draw main body in red
fill(255, 0, 0, 200);
box(10, 10, 200);
// draw front-facing tip in blue
fill(0, 0, 255, 200);
pushMatrix();
translate(0, 0, -120);
rotateX(PI/2);
drawCylinder(0, 20, 20, 8);
popMatrix();
// draw wings and tail fin in green
fill(0, 255, 0, 200);
beginShape(TRIANGLES);
vertex(-100, 2, 30); vertex(0, 2, -80); vertex(100, 2, 30); // wing top layer
vertex(-100, -2, 30); vertex(0, -2, -80); vertex(100, -2, 30); // wing bottom layer
vertex(-2, 0, 98); vertex(-2, -30, 98); vertex(-2, 0, 70); // tail left layer
vertex( 2, 0, 98); vertex( 2, -30, 98); vertex( 2, 0, 70); // tail right layer
endShape();
beginShape(QUADS);
vertex(-100, 2, 30); vertex(-100, -2, 30); vertex( 0, -2, -80); vertex( 0, 2, -80);
vertex( 100, 2, 30); vertex( 100, -2, 30); vertex( 0, -2, -80); vertex( 0, 2, -80);
vertex(-100, 2, 30); vertex(-100, -2, 30); vertex(100, -2, 30); vertex(100, 2, 30);
vertex(-2, 0, 98); vertex(2, 0, 98); vertex(2, -30, 98); vertex(-2, -30, 98);
vertex(-2, 0, 98); vertex(2, 0, 98); vertex(2, 0, 70); vertex(-2, 0, 70);
vertex(-2, -30, 98); vertex(2, -30, 98); vertex(2, 0, 70); vertex(-2, 0, 70);
endShape();
popMatrix();
}
void drawCylinder(float topRadius, float bottomRadius, float tall, int sides) {
float angle = 0;
float angleIncrement = TWO_PI / sides;
beginShape(QUAD_STRIP);
for (int i = 0; i < sides + 1; ++i) {
vertex(topRadius*cos(angle), 0, topRadius*sin(angle));
vertex(bottomRadius*cos(angle), tall, bottomRadius*sin(angle));
angle += angleIncrement;
}
endShape();
// If it is not a cone, draw the circular top cap
if (topRadius != 0) {
angle = 0;
beginShape(TRIANGLE_FAN);
// Center point
vertex(0, 0, 0);
for (int i = 0; i < sides + 1; i++) {
vertex(topRadius * cos(angle), 0, topRadius * sin(angle));
angle += angleIncrement;
}
endShape();
}
// If it is not a cone, draw the circular bottom cap
if (bottomRadius != 0) {
angle = 0;
beginShape(TRIANGLE_FAN);
// Center point
vertex(0, tall, 0);
for (int i = 0; i < sides + 1; i++) {
vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle));
angle += angleIncrement;
}
endShape();
}
}

View File

@ -0,0 +1,545 @@
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class using DMP (MotionApps v2.0) over Ethernet
// 2/27/2016 by hellphoenix
// Based on I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class using DMP (MotionApps v2.0) (6/21/2012 by Jeff Rowberg <jeff@rowberg.net>)
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2016-04-18 - Eliminated a potential infinite loop
// 2016-02-28 - Cleaned up code to be in line with other example codes
// - Added Ethernet outputs for Quaternion, Euler, RealAccel, WorldAccel
// 2016-02-27 - Initial working code compiled
// Bugs:
// - There is still a hangup after some time, though it only occurs when you are reading data from the website.
// If you only read the data from the serial port, there are no hangups.
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
#include <Ethernet.h>
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#include "Wire.h"
#include "avr/wdt.h"// Watchdog library
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high
// MAC address from Ethernet shield sticker under board
byte mac[] = {
0x90, 0xA2, 0xDA, 0x10, 0x26, 0x82
};
// assign an IP address for the controller:
IPAddress ip(192,168,1,50);
// the router's gateway address:
byte gateway[] = { 192, 168, 1, 1 };
// the subnet:
byte subnet[] = { 255, 255, 0, 0 };
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
String HTTP_req; // stores the HTTP request
/* =========================================================================
NOTE: In addition to connection 3.3v, GND, SDA, and SCL, this sketch
depends on the MPU-6050's INT pin being connected to the Arduino's
external interrupt #0 pin. On the Arduino Uno and Mega 2560, this is
digital I/O pin 2.
* ========================================================================= */
/* =========================================================================
NOTE: Arduino v1.0.1 with the Leonardo board generates a compile error
when using Serial.write(buf, len). The Teapot output uses this method.
The solution requires a modification to the Arduino USBAPI.h file, which
is fortunately simple, but annoying. This will be fixed in the next IDE
release. For more info, see these links:
http://arduino.cc/forum/index.php/topic,109987.0.html
http://code.google.com/p/arduino/issues/detail?id=958
* ========================================================================= */
// uncomment "OUTPUT_READABLE_QUATERNION" if you want to see the actual
// quaternion components in a [w, x, y, z] format (not best for parsing
// on a remote host such as Processing or something though)
//#define OUTPUT_READABLE_QUATERNION
// uncomment "OUTPUT_READABLE_EULER" if you want to see Euler angles
// (in degrees) calculated from the quaternions coming from the FIFO.
// Note that Euler angles suffer from gimbal lock (for more info, see
// http://en.wikipedia.org/wiki/Gimbal_lock)
//#define OUTPUT_READABLE_EULER
// uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/
// pitch/roll angles (in degrees) calculated from the quaternions coming
// from the FIFO. Note this also requires gravity vector calculations.
// Also note that yaw/pitch/roll angles suffer from gimbal lock (for
// more info, see: http://en.wikipedia.org/wiki/Gimbal_lock)
#define OUTPUT_READABLE_YAWPITCHROLL
// uncomment "OUTPUT_READABLE_REALACCEL" if you want to see acceleration
// components with gravity removed. This acceleration reference frame is
// not compensated for orientation, so +X is always +X according to the
// sensor, just without the effects of gravity. If you want acceleration
// compensated for orientation, us OUTPUT_READABLE_WORLDACCEL instead.
//#define OUTPUT_READABLE_REALACCEL
// uncomment "OUTPUT_READABLE_WORLDACCEL" if you want to see acceleration
// components with gravity removed and adjusted for the world frame of
// reference (yaw is relative to initial orientation, since no magnetometer
// is present in this case). Could be quite handy in some cases.
//#define OUTPUT_READABLE_WORLDACCEL
// uncomment "OUTPUT_TEAPOT" if you want output that matches the
// format used for the InvenSense teapot demo
//#define OUTPUT_TEAPOT
#define INTERRUPT_PIN 2 // use pin 2 on Arduino Uno & most boards
#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
wdt_enable(WDTO_1S); //Watchdog enable.
//WDTO_1S sets the watchdog timer to 1 second. The time set here is approximate.
// You can find more time settings at http://www.nongnu.org/avr-libc/user-manual/group__avr__watchdog.html .
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock (200kHz if CPU is 8MHz). Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize serial communication
// (115200 chosen because it is required for Teapot Demo output, but it's
// really up to you depending on your project)
Serial.begin(115200);
// NOTE: 8MHz or slower host processors, like the Teensy @ 3.3V or Arduino
// Pro Mini running at 3.3V, cannot handle this baud rate reliably due to
// the baud timing being too misaligned with processor ticks. You must use
// 38400 or slower in these cases, or use some kind of external separate
// crystal solution for the UART timer.
Ethernet.begin(mac, ip, gateway, subnet);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
while (!Serial); // wait for Leonardo enumeration, others continue immediately
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
Serial.println(F(")..."));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// configure LED for output
pinMode(LED_PIN, OUTPUT);
}
// ================================================================
// === MAIN PROGRAM LOOP ===
// ================================================================
void loop() {
// if programming failed, don't try to do anything
if (!dmpReady) return;
wdt_reset();//Resets the watchdog timer. If the timer is not reset, and the timer expires, a watchdog-initiated device reset will occur.
// wait for MPU interrupt or extra packet(s) available
while (!mpuInterrupt && fifoCount < packetSize) {
if (mpuInterrupt && fifoCount < packetSize) {
// try to get out of the infinite loop
fifoCount = mpu.getFIFOCount();
}
// other program behavior stuff here
// .
// .
// if you are really paranoid you can frequently test in between other
// stuff to see if mpuInterrupt is true, and if so, "break;" from the
// while() loop to immediately process the MPU data
// .
// .
// .
}
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & _BV(MPU6050_IMU::MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024) {
// reset so we can continue cleanly
mpu.resetFIFO();
fifoCount = mpu.getFIFOCount();
Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
} else if (mpuIntStatus & _BV(MPU6050_IMU::MPU6050_INTERRUPT_DMP_INT_BIT)) {
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO, then clear the buffer
mpu.getFIFOBytes(fifoBuffer, packetSize);
//mpu.resetFIFO();
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
#ifdef OUTPUT_READABLE_QUATERNION
// display quaternion values in easy matrix form: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
Serial.print("quat\t");
Serial.print(q.w);
Serial.print("\t");
Serial.print(q.x);
Serial.print("\t");
Serial.print(q.y);
Serial.print("\t");
Serial.println(q.z);
#endif
#ifdef OUTPUT_READABLE_EULER
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetEuler(euler, &q);
Serial.print("euler\t");
Serial.print(euler[0] * 180/M_PI);
Serial.print("\t");
Serial.print(euler[1] * 180/M_PI);
Serial.print("\t");
Serial.println(euler[2] * 180/M_PI);
#endif
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
Serial.print("ypr\t");
Serial.print(ypr[0] * 180/M_PI);
Serial.print("\t");
Serial.print(ypr[1] * 180/M_PI);
Serial.print("\t");
Serial.println(ypr[2] * 180/M_PI);
#endif
#ifdef OUTPUT_READABLE_REALACCEL
// display real acceleration, adjusted to remove gravity
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
Serial.print("areal\t");
Serial.print(aaReal.x);
Serial.print("\t");
Serial.print(aaReal.y);
Serial.print("\t");
Serial.println(aaReal.z);
#endif
#ifdef OUTPUT_READABLE_WORLDACCEL
// display initial world-frame acceleration, adjusted to remove gravity
// and rotated based on known orientation from quaternion
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
Serial.print("aworld\t");
Serial.print(aaWorld.x);
Serial.print("\t");
Serial.print(aaWorld.y);
Serial.print("\t");
Serial.println(aaWorld.z);
#endif
#ifdef OUTPUT_TEAPOT
// display quaternion values in InvenSense Teapot demo format:
teapotPacket[2] = fifoBuffer[0];
teapotPacket[3] = fifoBuffer[1];
teapotPacket[4] = fifoBuffer[4];
teapotPacket[5] = fifoBuffer[5];
teapotPacket[6] = fifoBuffer[8];
teapotPacket[7] = fifoBuffer[9];
teapotPacket[8] = fifoBuffer[12];
teapotPacket[9] = fifoBuffer[13];
Serial.write(teapotPacket, 14);
teapotPacket[11]++; // packetCount, loops at 0xFF on purpose
#endif
serversend();
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
}
}
void serversend(){
EthernetClient client = server.available(); // try to get client
if (client) { // got client?
//boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) { // client data available to read
char c = client.read(); // read 1 byte (character) from client
HTTP_req += c; // save the HTTP request 1 char at a time
// last line of client request is blank and ends with \n
// respond to client only after last line received
if (c == '\n') {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
//client.println("Connection: keep-alive");
client.println();
// AJAX request for switch state
if (HTTP_req.indexOf("ajax_switch") > -1) {
// read switch state and analog input
GetAjaxData(client);
}
else { // HTTP request for web page
// send web page - contains JavaScript with AJAX calls
client.println("<!DOCTYPE html>");
client.println("<html>");
client.println("<head>");
client.println("<title>Arduino Web Page</title>");
client.println("<script>");
client.println("function GetAjaxData() {");
client.println(
"nocache = \"&nocache=\" + Math.random() * 1000000;");
client.println("var request = new XMLHttpRequest();");
client.println("request.onreadystatechange = function() {");
client.println("if (this.readyState == 4) {");
client.println("if (this.status == 200) {");
client.println("if (this.responseText != null) {");
client.println("document.getElementById(\"sw_an_data\")\
.innerHTML = this.responseText;");
client.println("}}}}");
client.println(
"request.open(\"GET\", \"ajax_switch\" + nocache, true);");
client.println("request.send(null);");
client.println("setTimeout('GetAjaxData()', 10);");
client.println("}");
client.println("</script>");
client.println("</head>");
client.println("<body onload=\"GetAjaxData()\">");
client.println("<h1>MPU6050 Output</h1>");
client.println("<div id=\"sw_an_data\">");
client.println("</div>");
client.println("</body>");
client.println("</html>");
}
// display received HTTP request on serial port
Serial.print(HTTP_req);
HTTP_req = ""; // finished with request, empty string
client.stop(); // close the connection
break;
}
}
}
}
}
void GetAjaxData(EthernetClient cl)
{
#ifdef OUTPUT_READABLE_QUATERNION
// display quaternion values in easy matrix form: w x y z
cl.print("Quaternion Values:\t");
cl.print("<p>w:");
cl.print(q.w);
cl.print("\t");
cl.println("</p>");
cl.print("<p>x:");
cl.print(q.x);
cl.print("\t");
cl.println("</p>");
cl.print("<p>y:");
cl.print(q.y);
cl.print("\t");
cl.println("</p>");
cl.print("<p>z:");
cl.print(q.z);
cl.print("\t");
cl.println("</p>");
#endif
#ifdef OUTPUT_READABLE_EULER
// display Euler angles in degrees
cl.print("Euler Angles:\t");
cl.print("<p>Yaw:");
cl.print(euler[0] * 180/M_PI);
cl.print("\t");
cl.println("</p>");
cl.print("<p>Pitch:");
cl.print(euler[2] * 180/M_PI);
cl.print("\t");
cl.println("</p>");
cl.print("<p>Roll:");
cl.print(euler[1] * 180/M_PI);
cl.print("\t");
cl.println("</p>");
#endif
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// display Yaw/Pitch/Roll values in degrees
cl.print("Yaw, Pitch, and Roll:\t");
cl.print("<p>Yaw:");
cl.print(ypr[0] * 180/M_PI);
cl.print("\t");
cl.println("</p>");
cl.print("<p>Pitch:");
cl.print(ypr[2] * 180/M_PI);
cl.print("\t");
cl.println("</p>");
cl.print("<p>Roll:");
cl.print(ypr[1] * 180/M_PI);
cl.print("\t");
cl.println("</p>");
#endif
#ifdef OUTPUT_READABLE_REALACCEL
// display real acceleration, adjusted to remove gravity
cl.print("Real Accel:\t");
cl.print("<p>Yaw:");
cl.print(aaReal.x);
cl.print("\t");
cl.println("</p>");
cl.print("<p>Pitch:");
cl.print(aaReal.z);
cl.print("\t");
cl.println("</p>");
cl.print("<p>Roll:");
cl.print(aaReal.y);
cl.print("\t");
cl.println("</p>");
#endif
#ifdef OUTPUT_READABLE_WORLDACCEL
// display initial world-frame acceleration, adjusted to remove gravity
// and rotated based on known orientation from quaternion
cl.print("World Accel:\t");
cl.print("<p>Yaw:");
cl.print(aaWorld.x);
cl.print("\t");
cl.println("</p>");
cl.print("<p>Pitch:");
cl.print(aaWorld.z);
cl.print("\t");
cl.println("</p>");
cl.print("<p>Roll:");
cl.print(aaWorld.y);
cl.print("\t");
cl.println("</p>");
#endif
#ifdef OUTPUT_TEAPOT
cl.print("<p>teapotpacket:");
cl.write(teapotPacket, 14);
cl.print("\t");
cl.println("</p>");
#endif
}

View File

@ -0,0 +1,122 @@
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
MPU6050 mpu;
#define EARTH_GRAVITY_MS2 9.80665 // m/s2
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 gg; // [x, y, z] gyro sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorInt16 ggWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
void setup() {
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
mpu.initialize();
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(-156);
mpu.setYGyroOffset(-11);
mpu.setZGyroOffset(-14);
mpu.setXAccelOffset(-3699);
mpu.setYAccelOffset(-2519);
mpu.setZAccelOffset(1391); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
mpu.PrintActiveOffsets();
mpu.setDMPEnabled(true);
mpuIntStatus = mpu.getIntStatus();
dmpReady = true;
packetSize = mpu.dmpGetFIFOPacketSize();
}
}
void loop() {
if (!dmpReady) return;
if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) { // Get the Latest packet
// display quaternion values in easy matrix form: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
Serial.print("quat\t");
Serial.print(q.w);
Serial.print("\t");
Serial.print(q.x);
Serial.print("\t");
Serial.print(q.y);
Serial.print("\t");
Serial.println(q.z);
mpu.dmpGetGravity(&gravity, &q);
// display initial world-frame acceleration, adjusted to remove gravity
// and rotated based on known orientation from quaternion
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpConvertToWorldFrame(&aaWorld, &aa, &q);
Serial.print("aworld\t");
Serial.print(aaWorld.x * mpu.get_acce_resolution() * EARTH_GRAVITY_MS2);
Serial.print("\t");
Serial.print(aaWorld.y * mpu.get_acce_resolution() * EARTH_GRAVITY_MS2);
Serial.print("\t");
Serial.println(aaWorld.z * mpu.get_acce_resolution() * EARTH_GRAVITY_MS2);
// display initial world-frame acceleration, adjusted to remove gravity
// and rotated based on known orientation from quaternion
mpu.dmpGetGyro(&gg, fifoBuffer);
mpu.dmpConvertToWorldFrame(&ggWorld, &gg, &q);
Serial.print("ggWorld\t");
Serial.print(ggWorld.x * mpu.get_gyro_resolution() * DEG_TO_RAD);
Serial.print("\t");
Serial.print(ggWorld.y * mpu.get_gyro_resolution() * DEG_TO_RAD);
Serial.print("\t");
Serial.println(ggWorld.z * mpu.get_gyro_resolution() * DEG_TO_RAD);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
Serial.print("ypr\t");
Serial.print(ypr[0] * RAD_TO_DEG);
Serial.print("\t");
Serial.print(ypr[1] * RAD_TO_DEG);
Serial.print("\t");
Serial.println(ypr[2] * RAD_TO_DEG);
Serial.println();
delay(100);
}
}

View File

@ -0,0 +1,368 @@
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class using DMP (MotionApps v6.12)
// 6/21/2012 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2019-07-10 - Uses the new version of the DMP Firmware V6.12
// - Note: I believe the Teapot demo is broken with this versin as
// - the fifo buffer structure has changed
// 2016-04-18 - Eliminated a potential infinite loop
// 2013-05-08 - added seamless Fastwire support
// - added note about gyro calibration
// 2012-06-21 - added note about Arduino 1.0.1 + Leonardo compatibility error
// 2012-06-20 - improved FIFO overflow handling and simplified read process
// 2012-06-19 - completely rearranged DMP initialization code and simplification
// 2012-06-13 - pull gyro and accel data from FIFO packet instead of reading directly
// 2012-06-09 - fix broken FIFO read sequence and change interrupt detection to RISING
// 2012-06-05 - add gravity-compensated initial reference frame acceleration output
// - add 3D math helper file to DMP6 example sketch
// - add Euler output and Yaw/Pitch/Roll output formats
// 2012-06-04 - remove accel offset clearing for better results (thanks Sungon Lee)
// 2012-06-01 - fixed gyro sensitivity to be 2000 deg/sec instead of 250
// 2012-05-30 - basic DMP initialization working
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps612.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high
/* =========================================================================
NOTE: In addition to connection 3.3v, GND, SDA, and SCL, this sketch
depends on the MPU-6050's INT pin being connected to the Arduino's
external interrupt #0 pin. On the Arduino Uno and Mega 2560, this is
digital I/O pin 2.
========================================================================= */
/* =========================================================================
NOTE: Arduino v1.0.1 with the Leonardo board generates a compile error
when using Serial.write(buf, len). The Teapot output uses this method.
The solution requires a modification to the Arduino USBAPI.h file, which
is fortunately simple, but annoying. This will be fixed in the next IDE
release. For more info, see these links:
http://arduino.cc/forum/index.php/topic,109987.0.html
http://code.google.com/p/arduino/issues/detail?id=958
========================================================================= */
// uncomment "OUTPUT_READABLE_QUATERNION" if you want to see the actual
// quaternion components in a [w, x, y, z] format (not best for parsing
// on a remote host such as Processing or something though)
//#define OUTPUT_READABLE_QUATERNION
// uncomment "OUTPUT_READABLE_EULER" if you want to see Euler angles
// (in degrees) calculated from the quaternions coming from the FIFO.
// Note that Euler angles suffer from gimbal lock (for more info, see
// http://en.wikipedia.org/wiki/Gimbal_lock)
//#define OUTPUT_READABLE_EULER
// uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/
// pitch/roll angles (in degrees) calculated from the quaternions coming
// from the FIFO. Note this also requires gravity vector calculations.
// Also note that yaw/pitch/roll angles suffer from gimbal lock (for
// more info, see: http://en.wikipedia.org/wiki/Gimbal_lock)
#define OUTPUT_READABLE_YAWPITCHROLL
// uncomment "OUTPUT_READABLE_REALACCEL" if you want to see acceleration
// components with gravity removed. This acceleration reference frame is
// not compensated for orientation, so +X is always +X according to the
// sensor, just without the effects of gravity. If you want acceleration
// compensated for orientation, us OUTPUT_READABLE_WORLDACCEL instead.
//#define OUTPUT_READABLE_REALACCEL
// uncomment "OUTPUT_READABLE_WORLDACCEL" if you want to see acceleration
// components with gravity removed and adjusted for the world frame of
// reference (yaw is relative to initial orientation, since no magnetometer
// is present in this case). Could be quite handy in some cases.
//#define OUTPUT_READABLE_WORLDACCEL
// uncomment "OUTPUT_TEAPOT" if you want output that matches the
// format used for the InvenSense teapot demo
//#define OUTPUT_TEAPOT
#define INTERRUPT_PIN 2 // use pin 2 on Arduino Uno & most boards
#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 gy; // [x, y, z] gyro sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, 0x00, '\r', '\n' };
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize serial communication
// (115200 chosen because it is required for Teapot Demo output, but it's
// really up to you depending on your project)
Serial.begin(115200);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
// NOTE: 8MHz or slower host processors, like the Teensy @ 3.3V or Arduino
// Pro Mini running at 3.3V, cannot handle this baud rate reliably due to
// the baud timing being too misaligned with processor ticks. You must use
// 38400 or slower in these cases, or use some kind of external separate
// crystal solution for the UART timer.
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// wait for ready
Serial.println(F("\nSend any character to begin DMP programming and demo: "));
while (Serial.available() && Serial.read()); // empty buffer
while (!Serial.available()); // wait for data
while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(51);
mpu.setYGyroOffset(8);
mpu.setZGyroOffset(21);
mpu.setXAccelOffset(1150);
mpu.setYAccelOffset(-50);
mpu.setZAccelOffset(1060);
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// Calibration Time: generate offsets and calibrate our MPU6050
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
Serial.println();
mpu.PrintActiveOffsets();
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
Serial.println(F(")..."));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// configure LED for output
pinMode(LED_PIN, OUTPUT);
}
// ================================================================
// === MAIN PROGRAM LOOP ===
// ================================================================
void loop() {
// if programming failed, don't try to do anything
if (!dmpReady) return;
// read a packet from FIFO
if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) { // Get the Latest packet
#ifdef OUTPUT_READABLE_QUATERNION
// display quaternion values in easy matrix form: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
Serial.print("quat\t");
Serial.print(q.w);
Serial.print("\t");
Serial.print(q.x);
Serial.print("\t");
Serial.print(q.y);
Serial.print("\t");
Serial.println(q.z);
#endif
#ifdef OUTPUT_READABLE_EULER
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetEuler(euler, &q);
Serial.print("euler\t");
Serial.print(euler[0] * 180 / M_PI);
Serial.print("\t");
Serial.print(euler[1] * 180 / M_PI);
Serial.print("\t");
Serial.println(euler[2] * 180 / M_PI);
#endif
#ifdef OUTPUT_READABLE_YAWPITCHROLL
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
Serial.print("ypr\t");
Serial.print(ypr[0] * 180 / M_PI);
Serial.print("\t");
Serial.print(ypr[1] * 180 / M_PI);
Serial.print("\t");
Serial.print(ypr[2] * 180 / M_PI);
/*
mpu.dmpGetAccel(&aa, fifoBuffer);
Serial.print("\tRaw Accl XYZ\t");
Serial.print(aa.x);
Serial.print("\t");
Serial.print(aa.y);
Serial.print("\t");
Serial.print(aa.z);
mpu.dmpGetGyro(&gy, fifoBuffer);
Serial.print("\tRaw Gyro XYZ\t");
Serial.print(gy.x);
Serial.print("\t");
Serial.print(gy.y);
Serial.print("\t");
Serial.print(gy.z);
*/
Serial.println();
#endif
#ifdef OUTPUT_READABLE_REALACCEL
// display real acceleration, adjusted to remove gravity
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
Serial.print("areal\t");
Serial.print(aaReal.x);
Serial.print("\t");
Serial.print(aaReal.y);
Serial.print("\t");
Serial.println(aaReal.z);
#endif
#ifdef OUTPUT_READABLE_WORLDACCEL
// display initial world-frame acceleration, adjusted to remove gravity
// and rotated based on known orientation from quaternion
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
Serial.print("aworld\t");
Serial.print(aaWorld.x);
Serial.print("\t");
Serial.print(aaWorld.y);
Serial.print("\t");
Serial.println(aaWorld.z);
#endif
#ifdef OUTPUT_TEAPOT
// display quaternion values in InvenSense Teapot demo format:
teapotPacket[2] = fifoBuffer[0];
teapotPacket[3] = fifoBuffer[1];
teapotPacket[4] = fifoBuffer[4];
teapotPacket[5] = fifoBuffer[5];
teapotPacket[6] = fifoBuffer[8];
teapotPacket[7] = fifoBuffer[9];
teapotPacket[8] = fifoBuffer[12];
teapotPacket[9] = fifoBuffer[13];
Serial.write(teapotPacket, 14);
teapotPacket[11]++; // packetCount, loops at 0xFF on purpose
#endif
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
}
}

View File

@ -0,0 +1,189 @@
// I2C device class (I2Cdev) demonstration Processing sketch for MPU6050 DMP output
// 6/20/2012 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2012-06-20 - initial release
// 2016-10-28 - Changed to bi-plane 3d model based on tutorial at
// https://forum.processing.org/two/discussion/24350/display-obj-file-in-3d
// https://opengameart.org/content/low-poly-biplane
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
import processing.serial.*;
//import processing.opengl.*;
import toxi.geom.*;
import toxi.processing.*;
// NOTE: requires ToxicLibs to be installed in order to run properly.
// 1. Download from https://github.com/postspectacular/toxiclibs/releases
// 2. Extract into [userdir]/Processing/libraries
// (location may be different on Mac/Linux)
// 3. Run and bask in awesomeness
ToxiclibsSupport gfx;
Serial port; // The serial port
char[] teapotPacket = new char[14]; // InvenSense Teapot packet
int serialCount = 0; // current packet byte position
int synced = 0;
int interval = 0;
float[] q = new float[4];
Quaternion quat = new Quaternion(1, 0, 0, 0);
float[] gravity = new float[3];
float[] euler = new float[3];
float[] ypr = new float[3];
PShape plane; // 3d model
void setup() {
// 640x480 px square viewport
size(640, 480, P3D);
gfx = new ToxiclibsSupport(this);
// setup lights and antialiasing
lights();
smooth();
// display serial port list for debugging/clarity
println(Serial.list());
// get a specific serial port
String portName = "COM12";
// open the serial port
port = new Serial(this, portName, 115200);
// send single character to trigger DMP init/start
// (expected by MPU6050_DMP6 example Arduino sketch)
port.write('r');
// Load Plane object
// The file must be in the \data folder
// of the current sketch to load successfully
plane = loadShape("biplane.obj");
// apply its texture and set orientation
PImage img1=loadImage("diffuse_512.png");
plane.setTexture(img1);
plane.scale(30);
plane.rotateX(PI);
plane.rotateY(PI+HALF_PI);
}
void draw() {
if (millis() - interval > 1000) {
// resend single character to trigger DMP init/start
// in case the MPU is halted/reset while applet is running
port.write('r');
interval = millis();
}
// black background
background(0);
// translate everything to the middle of the viewport
pushMatrix();
translate(width / 2, height / 2);
// toxiclibs direct angle/axis rotation from quaternion (NO gimbal lock!)
// (axis order [1, 3, 2] and inversion [-1, +1, +1] is a consequence of
// different coordinate system orientation assumptions between Processing
// and InvenSense DMP)
float[] axis = quat.toAxisAngle();
rotate(axis[0], -axis[1], axis[3], axis[2]);
// draw plane
shape(plane, 0, 0);
popMatrix();
}
void serialEvent(Serial port) {
interval = millis();
while (port.available() > 0) {
int ch = port.read();
if (synced == 0 && ch != '$') return; // initial synchronization - also used to resync/realign if needed
synced = 1;
print ((char)ch);
if ((serialCount == 1 && ch != 2)
|| (serialCount == 12 && ch != '\r')
|| (serialCount == 13 && ch != '\n')) {
serialCount = 0;
synced = 0;
return;
}
if (serialCount > 0 || ch == '$') {
teapotPacket[serialCount++] = (char)ch;
if (serialCount == 14) {
serialCount = 0; // restart packet byte position
// get quaternion from data packet
q[0] = ((teapotPacket[2] << 8) | teapotPacket[3]) / 16384.0f;
q[1] = ((teapotPacket[4] << 8) | teapotPacket[5]) / 16384.0f;
q[2] = ((teapotPacket[6] << 8) | teapotPacket[7]) / 16384.0f;
q[3] = ((teapotPacket[8] << 8) | teapotPacket[9]) / 16384.0f;
for (int i = 0; i < 4; i++) if (q[i] >= 2) q[i] = -4 + q[i];
// set our toxilibs quaternion to new data
quat.set(q[0], q[1], q[2], q[3]);
// below calculations unnecessary for orientation only using toxilibs
// calculate gravity vector
gravity[0] = 2 * (q[1]*q[3] - q[0]*q[2]);
gravity[1] = 2 * (q[0]*q[1] + q[2]*q[3]);
gravity[2] = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];
// calculate Euler angles
euler[0] = atan2(2*q[1]*q[2] - 2*q[0]*q[3], 2*q[0]*q[0] + 2*q[1]*q[1] - 1);
euler[1] = -asin(2*q[1]*q[3] + 2*q[0]*q[2]);
euler[2] = atan2(2*q[2]*q[3] - 2*q[0]*q[1], 2*q[0]*q[0] + 2*q[3]*q[3] - 1);
// calculate yaw/pitch/roll angles
ypr[0] = atan2(2*q[1]*q[2] - 2*q[0]*q[3], 2*q[0]*q[0] + 2*q[1]*q[1] - 1);
ypr[1] = atan(gravity[0] / sqrt(gravity[1]*gravity[1] + gravity[2]*gravity[2]));
ypr[2] = atan(gravity[1] / sqrt(gravity[0]*gravity[0] + gravity[2]*gravity[2]));
// output various components for debugging
println("q:\t" + round(q[0]*100.0f)/100.0f + "\t" + round(q[1]*100.0f)/100.0f + "\t" + round(q[2]*100.0f)/100.0f + "\t" + round(q[3]*100.0f)/100.0f);
println("euler:\t" + euler[0]*180.0f/PI + "\t" + euler[1]*180.0f/PI + "\t" + euler[2]*180.0f/PI);
println("ypr:\t" + ypr[0]*180.0f/PI + "\t" + ypr[1]*180.0f/PI + "\t" + ypr[2]*180.0f/PI);
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

View File

@ -0,0 +1,152 @@
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class
// 10/7/2011 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2013-05-08 - added multiple output formats
// - added seamless Fastwire support
// 2011-10-07 - initial release
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2011 Jeff Rowberg
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.
===============================================
*/
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
//MPU6050 accelgyro(0x69); // <-- use for AD0 high
//MPU6050 accelgyro(0x68, &Wire1); // <-- use for AD0 low, but 2nd Wire (TWI/I2C) object
int16_t ax, ay, az;
int16_t gx, gy, gz;
// uncomment "OUTPUT_READABLE_ACCELGYRO" if you want to see a tab-separated
// list of the accel X/Y/Z and then gyro X/Y/Z values in decimal. Easy to read,
// not so easy to parse, and slow(er) over UART.
#define OUTPUT_READABLE_ACCELGYRO
// uncomment "OUTPUT_BINARY_ACCELGYRO" to send all 6 axes of data as 16-bit
// binary, one right after the other. This is very fast (as fast as possible
// without compression or data loss), and easy to parse, but impossible to read
// for a human.
//#define OUTPUT_BINARY_ACCELGYRO
#define LED_PIN 13
bool blinkState = false;
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize serial communication
// (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
// it's really up to you depending on your project)
Serial.begin(38400);
// initialize device
Serial.println("Initializing I2C devices...");
accelgyro.initialize();
// verify connection
Serial.println("Testing device connections...");
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
// use the code below to change accel/gyro offset values
/*
Serial.println("Updating internal sensor offsets...");
// -76 -2359 1688 0 0 0
Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); // -76
Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); // -2359
Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); // 1688
Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); // 0
Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); // 0
Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); // 0
Serial.print("\n");
accelgyro.setXGyroOffset(220);
accelgyro.setYGyroOffset(76);
accelgyro.setZGyroOffset(-85);
Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); // -76
Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); // -2359
Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); // 1688
Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); // 0
Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); // 0
Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); // 0
Serial.print("\n");
*/
// configure Arduino LED pin for output
pinMode(LED_PIN, OUTPUT);
}
void loop() {
// read raw accel/gyro measurements from device
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
// these methods (and a few others) are also available
//accelgyro.getAcceleration(&ax, &ay, &az);
//accelgyro.getRotation(&gx, &gy, &gz);
#ifdef OUTPUT_READABLE_ACCELGYRO
// display tab-separated accel/gyro x/y/z values
Serial.print("a/g:\t");
Serial.print(ax); Serial.print("\t");
Serial.print(ay); Serial.print("\t");
Serial.print(az); Serial.print("\t");
Serial.print(gx); Serial.print("\t");
Serial.print(gy); Serial.print("\t");
Serial.println(gz);
#endif
#ifdef OUTPUT_BINARY_ACCELGYRO
Serial.write((uint8_t)(ax >> 8)); Serial.write((uint8_t)(ax & 0xFF));
Serial.write((uint8_t)(ay >> 8)); Serial.write((uint8_t)(ay & 0xFF));
Serial.write((uint8_t)(az >> 8)); Serial.write((uint8_t)(az & 0xFF));
Serial.write((uint8_t)(gx >> 8)); Serial.write((uint8_t)(gx & 0xFF));
Serial.write((uint8_t)(gy >> 8)); Serial.write((uint8_t)(gy & 0xFF));
Serial.write((uint8_t)(gz >> 8)); Serial.write((uint8_t)(gz & 0xFF));
#endif
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
}

View File

@ -0,0 +1,20 @@
# BOARD_TAG = arduino:mbed_rp2040:pico
# BOARD_TAG = rp2040:rp2040:rpipico
BOARD_TAG = esp32:esp32:XIAO_ESP32C3
MONITOR_PORT = /dev/cu.usbmodem132401
ARDUINO_CLI_PATH := arduino-cli
compile:
$(ARDUINO_CLI_PATH) compile --fqbn $(BOARD_TAG) --export-binaries
upload:
@$(ARDUINO_CLI_PATH) upload -p $(MONITOR_PORT) --fqbn $(BOARD_TAG) --verbose
monitor:
@$(ARDUINO_CLI_PATH) monitor -p $(MONITOR_PORT) --config baudrate=9600
# screen $(MONITOR_PORT) 9600
clean:
@$(ARDUINO_CLI_PATH) cache clean
all: compile upload monitor

View File

@ -0,0 +1,151 @@
#######################################
# Syntax Coloring Map For MPU6050
#######################################
#######################################
# Class (KEYWORD1)
#######################################
MPU6050 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
initialize KEYWORD2
get_acce_resolution KEYWORD2
get_gyro_resolution KEYWORD2
testConnection KEYWORD2
getAuxVDDIOLevel KEYWORD2
setAuxVDDIOLevel KEYWORD2
getRate KEYWORD2
setRate KEYWORD2
getExternalFrameSync KEYWORD2
setExternalFrameSync KEYWORD2
getDLPFMode KEYWORD2
getFullScaleGyroRange KEYWORD2
setFullScaleGyroRange KEYWORD2
getAccelXSelfTestFactoryTrim KEYWORD2
getAccelYSelfTestFactoryTrim KEYWORD2
getAccelZSelfTestFactoryTrim KEYWORD2
getGyroXSelfTestFactoryTrim KEYWORD2
getGyroYSelfTestFactoryTrim KEYWORD2
getGyroZSelfTestFactoryTrim KEYWORD2
getAccelXSelfTest KEYWORD2
getAccelYSelfTest KEYWORD2
getAccelZSelfTest KEYWORD2
getFullScaleAccelRange KEYWORD2
setFullScaleAccelRange KEYWORD2
getDHPFMode KEYWORD2
setDHPFMode KEYWORD2
getMotion6 KEYWORD2
getMotion9 KEYWORD2
getAccelerationX KEYWORD2
getAccelerationY KEYWORD2
getAccelerationZ KEYWORD2
getTemperature KEYWORD2
getRotation KEYWORD2
getRotationX KEYWORD2
getRotationY KEYWORD2
getRotationZ KEYWORD2
setI2CMasterModeEnabled KEYWORD2
setI2CBypassEnabled KEYWORD2
setSleepEnabled KEYWORD2
getFreefallDetectionThreshold KEYWORD2
setFreefallDetectionThreshold KEYWORD2
getFreefallDetectionDuration KEYWORD2
setFreefallDetectionDuration KEYWORD2
getMotionDetectionThreshold KEYWORD2
setMotionDetectionThreshold KEYWORD2
getMotionDetectionDuration KEYWORD2
setMotionDetectionDuration KEYWORD2
getZeroMotionDetectionThreshold KEYWORD2
setZeroMotionDetectionThreshold KEYWORD2
getZeroMotionDetectionDuration KEYWORD2
setZeroMotionDetectionDuration KEYWORD2
getTempFIFOEnabled KEYWORD2
setTempFIFOEnabled KEYWORD2
getXGyroFIFOEnabled KEYWORD2
setXGyroFIFOEnabled KEYWORD2
getYGyroFIFOEnabled KEYWORD2
setYGyroFIFOEnabled KEYWORD2
getZGyroFIFOEnabled KEYWORD2
setZGyroFIFOEnabled KEYWORD2
getAccelFIFOEnabled KEYWORD2
setAccelFIFOEnabled KEYWORD2
getSlave2FIFOEnabled KEYWORD2f
setSlave2FIFOEnabled KEYWORD2
getSlave1FIFOEnabled KEYWORD2
setSlave1FIFOEnabled KEYWORD2
getSlave0FIFOEnabled KEYWORD2
setSlave0FIFOEnabled KEYWORD2
getMultiMasterEnabled KEYWORD2
setMultiMasterEnabled KEYWORD2
getWaitForExternalSensorEnabled KEYWORD2
setWaitForExternalSensorEnabled KEYWORD2
getSlave3FIFOEnabled KEYWORD2
setSlave3FIFOEnabled KEYWORD2
getSlaveReadWriteTransitionEnabled KEYWORD2
setSlaveReadWriteTransitionEnabled KEYWORD2
getMasterClockSpeed KEYWORD2
setMasterClockSpeed KEYWORD2
getSlaveAddress KEYWORD2
setSlaveAddress KEYWORD2
getSlaveRegister KEYWORD2
setSlaveRegister KEYWORD2
getSlaveEnabled KEYWORD2
setSlaveEnabled KEYWORD2
getSlaveWordByteSwap KEYWORD2
setSlaveWordByteSwap KEYWORD2
getSlaveWriteMode KEYWORD2
setSlaveWriteMode KEYWORD2
getSlaveWordGroupOffset KEYWORD2
setSlaveWordGroupOffset KEYWORD2
getSlaveDataLength KEYWORD2
setSlaveDataLength KEYWORD2
getSlave4Address KEYWORD2
setSlave4Address KEYWORD2
getSlave4Register KEYWORD2
setSlave4Register KEYWORD2
setSlave4OutputByte KEYWORD2
getSlave4Enabled KEYWORD2
setSlave4Enabled KEYWORD2
getSlave4InterruptEnabled KEYWORD2
setSlave4InterruptEnabled KEYWORD2
getSlave4WriteMode KEYWORD2
setSlave4WriteMode KEYWORD2
getSlave4MasterDelay KEYWORD2
setSlave4MasterDelay KEYWORD2
getSlate4InputByte KEYWORD2
getPassthroughStatus KEYWORD2
getSlave4IsDone KEYWORD2
getLostArbitration KEYWORD2
getSlave4Nack KEYWORD2
getSlave3Nack KEYWORD2
getSlave2Nack KEYWORD2
getSlave1Nack KEYWORD2
getSlave0Nack KEYWORD2
CalibrateGyro KEYWORD2
CalibrateAccel KEYWORD2
PID KEYWORD2
PrintActiveOffsets KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,10 @@
name=MPU6050
version=1.3.1
author=Electronic Cats
maintainer=Electronic Cats <store@electroniccats.com>
sentence=MPU6050 Arduino Library.
paragraph=MPU-6050 6-axis accelerometer/gyroscope Arduino Library.
category=Sensors
url=https://github.com/electroniccats/mpu6050
architectures=avr,samd,sam,esp8266,esp32,stm32,renesas,renesas_portenta,renesas_uno
includes=MPU6050.h

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,311 @@
// I2Cdev library collection - Main I2C device class header file
// Abstracts bit and byte I2C R/W functions into a convenient class
// 2013-06-05 by Jeff Rowberg <jeff@rowberg.net>
//
// Changelog:
// 2021-09-28 - allow custom Wire object as transaction function argument
// 2020-01-20 - hardija : complete support for Teensy 3.x
// 2015-10-30 - simondlevy : support i2c_t3 for Teensy3.1
// 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications
// 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan)
// 2012-06-09 - fix major issue with reading > 32 bytes at a time with Arduino Wire
// - add compiler warnings when using outdated or IDE or limited I2Cdev implementation
// 2011-11-01 - fix write*Bits mask calculation (thanks sasquatch @ Arduino forums)
// 2011-10-03 - added automatic Arduino version detection for ease of use
// 2011-10-02 - added Gene Knight's NBWire TwoWire class implementation with small modifications
// 2011-08-31 - added support for Arduino 1.0 Wire library (methods are different from 0.x)
// 2011-08-03 - added optional timeout parameter to read* methods to easily change from default
// 2011-08-02 - added support for 16-bit registers
// - fixed incorrect Doxygen comments on some methods
// - added timeout value for read operations (thanks mem @ Arduino forums)
// 2011-07-30 - changed read/write function structures to return success or byte counts
// - made all methods static for multi-device memory savings
// 2011-07-28 - initial release
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2013 Jeff Rowberg
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.
===============================================
*/
#ifndef _I2CDEV_H_
#define _I2CDEV_H_
// -----------------------------------------------------------------------------
// Enable deprecated pgmspace typedefs in avr-libc
// -----------------------------------------------------------------------------
#define __PROG_TYPES_COMPAT__
// -----------------------------------------------------------------------------
// I2C interface implementation setting
// -----------------------------------------------------------------------------
#ifndef I2CDEV_IMPLEMENTATION
#define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE
//#define I2CDEV_IMPLEMENTATION I2CDEV_TEENSY_3X_WIRE
//#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_SBWIRE
//#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_FASTWIRE
#endif // I2CDEV_IMPLEMENTATION
// comment this out if you are using a non-optimal IDE/implementation setting
// but want the compiler to shut up about it
#define I2CDEV_IMPLEMENTATION_WARNINGS
// -----------------------------------------------------------------------------
// I2C interface implementation options
// -----------------------------------------------------------------------------
#define I2CDEV_ARDUINO_WIRE 1 // Wire object from Arduino
#define I2CDEV_BUILTIN_NBWIRE 2 // Tweaked Wire object from Gene Knight's NBWire project
// ^^^ NBWire implementation is still buggy w/some interrupts!
#define I2CDEV_BUILTIN_FASTWIRE 3 // FastWire object from Francesco Ferrara's project
#define I2CDEV_I2CMASTER_LIBRARY 4 // I2C object from DSSCircuits I2C-Master Library at https://github.com/DSSCircuits/I2C-Master-Library
#define I2CDEV_BUILTIN_SBWIRE 5 // I2C object from Shuning (Steve) Bian's SBWire Library at https://github.com/freespace/SBWire
#define I2CDEV_TEENSY_3X_WIRE 6 // Teensy 3.x support using i2c_t3 library
// -----------------------------------------------------------------------------
// Arduino-style "Serial.print" debug constant (uncomment to enable)
// -----------------------------------------------------------------------------
//#define I2CDEV_SERIAL_DEBUG
#ifdef ARDUINO
#if ARDUINO < 100
#include "WProgram.h"
#else
#include "Arduino.h"
#endif
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include <Wire.h>
#endif
#if I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE
#include <i2c_t3.h>
#endif
#if I2CDEV_IMPLEMENTATION == I2CDEV_I2CMASTER_LIBRARY
#include <I2C.h>
#endif
#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE
#include "SBWire.h"
#endif
#endif
#ifdef SPARK
#include "application.h"
#define ARDUINO 101
#define BUFFER_LENGTH 32
#endif
#ifndef I2CDEVLIB_WIRE_BUFFER_LENGTH
#if defined(I2C_BUFFER_LENGTH)
// Arduino ESP32 core Wire uses this
#define I2CDEVLIB_WIRE_BUFFER_LENGTH I2C_BUFFER_LENGTH
#elif defined(BUFFER_LENGTH)
// Arduino AVR core Wire and many others use this
#define I2CDEVLIB_WIRE_BUFFER_LENGTH BUFFER_LENGTH
#elif defined(SERIAL_BUFFER_SIZE)
// Arduino SAMD core Wire uses this
#define I2CDEVLIB_WIRE_BUFFER_LENGTH SERIAL_BUFFER_SIZE
#else
// should be a safe fallback, though possibly inefficient
#define I2CDEVLIB_WIRE_BUFFER_LENGTH 32
#endif
#endif
// 1000ms default read timeout (modify with "I2Cdev::readTimeout = [ms];")
#define I2CDEV_DEFAULT_READ_TIMEOUT 1000
class I2Cdev {
public:
I2Cdev();
static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0);
static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0);
static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0);
static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0);
static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0);
static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0);
static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0);
static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0);
static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data, void *wireObj=0);
static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data, void *wireObj=0);
static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data, void *wireObj=0);
static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data, void *wireObj=0);
static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data, void *wireObj=0);
static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data, void *wireObj=0);
static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, void *wireObj=0);
static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, void *wireObj=0);
static uint16_t readTimeout;
};
#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
//////////////////////
// FastWire 0.24
// This is a library to help faster programs to read I2C devices.
// Copyright(C) 2012
// Francesco Ferrara
//////////////////////
/* Master */
#define TW_START 0x08
#define TW_REP_START 0x10
/* Master Transmitter */
#define TW_MT_SLA_ACK 0x18
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_ACK 0x28
#define TW_MT_DATA_NACK 0x30
#define TW_MT_ARB_LOST 0x38
/* Master Receiver */
#define TW_MR_ARB_LOST 0x38
#define TW_MR_SLA_ACK 0x40
#define TW_MR_SLA_NACK 0x48
#define TW_MR_DATA_ACK 0x50
#define TW_MR_DATA_NACK 0x58
#define TW_OK 0
#define TW_ERROR 1
class Fastwire {
private:
static boolean waitInt();
public:
static void setup(int khz, boolean pullup);
static byte beginTransmission(byte device);
static byte write(byte value);
static byte writeBuf(byte device, byte address, byte *data, byte num);
static byte readBuf(byte device, byte address, byte *data, byte num);
static void reset();
static byte stop();
};
#endif
#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
// NBWire implementation based heavily on code by Gene Knight <Gene@Telobot.com>
// Originally posted on the Arduino forum at http://arduino.cc/forum/index.php/topic,70705.0.html
// Originally offered to the i2cdevlib project at http://arduino.cc/forum/index.php/topic,68210.30.html
#define NBWIRE_BUFFER_LENGTH 32
class TwoWire {
private:
static uint8_t rxBuffer[];
static uint8_t rxBufferIndex;
static uint8_t rxBufferLength;
static uint8_t txAddress;
static uint8_t txBuffer[];
static uint8_t txBufferIndex;
static uint8_t txBufferLength;
// static uint8_t transmitting;
static void (*user_onRequest)(void);
static void (*user_onReceive)(int);
static void onRequestService(void);
static void onReceiveService(uint8_t*, int);
public:
TwoWire();
void begin();
void begin(uint8_t);
void begin(int);
void beginTransmission(uint8_t);
//void beginTransmission(int);
uint8_t endTransmission(uint16_t timeout=0);
void nbendTransmission(void (*function)(int)) ;
uint8_t requestFrom(uint8_t, int, uint16_t timeout=0);
//uint8_t requestFrom(int, int);
void nbrequestFrom(uint8_t, int, void (*function)(int));
void send(uint8_t);
void send(uint8_t*, uint8_t);
//void send(int);
void send(char*);
uint8_t available(void);
uint8_t receive(void);
void onReceive(void (*)(int));
void onRequest(void (*)(void));
};
#define TWI_READY 0
#define TWI_MRX 1
#define TWI_MTX 2
#define TWI_SRX 3
#define TWI_STX 4
#define TW_WRITE 0
#define TW_READ 1
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_NACK 0x30
#define CPU_FREQ 16000000L
#define TWI_FREQ 100000L
#define TWI_BUFFER_LENGTH 32
/* TWI Status is in TWSR, in the top 5 bits: TWS7 - TWS3 */
#define TW_STATUS_MASK ((1 << TWS7)|(1 << TWS6)|(1 << TWS5)|(1 << TWS4)|(1 << TWS3))
#define TW_STATUS (TWSR & TW_STATUS_MASK)
#define TW_START 0x08
#define TW_REP_START 0x10
#define TW_MT_SLA_ACK 0x18
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_ACK 0x28
#define TW_MT_DATA_NACK 0x30
#define TW_MT_ARB_LOST 0x38
#define TW_MR_ARB_LOST 0x38
#define TW_MR_SLA_ACK 0x40
#define TW_MR_SLA_NACK 0x48
#define TW_MR_DATA_ACK 0x50
#define TW_MR_DATA_NACK 0x58
#define TW_ST_SLA_ACK 0xA8
#define TW_ST_ARB_LOST_SLA_ACK 0xB0
#define TW_ST_DATA_ACK 0xB8
#define TW_ST_DATA_NACK 0xC0
#define TW_ST_LAST_DATA 0xC8
#define TW_SR_SLA_ACK 0x60
#define TW_SR_ARB_LOST_SLA_ACK 0x68
#define TW_SR_GCALL_ACK 0x70
#define TW_SR_ARB_LOST_GCALL_ACK 0x78
#define TW_SR_DATA_ACK 0x80
#define TW_SR_DATA_NACK 0x88
#define TW_SR_GCALL_DATA_ACK 0x90
#define TW_SR_GCALL_DATA_NACK 0x98
#define TW_SR_STOP 0xA0
#define TW_NO_INFO 0xF8
#define TW_BUS_ERROR 0x00
//#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
//#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
#ifndef sbi // set bit
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= (1 << bit))
#endif // sbi
#ifndef cbi // clear bit
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~(1 << bit))
#endif // cbi
extern TwoWire Wire;
#endif // I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
#endif /* _I2CDEV_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,874 @@
// I2Cdev library collection - MPU6050 I2C device class
// Based on InvenSense MPU-6050 register map document rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
// 10/3/2011 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2021/09/27 - split implementations out of header files, finally
// ... - ongoing debug release
// NOTE: THIS IS ONLY A PARIAL RELEASE. THIS DEVICE CLASS IS CURRENTLY UNDERGOING ACTIVE
// DEVELOPMENT AND IS STILL MISSING SOME IMPORTANT FEATURES. PLEASE KEEP THIS IN MIND IF
// YOU DECIDE TO USE THIS PARTICULAR CODE FOR ANYTHING.
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
#ifndef _MPU6050_H_
#define _MPU6050_H_
#include "I2Cdev.h"
#include "helper_3dmath.h"
// supporting link: http://forum.arduino.cc/index.php?&topic=143444.msg1079517#msg1079517
// also: http://forum.arduino.cc/index.php?&topic=141571.msg1062899#msg1062899s
#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP32)
#include <pgmspace.h>
#else
//#define PROGMEM /* empty */
//#define pgm_read_byte(x) (*(x))
//#define pgm_read_word(x) (*(x))
//#define pgm_read_float(x) (*(x))
//#define PSTR(STR) STR
#endif
#define MPU6050_ADDRESS_AD0_LOW 0x68 // address pin low (GND), default for InvenSense evaluation board
#define MPU6050_ADDRESS_AD0_HIGH 0x69 // address pin high (VCC)
#define MPU6050_DEFAULT_ADDRESS MPU6050_ADDRESS_AD0_LOW
#define MPU6050_RA_XG_OFFS_TC 0x00 //[7] PWR_MODE, [6:1] XG_OFFS_TC, [0] OTP_BNK_VLD
#define MPU6050_RA_YG_OFFS_TC 0x01 //[7] PWR_MODE, [6:1] YG_OFFS_TC, [0] OTP_BNK_VLD
#define MPU6050_RA_ZG_OFFS_TC 0x02 //[7] PWR_MODE, [6:1] ZG_OFFS_TC, [0] OTP_BNK_VLD
#define MPU6050_RA_X_FINE_GAIN 0x03 //[7:0] X_FINE_GAIN
#define MPU6050_RA_Y_FINE_GAIN 0x04 //[7:0] Y_FINE_GAIN
#define MPU6050_RA_Z_FINE_GAIN 0x05 //[7:0] Z_FINE_GAIN
#define MPU6050_RA_XA_OFFS_H 0x06 //[15:0] XA_OFFS
#define MPU6050_RA_XA_OFFS_L_TC 0x07
#define MPU6050_RA_YA_OFFS_H 0x08 //[15:0] YA_OFFS
#define MPU6050_RA_YA_OFFS_L_TC 0x09
#define MPU6050_RA_ZA_OFFS_H 0x0A //[15:0] ZA_OFFS
#define MPU6050_RA_ZA_OFFS_L_TC 0x0B
#define MPU6050_RA_SELF_TEST_X 0x0D //[7:5] XA_TEST[4-2], [4:0] XG_TEST[4-0]
#define MPU6050_RA_SELF_TEST_Y 0x0E //[7:5] YA_TEST[4-2], [4:0] YG_TEST[4-0]
#define MPU6050_RA_SELF_TEST_Z 0x0F //[7:5] ZA_TEST[4-2], [4:0] ZG_TEST[4-0]
#define MPU6050_RA_SELF_TEST_A 0x10 //[5:4] XA_TEST[1-0], [3:2] YA_TEST[1-0], [1:0] ZA_TEST[1-0]
#define MPU6050_RA_XG_OFFS_USRH 0x13 //[15:0] XG_OFFS_USR
#define MPU6050_RA_XG_OFFS_USRL 0x14
#define MPU6050_RA_YG_OFFS_USRH 0x15 //[15:0] YG_OFFS_USR
#define MPU6050_RA_YG_OFFS_USRL 0x16
#define MPU6050_RA_ZG_OFFS_USRH 0x17 //[15:0] ZG_OFFS_USR
#define MPU6050_RA_ZG_OFFS_USRL 0x18
#define MPU6050_RA_SMPLRT_DIV 0x19
#define MPU6050_RA_CONFIG 0x1A
#define MPU6050_RA_GYRO_CONFIG 0x1B
#define MPU6050_RA_ACCEL_CONFIG 0x1C
#define MPU6050_RA_FF_THR 0x1D
#define MPU6050_RA_FF_DUR 0x1E
#define MPU6050_RA_MOT_THR 0x1F
#define MPU6050_RA_MOT_DUR 0x20
#define MPU6050_RA_ZRMOT_THR 0x21
#define MPU6050_RA_ZRMOT_DUR 0x22
#define MPU6050_RA_FIFO_EN 0x23
#define MPU6050_RA_I2C_MST_CTRL 0x24
#define MPU6050_RA_I2C_SLV0_ADDR 0x25
#define MPU6050_RA_I2C_SLV0_REG 0x26
#define MPU6050_RA_I2C_SLV0_CTRL 0x27
#define MPU6050_RA_I2C_SLV1_ADDR 0x28
#define MPU6050_RA_I2C_SLV1_REG 0x29
#define MPU6050_RA_I2C_SLV1_CTRL 0x2A
#define MPU6050_RA_I2C_SLV2_ADDR 0x2B
#define MPU6050_RA_I2C_SLV2_REG 0x2C
#define MPU6050_RA_I2C_SLV2_CTRL 0x2D
#define MPU6050_RA_I2C_SLV3_ADDR 0x2E
#define MPU6050_RA_I2C_SLV3_REG 0x2F
#define MPU6050_RA_I2C_SLV3_CTRL 0x30
#define MPU6050_RA_I2C_SLV4_ADDR 0x31
#define MPU6050_RA_I2C_SLV4_REG 0x32
#define MPU6050_RA_I2C_SLV4_DO 0x33
#define MPU6050_RA_I2C_SLV4_CTRL 0x34
#define MPU6050_RA_I2C_SLV4_DI 0x35
#define MPU6050_RA_I2C_MST_STATUS 0x36
#define MPU6050_RA_INT_PIN_CFG 0x37
#define MPU6050_RA_INT_ENABLE 0x38
#define MPU6050_RA_DMP_INT_STATUS 0x39
#define MPU6050_RA_INT_STATUS 0x3A
#define MPU6050_RA_ACCEL_XOUT_H 0x3B
#define MPU6050_RA_ACCEL_XOUT_L 0x3C
#define MPU6050_RA_ACCEL_YOUT_H 0x3D
#define MPU6050_RA_ACCEL_YOUT_L 0x3E
#define MPU6050_RA_ACCEL_ZOUT_H 0x3F
#define MPU6050_RA_ACCEL_ZOUT_L 0x40
#define MPU6050_RA_TEMP_OUT_H 0x41
#define MPU6050_RA_TEMP_OUT_L 0x42
#define MPU6050_RA_GYRO_XOUT_H 0x43
#define MPU6050_RA_GYRO_XOUT_L 0x44
#define MPU6050_RA_GYRO_YOUT_H 0x45
#define MPU6050_RA_GYRO_YOUT_L 0x46
#define MPU6050_RA_GYRO_ZOUT_H 0x47
#define MPU6050_RA_GYRO_ZOUT_L 0x48
#define MPU6050_RA_EXT_SENS_DATA_00 0x49
#define MPU6050_RA_EXT_SENS_DATA_01 0x4A
#define MPU6050_RA_EXT_SENS_DATA_02 0x4B
#define MPU6050_RA_EXT_SENS_DATA_03 0x4C
#define MPU6050_RA_EXT_SENS_DATA_04 0x4D
#define MPU6050_RA_EXT_SENS_DATA_05 0x4E
#define MPU6050_RA_EXT_SENS_DATA_06 0x4F
#define MPU6050_RA_EXT_SENS_DATA_07 0x50
#define MPU6050_RA_EXT_SENS_DATA_08 0x51
#define MPU6050_RA_EXT_SENS_DATA_09 0x52
#define MPU6050_RA_EXT_SENS_DATA_10 0x53
#define MPU6050_RA_EXT_SENS_DATA_11 0x54
#define MPU6050_RA_EXT_SENS_DATA_12 0x55
#define MPU6050_RA_EXT_SENS_DATA_13 0x56
#define MPU6050_RA_EXT_SENS_DATA_14 0x57
#define MPU6050_RA_EXT_SENS_DATA_15 0x58
#define MPU6050_RA_EXT_SENS_DATA_16 0x59
#define MPU6050_RA_EXT_SENS_DATA_17 0x5A
#define MPU6050_RA_EXT_SENS_DATA_18 0x5B
#define MPU6050_RA_EXT_SENS_DATA_19 0x5C
#define MPU6050_RA_EXT_SENS_DATA_20 0x5D
#define MPU6050_RA_EXT_SENS_DATA_21 0x5E
#define MPU6050_RA_EXT_SENS_DATA_22 0x5F
#define MPU6050_RA_EXT_SENS_DATA_23 0x60
#define MPU6050_RA_MOT_DETECT_STATUS 0x61
#define MPU6050_RA_I2C_SLV0_DO 0x63
#define MPU6050_RA_I2C_SLV1_DO 0x64
#define MPU6050_RA_I2C_SLV2_DO 0x65
#define MPU6050_RA_I2C_SLV3_DO 0x66
#define MPU6050_RA_I2C_MST_DELAY_CTRL 0x67
#define MPU6050_RA_SIGNAL_PATH_RESET 0x68
#define MPU6050_RA_MOT_DETECT_CTRL 0x69
#define MPU6050_RA_USER_CTRL 0x6A
#define MPU6050_RA_PWR_MGMT_1 0x6B
#define MPU6050_RA_PWR_MGMT_2 0x6C
#define MPU6050_RA_BANK_SEL 0x6D
#define MPU6050_RA_MEM_START_ADDR 0x6E
#define MPU6050_RA_MEM_R_W 0x6F
#define MPU6050_RA_DMP_CFG_1 0x70
#define MPU6050_RA_DMP_CFG_2 0x71
#define MPU6050_RA_FIFO_COUNTH 0x72
#define MPU6050_RA_FIFO_COUNTL 0x73
#define MPU6050_RA_FIFO_R_W 0x74
#define MPU6050_RA_WHO_AM_I 0x75
#define MPU6050_SELF_TEST_XA_1_BIT 0x07
#define MPU6050_SELF_TEST_XA_1_LENGTH 0x03
#define MPU6050_SELF_TEST_XA_2_BIT 0x05
#define MPU6050_SELF_TEST_XA_2_LENGTH 0x02
#define MPU6050_SELF_TEST_YA_1_BIT 0x07
#define MPU6050_SELF_TEST_YA_1_LENGTH 0x03
#define MPU6050_SELF_TEST_YA_2_BIT 0x03
#define MPU6050_SELF_TEST_YA_2_LENGTH 0x02
#define MPU6050_SELF_TEST_ZA_1_BIT 0x07
#define MPU6050_SELF_TEST_ZA_1_LENGTH 0x03
#define MPU6050_SELF_TEST_ZA_2_BIT 0x01
#define MPU6050_SELF_TEST_ZA_2_LENGTH 0x02
#define MPU6050_SELF_TEST_XG_1_BIT 0x04
#define MPU6050_SELF_TEST_XG_1_LENGTH 0x05
#define MPU6050_SELF_TEST_YG_1_BIT 0x04
#define MPU6050_SELF_TEST_YG_1_LENGTH 0x05
#define MPU6050_SELF_TEST_ZG_1_BIT 0x04
#define MPU6050_SELF_TEST_ZG_1_LENGTH 0x05
#define MPU6050_TC_PWR_MODE_BIT 7
#define MPU6050_TC_OFFSET_BIT 6
#define MPU6050_TC_OFFSET_LENGTH 6
#define MPU6050_TC_OTP_BNK_VLD_BIT 0
#define MPU6050_VDDIO_LEVEL_VLOGIC 0
#define MPU6050_VDDIO_LEVEL_VDD 1
#define MPU6050_CFG_EXT_SYNC_SET_BIT 5
#define MPU6050_CFG_EXT_SYNC_SET_LENGTH 3
#define MPU6050_CFG_DLPF_CFG_BIT 2
#define MPU6050_CFG_DLPF_CFG_LENGTH 3
#define MPU6050_EXT_SYNC_DISABLED 0x0
#define MPU6050_EXT_SYNC_TEMP_OUT_L 0x1
#define MPU6050_EXT_SYNC_GYRO_XOUT_L 0x2
#define MPU6050_EXT_SYNC_GYRO_YOUT_L 0x3
#define MPU6050_EXT_SYNC_GYRO_ZOUT_L 0x4
#define MPU6050_EXT_SYNC_ACCEL_XOUT_L 0x5
#define MPU6050_EXT_SYNC_ACCEL_YOUT_L 0x6
#define MPU6050_EXT_SYNC_ACCEL_ZOUT_L 0x7
#define MPU6050_DLPF_BW_256 0x00
#define MPU6050_DLPF_BW_188 0x01
#define MPU6050_DLPF_BW_98 0x02
#define MPU6050_DLPF_BW_42 0x03
#define MPU6050_DLPF_BW_20 0x04
#define MPU6050_DLPF_BW_10 0x05
#define MPU6050_DLPF_BW_5 0x06
#define MPU6050_GCONFIG_FS_SEL_BIT 4
#define MPU6050_GCONFIG_FS_SEL_LENGTH 2
#define MPU6050_GYRO_FS_250 0x00
#define MPU6050_GYRO_FS_500 0x01
#define MPU6050_GYRO_FS_1000 0x02
#define MPU6050_GYRO_FS_2000 0x03
#define MPU6050_ACONFIG_XA_ST_BIT 7
#define MPU6050_ACONFIG_YA_ST_BIT 6
#define MPU6050_ACONFIG_ZA_ST_BIT 5
#define MPU6050_ACONFIG_AFS_SEL_BIT 4
#define MPU6050_ACONFIG_AFS_SEL_LENGTH 2
#define MPU6050_ACONFIG_ACCEL_HPF_BIT 2
#define MPU6050_ACONFIG_ACCEL_HPF_LENGTH 3
#define MPU6050_ACCEL_FS_2 0x00
#define MPU6050_ACCEL_FS_4 0x01
#define MPU6050_ACCEL_FS_8 0x02
#define MPU6050_ACCEL_FS_16 0x03
#define MPU6050_DHPF_RESET 0x00
#define MPU6050_DHPF_5 0x01
#define MPU6050_DHPF_2P5 0x02
#define MPU6050_DHPF_1P25 0x03
#define MPU6050_DHPF_0P63 0x04
#define MPU6050_DHPF_HOLD 0x07
#define MPU6050_TEMP_FIFO_EN_BIT 7
#define MPU6050_XG_FIFO_EN_BIT 6
#define MPU6050_YG_FIFO_EN_BIT 5
#define MPU6050_ZG_FIFO_EN_BIT 4
#define MPU6050_ACCEL_FIFO_EN_BIT 3
#define MPU6050_SLV2_FIFO_EN_BIT 2
#define MPU6050_SLV1_FIFO_EN_BIT 1
#define MPU6050_SLV0_FIFO_EN_BIT 0
#define MPU6050_MULT_MST_EN_BIT 7
#define MPU6050_WAIT_FOR_ES_BIT 6
#define MPU6050_SLV_3_FIFO_EN_BIT 5
#define MPU6050_I2C_MST_P_NSR_BIT 4
#define MPU6050_I2C_MST_CLK_BIT 3
#define MPU6050_I2C_MST_CLK_LENGTH 4
#define MPU6050_CLOCK_DIV_348 0x0
#define MPU6050_CLOCK_DIV_333 0x1
#define MPU6050_CLOCK_DIV_320 0x2
#define MPU6050_CLOCK_DIV_308 0x3
#define MPU6050_CLOCK_DIV_296 0x4
#define MPU6050_CLOCK_DIV_286 0x5
#define MPU6050_CLOCK_DIV_276 0x6
#define MPU6050_CLOCK_DIV_267 0x7
#define MPU6050_CLOCK_DIV_258 0x8
#define MPU6050_CLOCK_DIV_500 0x9
#define MPU6050_CLOCK_DIV_471 0xA
#define MPU6050_CLOCK_DIV_444 0xB
#define MPU6050_CLOCK_DIV_421 0xC
#define MPU6050_CLOCK_DIV_400 0xD
#define MPU6050_CLOCK_DIV_381 0xE
#define MPU6050_CLOCK_DIV_364 0xF
#define MPU6050_I2C_SLV_RW_BIT 7
#define MPU6050_I2C_SLV_ADDR_BIT 6
#define MPU6050_I2C_SLV_ADDR_LENGTH 7
#define MPU6050_I2C_SLV_EN_BIT 7
#define MPU6050_I2C_SLV_BYTE_SW_BIT 6
#define MPU6050_I2C_SLV_REG_DIS_BIT 5
#define MPU6050_I2C_SLV_GRP_BIT 4
#define MPU6050_I2C_SLV_LEN_BIT 3
#define MPU6050_I2C_SLV_LEN_LENGTH 4
#define MPU6050_I2C_SLV4_RW_BIT 7
#define MPU6050_I2C_SLV4_ADDR_BIT 6
#define MPU6050_I2C_SLV4_ADDR_LENGTH 7
#define MPU6050_I2C_SLV4_EN_BIT 7
#define MPU6050_I2C_SLV4_INT_EN_BIT 6
#define MPU6050_I2C_SLV4_REG_DIS_BIT 5
#define MPU6050_I2C_SLV4_MST_DLY_BIT 4
#define MPU6050_I2C_SLV4_MST_DLY_LENGTH 5
#define MPU6050_MST_PASS_THROUGH_BIT 7
#define MPU6050_MST_I2C_SLV4_DONE_BIT 6
#define MPU6050_MST_I2C_LOST_ARB_BIT 5
#define MPU6050_MST_I2C_SLV4_NACK_BIT 4
#define MPU6050_MST_I2C_SLV3_NACK_BIT 3
#define MPU6050_MST_I2C_SLV2_NACK_BIT 2
#define MPU6050_MST_I2C_SLV1_NACK_BIT 1
#define MPU6050_MST_I2C_SLV0_NACK_BIT 0
#define MPU6050_INTCFG_INT_LEVEL_BIT 7
#define MPU6050_INTCFG_INT_OPEN_BIT 6
#define MPU6050_INTCFG_LATCH_INT_EN_BIT 5
#define MPU6050_INTCFG_INT_RD_CLEAR_BIT 4
#define MPU6050_INTCFG_FSYNC_INT_LEVEL_BIT 3
#define MPU6050_INTCFG_FSYNC_INT_EN_BIT 2
#define MPU6050_INTCFG_I2C_BYPASS_EN_BIT 1
#define MPU6050_INTCFG_CLKOUT_EN_BIT 0
#define MPU6050_INTMODE_ACTIVEHIGH 0x00
#define MPU6050_INTMODE_ACTIVELOW 0x01
#define MPU6050_INTDRV_PUSHPULL 0x00
#define MPU6050_INTDRV_OPENDRAIN 0x01
#define MPU6050_INTLATCH_50USPULSE 0x00
#define MPU6050_INTLATCH_WAITCLEAR 0x01
#define MPU6050_INTCLEAR_STATUSREAD 0x00
#define MPU6050_INTCLEAR_ANYREAD 0x01
#define MPU6050_INTERRUPT_FF_BIT 7
#define MPU6050_INTERRUPT_MOT_BIT 6
#define MPU6050_INTERRUPT_ZMOT_BIT 5
#define MPU6050_INTERRUPT_FIFO_OFLOW_BIT 4
#define MPU6050_INTERRUPT_I2C_MST_INT_BIT 3
#define MPU6050_INTERRUPT_PLL_RDY_INT_BIT 2
#define MPU6050_INTERRUPT_DMP_INT_BIT 1
#define MPU6050_INTERRUPT_DATA_RDY_BIT 0
// TODO: figure out what these actually do
// UMPL source code is not very obivous
#define MPU6050_DMPINT_5_BIT 5
#define MPU6050_DMPINT_4_BIT 4
#define MPU6050_DMPINT_3_BIT 3
#define MPU6050_DMPINT_2_BIT 2
#define MPU6050_DMPINT_1_BIT 1
#define MPU6050_DMPINT_0_BIT 0
#define MPU6050_MOTION_MOT_XNEG_BIT 7
#define MPU6050_MOTION_MOT_XPOS_BIT 6
#define MPU6050_MOTION_MOT_YNEG_BIT 5
#define MPU6050_MOTION_MOT_YPOS_BIT 4
#define MPU6050_MOTION_MOT_ZNEG_BIT 3
#define MPU6050_MOTION_MOT_ZPOS_BIT 2
#define MPU6050_MOTION_MOT_ZRMOT_BIT 0
#define MPU6050_DELAYCTRL_DELAY_ES_SHADOW_BIT 7
#define MPU6050_DELAYCTRL_I2C_SLV4_DLY_EN_BIT 4
#define MPU6050_DELAYCTRL_I2C_SLV3_DLY_EN_BIT 3
#define MPU6050_DELAYCTRL_I2C_SLV2_DLY_EN_BIT 2
#define MPU6050_DELAYCTRL_I2C_SLV1_DLY_EN_BIT 1
#define MPU6050_DELAYCTRL_I2C_SLV0_DLY_EN_BIT 0
#define MPU6050_PATHRESET_GYRO_RESET_BIT 2
#define MPU6050_PATHRESET_ACCEL_RESET_BIT 1
#define MPU6050_PATHRESET_TEMP_RESET_BIT 0
#define MPU6050_DETECT_ACCEL_ON_DELAY_BIT 5
#define MPU6050_DETECT_ACCEL_ON_DELAY_LENGTH 2
#define MPU6050_DETECT_FF_COUNT_BIT 3
#define MPU6050_DETECT_FF_COUNT_LENGTH 2
#define MPU6050_DETECT_MOT_COUNT_BIT 1
#define MPU6050_DETECT_MOT_COUNT_LENGTH 2
#define MPU6050_DETECT_DECREMENT_RESET 0x0
#define MPU6050_DETECT_DECREMENT_1 0x1
#define MPU6050_DETECT_DECREMENT_2 0x2
#define MPU6050_DETECT_DECREMENT_4 0x3
#define MPU6050_USERCTRL_DMP_EN_BIT 7
#define MPU6050_USERCTRL_FIFO_EN_BIT 6
#define MPU6050_USERCTRL_I2C_MST_EN_BIT 5
#define MPU6050_USERCTRL_I2C_IF_DIS_BIT 4
#define MPU6050_USERCTRL_DMP_RESET_BIT 3
#define MPU6050_USERCTRL_FIFO_RESET_BIT 2
#define MPU6050_USERCTRL_I2C_MST_RESET_BIT 1
#define MPU6050_USERCTRL_SIG_COND_RESET_BIT 0
#define MPU6050_PWR1_DEVICE_RESET_BIT 7
#define MPU6050_PWR1_SLEEP_BIT 6
#define MPU6050_PWR1_CYCLE_BIT 5
#define MPU6050_PWR1_TEMP_DIS_BIT 3
#define MPU6050_PWR1_CLKSEL_BIT 2
#define MPU6050_PWR1_CLKSEL_LENGTH 3
#define MPU6050_CLOCK_INTERNAL 0x00
#define MPU6050_CLOCK_PLL_XGYRO 0x01
#define MPU6050_CLOCK_PLL_YGYRO 0x02
#define MPU6050_CLOCK_PLL_ZGYRO 0x03
#define MPU6050_CLOCK_PLL_EXT32K 0x04
#define MPU6050_CLOCK_PLL_EXT19M 0x05
#define MPU6050_CLOCK_KEEP_RESET 0x07
#define MPU6050_PWR2_LP_WAKE_CTRL_BIT 7
#define MPU6050_PWR2_LP_WAKE_CTRL_LENGTH 2
#define MPU6050_PWR2_STBY_XA_BIT 5
#define MPU6050_PWR2_STBY_YA_BIT 4
#define MPU6050_PWR2_STBY_ZA_BIT 3
#define MPU6050_PWR2_STBY_XG_BIT 2
#define MPU6050_PWR2_STBY_YG_BIT 1
#define MPU6050_PWR2_STBY_ZG_BIT 0
#define MPU6050_WAKE_FREQ_1P25 0x0
#define MPU6050_WAKE_FREQ_2P5 0x1
#define MPU6050_WAKE_FREQ_5 0x2
#define MPU6050_WAKE_FREQ_10 0x3
#define MPU6050_BANKSEL_PRFTCH_EN_BIT 6
#define MPU6050_BANKSEL_CFG_USER_BANK_BIT 5
#define MPU6050_BANKSEL_MEM_SEL_BIT 4
#define MPU6050_BANKSEL_MEM_SEL_LENGTH 5
#define MPU6050_WHO_AM_I_BIT 6
#define MPU6050_WHO_AM_I_LENGTH 6
#define MPU6050_DMP_MEMORY_BANKS 8
#define MPU6050_DMP_MEMORY_BANK_SIZE 256
#define MPU6050_DMP_MEMORY_CHUNK_SIZE 16
#define MPU6050_FIFO_DEFAULT_TIMEOUT 11000
enum class ACCEL_FS {
A2G,
A4G,
A8G,
A16G
};
enum class GYRO_FS {
G250DPS,
G500DPS,
G1000DPS,
G2000DPS
};
class MPU6050_Base {
public:
MPU6050_Base(uint8_t address=MPU6050_DEFAULT_ADDRESS, void *wireObj=0);
void initialize();
void initialize(ACCEL_FS accelRange, GYRO_FS gyroRange);
float get_acce_resolution();
float get_gyro_resolution();
bool testConnection();
// AUX_VDDIO register
uint8_t getAuxVDDIOLevel();
void setAuxVDDIOLevel(uint8_t level);
// SMPLRT_DIV register
uint8_t getRate();
void setRate(uint8_t rate);
// CONFIG register
uint8_t getExternalFrameSync();
void setExternalFrameSync(uint8_t sync);
uint8_t getDLPFMode();
void setDLPFMode(uint8_t bandwidth);
// GYRO_CONFIG register
uint8_t getFullScaleGyroRange();
void setFullScaleGyroRange(uint8_t range);
// SELF_TEST registers
uint8_t getAccelXSelfTestFactoryTrim();
uint8_t getAccelYSelfTestFactoryTrim();
uint8_t getAccelZSelfTestFactoryTrim();
uint8_t getGyroXSelfTestFactoryTrim();
uint8_t getGyroYSelfTestFactoryTrim();
uint8_t getGyroZSelfTestFactoryTrim();
// ACCEL_CONFIG register
bool getAccelXSelfTest();
void setAccelXSelfTest(bool enabled);
bool getAccelYSelfTest();
void setAccelYSelfTest(bool enabled);
bool getAccelZSelfTest();
void setAccelZSelfTest(bool enabled);
uint8_t getFullScaleAccelRange();
void setFullScaleAccelRange(uint8_t range);
uint8_t getDHPFMode();
void setDHPFMode(uint8_t mode);
// FF_THR register
uint8_t getFreefallDetectionThreshold();
void setFreefallDetectionThreshold(uint8_t threshold);
// FF_DUR register
uint8_t getFreefallDetectionDuration();
void setFreefallDetectionDuration(uint8_t duration);
// MOT_THR register
uint8_t getMotionDetectionThreshold();
void setMotionDetectionThreshold(uint8_t threshold);
// MOT_DUR register
uint8_t getMotionDetectionDuration();
void setMotionDetectionDuration(uint8_t duration);
// ZRMOT_THR register
uint8_t getZeroMotionDetectionThreshold();
void setZeroMotionDetectionThreshold(uint8_t threshold);
// ZRMOT_DUR register
uint8_t getZeroMotionDetectionDuration();
void setZeroMotionDetectionDuration(uint8_t duration);
// FIFO_EN register
bool getTempFIFOEnabled();
void setTempFIFOEnabled(bool enabled);
bool getXGyroFIFOEnabled();
void setXGyroFIFOEnabled(bool enabled);
bool getYGyroFIFOEnabled();
void setYGyroFIFOEnabled(bool enabled);
bool getZGyroFIFOEnabled();
void setZGyroFIFOEnabled(bool enabled);
bool getAccelFIFOEnabled();
void setAccelFIFOEnabled(bool enabled);
bool getSlave2FIFOEnabled();
void setSlave2FIFOEnabled(bool enabled);
bool getSlave1FIFOEnabled();
void setSlave1FIFOEnabled(bool enabled);
bool getSlave0FIFOEnabled();
void setSlave0FIFOEnabled(bool enabled);
// I2C_MST_CTRL register
bool getMultiMasterEnabled();
void setMultiMasterEnabled(bool enabled);
bool getWaitForExternalSensorEnabled();
void setWaitForExternalSensorEnabled(bool enabled);
bool getSlave3FIFOEnabled();
void setSlave3FIFOEnabled(bool enabled);
bool getSlaveReadWriteTransitionEnabled();
void setSlaveReadWriteTransitionEnabled(bool enabled);
uint8_t getMasterClockSpeed();
void setMasterClockSpeed(uint8_t speed);
// I2C_SLV* registers (Slave 0-3)
uint8_t getSlaveAddress(uint8_t num);
void setSlaveAddress(uint8_t num, uint8_t address);
uint8_t getSlaveRegister(uint8_t num);
void setSlaveRegister(uint8_t num, uint8_t reg);
bool getSlaveEnabled(uint8_t num);
void setSlaveEnabled(uint8_t num, bool enabled);
bool getSlaveWordByteSwap(uint8_t num);
void setSlaveWordByteSwap(uint8_t num, bool enabled);
bool getSlaveWriteMode(uint8_t num);
void setSlaveWriteMode(uint8_t num, bool mode);
bool getSlaveWordGroupOffset(uint8_t num);
void setSlaveWordGroupOffset(uint8_t num, bool enabled);
uint8_t getSlaveDataLength(uint8_t num);
void setSlaveDataLength(uint8_t num, uint8_t length);
// I2C_SLV* registers (Slave 4)
uint8_t getSlave4Address();
void setSlave4Address(uint8_t address);
uint8_t getSlave4Register();
void setSlave4Register(uint8_t reg);
void setSlave4OutputByte(uint8_t data);
bool getSlave4Enabled();
void setSlave4Enabled(bool enabled);
bool getSlave4InterruptEnabled();
void setSlave4InterruptEnabled(bool enabled);
bool getSlave4WriteMode();
void setSlave4WriteMode(bool mode);
uint8_t getSlave4MasterDelay();
void setSlave4MasterDelay(uint8_t delay);
uint8_t getSlate4InputByte();
// I2C_MST_STATUS register
bool getPassthroughStatus();
bool getSlave4IsDone();
bool getLostArbitration();
bool getSlave4Nack();
bool getSlave3Nack();
bool getSlave2Nack();
bool getSlave1Nack();
bool getSlave0Nack();
// INT_PIN_CFG register
bool getInterruptMode();
void setInterruptMode(bool mode);
bool getInterruptDrive();
void setInterruptDrive(bool drive);
bool getInterruptLatch();
void setInterruptLatch(bool latch);
bool getInterruptLatchClear();
void setInterruptLatchClear(bool clear);
bool getFSyncInterruptLevel();
void setFSyncInterruptLevel(bool level);
bool getFSyncInterruptEnabled();
void setFSyncInterruptEnabled(bool enabled);
bool getI2CBypassEnabled();
void setI2CBypassEnabled(bool enabled);
bool getClockOutputEnabled();
void setClockOutputEnabled(bool enabled);
// INT_ENABLE register
uint8_t getIntEnabled();
void setIntEnabled(uint8_t enabled);
bool getIntFreefallEnabled();
void setIntFreefallEnabled(bool enabled);
bool getIntMotionEnabled();
void setIntMotionEnabled(bool enabled);
bool getIntZeroMotionEnabled();
void setIntZeroMotionEnabled(bool enabled);
bool getIntFIFOBufferOverflowEnabled();
void setIntFIFOBufferOverflowEnabled(bool enabled);
bool getIntI2CMasterEnabled();
void setIntI2CMasterEnabled(bool enabled);
bool getIntDataReadyEnabled();
void setIntDataReadyEnabled(bool enabled);
// INT_STATUS register
uint8_t getIntStatus();
bool getIntFreefallStatus();
bool getIntMotionStatus();
bool getIntZeroMotionStatus();
bool getIntFIFOBufferOverflowStatus();
bool getIntI2CMasterStatus();
bool getIntDataReadyStatus();
// ACCEL_*OUT_* registers
void getMotion9(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz, int16_t* mx, int16_t* my, int16_t* mz);
void getMotion6(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz);
void getAcceleration(int16_t* x, int16_t* y, int16_t* z);
int16_t getAccelerationX();
int16_t getAccelerationY();
int16_t getAccelerationZ();
// TEMP_OUT_* registers
int16_t getTemperature();
// GYRO_*OUT_* registers
void getRotation(int16_t* x, int16_t* y, int16_t* z);
int16_t getRotationX();
int16_t getRotationY();
int16_t getRotationZ();
// EXT_SENS_DATA_* registers
uint8_t getExternalSensorByte(int position);
uint16_t getExternalSensorWord(int position);
uint32_t getExternalSensorDWord(int position);
// MOT_DETECT_STATUS register
uint8_t getMotionStatus();
bool getXNegMotionDetected();
bool getXPosMotionDetected();
bool getYNegMotionDetected();
bool getYPosMotionDetected();
bool getZNegMotionDetected();
bool getZPosMotionDetected();
bool getZeroMotionDetected();
// I2C_SLV*_DO register
void setSlaveOutputByte(uint8_t num, uint8_t data);
// I2C_MST_DELAY_CTRL register
bool getExternalShadowDelayEnabled();
void setExternalShadowDelayEnabled(bool enabled);
bool getSlaveDelayEnabled(uint8_t num);
void setSlaveDelayEnabled(uint8_t num, bool enabled);
// SIGNAL_PATH_RESET register
void resetGyroscopePath();
void resetAccelerometerPath();
void resetTemperaturePath();
// MOT_DETECT_CTRL register
uint8_t getAccelerometerPowerOnDelay();
void setAccelerometerPowerOnDelay(uint8_t delay);
uint8_t getFreefallDetectionCounterDecrement();
void setFreefallDetectionCounterDecrement(uint8_t decrement);
uint8_t getMotionDetectionCounterDecrement();
void setMotionDetectionCounterDecrement(uint8_t decrement);
// USER_CTRL register
bool getFIFOEnabled();
void setFIFOEnabled(bool enabled);
bool getI2CMasterModeEnabled();
void setI2CMasterModeEnabled(bool enabled);
void switchSPIEnabled(bool enabled);
void resetFIFO();
void resetI2CMaster();
void resetSensors();
// PWR_MGMT_1 register
void reset();
bool getSleepEnabled();
void setSleepEnabled(bool enabled);
bool getWakeCycleEnabled();
void setWakeCycleEnabled(bool enabled);
bool getTempSensorEnabled();
void setTempSensorEnabled(bool enabled);
uint8_t getClockSource();
void setClockSource(uint8_t source);
// PWR_MGMT_2 register
uint8_t getWakeFrequency();
void setWakeFrequency(uint8_t frequency);
bool getStandbyXAccelEnabled();
void setStandbyXAccelEnabled(bool enabled);
bool getStandbyYAccelEnabled();
void setStandbyYAccelEnabled(bool enabled);
bool getStandbyZAccelEnabled();
void setStandbyZAccelEnabled(bool enabled);
bool getStandbyXGyroEnabled();
void setStandbyXGyroEnabled(bool enabled);
bool getStandbyYGyroEnabled();
void setStandbyYGyroEnabled(bool enabled);
bool getStandbyZGyroEnabled();
void setStandbyZGyroEnabled(bool enabled);
// FIFO_COUNT_* registers
uint16_t getFIFOCount();
// FIFO_R_W register
uint8_t getFIFOByte();
int8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length);
void setFIFOByte(uint8_t data);
void getFIFOBytes(uint8_t *data, uint8_t length);
void setFIFOTimeout(uint32_t fifoTimeout);
uint32_t getFIFOTimeout();
// WHO_AM_I register
uint8_t getDeviceID();
void setDeviceID(uint8_t id);
// ======== UNDOCUMENTED/DMP REGISTERS/METHODS ========
// XG_OFFS_TC register
uint8_t getOTPBankValid();
void setOTPBankValid(bool enabled);
int8_t getXGyroOffsetTC();
void setXGyroOffsetTC(int8_t offset);
// YG_OFFS_TC register
int8_t getYGyroOffsetTC();
void setYGyroOffsetTC(int8_t offset);
// ZG_OFFS_TC register
int8_t getZGyroOffsetTC();
void setZGyroOffsetTC(int8_t offset);
// X_FINE_GAIN register
int8_t getXFineGain();
void setXFineGain(int8_t gain);
// Y_FINE_GAIN register
int8_t getYFineGain();
void setYFineGain(int8_t gain);
// Z_FINE_GAIN register
int8_t getZFineGain();
void setZFineGain(int8_t gain);
// XA_OFFS_* registers
int16_t getXAccelOffset();
void setXAccelOffset(int16_t offset);
// YA_OFFS_* register
int16_t getYAccelOffset();
void setYAccelOffset(int16_t offset);
// ZA_OFFS_* register
int16_t getZAccelOffset();
void setZAccelOffset(int16_t offset);
// XG_OFFS_USR* registers
int16_t getXGyroOffset();
void setXGyroOffset(int16_t offset);
// YG_OFFS_USR* register
int16_t getYGyroOffset();
void setYGyroOffset(int16_t offset);
// ZG_OFFS_USR* register
int16_t getZGyroOffset();
void setZGyroOffset(int16_t offset);
// INT_ENABLE register (DMP functions)
bool getIntPLLReadyEnabled();
void setIntPLLReadyEnabled(bool enabled);
bool getIntDMPEnabled();
void setIntDMPEnabled(bool enabled);
// DMP_INT_STATUS
bool getDMPInt5Status();
bool getDMPInt4Status();
bool getDMPInt3Status();
bool getDMPInt2Status();
bool getDMPInt1Status();
bool getDMPInt0Status();
// INT_STATUS register (DMP functions)
bool getIntPLLReadyStatus();
bool getIntDMPStatus();
// USER_CTRL register (DMP functions)
bool getDMPEnabled();
void setDMPEnabled(bool enabled);
void resetDMP();
// BANK_SEL register
void setMemoryBank(uint8_t bank, bool prefetchEnabled=false, bool userBank=false);
// MEM_START_ADDR register
void setMemoryStartAddress(uint8_t address);
// MEM_R_W register
uint8_t readMemoryByte();
void writeMemoryByte(uint8_t data);
void readMemoryBlock(uint8_t *data, uint16_t dataSize, uint8_t bank=0, uint8_t address=0);
bool writeMemoryBlock(const uint8_t *data, uint16_t dataSize, uint8_t bank=0, uint8_t address=0, bool verify=true, bool useProgMem=false);
bool writeProgMemoryBlock(const uint8_t *data, uint16_t dataSize, uint8_t bank=0, uint8_t address=0, bool verify=true);
bool writeDMPConfigurationSet(const uint8_t *data, uint16_t dataSize, bool useProgMem=false);
bool writeProgDMPConfigurationSet(const uint8_t *data, uint16_t dataSize);
// DMP_CFG_1 register
uint8_t getDMPConfig1();
void setDMPConfig1(uint8_t config);
// DMP_CFG_2 register
uint8_t getDMPConfig2();
void setDMPConfig2(uint8_t config);
// Calibration Routines
void CalibrateGyro(uint8_t Loops = 15); // Fine tune after setting offsets with less Loops.
void CalibrateAccel(uint8_t Loops = 15);// Fine tune after setting offsets with less Loops.
void PID(uint8_t ReadAddress, float kP,float kI, uint8_t Loops); // Does the math
void PrintActiveOffsets(); // See the results of the Calibration
int16_t * GetActiveOffsets();
protected:
uint8_t devAddr;
void *wireObj;
uint8_t buffer[14];
uint32_t fifoTimeout = MPU6050_FIFO_DEFAULT_TIMEOUT;
float accelerationResolution;
float gyroscopeResolution;
private:
int16_t offsets[6];
};
#ifndef I2CDEVLIB_MPU6050_TYPEDEF
#define I2CDEVLIB_MPU6050_TYPEDEF
typedef MPU6050_Base MPU6050;
#endif
#endif /* _MPU6050_H_ */

View File

@ -0,0 +1,632 @@
// I2Cdev library collection - MPU6050 I2C device class, 6-axis MotionApps 2.0 implementation
// Based on InvenSense MPU-6050 register map document rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
// 5/20/2013 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2021/09/27 - split implementations out of header files, finally
// 2019/07/08 - merged all DMP Firmware configuration items into the dmpMemory array
// - Simplified dmpInitialize() to accomidate the dmpmemory array alterations
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2021 Jeff Rowberg
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.
===============================================
*/
// MotionApps 2.0 DMP implementation, built using the MPU-6050EVB evaluation board
#define MPU6050_INCLUDE_DMP_MOTIONAPPS20
#include "MPU6050_6Axis_MotionApps20.h"
// Tom Carpenter's conditional PROGMEM code
// http://forum.arduino.cc/index.php?topic=129407.0
#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP32)
#include <pgmspace.h>
#else
// Teensy 3.0 library conditional PROGMEM code from Paul Stoffregen
#ifndef __PGMSPACE_H_
#define __PGMSPACE_H_ 1
#include <inttypes.h>
#define PROGMEM
#define PGM_P const char *
#define PSTR(str) (str)
#define F(x) x
typedef void prog_void;
typedef char prog_char;
typedef unsigned char prog_uchar;
typedef int8_t prog_int8_t;
typedef uint8_t prog_uint8_t;
typedef int16_t prog_int16_t;
typedef uint16_t prog_uint16_t;
typedef int32_t prog_int32_t;
typedef uint32_t prog_uint32_t;
#define strcpy_P(dest, src) strcpy((dest), (src))
#define strcat_P(dest, src) strcat((dest), (src))
#define strcmp_P(a, b) strcmp((a), (b))
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#define pgm_read_float(addr) (*(const float *)(addr))
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
#define pgm_read_word_near(addr) pgm_read_word(addr)
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
#define pgm_read_float_near(addr) pgm_read_float(addr)
#define pgm_read_byte_far(addr) pgm_read_byte(addr)
#define pgm_read_word_far(addr) pgm_read_word(addr)
#define pgm_read_dword_far(addr) pgm_read_dword(addr)
#define pgm_read_float_far(addr) pgm_read_float(addr)
#endif
#endif
/* Source is from the InvenSense MotionApps v2 demo code. Original source is
* unavailable, unless you happen to be amazing as decompiling binary by
* hand (in which case, please contact me, and I'm totally serious).
*
* Also, I'd like to offer many, many thanks to Noah Zerkin for all of the
* DMP reverse-engineering he did to help make this bit of wizardry
* possible.
*/
// NOTE! Enabling DEBUG adds about 3.3kB to the flash program size.
// Debug output is now working even on ATMega328P MCUs (e.g. Arduino Uno)
// after moving string constants to flash memory storage using the F()
// compiler macro (Arduino IDE 1.0+ required).
//#define DEBUG
/* Control whether debugging macros are active at compile time */
#undef DB_ACTIVE
#ifdef DEBUG
#define DB_ACTIVE 1
#else
#define DB_ACTIVE 0
#endif /* DEBUG */
/*
** Usage: DB_PRINT((...));
** Usage: DB_PRINTLN((...));
**
** "..." is whatever extra arguments fmt requires (possibly nothing).
**
** The structure of the macros means that the code is always validated
** but is not called when DEBUG is undefined.
** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike.
*/
#define DEBUG_PRINT(...)\
do { if (DB_ACTIVE) Serial.print(__VA_ARGS__); } while (0)
#define DEBUG_PRINTF(...)\
do { if (DB_ACTIVE) Serial.printf(__VA_ARGS__); } while (0)
#define DEBUG_PRINTLN(...)\
do { if (DB_ACTIVE) Serial.println(__VA_ARGS__); } while (0)
#define DEBUG_PRINTLNF(x, y)\
do { if (DB_ACTIVE) Serial.println(x, y); } while (0)
#define MPU6050_DMP_CODE_SIZE 1929 // dmpMemory[]
#define MPU6050_DMP_CONFIG_SIZE 192 // dmpConfig[]
#define MPU6050_DMP_UPDATES_SIZE 47 // dmpUpdates[]
/* ================================================================================================ *
| Default MotionApps v2.0 42-byte FIFO packet structure: |
| |
| [QUAT W][ ][QUAT X][ ][QUAT Y][ ][QUAT Z][ ][GYRO X][ ][GYRO Y][ ] |
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
| |
| [GYRO Z][ ][ACC X ][ ][ACC Y ][ ][ACC Z ][ ][ ] |
| 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
* ================================================================================================ */
// this block of memory gets written to the MPU on start-up, and it seems
// to be volatile memory, so it has to be done each time (it only takes ~1
// second though)
// I Only Changed this by applying all the configuration data and capturing it before startup:
// *** this is a capture of the DMP Firmware after all the messy changes were made so we can just load it
static const unsigned char dmpMemory[MPU6050_DMP_CODE_SIZE] PROGMEM = {
/* bank # 0 */
0xFB, 0x00, 0x00, 0x3E, 0x00, 0x0B, 0x00, 0x36, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00,
0x00, 0x65, 0x00, 0x54, 0xFF, 0xEF, 0x00, 0x00, 0xFA, 0x80, 0x00, 0x0B, 0x12, 0x82, 0x00, 0x01,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x28, 0x00, 0x00, 0xFF, 0xFF, 0x45, 0x81, 0xFF, 0xFF, 0xFA, 0x72, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xE8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7F, 0xFF, 0xFF, 0xFE, 0x80, 0x01,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0xCB, 0x47, 0xA2, 0x20, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x41, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x2A, 0x00, 0x00, 0x16, 0x55, 0x00, 0x00, 0x21, 0x82,
0xFD, 0x87, 0x26, 0x50, 0xFD, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x05, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6F, 0x00, 0x02, 0x65, 0x32, 0x00, 0x00, 0x5E, 0xC0,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFB, 0x8C, 0x6F, 0x5D, 0xFD, 0x5D, 0x08, 0xD9, 0x00, 0x7C, 0x73, 0x3B, 0x00, 0x6C, 0x12, 0xCC,
0x32, 0x00, 0x13, 0x9D, 0x32, 0x00, 0xD0, 0xD6, 0x32, 0x00, 0x08, 0x00, 0x40, 0x00, 0x01, 0xF4,
0xFF, 0xE6, 0x80, 0x79, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xD6, 0x00, 0x00, 0x27, 0x10,
/* bank # 1 */
0xFB, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFA, 0x36, 0xFF, 0xBC, 0x30, 0x8E, 0x00, 0x05, 0xFB, 0xF0, 0xFF, 0xD9, 0x5B, 0xC8,
0xFF, 0xD0, 0x9A, 0xBE, 0x00, 0x00, 0x10, 0xA9, 0xFF, 0xF4, 0x1E, 0xB2, 0x00, 0xCE, 0xBB, 0xF7,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x0C,
0xFF, 0xC2, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0xCF, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x09, 0x23, 0xA1, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x3F, 0x68, 0xB6, 0x79, 0x35, 0x28, 0xBC, 0xC6, 0x7E, 0xD1, 0x6C,
0x80, 0x00, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x6A, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x25, 0x4D, 0x00, 0x2F, 0x70, 0x6D, 0x00, 0x00, 0x05, 0xAE, 0x00, 0x0C, 0x02, 0xD0,
/* bank # 2 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x54, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x44, 0x00, 0x01, 0x00, 0x05, 0x8B, 0xC1, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0xFF, 0xEF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* bank # 3 */
0xD8, 0xDC, 0xBA, 0xA2, 0xF1, 0xDE, 0xB2, 0xB8, 0xB4, 0xA8, 0x81, 0x91, 0xF7, 0x4A, 0x90, 0x7F,
0x91, 0x6A, 0xF3, 0xF9, 0xDB, 0xA8, 0xF9, 0xB0, 0xBA, 0xA0, 0x80, 0xF2, 0xCE, 0x81, 0xF3, 0xC2,
0xF1, 0xC1, 0xF2, 0xC3, 0xF3, 0xCC, 0xA2, 0xB2, 0x80, 0xF1, 0xC6, 0xD8, 0x80, 0xBA, 0xA7, 0xDF,
0xDF, 0xDF, 0xF2, 0xA7, 0xC3, 0xCB, 0xC5, 0xB6, 0xF0, 0x87, 0xA2, 0x94, 0x24, 0x48, 0x70, 0x3C,
0x95, 0x40, 0x68, 0x34, 0x58, 0x9B, 0x78, 0xA2, 0xF1, 0x83, 0x92, 0x2D, 0x55, 0x7D, 0xD8, 0xB1,
0xB4, 0xB8, 0xA1, 0xD0, 0x91, 0x80, 0xF2, 0x70, 0xF3, 0x70, 0xF2, 0x7C, 0x80, 0xA8, 0xF1, 0x01,
0xB0, 0x98, 0x87, 0xD9, 0x43, 0xD8, 0x86, 0xC9, 0x88, 0xBA, 0xA1, 0xF2, 0x0E, 0xB8, 0x97, 0x80,
0xF1, 0xA9, 0xDF, 0xDF, 0xDF, 0xAA, 0xDF, 0xDF, 0xDF, 0xF2, 0xAA, 0x4C, 0xCD, 0x6C, 0xA9, 0x0C,
0xC9, 0x2C, 0x97, 0x97, 0x97, 0x97, 0xF1, 0xA9, 0x89, 0x26, 0x46, 0x66, 0xB0, 0xB4, 0xBA, 0x80,
0xAC, 0xDE, 0xF2, 0xCA, 0xF1, 0xB2, 0x8C, 0x02, 0xA9, 0xB6, 0x98, 0x00, 0x89, 0x0E, 0x16, 0x1E,
0xB8, 0xA9, 0xB4, 0x99, 0x2C, 0x54, 0x7C, 0xB0, 0x8A, 0xA8, 0x96, 0x36, 0x56, 0x76, 0xF1, 0xB9,
0xAF, 0xB4, 0xB0, 0x83, 0xC0, 0xB8, 0xA8, 0x97, 0x11, 0xB1, 0x8F, 0x98, 0xB9, 0xAF, 0xF0, 0x24,
0x08, 0x44, 0x10, 0x64, 0x18, 0xF1, 0xA3, 0x29, 0x55, 0x7D, 0xAF, 0x83, 0xB5, 0x93, 0xAF, 0xF0,
0x00, 0x28, 0x50, 0xF1, 0xA3, 0x86, 0x9F, 0x61, 0xA6, 0xDA, 0xDE, 0xDF, 0xD9, 0xFA, 0xA3, 0x86,
0x96, 0xDB, 0x31, 0xA6, 0xD9, 0xF8, 0xDF, 0xBA, 0xA6, 0x8F, 0xC2, 0xC5, 0xC7, 0xB2, 0x8C, 0xC1,
0xB8, 0xA2, 0xDF, 0xDF, 0xDF, 0xA3, 0xDF, 0xDF, 0xDF, 0xD8, 0xD8, 0xF1, 0xB8, 0xA8, 0xB2, 0x86,
/* bank # 4 */
0xB4, 0x98, 0x0D, 0x35, 0x5D, 0xB8, 0xAA, 0x98, 0xB0, 0x87, 0x2D, 0x35, 0x3D, 0xB2, 0xB6, 0xBA,
0xAF, 0x8C, 0x96, 0x19, 0x8F, 0x9F, 0xA7, 0x0E, 0x16, 0x1E, 0xB4, 0x9A, 0xB8, 0xAA, 0x87, 0x2C,
0x54, 0x7C, 0xB9, 0xA3, 0xDE, 0xDF, 0xDF, 0xA3, 0xB1, 0x80, 0xF2, 0xC4, 0xCD, 0xC9, 0xF1, 0xB8,
0xA9, 0xB4, 0x99, 0x83, 0x0D, 0x35, 0x5D, 0x89, 0xB9, 0xA3, 0x2D, 0x55, 0x7D, 0xB5, 0x93, 0xA3,
0x0E, 0x16, 0x1E, 0xA9, 0x2C, 0x54, 0x7C, 0xB8, 0xB4, 0xB0, 0xF1, 0x97, 0x83, 0xA8, 0x11, 0x84,
0xA5, 0x09, 0x98, 0xA3, 0x83, 0xF0, 0xDA, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0xD8, 0xF1, 0xA5,
0x29, 0x55, 0x7D, 0xA5, 0x85, 0x95, 0x02, 0x1A, 0x2E, 0x3A, 0x56, 0x5A, 0x40, 0x48, 0xF9, 0xF3,
0xA3, 0xD9, 0xF8, 0xF0, 0x98, 0x83, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0x97, 0x82, 0xA8, 0xF1,
0x11, 0xF0, 0x98, 0xA2, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0xDA, 0xF3, 0xDE, 0xD8, 0x83, 0xA5,
0x94, 0x01, 0xD9, 0xA3, 0x02, 0xF1, 0xA2, 0xC3, 0xC5, 0xC7, 0xD8, 0xF1, 0x84, 0x92, 0xA2, 0x4D,
0xDA, 0x2A, 0xD8, 0x48, 0x69, 0xD9, 0x2A, 0xD8, 0x68, 0x55, 0xDA, 0x32, 0xD8, 0x50, 0x71, 0xD9,
0x32, 0xD8, 0x70, 0x5D, 0xDA, 0x3A, 0xD8, 0x58, 0x79, 0xD9, 0x3A, 0xD8, 0x78, 0x93, 0xA3, 0x4D,
0xDA, 0x2A, 0xD8, 0x48, 0x69, 0xD9, 0x2A, 0xD8, 0x68, 0x55, 0xDA, 0x32, 0xD8, 0x50, 0x71, 0xD9,
0x32, 0xD8, 0x70, 0x5D, 0xDA, 0x3A, 0xD8, 0x58, 0x79, 0xD9, 0x3A, 0xD8, 0x78, 0xA8, 0x8A, 0x9A,
0xF0, 0x28, 0x50, 0x78, 0x9E, 0xF3, 0x88, 0x18, 0xF1, 0x9F, 0x1D, 0x98, 0xA8, 0xD9, 0x08, 0xD8,
0xC8, 0x9F, 0x12, 0x9E, 0xF3, 0x15, 0xA8, 0xDA, 0x12, 0x10, 0xD8, 0xF1, 0xAF, 0xC8, 0x97, 0x87,
/* bank # 5 */
0x34, 0xB5, 0xB9, 0x94, 0xA4, 0x21, 0xF3, 0xD9, 0x22, 0xD8, 0xF2, 0x2D, 0xF3, 0xD9, 0x2A, 0xD8,
0xF2, 0x35, 0xF3, 0xD9, 0x32, 0xD8, 0x81, 0xA4, 0x60, 0x60, 0x61, 0xD9, 0x61, 0xD8, 0x6C, 0x68,
0x69, 0xD9, 0x69, 0xD8, 0x74, 0x70, 0x71, 0xD9, 0x71, 0xD8, 0xB1, 0xA3, 0x84, 0x19, 0x3D, 0x5D,
0xA3, 0x83, 0x1A, 0x3E, 0x5E, 0x93, 0x10, 0x30, 0x81, 0x10, 0x11, 0xB8, 0xB0, 0xAF, 0x8F, 0x94,
0xF2, 0xDA, 0x3E, 0xD8, 0xB4, 0x9A, 0xA8, 0x87, 0x29, 0xDA, 0xF8, 0xD8, 0x87, 0x9A, 0x35, 0xDA,
0xF8, 0xD8, 0x87, 0x9A, 0x3D, 0xDA, 0xF8, 0xD8, 0xB1, 0xB9, 0xA4, 0x98, 0x85, 0x02, 0x2E, 0x56,
0xA5, 0x81, 0x00, 0x0C, 0x14, 0xA3, 0x97, 0xB0, 0x8A, 0xF1, 0x2D, 0xD9, 0x28, 0xD8, 0x4D, 0xD9,
0x48, 0xD8, 0x6D, 0xD9, 0x68, 0xD8, 0xB1, 0x84, 0x0D, 0xDA, 0x0E, 0xD8, 0xA3, 0x29, 0x83, 0xDA,
0x2C, 0x0E, 0xD8, 0xA3, 0x84, 0x49, 0x83, 0xDA, 0x2C, 0x4C, 0x0E, 0xD8, 0xB8, 0xB0, 0xA8, 0x8A,
0x9A, 0xF5, 0x20, 0xAA, 0xDA, 0xDF, 0xD8, 0xA8, 0x40, 0xAA, 0xD0, 0xDA, 0xDE, 0xD8, 0xA8, 0x60,
0xAA, 0xDA, 0xD0, 0xDF, 0xD8, 0xF1, 0x97, 0x86, 0xA8, 0x31, 0x9B, 0x06, 0x99, 0x07, 0xAB, 0x97,
0x28, 0x88, 0x9B, 0xF0, 0x0C, 0x20, 0x14, 0x40, 0xB8, 0xB0, 0xB4, 0xA8, 0x8C, 0x9C, 0xF0, 0x04,
0x28, 0x51, 0x79, 0x1D, 0x30, 0x14, 0x38, 0xB2, 0x82, 0xAB, 0xD0, 0x98, 0x2C, 0x50, 0x50, 0x78,
0x78, 0x9B, 0xF1, 0x1A, 0xB0, 0xF0, 0x8A, 0x9C, 0xA8, 0x29, 0x51, 0x79, 0x8B, 0x29, 0x51, 0x79,
0x8A, 0x24, 0x70, 0x59, 0x8B, 0x20, 0x58, 0x71, 0x8A, 0x44, 0x69, 0x38, 0x8B, 0x39, 0x40, 0x68,
0x8A, 0x64, 0x48, 0x31, 0x8B, 0x30, 0x49, 0x60, 0xA5, 0x88, 0x20, 0x09, 0x71, 0x58, 0x44, 0x68,
/* bank # 6 */
0x11, 0x39, 0x64, 0x49, 0x30, 0x19, 0xF1, 0xAC, 0x00, 0x2C, 0x54, 0x7C, 0xF0, 0x8C, 0xA8, 0x04,
0x28, 0x50, 0x78, 0xF1, 0x88, 0x97, 0x26, 0xA8, 0x59, 0x98, 0xAC, 0x8C, 0x02, 0x26, 0x46, 0x66,
0xF0, 0x89, 0x9C, 0xA8, 0x29, 0x51, 0x79, 0x24, 0x70, 0x59, 0x44, 0x69, 0x38, 0x64, 0x48, 0x31,
0xA9, 0x88, 0x09, 0x20, 0x59, 0x70, 0xAB, 0x11, 0x38, 0x40, 0x69, 0xA8, 0x19, 0x31, 0x48, 0x60,
0x8C, 0xA8, 0x3C, 0x41, 0x5C, 0x20, 0x7C, 0x00, 0xF1, 0x87, 0x98, 0x19, 0x86, 0xA8, 0x6E, 0x76,
0x7E, 0xA9, 0x99, 0x88, 0x2D, 0x55, 0x7D, 0x9E, 0xB9, 0xA3, 0x8A, 0x22, 0x8A, 0x6E, 0x8A, 0x56,
0x8A, 0x5E, 0x9F, 0xB1, 0x83, 0x06, 0x26, 0x46, 0x66, 0x0E, 0x2E, 0x4E, 0x6E, 0x9D, 0xB8, 0xAD,
0x00, 0x2C, 0x54, 0x7C, 0xF2, 0xB1, 0x8C, 0xB4, 0x99, 0xB9, 0xA3, 0x2D, 0x55, 0x7D, 0x81, 0x91,
0xAC, 0x38, 0xAD, 0x3A, 0xB5, 0x83, 0x91, 0xAC, 0x2D, 0xD9, 0x28, 0xD8, 0x4D, 0xD9, 0x48, 0xD8,
0x6D, 0xD9, 0x68, 0xD8, 0x8C, 0x9D, 0xAE, 0x29, 0xD9, 0x04, 0xAE, 0xD8, 0x51, 0xD9, 0x04, 0xAE,
0xD8, 0x79, 0xD9, 0x04, 0xD8, 0x81, 0xF3, 0x9D, 0xAD, 0x00, 0x8D, 0xAE, 0x19, 0x81, 0xAD, 0xD9,
0x01, 0xD8, 0xF2, 0xAE, 0xDA, 0x26, 0xD8, 0x8E, 0x91, 0x29, 0x83, 0xA7, 0xD9, 0xAD, 0xAD, 0xAD,
0xAD, 0xF3, 0x2A, 0xD8, 0xD8, 0xF1, 0xB0, 0xAC, 0x89, 0x91, 0x3E, 0x5E, 0x76, 0xF3, 0xAC, 0x2E,
0x2E, 0xF1, 0xB1, 0x8C, 0x5A, 0x9C, 0xAC, 0x2C, 0x28, 0x28, 0x28, 0x9C, 0xAC, 0x30, 0x18, 0xA8,
0x98, 0x81, 0x28, 0x34, 0x3C, 0x97, 0x24, 0xA7, 0x28, 0x34, 0x3C, 0x9C, 0x24, 0xF2, 0xB0, 0x89,
0xAC, 0x91, 0x2C, 0x4C, 0x6C, 0x8A, 0x9B, 0x2D, 0xD9, 0xD8, 0xD8, 0x51, 0xD9, 0xD8, 0xD8, 0x79,
/* bank # 7 */
0xD9, 0xD8, 0xD8, 0xF1, 0x9E, 0x88, 0xA3, 0x31, 0xDA, 0xD8, 0xD8, 0x91, 0x2D, 0xD9, 0x28, 0xD8,
0x4D, 0xD9, 0x48, 0xD8, 0x6D, 0xD9, 0x68, 0xD8, 0xB1, 0x83, 0x93, 0x35, 0x3D, 0x80, 0x25, 0xDA,
0xD8, 0xD8, 0x85, 0x69, 0xDA, 0xD8, 0xD8, 0xB4, 0x93, 0x81, 0xA3, 0x28, 0x34, 0x3C, 0xF3, 0xAB,
0x8B, 0xF8, 0xA3, 0x91, 0xB6, 0x09, 0xB4, 0xD9, 0xAB, 0xDE, 0xFA, 0xB0, 0x87, 0x9C, 0xB9, 0xA3,
0xDD, 0xF1, 0x20, 0x28, 0x30, 0x38, 0x9A, 0xF1, 0x28, 0x30, 0x38, 0x9D, 0xF1, 0xA3, 0xA3, 0xA3,
0xA3, 0xF2, 0xA3, 0xB4, 0x90, 0x80, 0xF2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
0xA3, 0xB2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xB0, 0x87, 0xB5, 0x99, 0xF1, 0x28, 0x30, 0x38,
0x98, 0xF1, 0xA3, 0xA3, 0xA3, 0xA3, 0x97, 0xA3, 0xA3, 0xA3, 0xA3, 0xF3, 0x9B, 0xA3, 0x30, 0xDC,
0xB9, 0xA7, 0xF1, 0x26, 0x26, 0x26, 0xFE, 0xD8, 0xFF,
};
#ifndef MPU6050_DMP_FIFO_RATE_DIVISOR
#define MPU6050_DMP_FIFO_RATE_DIVISOR 0x01 // The New instance of the Firmware has this as the default
#endif
// I Simplified this:
uint8_t MPU6050_6Axis_MotionApps20::dmpInitialize() {
// reset device
DEBUG_PRINTLN(F("\n\nResetting MPU6050..."));
reset();
delay(30); // wait after reset
// enable sleep mode and wake cycle
/*Serial.println(F("Enabling sleep mode..."));
setSleepEnabled(true);
Serial.println(F("Enabling wake cycle..."));
setWakeCycleEnabled(true);*/
// disable sleep mode
setSleepEnabled(false);
// get MPU hardware revision
setMemoryBank(0x10, true, true);
setMemoryStartAddress(0x06);
DEBUG_PRINTLN(F("Checking hardware revision..."));
DEBUG_PRINT(F("Revision @ user[16][6] = "));
DEBUG_PRINTLN(readMemoryByte());
DEBUG_PRINTLN(F("Resetting memory bank selection to 0..."));
setMemoryBank(0, false, false);
// check OTP bank valid
DEBUG_PRINTLN(F("Reading OTP bank valid flag..."));
DEBUG_PRINT(F("OTP bank is "));
DEBUG_PRINTLN(getOTPBankValid() ? F("valid!") : F("invalid!"));
// setup weird slave stuff (?)
DEBUG_PRINTLN(F("Setting slave 0 address to 0x7F..."));
setSlaveAddress(0, 0x7F);
DEBUG_PRINTLN(F("Disabling I2C Master mode..."));
setI2CMasterModeEnabled(false);
DEBUG_PRINTLN(F("Setting slave 0 address to 0x68 (self)..."));
setSlaveAddress(0, 0x68);
DEBUG_PRINTLN(F("Resetting I2C Master control..."));
resetI2CMaster();
delay(20);
DEBUG_PRINTLN(F("Setting clock source to Z Gyro..."));
setClockSource(MPU6050_CLOCK_PLL_ZGYRO);
DEBUG_PRINTLN(F("Setting DMP and FIFO_OFLOW interrupts enabled..."));
setIntEnabled(1<<MPU6050_INTERRUPT_FIFO_OFLOW_BIT|1<<MPU6050_INTERRUPT_DMP_INT_BIT);
DEBUG_PRINTLN(F("Setting sample rate to 200Hz..."));
setRate(4); // 1khz / (1 + 4) = 200 Hz
DEBUG_PRINTLN(F("Setting external frame sync to TEMP_OUT_L[0]..."));
setExternalFrameSync(MPU6050_EXT_SYNC_TEMP_OUT_L);
DEBUG_PRINTLN(F("Setting DLPF bandwidth to 42Hz..."));
setDLPFMode(MPU6050_DLPF_BW_42);
DEBUG_PRINTLN(F("Setting gyro sensitivity to +/- 2000 deg/sec..."));
setFullScaleGyroRange(MPU6050_GYRO_FS_2000);
// load DMP code into memory banks
DEBUG_PRINT(F("Writing DMP code to MPU memory banks ("));
DEBUG_PRINT(MPU6050_DMP_CODE_SIZE);
DEBUG_PRINTLN(F(" bytes)"));
if (!writeProgMemoryBlock(dmpMemory, MPU6050_DMP_CODE_SIZE)) return 1; // Failed
DEBUG_PRINTLN(F("Success! DMP code written and verified."));
// Set the FIFO Rate Divisor int the DMP Firmware Memory
unsigned char dmpUpdate[] = {0x00, MPU6050_DMP_FIFO_RATE_DIVISOR};
writeMemoryBlock(dmpUpdate, 0x02, 0x02, 0x16); // Lets write the dmpUpdate data to the Firmware image, we have 2 bytes to write in bank 0x02 with the Offset 0x16
//write start address MSB into register
setDMPConfig1(0x03);
//write start address LSB into register
setDMPConfig2(0x00);
DEBUG_PRINTLN(F("Clearing OTP Bank flag..."));
setOTPBankValid(false);
DEBUG_PRINTLN(F("Setting motion detection threshold to 2..."));
setMotionDetectionThreshold(2);
DEBUG_PRINTLN(F("Setting zero-motion detection threshold to 156..."));
setZeroMotionDetectionThreshold(156);
DEBUG_PRINTLN(F("Setting motion detection duration to 80..."));
setMotionDetectionDuration(80);
DEBUG_PRINTLN(F("Setting zero-motion detection duration to 0..."));
setZeroMotionDetectionDuration(0);
DEBUG_PRINTLN(F("Enabling FIFO..."));
setFIFOEnabled(true);
DEBUG_PRINTLN(F("Resetting DMP..."));
resetDMP();
DEBUG_PRINTLN(F("DMP is good to go! Finally."));
DEBUG_PRINTLN(F("Disabling DMP (you turn it on later)..."));
setDMPEnabled(false);
DEBUG_PRINTLN(F("Setting up internal 42-byte (default) DMP packet buffer..."));
dmpPacketSize = 42;
DEBUG_PRINTLN(F("Resetting FIFO and clearing INT status one last time..."));
resetFIFO();
getIntStatus();
return 0; // success
}
// Nothing else changed
bool MPU6050_6Axis_MotionApps20::dmpPacketAvailable() {
return getFIFOCount() >= dmpGetFIFOPacketSize();
}
// uint8_t MPU6050_6Axis_MotionApps20::dmpSetFIFORate(uint8_t fifoRate);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetFIFORate();
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetSampleStepSizeMS();
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetSampleFrequency();
// int32_t MPU6050_6Axis_MotionApps20::dmpDecodeTemperature(int8_t tempReg);
//uint8_t MPU6050_6Axis_MotionApps20::dmpRegisterFIFORateProcess(inv_obj_func func, int16_t priority);
//uint8_t MPU6050_6Axis_MotionApps20::dmpUnregisterFIFORateProcess(inv_obj_func func);
//uint8_t MPU6050_6Axis_MotionApps20::dmpRunFIFORateProcesses();
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendQuaternion(uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendGyro(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendAccel(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendLinearAccel(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendLinearAccelInWorld(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendControlData(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendExternalSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendGravity(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendPacketNumber(uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendQuantizedAccel(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_6Axis_MotionApps20::dmpSendEIS(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t MPU6050_6Axis_MotionApps20::dmpGetAccel(int32_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((int32_t)packet[28] << 24) | ((int32_t)packet[29] << 16) | ((int32_t)packet[30] << 8) | (int32_t)packet[31]);
data[1] = (((int32_t)packet[32] << 24) | ((int32_t)packet[33] << 16) | ((int32_t)packet[34] << 8) | (int32_t)packet[35]);
data[2] = (((int32_t)packet[36] << 24) | ((int32_t)packet[37] << 16) | ((int32_t)packet[38] << 8) | (int32_t)packet[39]);
return 0;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpGetAccel(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = ((int16_t)packet[28] << 8) | (int16_t)packet[29];
data[1] = ((int16_t)packet[32] << 8) | (int16_t)packet[33];
data[2] = ((int16_t)packet[36] << 8) | (int16_t)packet[37];
return 0;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpGetAccel(VectorInt16 *v, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
v -> x = ((int16_t)packet[28] << 8) | (int16_t)packet[29];
v -> y = ((int16_t)packet[32] << 8) | (int16_t)packet[33];
v -> z = ((int16_t)packet[36] << 8) | (int16_t)packet[37];
return 0;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpGetQuaternion(int32_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((int32_t)packet[0] << 24) | ((int32_t)packet[1] << 16) | ((int32_t)packet[2] << 8) | (int32_t)packet[3]);
data[1] = (((int32_t)packet[4] << 24) | ((int32_t)packet[5] << 16) | ((int32_t)packet[6] << 8) | (int32_t)packet[7]);
data[2] = (((int32_t)packet[8] << 24) | ((int32_t)packet[9] << 16) | ((int32_t)packet[10] << 8) | (int32_t)packet[11]);
data[3] = (((int32_t)packet[12] << 24) | ((int32_t)packet[13] << 16) | ((int32_t)packet[14] << 8) | (int32_t)packet[15]);
return 0;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpGetQuaternion(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((int16_t)packet[0] << 8) | (int16_t)packet[1]);
data[1] = (((int16_t)packet[4] << 8) | (int16_t)packet[5]);
data[2] = (((int16_t)packet[8] << 8) | (int16_t)packet[9]);
data[3] = (((int16_t)packet[12] << 8) | (int16_t)packet[13]);
return 0;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpGetQuaternion(Quaternion *q, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
int16_t qI[4];
uint8_t status = dmpGetQuaternion(qI, packet);
if (status == 0) {
q -> w = (float)qI[0] / 16384.0f;
q -> x = (float)qI[1] / 16384.0f;
q -> y = (float)qI[2] / 16384.0f;
q -> z = (float)qI[3] / 16384.0f;
return 0;
}
return status; // int16 return value, indicates error if this line is reached
}
// uint8_t MPU6050_6Axis_MotionApps20::dmpGet6AxisQuaternion(long *data, const uint8_t* packet);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetRelativeQuaternion(long *data, const uint8_t* packet);
uint8_t MPU6050_6Axis_MotionApps20::dmpGetGyro(int32_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((int32_t)packet[16] << 24) | ((int32_t)packet[17] << 16) | ((int32_t)packet[18] << 8) | (int32_t)packet[19]);
data[1] = (((int32_t)packet[20] << 24) | ((int32_t)packet[21] << 16) | ((int32_t)packet[22] << 8) | (int32_t)packet[23]);
data[2] = (((int32_t)packet[24] << 24) | ((int32_t)packet[25] << 16) | ((int32_t)packet[26] << 8) | (int32_t)packet[27]);
return 0;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpGetGyro(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = ((int16_t)packet[16] << 8) | (int16_t)packet[17];
data[1] = ((int16_t)packet[20] << 8) | (int16_t)packet[21];
data[2] = ((int16_t)packet[24] << 8) | (int16_t)packet[25];
return 0;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpGetGyro(VectorInt16 *v, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
v -> x = ((int16_t)packet[16] << 8) | (int16_t)packet[17];
v -> y = ((int16_t)packet[20] << 8) | (int16_t)packet[21];
v -> z = ((int16_t)packet[24] << 8) | (int16_t)packet[25];
return 0;
}
// uint8_t MPU6050_6Axis_MotionApps20::dmpSetLinearAccelFilterCoefficient(float coef);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetLinearAccel(long *data, const uint8_t* packet);
uint8_t MPU6050_6Axis_MotionApps20::dmpGetLinearAccel(VectorInt16 *v, VectorInt16 *vRaw, VectorFloat *gravity) {
// get rid of the gravity component (+1g = +8192 in standard DMP FIFO packet, sensitivity is 2g)
v -> x = vRaw -> x - gravity -> x*8192;
v -> y = vRaw -> y - gravity -> y*8192;
v -> z = vRaw -> z - gravity -> z*8192;
return 0;
}
// uint8_t MPU6050_6Axis_MotionApps20::dmpConvertToWorldFrame(long *data, const uint8_t* packet);
uint8_t MPU6050_6Axis_MotionApps20::dmpConvertToWorldFrame(VectorInt16 *v, VectorInt16 *vReal, Quaternion *q) {
// rotate measured 3D acceleration vector into original state
// frame of reference based on orientation quaternion
memcpy(v, vReal, sizeof(VectorInt16));
v -> rotate(q);
return 0;
}
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetGyroAndAccelSensor(long *data, const uint8_t* packet);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetGyroSensor(long *data, const uint8_t* packet);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetControlData(long *data, const uint8_t* packet);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetTemperature(long *data, const uint8_t* packet);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetGravity(long *data, const uint8_t* packet);
uint8_t MPU6050_6Axis_MotionApps20::dmpGetGravity(int16_t *data, const uint8_t* packet) {
/* +1g corresponds to +8192, sensitivity is 2g. */
int16_t qI[4];
uint8_t status = dmpGetQuaternion(qI, packet);
data[0] = ((int32_t)qI[1] * qI[3] - (int32_t)qI[0] * qI[2]) / 16384;
data[1] = ((int32_t)qI[0] * qI[1] + (int32_t)qI[2] * qI[3]) / 16384;
data[2] = ((int32_t)qI[0] * qI[0] - (int32_t)qI[1] * qI[1] - (int32_t)qI[2] * qI[2] + (int32_t)qI[3] * qI[3]) / (int32_t)(2 * 16384L);
return status;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpGetGravity(VectorFloat *v, Quaternion *q) {
v -> x = 2 * (q -> x*q -> z - q -> w*q -> y);
v -> y = 2 * (q -> w*q -> x + q -> y*q -> z);
v -> z = q -> w*q -> w - q -> x*q -> x - q -> y*q -> y + q -> z*q -> z;
return 0;
}
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetUnquantizedAccel(long *data, const uint8_t* packet);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetQuantizedAccel(long *data, const uint8_t* packet);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetExternalSensorData(long *data, int size, const uint8_t* packet);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetEIS(long *data, const uint8_t* packet);
uint8_t MPU6050_6Axis_MotionApps20::dmpGetEuler(float *data, Quaternion *q) {
data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1); // psi
data[1] = -asin(2*q -> x*q -> z + 2*q -> w*q -> y); // theta
data[2] = atan2(2*q -> y*q -> z - 2*q -> w*q -> x, 2*q -> w*q -> w + 2*q -> z*q -> z - 1); // phi
return 0;
}
#ifdef USE_OLD_DMPGETYAWPITCHROLL
uint8_t MPU6050_6Axis_MotionApps20::dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity) {
// yaw: (about Z axis)
data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1);
// pitch: (nose up/down, about Y axis)
data[1] = atan(gravity -> x / sqrt(gravity -> y*gravity -> y + gravity -> z*gravity -> z));
// roll: (tilt left/right, about X axis)
data[2] = atan(gravity -> y / sqrt(gravity -> x*gravity -> x + gravity -> z*gravity -> z));
return 0;
}
#else
uint8_t MPU6050_6Axis_MotionApps20::dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity) {
// yaw: (about Z axis)
data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1);
// pitch: (nose up/down, about Y axis)
data[1] = atan2(gravity -> x , sqrt(gravity -> y*gravity -> y + gravity -> z*gravity -> z));
// roll: (tilt left/right, about X axis)
data[2] = atan2(gravity -> y , gravity -> z);
if (gravity -> z < 0) {
if(data[1] > 0) {
data[1] = PI - data[1];
} else {
data[1] = -PI - data[1];
}
}
return 0;
}
#endif
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetAccelFloat(float *data, const uint8_t* packet);
// uint8_t MPU6050_6Axis_MotionApps20::dmpGetQuaternionFloat(float *data, const uint8_t* packet);
uint8_t MPU6050_6Axis_MotionApps20::dmpProcessFIFOPacket(const unsigned char *dmpData) {
(void)dmpData; // unused parameter
/*for (uint8_t k = 0; k < dmpPacketSize; k++) {
if (dmpData[k] < 0x10) Serial.print("0");
Serial.print(dmpData[k], HEX);
Serial.print(" ");
}
Serial.print("\n");*/
//Serial.println((uint16_t)dmpPacketBuffer);
return 0;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpReadAndProcessFIFOPacket(uint8_t numPackets, uint8_t *processed) {
uint8_t status;
uint8_t buf[dmpPacketSize];
for (uint8_t i = 0; i < numPackets; i++) {
// read packet from FIFO
getFIFOBytes(buf, dmpPacketSize);
// process packet
if ((status = dmpProcessFIFOPacket(buf)) > 0) return status;
// increment external process count variable, if supplied
if (processed != 0) (*processed)++;
}
return 0;
}
// uint8_t MPU6050_6Axis_MotionApps20::dmpSetFIFOProcessedCallback(void (*func) (void));
// uint8_t MPU6050_6Axis_MotionApps20::dmpInitFIFOParam();
// uint8_t MPU6050_6Axis_MotionApps20::dmpCloseFIFO();
// uint8_t MPU6050_6Axis_MotionApps20::dmpSetGyroDataSource(uint_fast8_t source);
// uint8_t MPU6050_6Axis_MotionApps20::dmpDecodeQuantizedAccel();
// uint32_t MPU6050_6Axis_MotionApps20::dmpGetGyroSumOfSquare();
// uint32_t MPU6050_6Axis_MotionApps20::dmpGetAccelSumOfSquare();
// void MPU6050_6Axis_MotionApps20::dmpOverrideQuaternion(long *q);
uint16_t MPU6050_6Axis_MotionApps20::dmpGetFIFOPacketSize() {
return dmpPacketSize;
}
uint8_t MPU6050_6Axis_MotionApps20::dmpGetCurrentFIFOPacket(uint8_t *data) { // overflow proof
return(GetCurrentFIFOPacket(data, dmpPacketSize));
}

View File

@ -0,0 +1,154 @@
// I2Cdev library collection - MPU6050 I2C device class
// Based on InvenSense MPU-6050 register map document rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
// 10/3/2011 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2021/09/27 - split implementations out of header files, finally
// ... - ongoing debug release
// NOTE: THIS IS ONLY A PARIAL RELEASE. THIS DEVICE CLASS IS CURRENTLY UNDERGOING ACTIVE
// DEVELOPMENT AND IS STILL MISSING SOME IMPORTANT FEATURES. PLEASE KEEP THIS IN MIND IF
// YOU DECIDE TO USE THIS PARTICULAR CODE FOR ANYTHING.
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
#ifndef _MPU6050_6AXIS_MOTIONAPPS20_H_
#define _MPU6050_6AXIS_MOTIONAPPS20_H_
// take ownership of the "MPU6050" typedef
#define I2CDEVLIB_MPU6050_TYPEDEF
#include "MPU6050.h"
class MPU6050_6Axis_MotionApps20 : public MPU6050_Base {
public:
MPU6050_6Axis_MotionApps20(uint8_t address=MPU6050_DEFAULT_ADDRESS, void *wireObj=0) : MPU6050_Base(address, wireObj) { }
uint8_t dmpInitialize();
bool dmpPacketAvailable();
uint8_t dmpSetFIFORate(uint8_t fifoRate);
uint8_t dmpGetFIFORate();
uint8_t dmpGetSampleStepSizeMS();
uint8_t dmpGetSampleFrequency();
int32_t dmpDecodeTemperature(int8_t tempReg);
// Register callbacks after a packet of FIFO data is processed
//uint8_t dmpRegisterFIFORateProcess(inv_obj_func func, int16_t priority);
//uint8_t dmpUnregisterFIFORateProcess(inv_obj_func func);
uint8_t dmpRunFIFORateProcesses();
// Setup FIFO for various output
uint8_t dmpSendQuaternion(uint_fast16_t accuracy);
uint8_t dmpSendGyro(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendAccel(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendLinearAccel(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendLinearAccelInWorld(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendControlData(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendExternalSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendGravity(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendPacketNumber(uint_fast16_t accuracy);
uint8_t dmpSendQuantizedAccel(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendEIS(uint_fast16_t elements, uint_fast16_t accuracy);
// Get Fixed Point data from FIFO
uint8_t dmpGetAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetQuaternion(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuaternion(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuaternion(Quaternion *q, const uint8_t* packet=0);
uint8_t dmpGet6AxisQuaternion(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGet6AxisQuaternion(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGet6AxisQuaternion(Quaternion *q, const uint8_t* packet=0);
uint8_t dmpGetRelativeQuaternion(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetRelativeQuaternion(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetRelativeQuaternion(Quaternion *data, const uint8_t* packet=0);
uint8_t dmpGetGyro(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyro(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyro(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpSetLinearAccelFilterCoefficient(float coef);
uint8_t dmpGetLinearAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetLinearAccel(VectorInt16 *v, VectorInt16 *vRaw, VectorFloat *gravity);
uint8_t dmpConvertToWorldFrame(int32_t *data, const uint8_t* packet=0);
uint8_t dmpConvertToWorldFrame(int16_t *data, const uint8_t* packet=0);
uint8_t dmpConvertToWorldFrame(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpConvertToWorldFrame(VectorInt16 *v, VectorInt16 *vReal, Quaternion *q);
uint8_t dmpGetGyroAndAccelSensor(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroAndAccelSensor(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroAndAccelSensor(VectorInt16 *g, VectorInt16 *a, const uint8_t* packet=0);
uint8_t dmpGetGyroSensor(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroSensor(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroSensor(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetControlData(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetTemperature(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGravity(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGravity(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGravity(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetGravity(VectorFloat *v, Quaternion *q);
uint8_t dmpGetUnquantizedAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetUnquantizedAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetUnquantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetQuantizedAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuantizedAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetExternalSensorData(int32_t *data, uint16_t size, const uint8_t* packet=0);
uint8_t dmpGetEIS(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetEuler(float *data, Quaternion *q);
uint8_t dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity);
// Get Floating Point data from FIFO
uint8_t dmpGetAccelFloat(float *data, const uint8_t* packet=0);
uint8_t dmpGetQuaternionFloat(float *data, const uint8_t* packet=0);
uint8_t dmpProcessFIFOPacket(const unsigned char *dmpData);
uint8_t dmpReadAndProcessFIFOPacket(uint8_t numPackets, uint8_t *processed=NULL);
uint8_t dmpSetFIFOProcessedCallback(void (*func) (void));
uint8_t dmpInitFIFOParam();
uint8_t dmpCloseFIFO();
uint8_t dmpSetGyroDataSource(uint8_t source);
uint8_t dmpDecodeQuantizedAccel();
uint32_t dmpGetGyroSumOfSquare();
uint32_t dmpGetAccelSumOfSquare();
void dmpOverrideQuaternion(long *q);
uint16_t dmpGetFIFOPacketSize();
uint8_t dmpGetCurrentFIFOPacket(uint8_t *data); // overflow proof
private:
uint8_t *dmpPacketBuffer;
uint16_t dmpPacketSize;
};
typedef MPU6050_6Axis_MotionApps20 MPU6050;
#endif /* _MPU6050_6AXIS_MOTIONAPPS20_H_ */

View File

@ -0,0 +1,627 @@
// I2Cdev library collection - MPU6050 I2C device class, 6-axis MotionApps 6.12 implementation
// Based on InvenSense MPU-6050 register map document rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
// 5/20/2013 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2021/09/27 - split implementations out of header files, finally
// 2019/07/10 - I incorporated DMP Firmware Version 6.12 Latest as of today with many features and bug fixes.
// - MPU6050 Registers have not changed just the DMP Image so that full backwards compatibility is present
// - Run-time calibration routine is enabled which calibrates after no motion state is detected
// - once no motion state is detected Calibration completes within 0.5 seconds
// - The Drawback is that the firmware image is larger.
// ... - ongoing debug release
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
// MotionApps 2.0 DMP implementation, built using the MPU-6050EVB evaluation board
#define MPU6050_INCLUDE_DMP_MOTIONAPPS612
#include "MPU6050_6Axis_MotionApps612.h"
// Tom Carpenter's conditional PROGMEM code
// http://forum.arduino.cc/index.php?topic=129407.0
#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP32)
#include <pgmspace.h>
#else
// Teensy 3.0 library conditional PROGMEM code from Paul Stoffregen
#ifndef __PGMSPACE_H_
#define __PGMSPACE_H_ 1
#include <inttypes.h>
#define PROGMEM
#define PGM_P const char *
#define PSTR(str) (str)
#define F(x) x
typedef void prog_void;
typedef char prog_char;
typedef unsigned char prog_uchar;
typedef int8_t prog_int8_t;
typedef uint8_t prog_uint8_t;
typedef int16_t prog_int16_t;
typedef uint16_t prog_uint16_t;
typedef int32_t prog_int32_t;
typedef uint32_t prog_uint32_t;
#define strcpy_P(dest, src) strcpy((dest), (src))
#define strcat_P(dest, src) strcat((dest), (src))
#define strcmp_P(a, b) strcmp((a), (b))
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#define pgm_read_float(addr) (*(const float *)(addr))
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
#define pgm_read_word_near(addr) pgm_read_word(addr)
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
#define pgm_read_float_near(addr) pgm_read_float(addr)
#define pgm_read_byte_far(addr) pgm_read_byte(addr)
#define pgm_read_word_far(addr) pgm_read_word(addr)
#define pgm_read_dword_far(addr) pgm_read_dword(addr)
#define pgm_read_float_far(addr) pgm_read_float(addr)
#endif
#endif
/* Source is from the InvenSense MotionApps v2 demo code. Original source is
* unavailable, unless you happen to be amazing as decompiling binary by
* hand (in which case, please contact me, and I'm totally serious).
*
* Also, I'd like to offer many, many thanks to Noah Zerkin for all of the
* DMP reverse-engineering he did to help make this bit of wizardry
* possible.
*/
// NOTE! Enabling DEBUG adds about 3.3kB to the flash program size.
// Debug output is now working even on ATMega328P MCUs (e.g. Arduino Uno)
// after moving string constants to flash memory storage using the F()
// compiler macro (Arduino IDE 1.0+ required).
//#define DEBUG
/* Control whether debugging macros are active at compile time */
#undef DB_ACTIVE
#ifdef DEBUG
#define DB_ACTIVE 1
#else
#define DB_ACTIVE 0
#endif /* DEBUG */
/*
** Usage: DB_PRINT((...));
** Usage: DB_PRINTLN((...));
**
** "..." is whatever extra arguments fmt requires (possibly nothing).
**
** The structure of the macros means that the code is always validated
** but is not called when DEBUG is undefined.
** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike.
*/
#define DEBUG_PRINT(...)\
do { if (DB_ACTIVE) Serial.print(__VA_ARGS__); } while (0)
#define DEBUG_PRINTF(...)\
do { if (DB_ACTIVE) Serial.printf(__VA_ARGS__); } while (0)
#define DEBUG_PRINTLN(...)\
do { if (DB_ACTIVE) Serial.println(__VA_ARGS__); } while (0)
#define DEBUG_PRINTLNF(x, y)\
do { if (DB_ACTIVE) Serial.println(x, y); } while (0)
#define MPU6050_DMP_CODE_SIZE 3062 // dmpMemory[]
/* ================================================================ *
| Default MotionApps v6.12 28-byte FIFO packet structure: |
| |
| [QUAT W][ ][QUAT X][ ][QUAT Y][ ][QUAT Z][ ] |
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
| |
| [GYRO X][GYRO Y][GYRO Z][ACC X ][ACC Y ][ACC Z ] |
| 16 17 18 19 20 21 22 23 24 25 26 27 |
* ================================================================ */
// this block of memory gets written to the MPU on start-up, and it seems
// to be volatile memory, so it has to be done each time (it only takes ~1
// second though)
// *** this is a capture of the DMP Firmware V6.1.2 after all the messy changes were made so we can just load it
const unsigned char dmpMemory[MPU6050_DMP_CODE_SIZE] PROGMEM = {
/* bank # 0 */
0x00, 0xF8, 0xF6, 0x2A, 0x3F, 0x68, 0xF5, 0x7A, 0x00, 0x06, 0xFF, 0xFE, 0x00, 0x03, 0x00, 0x00,
0x00, 0x65, 0x00, 0x54, 0xFF, 0xEF, 0x00, 0x00, 0xFA, 0x80, 0x00, 0x0B, 0x12, 0x82, 0x00, 0x01,
0x03, 0x0C, 0x30, 0xC3, 0x0A, 0x74, 0x56, 0x2D, 0x0D, 0x62, 0xDB, 0xC7, 0x16, 0xF4, 0xBA, 0x02,
0x38, 0x83, 0xF8, 0x83, 0x30, 0x00, 0xF8, 0x83, 0x25, 0x8E, 0xF8, 0x83, 0x30, 0x00, 0xF8, 0x83,
0xFF, 0xFF, 0xFF, 0xFF, 0x0C, 0xBD, 0xD8, 0x11, 0x24, 0x00, 0x04, 0x00, 0x1A, 0x82, 0x79, 0xA1,
0x00, 0x36, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x38, 0x83, 0x6F, 0xA2,
0x00, 0x3E, 0x03, 0x30, 0x40, 0x00, 0x00, 0x00, 0x02, 0xCA, 0xE3, 0x09, 0x3E, 0x80, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x1F, 0xA4, 0xE8, 0xE4, 0xFF, 0xF5, 0xDC, 0xB9, 0x00, 0x5B, 0x79, 0xCF, 0x1F, 0x3F, 0x78, 0x76,
0x00, 0x86, 0x7C, 0x5A, 0x00, 0x86, 0x23, 0x47, 0xFA, 0xB9, 0x86, 0x31, 0x00, 0x74, 0x87, 0x8A,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x05, 0xFF, 0xFF, 0xE9, 0xA8, 0x00, 0x00, 0x21, 0x82,
0xFA, 0xB8, 0x4D, 0x46, 0xFF, 0xFA, 0xDF, 0x3D, 0xFF, 0xFF, 0xB2, 0xB3, 0x00, 0x00, 0x00, 0x00,
0x3F, 0xFF, 0xBA, 0x98, 0x00, 0x5D, 0xAC, 0x08, 0x00, 0x0A, 0x63, 0x78, 0x00, 0x01, 0x46, 0x21,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x42, 0xB5, 0x00, 0x06, 0x00, 0x64, 0x00, 0x64, 0x00, 0x06,
0x14, 0x06, 0x02, 0x9F, 0x0F, 0x47, 0x91, 0x32, 0xD9, 0x0E, 0x9F, 0xC9, 0x1D, 0xCF, 0x4C, 0x34,
0x3B, 0xB6, 0x7A, 0xE8, 0x00, 0x64, 0x00, 0x06, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
/* bank # 1 */
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x00, 0x00, 0xFF, 0xF1, 0x00, 0x00, 0xFA, 0x46, 0x00, 0x00, 0xA2, 0xB8, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x04, 0xD6, 0x00, 0x00, 0x04, 0xCC, 0x00, 0x00, 0x04, 0xCC, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x05, 0x00, 0x64, 0x00, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x32, 0xF8, 0x98, 0x00, 0x00, 0xFF, 0x65, 0x00, 0x00, 0x83, 0x0F, 0x00, 0x00,
0x00, 0x06, 0x00, 0x00, 0xFF, 0xF1, 0x00, 0x00, 0xFA, 0x46, 0x00, 0x00, 0xA2, 0xB8, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0xB2, 0x6A, 0x00, 0x02, 0x00, 0x00,
0x00, 0x01, 0xFB, 0x83, 0x00, 0x7C, 0x00, 0x00, 0xFB, 0x15, 0xFC, 0x00, 0x1F, 0xB4, 0xFF, 0x83,
0x00, 0x00, 0x00, 0x01, 0x00, 0x65, 0x00, 0x07, 0x00, 0x64, 0x03, 0xE8, 0x00, 0x64, 0x00, 0x28,
0x00, 0x00, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x16, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x00, 0x00, 0x10, 0x00,
/* bank # 2 */
0x00, 0x28, 0x00, 0x00, 0xFF, 0xFF, 0x45, 0x81, 0xFF, 0xFF, 0xFA, 0x72, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x01, 0x00, 0x05, 0xBA, 0xC6, 0x00, 0x47, 0x78, 0xA2,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x23, 0xBB, 0x00, 0x2E, 0xA2, 0x5B, 0x00, 0x00, 0x05, 0x68, 0x00, 0x0B, 0xCF, 0x49,
0x00, 0x04, 0xFF, 0xFD, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x64, 0x00, 0x07, 0x00, 0x08, 0x00, 0x06, 0x00, 0x06, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x2E, 0xA2, 0x5B, 0x00, 0x00, 0x05, 0x68, 0x00, 0x0B, 0xCF, 0x49, 0x00, 0x00, 0x00, 0x00,
0x00, 0xF8, 0xF6, 0x2A, 0x3F, 0x68, 0xF5, 0x7A, 0x00, 0x04, 0xFF, 0xFD, 0x00, 0x02, 0x00, 0x00,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x0E,
0xFF, 0xFF, 0xFF, 0xCF, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0xFF, 0xFF, 0xFF, 0x9C,
0x00, 0x00, 0x43, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x64,
0xFF, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* bank # 3 */
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x24, 0x26, 0xD3,
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00, 0x96, 0x00, 0x3C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x9E, 0x65, 0x5D,
0x0C, 0x0A, 0x4E, 0x68, 0xCD, 0xCF, 0x77, 0x09, 0x50, 0x16, 0x67, 0x59, 0xC6, 0x19, 0xCE, 0x82,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x71, 0x1C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xD7, 0x84, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x11, 0xDC, 0x47, 0x03, 0x00, 0x00, 0x00, 0xC7, 0x93, 0x8F, 0x9D, 0x1E, 0x1B, 0x1C, 0x19,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0E, 0xDF, 0xA4, 0x38, 0x1F, 0x9E, 0x65, 0x5D,
0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x71, 0x1C, 0x02, 0x03, 0x18, 0x85, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3F, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF4, 0xC9, 0xFF, 0xFF, 0xBC, 0xF0, 0x00, 0x01, 0x0C, 0x0F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF5, 0xB7, 0xBA, 0xB3, 0x67, 0x7D, 0xDF, 0x7E, 0x72, 0x90, 0x2E, 0x55, 0x4C, 0xF6, 0xE6, 0x88,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* bank # 4 */
0xD8, 0xDC, 0xB4, 0xB8, 0xB0, 0xD8, 0xB9, 0xAB, 0xF3, 0xF8, 0xFA, 0xB3, 0xB7, 0xBB, 0x8E, 0x9E,
0xAE, 0xF1, 0x32, 0xF5, 0x1B, 0xF1, 0xB4, 0xB8, 0xB0, 0x80, 0x97, 0xF1, 0xA9, 0xDF, 0xDF, 0xDF,
0xAA, 0xDF, 0xDF, 0xDF, 0xF2, 0xAA, 0x4C, 0xCD, 0x6C, 0xA9, 0x0C, 0xC9, 0x2C, 0x97, 0xF1, 0xA9,
0x89, 0x26, 0x46, 0x66, 0xB2, 0x89, 0x99, 0xA9, 0x2D, 0x55, 0x7D, 0xB0, 0xB0, 0x8A, 0xA8, 0x96,
0x36, 0x56, 0x76, 0xF1, 0xBA, 0xA3, 0xB4, 0xB2, 0x80, 0xC0, 0xB8, 0xA8, 0x97, 0x11, 0xB2, 0x83,
0x98, 0xBA, 0xA3, 0xF0, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0xB2, 0xB9, 0xB4, 0x98, 0x83, 0xF1,
0xA3, 0x29, 0x55, 0x7D, 0xBA, 0xB5, 0xB1, 0xA3, 0x83, 0x93, 0xF0, 0x00, 0x28, 0x50, 0xF5, 0xB2,
0xB6, 0xAA, 0x83, 0x93, 0x28, 0x54, 0x7C, 0xF1, 0xB9, 0xA3, 0x82, 0x93, 0x61, 0xBA, 0xA2, 0xDA,
0xDE, 0xDF, 0xDB, 0x81, 0x9A, 0xB9, 0xAE, 0xF5, 0x60, 0x68, 0x70, 0xF1, 0xDA, 0xBA, 0xA2, 0xDF,
0xD9, 0xBA, 0xA2, 0xFA, 0xB9, 0xA3, 0x82, 0x92, 0xDB, 0x31, 0xBA, 0xA2, 0xD9, 0xBA, 0xA2, 0xF8,
0xDF, 0x85, 0xA4, 0xD0, 0xC1, 0xBB, 0xAD, 0x83, 0xC2, 0xC5, 0xC7, 0xB8, 0xA2, 0xDF, 0xDF, 0xDF,
0xBA, 0xA0, 0xDF, 0xDF, 0xDF, 0xD8, 0xD8, 0xF1, 0xB8, 0xAA, 0xB3, 0x8D, 0xB4, 0x98, 0x0D, 0x35,
0x5D, 0xB2, 0xB6, 0xBA, 0xAF, 0x8C, 0x96, 0x19, 0x8F, 0x9F, 0xA7, 0x0E, 0x16, 0x1E, 0xB4, 0x9A,
0xB8, 0xAA, 0x87, 0x2C, 0x54, 0x7C, 0xBA, 0xA4, 0xB0, 0x8A, 0xB6, 0x91, 0x32, 0x56, 0x76, 0xB2,
0x84, 0x94, 0xA4, 0xC8, 0x08, 0xCD, 0xD8, 0xB8, 0xB4, 0xB0, 0xF1, 0x99, 0x82, 0xA8, 0x2D, 0x55,
0x7D, 0x98, 0xA8, 0x0E, 0x16, 0x1E, 0xA2, 0x2C, 0x54, 0x7C, 0x92, 0xA4, 0xF0, 0x2C, 0x50, 0x78,
/* bank # 5 */
0xF1, 0x84, 0xA8, 0x98, 0xC4, 0xCD, 0xFC, 0xD8, 0x0D, 0xDB, 0xA8, 0xFC, 0x2D, 0xF3, 0xD9, 0xBA,
0xA6, 0xF8, 0xDA, 0xBA, 0xA6, 0xDE, 0xD8, 0xBA, 0xB2, 0xB6, 0x86, 0x96, 0xA6, 0xD0, 0xF3, 0xC8,
0x41, 0xDA, 0xA6, 0xC8, 0xF8, 0xD8, 0xB0, 0xB4, 0xB8, 0x82, 0xA8, 0x92, 0xF5, 0x2C, 0x54, 0x88,
0x98, 0xF1, 0x35, 0xD9, 0xF4, 0x18, 0xD8, 0xF1, 0xA2, 0xD0, 0xF8, 0xF9, 0xA8, 0x84, 0xD9, 0xC7,
0xDF, 0xF8, 0xF8, 0x83, 0xC5, 0xDA, 0xDF, 0x69, 0xDF, 0x83, 0xC1, 0xD8, 0xF4, 0x01, 0x14, 0xF1,
0xA8, 0x82, 0x4E, 0xA8, 0x84, 0xF3, 0x11, 0xD1, 0x82, 0xF5, 0xD9, 0x92, 0x28, 0x97, 0x88, 0xF1,
0x09, 0xF4, 0x1C, 0x1C, 0xD8, 0x84, 0xA8, 0xF3, 0xC0, 0xF9, 0xD1, 0xD9, 0x97, 0x82, 0xF1, 0x29,
0xF4, 0x0D, 0xD8, 0xF3, 0xF9, 0xF9, 0xD1, 0xD9, 0x82, 0xF4, 0xC2, 0x03, 0xD8, 0xDE, 0xDF, 0x1A,
0xD8, 0xF1, 0xA2, 0xFA, 0xF9, 0xA8, 0x84, 0x98, 0xD9, 0xC7, 0xDF, 0xF8, 0xF8, 0xF8, 0x83, 0xC7,
0xDA, 0xDF, 0x69, 0xDF, 0xF8, 0x83, 0xC3, 0xD8, 0xF4, 0x01, 0x14, 0xF1, 0x98, 0xA8, 0x82, 0x2E,
0xA8, 0x84, 0xF3, 0x11, 0xD1, 0x82, 0xF5, 0xD9, 0x92, 0x50, 0x97, 0x88, 0xF1, 0x09, 0xF4, 0x1C,
0xD8, 0x84, 0xA8, 0xF3, 0xC0, 0xF8, 0xF9, 0xD1, 0xD9, 0x97, 0x82, 0xF1, 0x49, 0xF4, 0x0D, 0xD8,
0xF3, 0xF9, 0xF9, 0xD1, 0xD9, 0x82, 0xF4, 0xC4, 0x03, 0xD8, 0xDE, 0xDF, 0xD8, 0xF1, 0xAD, 0x88,
0x98, 0xCC, 0xA8, 0x09, 0xF9, 0xD9, 0x82, 0x92, 0xA8, 0xF5, 0x7C, 0xF1, 0x88, 0x3A, 0xCF, 0x94,
0x4A, 0x6E, 0x98, 0xDB, 0x69, 0x31, 0xDA, 0xAD, 0xF2, 0xDE, 0xF9, 0xD8, 0x87, 0x95, 0xA8, 0xF2,
0x21, 0xD1, 0xDA, 0xA5, 0xF9, 0xF4, 0x17, 0xD9, 0xF1, 0xAE, 0x8E, 0xD0, 0xC0, 0xC3, 0xAE, 0x82,
/* bank # 6 */
0xC6, 0x84, 0xC3, 0xA8, 0x85, 0x95, 0xC8, 0xA5, 0x88, 0xF2, 0xC0, 0xF1, 0xF4, 0x01, 0x0E, 0xF1,
0x8E, 0x9E, 0xA8, 0xC6, 0x3E, 0x56, 0xF5, 0x54, 0xF1, 0x88, 0x72, 0xF4, 0x01, 0x15, 0xF1, 0x98,
0x45, 0x85, 0x6E, 0xF5, 0x8E, 0x9E, 0x04, 0x88, 0xF1, 0x42, 0x98, 0x5A, 0x8E, 0x9E, 0x06, 0x88,
0x69, 0xF4, 0x01, 0x1C, 0xF1, 0x98, 0x1E, 0x11, 0x08, 0xD0, 0xF5, 0x04, 0xF1, 0x1E, 0x97, 0x02,
0x02, 0x98, 0x36, 0x25, 0xDB, 0xF9, 0xD9, 0x85, 0xA5, 0xF3, 0xC1, 0xDA, 0x85, 0xA5, 0xF3, 0xDF,
0xD8, 0x85, 0x95, 0xA8, 0xF3, 0x09, 0xDA, 0xA5, 0xFA, 0xD8, 0x82, 0x92, 0xA8, 0xF5, 0x78, 0xF1,
0x88, 0x1A, 0x84, 0x9F, 0x26, 0x88, 0x98, 0x21, 0xDA, 0xF4, 0x1D, 0xF3, 0xD8, 0x87, 0x9F, 0x39,
0xD1, 0xAF, 0xD9, 0xDF, 0xDF, 0xFB, 0xF9, 0xF4, 0x0C, 0xF3, 0xD8, 0xFA, 0xD0, 0xF8, 0xDA, 0xF9,
0xF9, 0xD0, 0xDF, 0xD9, 0xF9, 0xD8, 0xF4, 0x0B, 0xD8, 0xF3, 0x87, 0x9F, 0x39, 0xD1, 0xAF, 0xD9,
0xDF, 0xDF, 0xF4, 0x1D, 0xF3, 0xD8, 0xFA, 0xFC, 0xA8, 0x69, 0xF9, 0xF9, 0xAF, 0xD0, 0xDA, 0xDE,
0xFA, 0xD9, 0xF8, 0x8F, 0x9F, 0xA8, 0xF1, 0xCC, 0xF3, 0x98, 0xDB, 0x45, 0xD9, 0xAF, 0xDF, 0xD0,
0xF8, 0xD8, 0xF1, 0x8F, 0x9F, 0xA8, 0xCA, 0xF3, 0x88, 0x09, 0xDA, 0xAF, 0x8F, 0xCB, 0xF8, 0xD8,
0xF2, 0xAD, 0x97, 0x8D, 0x0C, 0xD9, 0xA5, 0xDF, 0xF9, 0xBA, 0xA6, 0xF3, 0xFA, 0xF4, 0x12, 0xF2,
0xD8, 0x95, 0x0D, 0xD1, 0xD9, 0xBA, 0xA6, 0xF3, 0xFA, 0xDA, 0xA5, 0xF2, 0xC1, 0xBA, 0xA6, 0xF3,
0xDF, 0xD8, 0xF1, 0xBA, 0xB2, 0xB6, 0x86, 0x96, 0xA6, 0xD0, 0xCA, 0xF3, 0x49, 0xDA, 0xA6, 0xCB,
0xF8, 0xD8, 0xB0, 0xB4, 0xB8, 0xD8, 0xAD, 0x84, 0xF2, 0xC0, 0xDF, 0xF1, 0x8F, 0xCB, 0xC3, 0xA8,
/* bank # 7 */
0xB2, 0xB6, 0x86, 0x96, 0xC8, 0xC1, 0xCB, 0xC3, 0xF3, 0xB0, 0xB4, 0x88, 0x98, 0xA8, 0x21, 0xDB,
0x71, 0x8D, 0x9D, 0x71, 0x85, 0x95, 0x21, 0xD9, 0xAD, 0xF2, 0xFA, 0xD8, 0x85, 0x97, 0xA8, 0x28,
0xD9, 0xF4, 0x08, 0xD8, 0xF2, 0x8D, 0x29, 0xDA, 0xF4, 0x05, 0xD9, 0xF2, 0x85, 0xA4, 0xC2, 0xF2,
0xD8, 0xA8, 0x8D, 0x94, 0x01, 0xD1, 0xD9, 0xF4, 0x11, 0xF2, 0xD8, 0x87, 0x21, 0xD8, 0xF4, 0x0A,
0xD8, 0xF2, 0x84, 0x98, 0xA8, 0xC8, 0x01, 0xD1, 0xD9, 0xF4, 0x11, 0xD8, 0xF3, 0xA4, 0xC8, 0xBB,
0xAF, 0xD0, 0xF2, 0xDE, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xD8, 0xF1, 0xB8, 0xF6,
0xB5, 0xB9, 0xB0, 0x8A, 0x95, 0xA3, 0xDE, 0x3C, 0xA3, 0xD9, 0xF8, 0xD8, 0x5C, 0xA3, 0xD9, 0xF8,
0xD8, 0x7C, 0xA3, 0xD9, 0xF8, 0xD8, 0xF8, 0xF9, 0xD1, 0xA5, 0xD9, 0xDF, 0xDA, 0xFA, 0xD8, 0xB1,
0x85, 0x30, 0xF7, 0xD9, 0xDE, 0xD8, 0xF8, 0x30, 0xAD, 0xDA, 0xDE, 0xD8, 0xF2, 0xB4, 0x8C, 0x99,
0xA3, 0x2D, 0x55, 0x7D, 0xA0, 0x83, 0xDF, 0xDF, 0xDF, 0xB5, 0x91, 0xA0, 0xF6, 0x29, 0xD9, 0xFB,
0xD8, 0xA0, 0xFC, 0x29, 0xD9, 0xFA, 0xD8, 0xA0, 0xD0, 0x51, 0xD9, 0xF8, 0xD8, 0xFC, 0x51, 0xD9,
0xF9, 0xD8, 0x79, 0xD9, 0xFB, 0xD8, 0xA0, 0xD0, 0xFC, 0x79, 0xD9, 0xFA, 0xD8, 0xA1, 0xF9, 0xF9,
0xF9, 0xF9, 0xF9, 0xA0, 0xDA, 0xDF, 0xDF, 0xDF, 0xD8, 0xA1, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xAC,
0xDE, 0xF8, 0xAD, 0xDE, 0x83, 0x93, 0xAC, 0x2C, 0x54, 0x7C, 0xF1, 0xA8, 0xDF, 0xDF, 0xDF, 0xF6,
0x9D, 0x2C, 0xDA, 0xA0, 0xDF, 0xD9, 0xFA, 0xDB, 0x2D, 0xF8, 0xD8, 0xA8, 0x50, 0xDA, 0xA0, 0xD0,
0xDE, 0xD9, 0xD0, 0xF8, 0xF8, 0xF8, 0xDB, 0x55, 0xF8, 0xD8, 0xA8, 0x78, 0xDA, 0xA0, 0xD0, 0xDF,
/* bank # 8 */
0xD9, 0xD0, 0xFA, 0xF8, 0xF8, 0xF8, 0xF8, 0xDB, 0x7D, 0xF8, 0xD8, 0x9C, 0xA8, 0x8C, 0xF5, 0x30,
0xDB, 0x38, 0xD9, 0xD0, 0xDE, 0xDF, 0xA0, 0xD0, 0xDE, 0xDF, 0xD8, 0xA8, 0x48, 0xDB, 0x58, 0xD9,
0xDF, 0xD0, 0xDE, 0xA0, 0xDF, 0xD0, 0xDE, 0xD8, 0xA8, 0x68, 0xDB, 0x70, 0xD9, 0xDF, 0xDF, 0xA0,
0xDF, 0xDF, 0xD8, 0xF1, 0xA8, 0x88, 0x90, 0x2C, 0x54, 0x7C, 0x98, 0xA8, 0xD0, 0x5C, 0x38, 0xD1,
0xDA, 0xF2, 0xAE, 0x8C, 0xDF, 0xF9, 0xD8, 0xB0, 0x87, 0xA8, 0xC1, 0xC1, 0xB1, 0x88, 0xA8, 0xC6,
0xF9, 0xF9, 0xDA, 0x36, 0xD8, 0xA8, 0xF9, 0xDA, 0x36, 0xD8, 0xA8, 0xF9, 0xDA, 0x36, 0xD8, 0xA8,
0xF9, 0xDA, 0x36, 0xD8, 0xA8, 0xF9, 0xDA, 0x36, 0xD8, 0xF7, 0x8D, 0x9D, 0xAD, 0xF8, 0x18, 0xDA,
0xF2, 0xAE, 0xDF, 0xD8, 0xF7, 0xAD, 0xFA, 0x30, 0xD9, 0xA4, 0xDE, 0xF9, 0xD8, 0xF2, 0xAE, 0xDE,
0xFA, 0xF9, 0x83, 0xA7, 0xD9, 0xC3, 0xC5, 0xC7, 0xF1, 0x88, 0x9B, 0xA7, 0x7A, 0xAD, 0xF7, 0xDE,
0xDF, 0xA4, 0xF8, 0x84, 0x94, 0x08, 0xA7, 0x97, 0xF3, 0x00, 0xAE, 0xF2, 0x98, 0x19, 0xA4, 0x88,
0xC6, 0xA3, 0x94, 0x88, 0xF6, 0x32, 0xDF, 0xF2, 0x83, 0x93, 0xDB, 0x09, 0xD9, 0xF2, 0xAA, 0xDF,
0xD8, 0xD8, 0xAE, 0xF8, 0xF9, 0xD1, 0xDA, 0xF3, 0xA4, 0xDE, 0xA7, 0xF1, 0x88, 0x9B, 0x7A, 0xD8,
0xF3, 0x84, 0x94, 0xAE, 0x19, 0xF9, 0xDA, 0xAA, 0xF1, 0xDF, 0xD8, 0xA8, 0x81, 0xC0, 0xC3, 0xC5,
0xC7, 0xA3, 0x92, 0x83, 0xF6, 0x28, 0xAD, 0xDE, 0xD9, 0xF8, 0xD8, 0xA3, 0x50, 0xAD, 0xD9, 0xF8,
0xD8, 0xA3, 0x78, 0xAD, 0xD9, 0xF8, 0xD8, 0xF8, 0xF9, 0xD1, 0xA1, 0xDA, 0xDE, 0xC3, 0xC5, 0xC7,
0xD8, 0xA1, 0x81, 0x94, 0xF8, 0x18, 0xF2, 0xB0, 0x89, 0xAC, 0xC3, 0xC5, 0xC7, 0xF1, 0xD8, 0xB8,
/* bank # 9 */
0xB4, 0xB0, 0x97, 0x86, 0xA8, 0x31, 0x9B, 0x06, 0x99, 0x07, 0xAB, 0x97, 0x28, 0x88, 0x9B, 0xF0,
0x0C, 0x20, 0x14, 0x40, 0xB0, 0xB4, 0xB8, 0xF0, 0xA8, 0x8A, 0x9A, 0x28, 0x50, 0x78, 0xB7, 0x9B,
0xA8, 0x29, 0x51, 0x79, 0x24, 0x70, 0x59, 0x44, 0x69, 0x38, 0x64, 0x48, 0x31, 0xF1, 0xBB, 0xAB,
0x88, 0x00, 0x2C, 0x54, 0x7C, 0xF0, 0xB3, 0x8B, 0xB8, 0xA8, 0x04, 0x28, 0x50, 0x78, 0xF1, 0xB0,
0x88, 0xB4, 0x97, 0x26, 0xA8, 0x59, 0x98, 0xBB, 0xAB, 0xB3, 0x8B, 0x02, 0x26, 0x46, 0x66, 0xB0,
0xB8, 0xF0, 0x8A, 0x9C, 0xA8, 0x29, 0x51, 0x79, 0x8B, 0x29, 0x51, 0x79, 0x8A, 0x24, 0x70, 0x59,
0x8B, 0x20, 0x58, 0x71, 0x8A, 0x44, 0x69, 0x38, 0x8B, 0x39, 0x40, 0x68, 0x8A, 0x64, 0x48, 0x31,
0x8B, 0x30, 0x49, 0x60, 0x88, 0xF1, 0xAC, 0x00, 0x2C, 0x54, 0x7C, 0xF0, 0x8C, 0xA8, 0x04, 0x28,
0x50, 0x78, 0xF1, 0x88, 0x97, 0x26, 0xA8, 0x59, 0x98, 0xAC, 0x8C, 0x02, 0x26, 0x46, 0x66, 0xF0,
0x89, 0x9C, 0xA8, 0x29, 0x51, 0x79, 0x24, 0x70, 0x59, 0x44, 0x69, 0x38, 0x64, 0x48, 0x31, 0xA9,
0x88, 0x09, 0x20, 0x59, 0x70, 0xAB, 0x11, 0x38, 0x40, 0x69, 0xA8, 0x19, 0x31, 0x48, 0x60, 0x8C,
0xA8, 0x3C, 0x41, 0x5C, 0x20, 0x7C, 0x00, 0xF1, 0x87, 0x98, 0x19, 0x86, 0xA8, 0x6E, 0x76, 0x7E,
0xA9, 0x99, 0x88, 0x2D, 0x55, 0x7D, 0xD8, 0xB1, 0xB5, 0xB9, 0xA3, 0xDF, 0xDF, 0xDF, 0xAE, 0xD0,
0xDF, 0xAA, 0xD0, 0xDE, 0xF2, 0xAB, 0xF8, 0xF9, 0xD9, 0xB0, 0x87, 0xC4, 0xAA, 0xF1, 0xDF, 0xDF,
0xBB, 0xAF, 0xDF, 0xDF, 0xB9, 0xD8, 0xB1, 0xF1, 0xA3, 0x97, 0x8E, 0x60, 0xDF, 0xB0, 0x84, 0xF2,
0xC8, 0xF8, 0xF9, 0xD9, 0xDE, 0xD8, 0x93, 0x85, 0xF1, 0x4A, 0xB1, 0x83, 0xA3, 0x08, 0xB5, 0x83,
/* bank # 10 */
0x9A, 0x08, 0x10, 0xB7, 0x9F, 0x10, 0xD8, 0xF1, 0xB0, 0xBA, 0xAE, 0xB0, 0x8A, 0xC2, 0xB2, 0xB6,
0x8E, 0x9E, 0xF1, 0xFB, 0xD9, 0xF4, 0x1D, 0xD8, 0xF9, 0xD9, 0x0C, 0xF1, 0xD8, 0xF8, 0xF8, 0xAD,
0x61, 0xD9, 0xAE, 0xFB, 0xD8, 0xF4, 0x0C, 0xF1, 0xD8, 0xF8, 0xF8, 0xAD, 0x19, 0xD9, 0xAE, 0xFB,
0xDF, 0xD8, 0xF4, 0x16, 0xF1, 0xD8, 0xF8, 0xAD, 0x8D, 0x61, 0xD9, 0xF4, 0xF4, 0xAC, 0xF5, 0x9C,
0x9C, 0x8D, 0xDF, 0x2B, 0xBA, 0xB6, 0xAE, 0xFA, 0xF8, 0xF4, 0x0B, 0xD8, 0xF1, 0xAE, 0xD0, 0xF8,
0xAD, 0x51, 0xDA, 0xAE, 0xFA, 0xF8, 0xF1, 0xD8, 0xB9, 0xB1, 0xB6, 0xA3, 0x83, 0x9C, 0x08, 0xB9,
0xB1, 0x83, 0x9A, 0xB5, 0xAA, 0xC0, 0xFD, 0x30, 0x83, 0xB7, 0x9F, 0x10, 0xB5, 0x8B, 0x93, 0xF2,
0x02, 0x02, 0xD1, 0xAB, 0xDA, 0xDE, 0xD8, 0xF1, 0xB0, 0x80, 0xBA, 0xAB, 0xC0, 0xC3, 0xB2, 0x84,
0xC1, 0xC3, 0xD8, 0xB1, 0xB9, 0xF3, 0x8B, 0xA3, 0x91, 0xB6, 0x09, 0xB4, 0xD9, 0xAB, 0xDE, 0xB0,
0x87, 0x9C, 0xB9, 0xA3, 0xDD, 0xF1, 0xB3, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0xB0, 0x87, 0x20, 0x28,
0x30, 0x38, 0xB2, 0x8B, 0xB6, 0x9B, 0xF2, 0xA3, 0xC0, 0xC8, 0xC2, 0xC4, 0xCC, 0xC6, 0xA3, 0xA3,
0xA3, 0xF1, 0xB0, 0x87, 0xB5, 0x9A, 0xD8, 0xF3, 0x9B, 0xA3, 0xA3, 0xDC, 0xBA, 0xAC, 0xDF, 0xB9, //Reverted back as packet size changes causing isues... TODO:change 2742 from 0xD8 to 0x20 Including the DMP_FEATURE_TAP -- known issue in which if you do not enable DMP_FEATURE_TAP then the interrupts will be at 200Hz even if fifo rate
0xA3, 0xFE, 0xF2, 0xAB, 0xC4, 0xAA, 0xF1, 0xDF, 0xDF, 0xBB, 0xAF, 0xDF, 0xDF, 0xA3, 0xA3, 0xA3,
0xD8, 0xD8, 0xD8, 0xBB, 0xB3, 0xB7, 0xF1, 0xAA, 0xF9, 0xDA, 0xFF, 0xD9, 0x80, 0x9A, 0xAA, 0x28,
0xB4, 0x80, 0x98, 0xA7, 0x20, 0xB7, 0x97, 0x87, 0xA8, 0x66, 0x88, 0xF0, 0x79, 0x51, 0xF1, 0x90,
0x2C, 0x87, 0x0C, 0xA7, 0x81, 0x97, 0x62, 0x93, 0xF0, 0x71, 0x71, 0x60, 0x85, 0x94, 0x01, 0x29,
/* bank # 11 */
0x51, 0x79, 0x90, 0xA5, 0xF1, 0x28, 0x4C, 0x6C, 0x87, 0x0C, 0x95, 0x18, 0x85, 0x78, 0xA3, 0x83,
0x90, 0x28, 0x4C, 0x6C, 0x88, 0x6C, 0xD8, 0xF3, 0xA2, 0x82, 0x00, 0xF2, 0x10, 0xA8, 0x92, 0x19,
0x80, 0xA2, 0xF2, 0xD9, 0x26, 0xD8, 0xF1, 0x88, 0xA8, 0x4D, 0xD9, 0x48, 0xD8, 0x96, 0xA8, 0x39,
0x80, 0xD9, 0x3C, 0xD8, 0x95, 0x80, 0xA8, 0x39, 0xA6, 0x86, 0x98, 0xD9, 0x2C, 0xDA, 0x87, 0xA7,
0x2C, 0xD8, 0xA8, 0x89, 0x95, 0x19, 0xA9, 0x80, 0xD9, 0x38, 0xD8, 0xA8, 0x89, 0x39, 0xA9, 0x80,
0xDA, 0x3C, 0xD8, 0xA8, 0x2E, 0xA8, 0x39, 0x90, 0xD9, 0x0C, 0xD8, 0xA8, 0x95, 0x31, 0x98, 0xD9,
0x0C, 0xD8, 0xA8, 0x09, 0xD9, 0xFF, 0xD8, 0x01, 0xDA, 0xFF, 0xD8, 0x95, 0x39, 0xA9, 0xDA, 0x26,
0xFF, 0xD8, 0x90, 0xA8, 0x0D, 0x89, 0x99, 0xA8, 0x10, 0x80, 0x98, 0x21, 0xDA, 0x2E, 0xD8, 0x89,
0x99, 0xA8, 0x31, 0x80, 0xDA, 0x2E, 0xD8, 0xA8, 0x86, 0x96, 0x31, 0x80, 0xDA, 0x2E, 0xD8, 0xA8,
0x87, 0x31, 0x80, 0xDA, 0x2E, 0xD8, 0xA8, 0x82, 0x92, 0xF3, 0x41, 0x80, 0xF1, 0xD9, 0x2E, 0xD8,
0xA8, 0x82, 0xF3, 0x19, 0x80, 0xF1, 0xD9, 0x2E, 0xD8, 0x82, 0xAC, 0xF3, 0xC0, 0xA2, 0x80, 0x22,
0xF1, 0xA6, 0x2E, 0xA7, 0x2E, 0xA9, 0x22, 0x98, 0xA8, 0x29, 0xDA, 0xAC, 0xDE, 0xFF, 0xD8, 0xA2,
0xF2, 0x2A, 0xF1, 0xA9, 0x2E, 0x82, 0x92, 0xA8, 0xF2, 0x31, 0x80, 0xA6, 0x96, 0xF1, 0xD9, 0x00,
0xAC, 0x8C, 0x9C, 0x0C, 0x30, 0xAC, 0xDE, 0xD0, 0xDE, 0xFF, 0xD8, 0x8C, 0x9C, 0xAC, 0xD0, 0x10,
0xAC, 0xDE, 0x80, 0x92, 0xA2, 0xF2, 0x4C, 0x82, 0xA8, 0xF1, 0xCA, 0xF2, 0x35, 0xF1, 0x96, 0x88,
0xA6, 0xD9, 0x00, 0xD8, 0xF1, 0xFF,
};
// this is the most basic initialization I can create. with the intent that we access the register bytes as few times as needed to get the job done.
// for detailed descriptins of all registers and there purpose google "MPU-6000/MPU-6050 Register Map and Descriptions"
uint8_t MPU6050::dmpInitialize(uint8_t rateDivisor, uint8_t mpuAddr) { // Lets get it over with fast Write everything once and set it up necely
uint8_t val;
uint16_t ival;
// Reset procedure per instructions in the "MPU-6000/MPU-6050 Register Map and Descriptions" page 41
I2Cdev::writeBit(devAddr,0x6B, 7, (val = 1), wireObj); //PWR_MGMT_1: reset with 100ms delay
delay(100);
I2Cdev::writeBits(devAddr,0x6A, 2, 3, (val = 0b111), wireObj); // full SIGNAL_PATH_RESET: with another 100ms delay
delay(100);
I2Cdev::writeBytes(devAddr,0x6B, 1, &(val = 0x01), wireObj); // 1000 0001 PWR_MGMT_1:Clock Source Select PLL_X_gyro
I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x00), wireObj); // 0000 0000 INT_ENABLE: no Interrupt
I2Cdev::writeBytes(devAddr,0x23, 1, &(val = 0x00), wireObj); // 0000 0000 MPU FIFO_EN: (all off) Using DMP's FIFO instead
I2Cdev::writeBytes(devAddr,0x1C, 1, &(val = 0x00), wireObj); // 0000 0000 ACCEL_CONFIG: 0 = Accel Full Scale Select: 2g
I2Cdev::writeBytes(devAddr,0x37, 1, &(val = 0x80), wireObj); // 1001 0000 INT_PIN_CFG: ACTL The logic level for int pin is active low. and interrupt status bits are cleared on any read
I2Cdev::writeBytes(devAddr,0x6B, 1, &(val = 0x01), wireObj); // 0000 0001 PWR_MGMT_1: Clock Source Select PLL_X_gyro
I2Cdev::writeBytes(devAddr,0x19, 1, &(val = rateDivisor), wireObj); // 0000 0100 SMPLRT_DIV: Divides the internal sample rate 400Hz ( Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV))
I2Cdev::writeBytes(devAddr,0x1A, 1, &(val = 0x01), wireObj); // 0000 0001 CONFIG: Digital Low Pass Filter (DLPF) Configuration 188HZ //Im betting this will be the beat
if (!writeProgMemoryBlock(dmpMemory, MPU6050_DMP_CODE_SIZE)) return 1; // Loads the DMP image into the MPU6050 Memory // Should Never Fail
I2Cdev::writeWords(devAddr, 0x70, 1, &(ival = 0x0400), wireObj); // DMP Program Start Address
I2Cdev::writeBytes(devAddr,0x1B, 1, &(val = 0x18), wireObj); // 0001 1000 GYRO_CONFIG: 3 = +2000 Deg/sec
I2Cdev::writeBytes(devAddr,0x6A, 1, &(val = 0xC0), wireObj); // 1100 1100 USER_CTRL: Enable Fifo and Reset Fifo
I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x02), wireObj); // 0000 0010 INT_ENABLE: RAW_DMP_INT_EN on
I2Cdev::writeBit(devAddr,0x6A, 2, 1, wireObj); // Reset FIFO one last time just for kicks. (MPUi2cWrite reads 0x6A first and only alters 1 bit and then saves the byte)
setDMPEnabled(false); // disable DMP for compatibility with the MPU6050 library
/*
dmpPacketSize += 16;//DMP_FEATURE_6X_LP_QUAT
dmpPacketSize += 6;//DMP_FEATURE_SEND_RAW_ACCEL
dmpPacketSize += 6;//DMP_FEATURE_SEND_RAW_GYRO
*/
dmpPacketSize = 28;
return 0;
}
bool MPU6050::dmpPacketAvailable() {
return getFIFOCount() >= dmpGetFIFOPacketSize();
}
// uint8_t MPU6050::dmpSetFIFORate(uint8_t fifoRate);
// uint8_t MPU6050::dmpGetFIFORate();
// uint8_t MPU6050::dmpGetSampleStepSizeMS();
// uint8_t MPU6050::dmpGetSampleFrequency();
// int32_t MPU6050::dmpDecodeTemperature(int8_t tempReg);
//uint8_t MPU6050::dmpRegisterFIFORateProcess(inv_obj_func func, int16_t priority);
//uint8_t MPU6050::dmpUnregisterFIFORateProcess(inv_obj_func func);
//uint8_t MPU6050::dmpRunFIFORateProcesses();
// uint8_t MPU6050::dmpSendQuaternion(uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendGyro(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendAccel(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendLinearAccel(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendLinearAccelInWorld(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendControlData(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendExternalSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendGravity(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendPacketNumber(uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendQuantizedAccel(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050::dmpSendEIS(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t MPU6050::dmpGetAccel(int32_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((uint32_t)packet[16] << 8) | packet[17]);
data[1] = (((uint32_t)packet[18] << 8) | packet[19]);
data[2] = (((uint32_t)packet[20] << 8) | packet[21]);
return 0;
}
uint8_t MPU6050::dmpGetAccel(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (packet[16] << 8) | packet[17];
data[1] = (packet[18] << 8) | packet[19];
data[2] = (packet[20] << 8) | packet[21];
return 0;
}
uint8_t MPU6050::dmpGetAccel(VectorInt16 *v, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
v -> x = (packet[16] << 8) | packet[17];
v -> y = (packet[18] << 8) | packet[19];
v -> z = (packet[20] << 8) | packet[21];
return 0;
}
uint8_t MPU6050::dmpGetQuaternion(int32_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((uint32_t)packet[0] << 24) | ((uint32_t)packet[1] << 16) | ((uint32_t)packet[2] << 8) | packet[3]);
data[1] = (((uint32_t)packet[4] << 24) | ((uint32_t)packet[5] << 16) | ((uint32_t)packet[6] << 8) | packet[7]);
data[2] = (((uint32_t)packet[8] << 24) | ((uint32_t)packet[9] << 16) | ((uint32_t)packet[10] << 8) | packet[11]);
data[3] = (((uint32_t)packet[12] << 24) | ((uint32_t)packet[13] << 16) | ((uint32_t)packet[14] << 8) | packet[15]);
return 0;
}
uint8_t MPU6050::dmpGetQuaternion(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = ((packet[0] << 8) | packet[1]);
data[1] = ((packet[4] << 8) | packet[5]);
data[2] = ((packet[8] << 8) | packet[9]);
data[3] = ((packet[12] << 8) | packet[13]);
return 0;
}
uint8_t MPU6050::dmpGetQuaternion(Quaternion *q, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
int16_t qI[4];
uint8_t status = dmpGetQuaternion(qI, packet);
if (status == 0) {
q -> w = (float)qI[0] / 16384.0f;
q -> x = (float)qI[1] / 16384.0f;
q -> y = (float)qI[2] / 16384.0f;
q -> z = (float)qI[3] / 16384.0f;
return 0;
}
return status; // int16 return value, indicates error if this line is reached
}
// uint8_t MPU6050::dmpGet6AxisQuaternion(long *data, const uint8_t* packet);
// uint8_t MPU6050::dmpGetRelativeQuaternion(long *data, const uint8_t* packet);
uint8_t MPU6050::dmpGetGyro(int32_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((uint32_t)packet[22] << 8) | packet[23]);
data[1] = (((uint32_t)packet[24] << 8) | packet[25]);
data[2] = (((uint32_t)packet[26] << 8) | packet[27]);
return 0;
}
uint8_t MPU6050::dmpGetGyro(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (packet[22] << 8) | packet[23];
data[1] = (packet[24] << 8) | packet[25];
data[2] = (packet[26] << 8) | packet[27];
return 0;
}
uint8_t MPU6050::dmpGetGyro(VectorInt16 *v, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
v -> x = (packet[22] << 8) | packet[23];
v -> y = (packet[24] << 8) | packet[25];
v -> z = (packet[26] << 8) | packet[27];
return 0;
}
// uint8_t MPU6050::dmpSetLinearAccelFilterCoefficient(float coef);
// uint8_t MPU6050::dmpGetLinearAccel(long *data, const uint8_t* packet);
uint8_t MPU6050::dmpGetLinearAccel(VectorInt16 *v, VectorInt16 *vRaw, VectorFloat *gravity) {
// get rid of the gravity component (+1g = +16384 in standard DMP FIFO packet, sensitivity is 2g)
v -> x = vRaw -> x - gravity -> x*16384;
v -> y = vRaw -> y - gravity -> y*16384;
v -> z = vRaw -> z - gravity -> z*16384;
return 0;
}
// uint8_t MPU6050::dmpGetLinearAccelInWorld(long *data, const uint8_t* packet);
uint8_t MPU6050::dmpGetLinearAccelInWorld(VectorInt16 *v, VectorInt16 *vReal, Quaternion *q) {
// rotate measured 3D acceleration vector into original state
// frame of reference based on orientation quaternion
memcpy(v, vReal, sizeof(VectorInt16));
v -> rotate(q);
return 0;
}
// uint8_t MPU6050::dmpGetGyroAndAccelSensor(long *data, const uint8_t* packet);
// uint8_t MPU6050::dmpGetGyroSensor(long *data, const uint8_t* packet);
// uint8_t MPU6050::dmpGetControlData(long *data, const uint8_t* packet);
// uint8_t MPU6050::dmpGetTemperature(long *data, const uint8_t* packet);
// uint8_t MPU6050::dmpGetGravity(long *data, const uint8_t* packet);
uint8_t MPU6050::dmpGetGravity(int16_t *data, const uint8_t* packet) {
/* +1g corresponds to +16384, sensitivity is 2g. */
int16_t qI[4];
uint8_t status = dmpGetQuaternion(qI, packet);
data[0] = ((int32_t)qI[1] * qI[3] - (int32_t)qI[0] * qI[2]) / 16384;
data[1] = ((int32_t)qI[0] * qI[1] + (int32_t)qI[2] * qI[3]) / 16384;
data[2] = ((int32_t)qI[0] * qI[0] - (int32_t)qI[1] * qI[1]
- (int32_t)qI[2] * qI[2] + (int32_t)qI[3] * qI[3]) / (int32_t)(2 * 16384L);
return status;
}
uint8_t MPU6050::dmpGetGravity(VectorFloat *v, Quaternion *q) {
v -> x = 2 * (q -> x*q -> z - q -> w*q -> y);
v -> y = 2 * (q -> w*q -> x + q -> y*q -> z);
v -> z = q -> w*q -> w - q -> x*q -> x - q -> y*q -> y + q -> z*q -> z;
return 0;
}
// uint8_t MPU6050::dmpGetUnquantizedAccel(long *data, const uint8_t* packet);
// uint8_t MPU6050::dmpGetQuantizedAccel(long *data, const uint8_t* packet);
// uint8_t MPU6050::dmpGetExternalSensorData(long *data, int size, const uint8_t* packet);
// uint8_t MPU6050::dmpGetEIS(long *data, const uint8_t* packet);
uint8_t MPU6050::dmpGetEuler(float *data, Quaternion *q) {
data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1); // psi
data[1] = -asin(2*q -> x*q -> z + 2*q -> w*q -> y); // theta
data[2] = atan2(2*q -> y*q -> z - 2*q -> w*q -> x, 2*q -> w*q -> w + 2*q -> z*q -> z - 1); // phi
return 0;
}
#ifdef USE_OLD_DMPGETYAWPITCHROLL
uint8_t MPU6050::dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity) {
// yaw: (about Z axis)
data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1);
// pitch: (nose up/down, about Y axis)
data[1] = atan(gravity -> x / sqrt(gravity -> y*gravity -> y + gravity -> z*gravity -> z));
// roll: (tilt left/right, about X axis)
data[2] = atan(gravity -> y / sqrt(gravity -> x*gravity -> x + gravity -> z*gravity -> z));
return 0;
}
#else
uint8_t MPU6050::dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity) {
// yaw: (about Z axis)
data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1);
// pitch: (nose up/down, about Y axis)
data[1] = atan2(gravity -> x , sqrt(gravity -> y*gravity -> y + gravity -> z*gravity -> z));
// roll: (tilt left/right, about X axis)
data[2] = atan2(gravity -> y , gravity -> z);
if (gravity -> z < 0) {
if(data[1] > 0) {
data[1] = PI - data[1];
} else {
data[1] = -PI - data[1];
}
}
return 0;
}
#endif
// uint8_t MPU6050::dmpGetAccelFloat(float *data, const uint8_t* packet);
// uint8_t MPU6050::dmpGetQuaternionFloat(float *data, const uint8_t* packet);
uint8_t MPU6050::dmpProcessFIFOPacket(const unsigned char *dmpData) {
(void)dmpData; // unused parameter
/*for (uint8_t k = 0; k < dmpPacketSize; k++) {
if (dmpData[k] < 0x10) Serial.print("0");
Serial.print(dmpData[k], HEX);
Serial.print(" ");
}
Serial.print("\n");*/
//Serial.println((uint16_t)dmpPacketBuffer);
return 0;
}
uint8_t MPU6050::dmpReadAndProcessFIFOPacket(uint8_t numPackets, uint8_t *processed) {
uint8_t status;
uint8_t buf[dmpPacketSize];
for (uint8_t i = 0; i < numPackets; i++) {
// read packet from FIFO
getFIFOBytes(buf, dmpPacketSize);
// process packet
if ((status = dmpProcessFIFOPacket(buf)) > 0) return status;
// increment external process count variable, if supplied
if (processed != 0) (*processed)++;
}
return 0;
}
// uint8_t MPU6050::dmpSetFIFOProcessedCallback(void (*func) (void));
// uint8_t MPU6050::dmpInitFIFOParam();
// uint8_t MPU6050::dmpCloseFIFO();
// uint8_t MPU6050::dmpSetGyroDataSource(uint_fast8_t source);
// uint8_t MPU6050::dmpDecodeQuantizedAccel();
// uint32_t MPU6050::dmpGetGyroSumOfSquare();
// uint32_t MPU6050::dmpGetAccelSumOfSquare();
// void MPU6050::dmpOverrideQuaternion(long *q);
uint16_t MPU6050::dmpGetFIFOPacketSize() {
return dmpPacketSize;
}
uint8_t MPU6050::dmpGetCurrentFIFOPacket(uint8_t *data) { // overflow proof
return(GetCurrentFIFOPacket(data, dmpPacketSize));
}

View File

@ -0,0 +1,158 @@
// I2Cdev library collection - MPU6050 I2C device class
// Based on InvenSense MPU-6050 register map document rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
// 10/3/2011 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2021/09/27 - split implementations out of header files, finally
// ... - ongoing debug release
// NOTE: THIS IS ONLY A PARIAL RELEASE. THIS DEVICE CLASS IS CURRENTLY UNDERGOING ACTIVE
// DEVELOPMENT AND IS STILL MISSING SOME IMPORTANT FEATURES. PLEASE KEEP THIS IN MIND IF
// YOU DECIDE TO USE THIS PARTICULAR CODE FOR ANYTHING.
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
#ifndef _MPU6050_6AXIS_MOTIONAPPS612_H_
#define _MPU6050_6AXIS_MOTIONAPPS612_H_
// take ownership of the "MPU6050" typedef
#define I2CDEVLIB_MPU6050_TYPEDEF
#include "MPU6050.h"
// this divisor is pre configured into the above image and can't be modified at this time.
#ifndef MPU6050_DMP_FIFO_RATE_DIVISOR
#define MPU6050_DMP_FIFO_RATE_DIVISOR 0x01 // The New instance of the Firmware has this as the default
#endif
class MPU6050_6Axis_MotionApps612 : public MPU6050_Base {
public:
MPU6050_6Axis_MotionApps612(uint8_t address=MPU6050_DEFAULT_ADDRESS, void *wireObj=0) : MPU6050_Base(address, wireObj) { }
uint8_t dmpInitialize(uint8_t rateDivisor = MPU6050_DMP_FIFO_RATE_DIVISOR, uint8_t mpuAddr = 0x68);
bool dmpPacketAvailable();
uint8_t dmpSetFIFORate(uint8_t fifoRate);
uint8_t dmpGetFIFORate();
uint8_t dmpGetSampleStepSizeMS();
uint8_t dmpGetSampleFrequency();
int32_t dmpDecodeTemperature(int8_t tempReg);
// Register callbacks after a packet of FIFO data is processed
//uint8_t dmpRegisterFIFORateProcess(inv_obj_func func, int16_t priority);
//uint8_t dmpUnregisterFIFORateProcess(inv_obj_func func);
uint8_t dmpRunFIFORateProcesses();
// Setup FIFO for various output
uint8_t dmpSendQuaternion(uint_fast16_t accuracy);
uint8_t dmpSendGyro(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendAccel(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendLinearAccel(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendLinearAccelInWorld(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendControlData(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendExternalSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendGravity(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendPacketNumber(uint_fast16_t accuracy);
uint8_t dmpSendQuantizedAccel(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendEIS(uint_fast16_t elements, uint_fast16_t accuracy);
// Get Fixed Point data from FIFO
uint8_t dmpGetAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetQuaternion(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuaternion(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuaternion(Quaternion *q, const uint8_t* packet=0);
uint8_t dmpGet6AxisQuaternion(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGet6AxisQuaternion(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGet6AxisQuaternion(Quaternion *q, const uint8_t* packet=0);
uint8_t dmpGetRelativeQuaternion(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetRelativeQuaternion(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetRelativeQuaternion(Quaternion *data, const uint8_t* packet=0);
uint8_t dmpGetGyro(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyro(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyro(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpSetLinearAccelFilterCoefficient(float coef);
uint8_t dmpGetLinearAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetLinearAccel(VectorInt16 *v, VectorInt16 *vRaw, VectorFloat *gravity);
uint8_t dmpGetLinearAccelInWorld(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccelInWorld(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccelInWorld(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetLinearAccelInWorld(VectorInt16 *v, VectorInt16 *vReal, Quaternion *q);
uint8_t dmpGetGyroAndAccelSensor(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroAndAccelSensor(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroAndAccelSensor(VectorInt16 *g, VectorInt16 *a, const uint8_t* packet=0);
uint8_t dmpGetGyroSensor(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroSensor(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroSensor(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetControlData(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetTemperature(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGravity(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGravity(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGravity(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetGravity(VectorFloat *v, Quaternion *q);
uint8_t dmpGetUnquantizedAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetUnquantizedAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetUnquantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetQuantizedAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuantizedAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetExternalSensorData(int32_t *data, uint16_t size, const uint8_t* packet=0);
uint8_t dmpGetEIS(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetEuler(float *data, Quaternion *q);
uint8_t dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity);
// Get Floating Point data from FIFO
uint8_t dmpGetAccelFloat(float *data, const uint8_t* packet=0);
uint8_t dmpGetQuaternionFloat(float *data, const uint8_t* packet=0);
uint8_t dmpProcessFIFOPacket(const unsigned char *dmpData);
uint8_t dmpReadAndProcessFIFOPacket(uint8_t numPackets, uint8_t *processed=NULL);
uint8_t dmpSetFIFOProcessedCallback(void (*func) (void));
uint8_t dmpInitFIFOParam();
uint8_t dmpCloseFIFO();
uint8_t dmpSetGyroDataSource(uint8_t source);
uint8_t dmpDecodeQuantizedAccel();
uint32_t dmpGetGyroSumOfSquare();
uint32_t dmpGetAccelSumOfSquare();
void dmpOverrideQuaternion(long *q);
uint16_t dmpGetFIFOPacketSize();
uint8_t dmpGetCurrentFIFOPacket(uint8_t *data); // overflow proof
private:
uint8_t *dmpPacketBuffer;
uint16_t dmpPacketSize;
};
typedef MPU6050_6Axis_MotionApps612 MPU6050;
#endif /* _MPU6050_6AXIS_MOTIONAPPS612_H_ */

View File

@ -0,0 +1,902 @@
// I2Cdev library collection - MPU6050 I2C device class, 9-axis MotionApps 4.1 implementation
// Based on InvenSense MPU-6050 register map document rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
// 6/18/2012 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2021/09/27 - split implementations out of header files, finally
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2021 Jeff Rowberg
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.
===============================================
*/
// MotionApps 4.1 DMP implementation, built using the MPU-9150 "MotionFit" board
#define MPU6050_INCLUDE_DMP_MOTIONAPPS41
#include "MPU6050_9Axis_MotionApps41.h"
// Tom Carpenter's conditional PROGMEM code
// http://forum.arduino.cc/index.php?topic=129407.0
#ifdef __AVR__
#include <avr/pgmspace.h>
#elif defined(ESP32)
#include <pgmspace.h>
#else
// Teensy 3.0 library conditional PROGMEM code from Paul Stoffregen
#ifndef __PGMSPACE_H_
#define __PGMSPACE_H_ 1
#include <inttypes.h>
#define PROGMEM
#define PGM_P const char *
#define PSTR(str) (str)
#define F(x) x
typedef void prog_void;
typedef char prog_char;
//typedef unsigned char prog_uchar;
typedef int8_t prog_int8_t;
typedef uint8_t prog_uint8_t;
typedef int16_t prog_int16_t;
typedef uint16_t prog_uint16_t;
typedef int32_t prog_int32_t;
typedef uint32_t prog_uint32_t;
#define strcpy_P(dest, src) strcpy((dest), (src))
#define strcat_P(dest, src) strcat((dest), (src))
#define strcmp_P(a, b) strcmp((a), (b))
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#define pgm_read_float(addr) (*(const float *)(addr))
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
#define pgm_read_word_near(addr) pgm_read_word(addr)
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
#define pgm_read_float_near(addr) pgm_read_float(addr)
#define pgm_read_byte_far(addr) pgm_read_byte(addr)
#define pgm_read_word_far(addr) pgm_read_word(addr)
#define pgm_read_dword_far(addr) pgm_read_dword(addr)
#define pgm_read_float_far(addr) pgm_read_float(addr)
#endif
#endif
// NOTE! Enabling DEBUG adds about 3.3kB to the flash program size.
// Debug output is now working even on ATMega328P MCUs (e.g. Arduino Uno)
// after moving string constants to flash memory storage using the F()
// compiler macro (Arduino IDE 1.0+ required).
// #define DEBUG
/* Control whether debugging macros are active at compile time */
#undef DB_ACTIVE
#ifdef DEBUG
#define DB_ACTIVE 1
#else
#define DB_ACTIVE 0
#endif /* DEBUG */
/*
** Usage: DB_PRINT((...));
** Usage: DB_PRINTLN((...));
**
** "..." is whatever extra arguments fmt requires (possibly nothing).
**
** The structure of the macros means that the code is always validated
** but is not called when DEBUG is undefined.
** -- See chapter 8 of 'The Practice of Programming', by Kernighan and Pike.
*/
#define DEBUG_PRINT(...)\
do { if (DB_ACTIVE) Serial.print(__VA_ARGS__); } while (0)
#define DEBUG_PRINTF(...)\
do { if (DB_ACTIVE) Serial.printf(__VA_ARGS__); } while (0)
#define DEBUG_PRINTLN(...)\
do { if (DB_ACTIVE) Serial.println(__VA_ARGS__); } while (0)
#define DEBUG_PRINTLNF(x, y)\
do { if (DB_ACTIVE) Serial.println(x, y); } while (0)
#define MPU6050_DMP_CODE_SIZE 1962 // dmpMemory[]
#define MPU6050_DMP_CONFIG_SIZE 232 // dmpConfig[]
#define MPU6050_DMP_UPDATES_SIZE 140 // dmpUpdates[]
/* ================================================================================================ *
| Default MotionApps v4.1 48-byte FIFO packet structure: |
| |
| [QUAT W][ ][QUAT X][ ][QUAT Y][ ][QUAT Z][ ][GYRO X][ ][GYRO Y][ ] |
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
| |
| [GYRO Z][ ][MAG X ][MAG Y ][MAG Z ][ACC X ][ ][ACC Y ][ ][ACC Z ][ ][ ] |
| 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
* ================================================================================================ */
// this block of memory gets written to the MPU on start-up, and it seems
// to be volatile memory, so it has to be done each time (it only takes ~1
// second though)
static const unsigned char dmpMemory[MPU6050_DMP_CODE_SIZE] PROGMEM = {
// bank 0, 256 bytes
0xFB, 0x00, 0x00, 0x3E, 0x00, 0x0B, 0x00, 0x36, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00,
0x00, 0x65, 0x00, 0x54, 0xFF, 0xEF, 0x00, 0x00, 0xFA, 0x80, 0x00, 0x0B, 0x12, 0x82, 0x00, 0x01,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x28, 0x00, 0x00, 0xFF, 0xFF, 0x45, 0x81, 0xFF, 0xFF, 0xFA, 0x72, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xE8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7F, 0xFF, 0xFF, 0xFE, 0x80, 0x01,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3E, 0x03, 0x30, 0x40, 0x00, 0x00, 0x00, 0x02, 0xCA, 0xE3, 0x09, 0x3E, 0x80, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x41, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x2A, 0x00, 0x00, 0x16, 0x55, 0x00, 0x00, 0x21, 0x82,
0xFD, 0x87, 0x26, 0x50, 0xFD, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x05, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6F, 0x00, 0x02, 0x65, 0x32, 0x00, 0x00, 0x5E, 0xC0,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFB, 0x8C, 0x6F, 0x5D, 0xFD, 0x5D, 0x08, 0xD9, 0x00, 0x7C, 0x73, 0x3B, 0x00, 0x6C, 0x12, 0xCC,
0x32, 0x00, 0x13, 0x9D, 0x32, 0x00, 0xD0, 0xD6, 0x32, 0x00, 0x08, 0x00, 0x40, 0x00, 0x01, 0xF4,
0xFF, 0xE6, 0x80, 0x79, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xD6, 0x00, 0x00, 0x27, 0x10,
// bank 1, 256 bytes
0xFB, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFA, 0x36, 0xFF, 0xBC, 0x30, 0x8E, 0x00, 0x05, 0xFB, 0xF0, 0xFF, 0xD9, 0x5B, 0xC8,
0xFF, 0xD0, 0x9A, 0xBE, 0x00, 0x00, 0x10, 0xA9, 0xFF, 0xF4, 0x1E, 0xB2, 0x00, 0xCE, 0xBB, 0xF7,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x0C,
0xFF, 0xC2, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0xCF, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x3F, 0x68, 0xB6, 0x79, 0x35, 0x28, 0xBC, 0xC6, 0x7E, 0xD1, 0x6C,
0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x6A, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x25, 0x4D, 0x00, 0x2F, 0x70, 0x6D, 0x00, 0x00, 0x05, 0xAE, 0x00, 0x0C, 0x02, 0xD0,
// bank 2, 256 bytes
0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x54, 0xFF, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0xFF, 0xEF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x78, 0xA2,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// bank 3, 256 bytes
0xD8, 0xDC, 0xF4, 0xD8, 0xB9, 0xAB, 0xF3, 0xF8, 0xFA, 0xF1, 0xBA, 0xA2, 0xDE, 0xB2, 0xB8, 0xB4,
0xA8, 0x81, 0x98, 0xF7, 0x4A, 0x90, 0x7F, 0x91, 0x6A, 0xF3, 0xF9, 0xDB, 0xA8, 0xF9, 0xB0, 0xBA,
0xA0, 0x80, 0xF2, 0xCE, 0x81, 0xF3, 0xC2, 0xF1, 0xC1, 0xF2, 0xC3, 0xF3, 0xCC, 0xA2, 0xB2, 0x80,
0xF1, 0xC6, 0xD8, 0x80, 0xBA, 0xA7, 0xDF, 0xDF, 0xDF, 0xF2, 0xA7, 0xC3, 0xCB, 0xC5, 0xB6, 0xF0,
0x87, 0xA2, 0x94, 0x24, 0x48, 0x70, 0x3C, 0x95, 0x40, 0x68, 0x34, 0x58, 0x9B, 0x78, 0xA2, 0xF1,
0x83, 0x92, 0x2D, 0x55, 0x7D, 0xD8, 0xB1, 0xB4, 0xB8, 0xA1, 0xD0, 0x91, 0x80, 0xF2, 0x70, 0xF3,
0x70, 0xF2, 0x7C, 0x80, 0xA8, 0xF1, 0x01, 0xB0, 0x98, 0x87, 0xD9, 0x43, 0xD8, 0x86, 0xC9, 0x88,
0xBA, 0xA1, 0xF2, 0x0E, 0xB8, 0x97, 0x80, 0xF1, 0xA9, 0xDF, 0xDF, 0xDF, 0xAA, 0xDF, 0xDF, 0xDF,
0xF2, 0xAA, 0xC5, 0xCD, 0xC7, 0xA9, 0x0C, 0xC9, 0x2C, 0x97, 0x97, 0x97, 0x97, 0xF1, 0xA9, 0x89,
0x26, 0x46, 0x66, 0xB0, 0xB4, 0xBA, 0x80, 0xAC, 0xDE, 0xF2, 0xCA, 0xF1, 0xB2, 0x8C, 0x02, 0xA9,
0xB6, 0x98, 0x00, 0x89, 0x0E, 0x16, 0x1E, 0xB8, 0xA9, 0xB4, 0x99, 0x2C, 0x54, 0x7C, 0xB0, 0x8A,
0xA8, 0x96, 0x36, 0x56, 0x76, 0xF1, 0xB9, 0xAF, 0xB4, 0xB0, 0x83, 0xC0, 0xB8, 0xA8, 0x97, 0x11,
0xB1, 0x8F, 0x98, 0xB9, 0xAF, 0xF0, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0xF1, 0xA3, 0x29, 0x55,
0x7D, 0xAF, 0x83, 0xB5, 0x93, 0xF0, 0x00, 0x28, 0x50, 0xF5, 0xBA, 0xAD, 0x8F, 0x9F, 0x28, 0x54,
0x7C, 0xB9, 0xF1, 0xA3, 0x86, 0x9F, 0x61, 0xA6, 0xDA, 0xDE, 0xDF, 0xDB, 0xB2, 0xB6, 0x8E, 0x9D,
0xAE, 0xF5, 0x60, 0x68, 0x70, 0xB1, 0xB5, 0xF1, 0xDA, 0xA6, 0xDF, 0xD9, 0xA6, 0xFA, 0xA3, 0x86,
// bank 4, 256 bytes
0x96, 0xDB, 0x31, 0xA6, 0xD9, 0xF8, 0xDF, 0xBA, 0xA6, 0x8F, 0xC2, 0xC5, 0xC7, 0xB2, 0x8C, 0xC1,
0xB8, 0xA2, 0xDF, 0xDF, 0xDF, 0xA3, 0xDF, 0xDF, 0xDF, 0xD8, 0xD8, 0xF1, 0xB8, 0xA8, 0xB2, 0x86,
0xB4, 0x98, 0x0D, 0x35, 0x5D, 0xB8, 0xAA, 0x98, 0xB0, 0x87, 0x2D, 0x35, 0x3D, 0xB2, 0xB6, 0xBA,
0xAF, 0x8C, 0x96, 0x19, 0x8F, 0x9F, 0xA7, 0x0E, 0x16, 0x1E, 0xB4, 0x9A, 0xB8, 0xAA, 0x87, 0x2C,
0x54, 0x7C, 0xB9, 0xA3, 0xDE, 0xDF, 0xDF, 0xA3, 0xB1, 0x80, 0xF2, 0xC4, 0xCD, 0xC9, 0xF1, 0xB8,
0xA9, 0xB4, 0x99, 0x83, 0x0D, 0x35, 0x5D, 0x89, 0xB9, 0xA3, 0x2D, 0x55, 0x7D, 0xB5, 0x93, 0xA3,
0x0E, 0x16, 0x1E, 0xA9, 0x2C, 0x54, 0x7C, 0xB8, 0xB4, 0xB0, 0xF1, 0x97, 0x83, 0xA8, 0x11, 0x84,
0xA5, 0x09, 0x98, 0xA3, 0x83, 0xF0, 0xDA, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0xD8, 0xF1, 0xA5,
0x29, 0x55, 0x7D, 0xA5, 0x85, 0x95, 0x02, 0x1A, 0x2E, 0x3A, 0x56, 0x5A, 0x40, 0x48, 0xF9, 0xF3,
0xA3, 0xD9, 0xF8, 0xF0, 0x98, 0x83, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0x97, 0x82, 0xA8, 0xF1,
0x11, 0xF0, 0x98, 0xA2, 0x24, 0x08, 0x44, 0x10, 0x64, 0x18, 0xDA, 0xF3, 0xDE, 0xD8, 0x83, 0xA5,
0x94, 0x01, 0xD9, 0xA3, 0x02, 0xF1, 0xA2, 0xC3, 0xC5, 0xC7, 0xD8, 0xF1, 0x84, 0x92, 0xA2, 0x4D,
0xDA, 0x2A, 0xD8, 0x48, 0x69, 0xD9, 0x2A, 0xD8, 0x68, 0x55, 0xDA, 0x32, 0xD8, 0x50, 0x71, 0xD9,
0x32, 0xD8, 0x70, 0x5D, 0xDA, 0x3A, 0xD8, 0x58, 0x79, 0xD9, 0x3A, 0xD8, 0x78, 0x93, 0xA3, 0x4D,
0xDA, 0x2A, 0xD8, 0x48, 0x69, 0xD9, 0x2A, 0xD8, 0x68, 0x55, 0xDA, 0x32, 0xD8, 0x50, 0x71, 0xD9,
0x32, 0xD8, 0x70, 0x5D, 0xDA, 0x3A, 0xD8, 0x58, 0x79, 0xD9, 0x3A, 0xD8, 0x78, 0xA8, 0x8A, 0x9A,
// bank 5, 256 bytes
0xF0, 0x28, 0x50, 0x78, 0x9E, 0xF3, 0x88, 0x18, 0xF1, 0x9F, 0x1D, 0x98, 0xA8, 0xD9, 0x08, 0xD8,
0xC8, 0x9F, 0x12, 0x9E, 0xF3, 0x15, 0xA8, 0xDA, 0x12, 0x10, 0xD8, 0xF1, 0xAF, 0xC8, 0x97, 0x87,
0x34, 0xB5, 0xB9, 0x94, 0xA4, 0x21, 0xF3, 0xD9, 0x22, 0xD8, 0xF2, 0x2D, 0xF3, 0xD9, 0x2A, 0xD8,
0xF2, 0x35, 0xF3, 0xD9, 0x32, 0xD8, 0x81, 0xA4, 0x60, 0x60, 0x61, 0xD9, 0x61, 0xD8, 0x6C, 0x68,
0x69, 0xD9, 0x69, 0xD8, 0x74, 0x70, 0x71, 0xD9, 0x71, 0xD8, 0xB1, 0xA3, 0x84, 0x19, 0x3D, 0x5D,
0xA3, 0x83, 0x1A, 0x3E, 0x5E, 0x93, 0x10, 0x30, 0x81, 0x10, 0x11, 0xB8, 0xB0, 0xAF, 0x8F, 0x94,
0xF2, 0xDA, 0x3E, 0xD8, 0xB4, 0x9A, 0xA8, 0x87, 0x29, 0xDA, 0xF8, 0xD8, 0x87, 0x9A, 0x35, 0xDA,
0xF8, 0xD8, 0x87, 0x9A, 0x3D, 0xDA, 0xF8, 0xD8, 0xB1, 0xB9, 0xA4, 0x98, 0x85, 0x02, 0x2E, 0x56,
0xA5, 0x81, 0x00, 0x0C, 0x14, 0xA3, 0x97, 0xB0, 0x8A, 0xF1, 0x2D, 0xD9, 0x28, 0xD8, 0x4D, 0xD9,
0x48, 0xD8, 0x6D, 0xD9, 0x68, 0xD8, 0xB1, 0x84, 0x0D, 0xDA, 0x0E, 0xD8, 0xA3, 0x29, 0x83, 0xDA,
0x2C, 0x0E, 0xD8, 0xA3, 0x84, 0x49, 0x83, 0xDA, 0x2C, 0x4C, 0x0E, 0xD8, 0xB8, 0xB0, 0x97, 0x86,
0xA8, 0x31, 0x9B, 0x06, 0x99, 0x07, 0xAB, 0x97, 0x28, 0x88, 0x9B, 0xF0, 0x0C, 0x20, 0x14, 0x40,
0xB9, 0xA3, 0x8A, 0xC3, 0xC5, 0xC7, 0x9A, 0xA3, 0x28, 0x50, 0x78, 0xF1, 0xB5, 0x93, 0x01, 0xD9,
0xDF, 0xDF, 0xDF, 0xD8, 0xB8, 0xB4, 0xA8, 0x8C, 0x9C, 0xF0, 0x04, 0x28, 0x51, 0x79, 0x1D, 0x30,
0x14, 0x38, 0xB2, 0x82, 0xAB, 0xD0, 0x98, 0x2C, 0x50, 0x50, 0x78, 0x78, 0x9B, 0xF1, 0x1A, 0xB0,
0xF0, 0xB1, 0x83, 0x9C, 0xA8, 0x29, 0x51, 0x79, 0xB0, 0x8B, 0x29, 0x51, 0x79, 0xB1, 0x83, 0x24,
// bank 6, 256 bytes
0x70, 0x59, 0xB0, 0x8B, 0x20, 0x58, 0x71, 0xB1, 0x83, 0x44, 0x69, 0x38, 0xB0, 0x8B, 0x39, 0x40,
0x68, 0xB1, 0x83, 0x64, 0x48, 0x31, 0xB0, 0x8B, 0x30, 0x49, 0x60, 0xA5, 0x88, 0x20, 0x09, 0x71,
0x58, 0x44, 0x68, 0x11, 0x39, 0x64, 0x49, 0x30, 0x19, 0xF1, 0xAC, 0x00, 0x2C, 0x54, 0x7C, 0xF0,
0x8C, 0xA8, 0x04, 0x28, 0x50, 0x78, 0xF1, 0x88, 0x97, 0x26, 0xA8, 0x59, 0x98, 0xAC, 0x8C, 0x02,
0x26, 0x46, 0x66, 0xF0, 0x89, 0x9C, 0xA8, 0x29, 0x51, 0x79, 0x24, 0x70, 0x59, 0x44, 0x69, 0x38,
0x64, 0x48, 0x31, 0xA9, 0x88, 0x09, 0x20, 0x59, 0x70, 0xAB, 0x11, 0x38, 0x40, 0x69, 0xA8, 0x19,
0x31, 0x48, 0x60, 0x8C, 0xA8, 0x3C, 0x41, 0x5C, 0x20, 0x7C, 0x00, 0xF1, 0x87, 0x98, 0x19, 0x86,
0xA8, 0x6E, 0x76, 0x7E, 0xA9, 0x99, 0x88, 0x2D, 0x55, 0x7D, 0x9E, 0xB9, 0xA3, 0x8A, 0x22, 0x8A,
0x6E, 0x8A, 0x56, 0x8A, 0x5E, 0x9F, 0xB1, 0x83, 0x06, 0x26, 0x46, 0x66, 0x0E, 0x2E, 0x4E, 0x6E,
0x9D, 0xB8, 0xAD, 0x00, 0x2C, 0x54, 0x7C, 0xF2, 0xB1, 0x8C, 0xB4, 0x99, 0xB9, 0xA3, 0x2D, 0x55,
0x7D, 0x81, 0x91, 0xAC, 0x38, 0xAD, 0x3A, 0xB5, 0x83, 0x91, 0xAC, 0x2D, 0xD9, 0x28, 0xD8, 0x4D,
0xD9, 0x48, 0xD8, 0x6D, 0xD9, 0x68, 0xD8, 0x8C, 0x9D, 0xAE, 0x29, 0xD9, 0x04, 0xAE, 0xD8, 0x51,
0xD9, 0x04, 0xAE, 0xD8, 0x79, 0xD9, 0x04, 0xD8, 0x81, 0xF3, 0x9D, 0xAD, 0x00, 0x8D, 0xAE, 0x19,
0x81, 0xAD, 0xD9, 0x01, 0xD8, 0xF2, 0xAE, 0xDA, 0x26, 0xD8, 0x8E, 0x91, 0x29, 0x83, 0xA7, 0xD9,
0xAD, 0xAD, 0xAD, 0xAD, 0xF3, 0x2A, 0xD8, 0xD8, 0xF1, 0xB0, 0xAC, 0x89, 0x91, 0x3E, 0x5E, 0x76,
0xF3, 0xAC, 0x2E, 0x2E, 0xF1, 0xB1, 0x8C, 0x5A, 0x9C, 0xAC, 0x2C, 0x28, 0x28, 0x28, 0x9C, 0xAC,
// bank 7, 170 bytes (remainder)
0x30, 0x18, 0xA8, 0x98, 0x81, 0x28, 0x34, 0x3C, 0x97, 0x24, 0xA7, 0x28, 0x34, 0x3C, 0x9C, 0x24,
0xF2, 0xB0, 0x89, 0xAC, 0x91, 0x2C, 0x4C, 0x6C, 0x8A, 0x9B, 0x2D, 0xD9, 0xD8, 0xD8, 0x51, 0xD9,
0xD8, 0xD8, 0x79, 0xD9, 0xD8, 0xD8, 0xF1, 0x9E, 0x88, 0xA3, 0x31, 0xDA, 0xD8, 0xD8, 0x91, 0x2D,
0xD9, 0x28, 0xD8, 0x4D, 0xD9, 0x48, 0xD8, 0x6D, 0xD9, 0x68, 0xD8, 0xB1, 0x83, 0x93, 0x35, 0x3D,
0x80, 0x25, 0xDA, 0xD8, 0xD8, 0x85, 0x69, 0xDA, 0xD8, 0xD8, 0xB4, 0x93, 0x81, 0xA3, 0x28, 0x34,
0x3C, 0xF3, 0xAB, 0x8B, 0xA3, 0x91, 0xB6, 0x09, 0xB4, 0xD9, 0xAB, 0xDE, 0xB0, 0x87, 0x9C, 0xB9,
0xA3, 0xDD, 0xF1, 0xA3, 0xA3, 0xA3, 0xA3, 0x95, 0xF1, 0xA3, 0xA3, 0xA3, 0x9D, 0xF1, 0xA3, 0xA3,
0xA3, 0xA3, 0xF2, 0xA3, 0xB4, 0x90, 0x80, 0xF2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
0xA3, 0xA3, 0xB2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xB0, 0x87, 0xB5, 0x99, 0xF1, 0xA3, 0xA3,
0xA3, 0x98, 0xF1, 0xA3, 0xA3, 0xA3, 0xA3, 0x97, 0xA3, 0xA3, 0xA3, 0xA3, 0xF3, 0x9B, 0xA3, 0xA3,
0xDC, 0xB9, 0xA7, 0xF1, 0x26, 0x26, 0x26, 0xD8, 0xD8, 0xFF
};
#ifndef MPU6050_DMP_FIFO_RATE_DIVISOR
#define MPU6050_DMP_FIFO_RATE_DIVISOR 0x03
#endif
static const unsigned char dmpConfig[MPU6050_DMP_CONFIG_SIZE] PROGMEM = {
// BANK OFFSET LENGTH [DATA]
0x02, 0xEC, 0x04, 0x00, 0x47, 0x7D, 0x1A, // ?
0x03, 0x82, 0x03, 0x4C, 0xCD, 0x6C, // FCFG_1 inv_set_gyro_calibration
0x03, 0xB2, 0x03, 0x36, 0x56, 0x76, // FCFG_3 inv_set_gyro_calibration
0x00, 0x68, 0x04, 0x02, 0xCA, 0xE3, 0x09, // D_0_104 inv_set_gyro_calibration
0x01, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, // D_1_152 inv_set_accel_calibration
0x03, 0x86, 0x03, 0x0C, 0xC9, 0x2C, // FCFG_2 inv_set_accel_calibration
0x03, 0x90, 0x03, 0x26, 0x46, 0x66, // (continued)...FCFG_2 inv_set_accel_calibration
0x00, 0x6C, 0x02, 0x40, 0x00, // D_0_108 inv_set_accel_calibration
0x02, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, // CPASS_MTX_00 inv_set_compass_calibration
0x02, 0x44, 0x04, 0x40, 0x00, 0x00, 0x00, // CPASS_MTX_01
0x02, 0x48, 0x04, 0x00, 0x00, 0x00, 0x00, // CPASS_MTX_02
0x02, 0x4C, 0x04, 0x40, 0x00, 0x00, 0x00, // CPASS_MTX_10
0x02, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, // CPASS_MTX_11
0x02, 0x54, 0x04, 0x00, 0x00, 0x00, 0x00, // CPASS_MTX_12
0x02, 0x58, 0x04, 0x00, 0x00, 0x00, 0x00, // CPASS_MTX_20
0x02, 0x5C, 0x04, 0x00, 0x00, 0x00, 0x00, // CPASS_MTX_21
0x02, 0xBC, 0x04, 0xC0, 0x00, 0x00, 0x00, // CPASS_MTX_22
0x01, 0xEC, 0x04, 0x00, 0x00, 0x40, 0x00, // D_1_236 inv_apply_endian_accel
0x03, 0x86, 0x06, 0x0C, 0xC9, 0x2C, 0x97, 0x97, 0x97, // FCFG_2 inv_set_mpu_sensors
0x04, 0x22, 0x03, 0x0D, 0x35, 0x5D, // CFG_MOTION_BIAS inv_turn_on_bias_from_no_motion
0x00, 0xA3, 0x01, 0x00, // ?
0x04, 0x29, 0x04, 0x87, 0x2D, 0x35, 0x3D, // FCFG_5 inv_set_bias_update
0x07, 0x62, 0x05, 0xF1, 0x20, 0x28, 0x30, 0x38, // CFG_8 inv_send_quaternion
0x07, 0x9F, 0x01, 0x30, // CFG_16 inv_set_footer
0x07, 0x67, 0x01, 0x9A, // CFG_GYRO_SOURCE inv_send_gyro
0x07, 0x68, 0x04, 0xF1, 0x28, 0x30, 0x38, // CFG_9 inv_send_gyro -> inv_construct3_fifo
0x07, 0x62, 0x05, 0xF1, 0x20, 0x28, 0x30, 0x38, // ?
0x02, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, // ?
0x07, 0x83, 0x06, 0xC2, 0xCA, 0xC4, 0xA3, 0xA3, 0xA3, // ?
// SPECIAL 0x01 = enable interrupts
0x00, 0x00, 0x00, 0x01, // SET INT_ENABLE, SPECIAL INSTRUCTION
0x07, 0xA7, 0x01, 0xFE, // ?
0x07, 0x62, 0x05, 0xF1, 0x20, 0x28, 0x30, 0x38, // ?
0x07, 0x67, 0x01, 0x9A, // ?
0x07, 0x68, 0x04, 0xF1, 0x28, 0x30, 0x38, // CFG_12 inv_send_accel -> inv_construct3_fifo
0x07, 0x8D, 0x04, 0xF1, 0x28, 0x30, 0x38, // ??? CFG_12 inv_send_mag -> inv_construct3_fifo
0x02, 0x16, 0x02, 0x00, MPU6050_DMP_FIFO_RATE_DIVISOR // D_0_22 inv_set_fifo_rate
// This very last 0x03 WAS a 0x09, which drops the FIFO rate down to 20 Hz. 0x07 is 25 Hz,
// 0x01 is 100Hz. Going faster than 100Hz (0x00=200Hz) tends to result in very noisy data.
// DMP output frequency is calculated easily using this equation: (200Hz / (1 + value))
// It is important to make sure the host processor can keep up with reading and processing
// the FIFO output at the desired rate. Handling FIFO overflow cleanly is also a good idea.
};
const unsigned char dmpUpdates[MPU6050_DMP_UPDATES_SIZE] PROGMEM = {
0x01, 0xB2, 0x02, 0xFF, 0xF5,
0x01, 0x90, 0x04, 0x0A, 0x0D, 0x97, 0xC0,
0x00, 0xA3, 0x01, 0x00,
0x04, 0x29, 0x04, 0x87, 0x2D, 0x35, 0x3D,
0x01, 0x6A, 0x02, 0x06, 0x00,
0x01, 0x60, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x04, 0x40, 0x00, 0x00, 0x00,
0x02, 0x60, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x08, 0x02, 0x01, 0x20,
0x01, 0x0A, 0x02, 0x00, 0x4E,
0x01, 0x02, 0x02, 0xFE, 0xB3,
0x02, 0x6C, 0x04, 0x00, 0x00, 0x00, 0x00, // READ
0x02, 0x6C, 0x04, 0xFA, 0xFE, 0x00, 0x00,
0x02, 0x60, 0x0C, 0xFF, 0xFF, 0xCB, 0x4D, 0x00, 0x01, 0x08, 0xC1, 0xFF, 0xFF, 0xBC, 0x2C,
0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00,
0x02, 0xF8, 0x04, 0x00, 0x00, 0x00, 0x00,
0x02, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x04, 0x40, 0x00, 0x00, 0x00,
0x00, 0x60, 0x04, 0x00, 0x40, 0x00, 0x00
};
uint8_t MPU6050_9Axis_MotionApps41::dmpInitialize() {
// reset device
DEBUG_PRINTLN(F("\n\nResetting MPU6050..."));
reset();
delay(30); // wait after reset
// disable sleep mode
DEBUG_PRINTLN(F("Disabling sleep mode..."));
setSleepEnabled(false);
// get MPU product ID
//DEBUG_PRINTLN(F("Getting product ID..."));
//uint8_t productID = 0; //getProductID();
//DEBUG_PRINT(F("Product ID = "));
//DEBUG_PRINT(productID);
// get MPU hardware revision
DEBUG_PRINTLN(F("Selecting user bank 16..."));
setMemoryBank(0x10, true, true);
DEBUG_PRINTLN(F("Selecting memory byte 6..."));
setMemoryStartAddress(0x06);
DEBUG_PRINTLN(F("Checking hardware revision..."));
uint8_t hwRevision = readMemoryByte();
(void)hwRevision; // suppress unused variable compile warning
DEBUG_PRINT(F("Revision @ user[16][6] = "));
DEBUG_PRINTLNF(hwRevision, HEX);
DEBUG_PRINTLN(F("Resetting memory bank selection to 0..."));
setMemoryBank(0, false, false);
// check OTP bank valid
DEBUG_PRINTLN(F("Reading OTP bank valid flag..."));
uint8_t otpValid = getOTPBankValid();
(void)otpValid; // suppress unused variable compile warning
DEBUG_PRINT(F("OTP bank is "));
DEBUG_PRINTLN(otpValid ? F("valid!") : F("invalid!"));
// get X/Y/Z gyro offsets
DEBUG_PRINTLN(F("Reading gyro offset values..."));
int8_t xgOffset = getXGyroOffset();
int8_t ygOffset = getYGyroOffset();
int8_t zgOffset = getZGyroOffset();
DEBUG_PRINT(F("X gyro offset = "));
DEBUG_PRINTLN(xgOffset);
DEBUG_PRINT(F("Y gyro offset = "));
DEBUG_PRINTLN(ygOffset);
DEBUG_PRINT(F("Z gyro offset = "));
DEBUG_PRINTLN(zgOffset);
I2Cdev::readByte(devAddr, MPU6050_RA_USER_CTRL, buffer, I2Cdev::readTimeout, wireObj); // ?
DEBUG_PRINTLN(F("Enabling interrupt latch, clear on any read, AUX bypass enabled"));
I2Cdev::writeByte(devAddr, MPU6050_RA_INT_PIN_CFG, 0x32, wireObj);
// enable MPU AUX I2C bypass mode
//DEBUG_PRINTLN(F("Enabling AUX I2C bypass mode..."));
//setI2CBypassEnabled(true);
DEBUG_PRINTLN(F("Setting magnetometer mode to power-down..."));
//mag -> setMode(0);
I2Cdev::writeByte(0x0E, 0x0A, 0x00, wireObj);
DEBUG_PRINTLN(F("Setting magnetometer mode to fuse access..."));
//mag -> setMode(0x0F);
I2Cdev::writeByte(0x0E, 0x0A, 0x0F, wireObj);
DEBUG_PRINTLN(F("Reading mag magnetometer factory calibration..."));
int8_t asax, asay, asaz;
//mag -> getAdjustment(&asax, &asay, &asaz);
I2Cdev::readBytes(0x0E, 0x10, 3, buffer, I2Cdev::readTimeout, wireObj);
asax = (int8_t)buffer[0];
asay = (int8_t)buffer[1];
asaz = (int8_t)buffer[2];
(void)asax; // suppress unused variable compiler warning
(void)asay; // suppress unused variable compiler warning
(void)asaz; // suppress unused variable compiler warning
DEBUG_PRINT(F("Adjustment X/Y/Z = "));
DEBUG_PRINT(asax);
DEBUG_PRINT(F(" / "));
DEBUG_PRINT(asay);
DEBUG_PRINT(F(" / "));
DEBUG_PRINTLN(asaz);
DEBUG_PRINTLN(F("Setting magnetometer mode to power-down..."));
//mag -> setMode(0);
I2Cdev::writeByte(0x0E, 0x0A, 0x00, wireObj);
// load DMP code into memory banks
DEBUG_PRINT(F("Writing DMP code to MPU memory banks ("));
DEBUG_PRINT(MPU6050_DMP_CODE_SIZE);
DEBUG_PRINTLN(F(" bytes)"));
if (writeProgMemoryBlock(dmpMemory, MPU6050_DMP_CODE_SIZE)) {
DEBUG_PRINTLN(F("Success! DMP code written and verified."));
DEBUG_PRINTLN(F("Configuring DMP and related settings..."));
// write DMP configuration
DEBUG_PRINT(F("Writing DMP configuration to MPU memory banks ("));
DEBUG_PRINT(MPU6050_DMP_CONFIG_SIZE);
DEBUG_PRINTLN(F(" bytes in config def)"));
if (writeProgDMPConfigurationSet(dmpConfig, MPU6050_DMP_CONFIG_SIZE)) {
DEBUG_PRINTLN(F("Success! DMP configuration written and verified."));
DEBUG_PRINTLN(F("Setting DMP and FIFO_OFLOW interrupts enabled..."));
setIntEnabled(1<<MPU6050_INTERRUPT_FIFO_OFLOW_BIT|1<<MPU6050_INTERRUPT_DMP_INT_BIT);
DEBUG_PRINTLN(F("Setting sample rate to 200Hz..."));
setRate(4); // 1khz / (1 + 4) = 200 Hz
DEBUG_PRINTLN(F("Setting clock source to Z Gyro..."));
setClockSource(MPU6050_CLOCK_PLL_ZGYRO);
DEBUG_PRINTLN(F("Setting DLPF bandwidth to 42Hz..."));
setDLPFMode(MPU6050_DLPF_BW_42);
DEBUG_PRINTLN(F("Setting external frame sync to TEMP_OUT_L[0]..."));
setExternalFrameSync(MPU6050_EXT_SYNC_TEMP_OUT_L);
DEBUG_PRINTLN(F("Setting gyro sensitivity to +/- 2000 deg/sec..."));
setFullScaleGyroRange(MPU6050_GYRO_FS_2000);
DEBUG_PRINTLN(F("Setting DMP configuration bytes (function unknown)..."));
setDMPConfig1(0x03);
setDMPConfig2(0x00);
DEBUG_PRINTLN(F("Clearing OTP Bank flag..."));
setOTPBankValid(false);
DEBUG_PRINTLN(F("Setting X/Y/Z gyro offsets to previous values..."));
setXGyroOffsetTC(xgOffset);
setYGyroOffsetTC(ygOffset);
setZGyroOffsetTC(zgOffset);
//DEBUG_PRINTLN(F("Setting X/Y/Z gyro user offsets to zero..."));
//setXGyroOffset(0);
//setYGyroOffset(0);
//setZGyroOffset(0);
DEBUG_PRINTLN(F("Writing final memory update 1/19 (function unknown)..."));
uint8_t dmpUpdate[16], j;
uint16_t pos = 0;
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 2/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Resetting FIFO..."));
resetFIFO();
DEBUG_PRINTLN(F("Reading FIFO count..."));
uint8_t fifoCount = getFIFOCount();
DEBUG_PRINT(F("Current FIFO count="));
DEBUG_PRINTLN(fifoCount);
uint8_t fifoBuffer[128];
//getFIFOBytes(fifoBuffer, fifoCount);
DEBUG_PRINTLN(F("Writing final memory update 3/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 4/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Disabling all standby flags..."));
I2Cdev::writeByte(0x68, MPU6050_RA_PWR_MGMT_2, 0x00, wireObj);
DEBUG_PRINTLN(F("Setting accelerometer sensitivity to +/- 2g..."));
I2Cdev::writeByte(0x68, MPU6050_RA_ACCEL_CONFIG, 0x00, wireObj);
DEBUG_PRINTLN(F("Setting motion detection threshold to 2..."));
setMotionDetectionThreshold(2);
DEBUG_PRINTLN(F("Setting zero-motion detection threshold to 156..."));
setZeroMotionDetectionThreshold(156);
DEBUG_PRINTLN(F("Setting motion detection duration to 80..."));
setMotionDetectionDuration(80);
DEBUG_PRINTLN(F("Setting zero-motion detection duration to 0..."));
setZeroMotionDetectionDuration(0);
DEBUG_PRINTLN(F("Setting AK8975 to single measurement mode..."));
//mag -> setMode(1);
I2Cdev::writeByte(0x0E, 0x0A, 0x01, wireObj);
// setup AK8975 (0x0E) as Slave 0 in read mode
DEBUG_PRINTLN(F("Setting up AK8975 read slave 0..."));
I2Cdev::writeByte(0x68, MPU6050_RA_I2C_SLV0_ADDR, 0x8E, wireObj);
I2Cdev::writeByte(0x68, MPU6050_RA_I2C_SLV0_REG, 0x01, wireObj);
I2Cdev::writeByte(0x68, MPU6050_RA_I2C_SLV0_CTRL, 0xDA, wireObj);
// setup AK8975 (0x0E) as Slave 2 in write mode
DEBUG_PRINTLN(F("Setting up AK8975 write slave 2..."));
I2Cdev::writeByte(0x68, MPU6050_RA_I2C_SLV2_ADDR, 0x0E, wireObj);
I2Cdev::writeByte(0x68, MPU6050_RA_I2C_SLV2_REG, 0x0A, wireObj);
I2Cdev::writeByte(0x68, MPU6050_RA_I2C_SLV2_CTRL, 0x81, wireObj);
I2Cdev::writeByte(0x68, MPU6050_RA_I2C_SLV2_DO, 0x01, wireObj);
// setup I2C timing/delay control
DEBUG_PRINTLN(F("Setting up slave access delay..."));
I2Cdev::writeByte(0x68, MPU6050_RA_I2C_SLV4_CTRL, 0x18, wireObj);
I2Cdev::writeByte(0x68, MPU6050_RA_I2C_MST_DELAY_CTRL, 0x05, wireObj);
// enable interrupts
DEBUG_PRINTLN(F("Enabling default interrupt behavior/no bypass..."));
I2Cdev::writeByte(0x68, MPU6050_RA_INT_PIN_CFG, 0x00, wireObj);
// enable I2C master mode and reset DMP/FIFO
DEBUG_PRINTLN(F("Enabling I2C master mode..."));
I2Cdev::writeByte(0x68, MPU6050_RA_USER_CTRL, 0x20, wireObj);
DEBUG_PRINTLN(F("Resetting FIFO..."));
I2Cdev::writeByte(0x68, MPU6050_RA_USER_CTRL, 0x24, wireObj);
DEBUG_PRINTLN(F("Rewriting I2C master mode enabled because...I don't know"));
I2Cdev::writeByte(0x68, MPU6050_RA_USER_CTRL, 0x20, wireObj);
DEBUG_PRINTLN(F("Enabling and resetting DMP/FIFO..."));
I2Cdev::writeByte(0x68, MPU6050_RA_USER_CTRL, 0xE8, wireObj);
DEBUG_PRINTLN(F("Writing final memory update 5/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 6/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 7/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 8/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 9/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 10/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 11/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Reading final memory update 12/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
readMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
#ifdef DEBUG
DEBUG_PRINT(F("Read bytes: "));
for (j = 0; j < 4; j++) {
DEBUG_PRINT(dmpUpdate[3 + j], HEX);
DEBUG_PRINT(" ");
}
DEBUG_PRINTLN("");
#endif
DEBUG_PRINTLN(F("Writing final memory update 13/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 14/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 15/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 16/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Writing final memory update 17/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Waiting for FIRO count >= 46..."));
while ((fifoCount = getFIFOCount()) < 46);
DEBUG_PRINTLN(F("Reading FIFO..."));
getFIFOBytes(fifoBuffer, (fifoCount < 128) ? fifoCount : 128); // safeguard only 128 bytes
DEBUG_PRINTLN(F("Reading interrupt status..."));
getIntStatus();
DEBUG_PRINTLN(F("Writing final memory update 18/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Waiting for FIRO count >= 48..."));
while ((fifoCount = getFIFOCount()) < 48);
DEBUG_PRINTLN(F("Reading FIFO..."));
getFIFOBytes(fifoBuffer, (fifoCount < 128) ? fifoCount : 128); // safeguard only 128 bytes
DEBUG_PRINTLN(F("Reading interrupt status..."));
getIntStatus();
DEBUG_PRINTLN(F("Waiting for FIRO count >= 48..."));
while ((fifoCount = getFIFOCount()) < 48);
DEBUG_PRINTLN(F("Reading FIFO..."));
getFIFOBytes(fifoBuffer, (fifoCount < 128) ? fifoCount : 128); // safeguard only 128 bytes
DEBUG_PRINTLN(F("Reading interrupt status..."));
getIntStatus();
DEBUG_PRINTLN(F("Writing final memory update 19/19 (function unknown)..."));
for (j = 0; j < 4 || j < dmpUpdate[2] + 3; j++, pos++) dmpUpdate[j] = pgm_read_byte(&dmpUpdates[pos]);
writeMemoryBlock(dmpUpdate + 3, dmpUpdate[2], dmpUpdate[0], dmpUpdate[1]);
DEBUG_PRINTLN(F("Disabling DMP (you turn it on later)..."));
setDMPEnabled(false);
DEBUG_PRINTLN(F("Setting up internal 48-byte (default) DMP packet buffer..."));
dmpPacketSize = 48;
/*if ((dmpPacketBuffer = (uint8_t *)malloc(42)) == 0) {
return 3; // TODO: proper error code for no memory
}*/
DEBUG_PRINTLN(F("Resetting FIFO and clearing INT status one last time..."));
resetFIFO();
getIntStatus();
} else {
DEBUG_PRINTLN(F("ERROR! DMP configuration verification failed."));
return 2; // configuration block loading failed
}
} else {
DEBUG_PRINTLN(F("ERROR! DMP code verification failed."));
return 1; // main binary block loading failed
}
return 0; // success
}
bool MPU6050_9Axis_MotionApps41::dmpPacketAvailable() {
return getFIFOCount() >= dmpGetFIFOPacketSize();
}
// uint8_t MPU6050_9Axis_MotionApps41::dmpSetFIFORate(uint8_t fifoRate);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetFIFORate();
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetSampleStepSizeMS();
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetSampleFrequency();
// int32_t MPU6050_9Axis_MotionApps41::dmpDecodeTemperature(int8_t tempReg);
//uint8_t MPU6050_9Axis_MotionApps41::dmpRegisterFIFORateProcess(inv_obj_func func, int16_t priority);
//uint8_t MPU6050_9Axis_MotionApps41::dmpUnregisterFIFORateProcess(inv_obj_func func);
//uint8_t MPU6050_9Axis_MotionApps41::dmpRunFIFORateProcesses();
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendQuaternion(uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendGyro(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendAccel(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendLinearAccel(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendLinearAccelInWorld(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendControlData(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendExternalSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendGravity(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendPacketNumber(uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendQuantizedAccel(uint_fast16_t elements, uint_fast16_t accuracy);
// uint8_t MPU6050_9Axis_MotionApps41::dmpSendEIS(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t MPU6050_9Axis_MotionApps41::dmpGetAccel(int32_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((uint32_t)packet[34] << 24) | ((uint32_t)packet[35] << 16) | ((uint32_t)packet[36] << 8) | packet[37]);
data[1] = (((uint32_t)packet[38] << 24) | ((uint32_t)packet[39] << 16) | ((uint32_t)packet[40] << 8) | packet[41]);
data[2] = (((uint32_t)packet[42] << 24) | ((uint32_t)packet[43] << 16) | ((uint32_t)packet[44] << 8) | packet[45]);
return 0;
}
uint8_t MPU6050_9Axis_MotionApps41::dmpGetAccel(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (packet[34] << 8) | packet[35];
data[1] = (packet[38] << 8) | packet[39];
data[2] = (packet[42] << 8) | packet[43];
return 0;
}
uint8_t MPU6050_9Axis_MotionApps41::dmpGetAccel(VectorInt16 *v, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
v -> x = (packet[34] << 8) | packet[35];
v -> y = (packet[38] << 8) | packet[39];
v -> z = (packet[42] << 8) | packet[43];
return 0;
}
uint8_t MPU6050_9Axis_MotionApps41::dmpGetQuaternion(int32_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((uint32_t)packet[0] << 24) | ((uint32_t)packet[1] << 16) | ((uint32_t)packet[2] << 8) | packet[3]);
data[1] = (((uint32_t)packet[4] << 24) | ((uint32_t)packet[5] << 16) | ((uint32_t)packet[6] << 8) | packet[7]);
data[2] = (((uint32_t)packet[8] << 24) | ((uint32_t)packet[9] << 16) | ((uint32_t)packet[10] << 8) | packet[11]);
data[3] = (((uint32_t)packet[12] << 24) | ((uint32_t)packet[13] << 16) | ((uint32_t)packet[14] << 8) | packet[15]);
return 0;
}
uint8_t MPU6050_9Axis_MotionApps41::dmpGetQuaternion(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = ((packet[0] << 8) | packet[1]);
data[1] = ((packet[4] << 8) | packet[5]);
data[2] = ((packet[8] << 8) | packet[9]);
data[3] = ((packet[12] << 8) | packet[13]);
return 0;
}
uint8_t MPU6050_9Axis_MotionApps41::dmpGetQuaternion(Quaternion *q, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
int16_t qI[4];
uint8_t status = dmpGetQuaternion(qI, packet);
if (status == 0) {
q -> w = (float)qI[0] / 16384.0f;
q -> x = (float)qI[1] / 16384.0f;
q -> y = (float)qI[2] / 16384.0f;
q -> z = (float)qI[3] / 16384.0f;
return 0;
}
return status; // int16 return value, indicates error if this line is reached
}
// uint8_t MPU6050_9Axis_MotionApps41::dmpGet6AxisQuaternion(long *data, const uint8_t* packet);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetRelativeQuaternion(long *data, const uint8_t* packet);
uint8_t MPU6050_9Axis_MotionApps41::dmpGetGyro(int32_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (((uint32_t)packet[16] << 24) | ((uint32_t)packet[17] << 16) | ((uint32_t)packet[18] << 8) | packet[19]);
data[1] = (((uint32_t)packet[20] << 24) | ((uint32_t)packet[21] << 16) | ((uint32_t)packet[22] << 8) | packet[23]);
data[2] = (((uint32_t)packet[24] << 24) | ((uint32_t)packet[25] << 16) | ((uint32_t)packet[26] << 8) | packet[27]);
return 0;
}
uint8_t MPU6050_9Axis_MotionApps41::dmpGetGyro(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (packet[16] << 8) | packet[17];
data[1] = (packet[20] << 8) | packet[21];
data[2] = (packet[24] << 8) | packet[25];
return 0;
}
uint8_t MPU6050_9Axis_MotionApps41::dmpGetMag(int16_t *data, const uint8_t* packet) {
// TODO: accommodate different arrangements of sent data (ONLY default supported now)
if (packet == 0) packet = dmpPacketBuffer;
data[0] = (packet[28] << 8) | packet[29];
data[1] = (packet[30] << 8) | packet[31];
data[2] = (packet[32] << 8) | packet[33];
return 0;
}
// uint8_t MPU6050_9Axis_MotionApps41::dmpSetLinearAccelFilterCoefficient(float coef);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetLinearAccel(long *data, const uint8_t* packet);
uint8_t MPU6050_9Axis_MotionApps41::dmpGetLinearAccel(VectorInt16 *v, VectorInt16 *vRaw, VectorFloat *gravity) {
// get rid of the gravity component (+1g = +4096 in standard DMP FIFO packet)
v -> x = vRaw -> x - gravity -> x*4096;
v -> y = vRaw -> y - gravity -> y*4096;
v -> z = vRaw -> z - gravity -> z*4096;
return 0;
}
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetLinearAccelInWorld(long *data, const uint8_t* packet);
uint8_t MPU6050_9Axis_MotionApps41::dmpGetLinearAccelInWorld(VectorInt16 *v, VectorInt16 *vReal, Quaternion *q) {
// rotate measured 3D acceleration vector into original state
// frame of reference based on orientation quaternion
memcpy(v, vReal, sizeof(VectorInt16));
v -> rotate(q);
return 0;
}
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetGyroAndAccelSensor(long *data, const uint8_t* packet);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetGyroSensor(long *data, const uint8_t* packet);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetControlData(long *data, const uint8_t* packet);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetTemperature(long *data, const uint8_t* packet);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetGravity(long *data, const uint8_t* packet);
uint8_t MPU6050_9Axis_MotionApps41::dmpGetGravity(int16_t *data, const uint8_t* packet) {
/* +1g corresponds to +8192, sensitivity is 2g. */
int16_t qI[4];
uint8_t status = dmpGetQuaternion(qI, packet);
data[0] = ((int32_t)qI[1] * qI[3] - (int32_t)qI[0] * qI[2]) / 16384;
data[1] = ((int32_t)qI[0] * qI[1] + (int32_t)qI[2] * qI[3]) / 16384;
data[2] = ((int32_t)qI[0] * qI[0] - (int32_t)qI[1] * qI[1]
- (int32_t)qI[2] * qI[2] + (int32_t)qI[3] * qI[3]) / (int32_t)(2 * 16384L);
return status;
}
uint8_t MPU6050_9Axis_MotionApps41::dmpGetGravity(VectorFloat *v, Quaternion *q) {
v -> x = 2 * (q -> x*q -> z - q -> w*q -> y);
v -> y = 2 * (q -> w*q -> x + q -> y*q -> z);
v -> z = q -> w*q -> w - q -> x*q -> x - q -> y*q -> y + q -> z*q -> z;
return 0;
}
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetUnquantizedAccel(long *data, const uint8_t* packet);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetQuantizedAccel(long *data, const uint8_t* packet);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetExternalSensorData(long *data, int size, const uint8_t* packet);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetEIS(long *data, const uint8_t* packet);
uint8_t MPU6050_9Axis_MotionApps41::dmpGetEuler(float *data, Quaternion *q) {
data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1); // psi
data[1] = -asin(2*q -> x*q -> z + 2*q -> w*q -> y); // theta
data[2] = atan2(2*q -> y*q -> z - 2*q -> w*q -> x, 2*q -> w*q -> w + 2*q -> z*q -> z - 1); // phi
return 0;
}
#ifdef USE_OLD_DMPGETYAWPITCHROLL
uint8_t MPU6050_9Axis_MotionApps41::dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity) {
// yaw: (about Z axis)
data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1);
// pitch: (nose up/down, about Y axis)
data[1] = atan(gravity -> x / sqrt(gravity -> y*gravity -> y + gravity -> z*gravity -> z));
// roll: (tilt left/right, about X axis)
data[2] = atan(gravity -> y / sqrt(gravity -> x*gravity -> x + gravity -> z*gravity -> z));
return 0;
}
#else
uint8_t MPU6050_9Axis_MotionApps41::dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity) {
// yaw: (about Z axis)
data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1);
// pitch: (nose up/down, about Y axis)
data[1] = atan2(gravity -> x , sqrt(gravity -> y*gravity -> y + gravity -> z*gravity -> z));
// roll: (tilt left/right, about X axis)
data[2] = atan2(gravity -> y , gravity -> z);
if(gravity->z<0) {
if(data[1]>0) {
data[1] = PI - data[1];
} else {
data[1] = -PI - data[1];
}
}
return 0;
}
#endif
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetAccelFloat(float *data, const uint8_t* packet);
// uint8_t MPU6050_9Axis_MotionApps41::dmpGetQuaternionFloat(float *data, const uint8_t* packet);
uint8_t MPU6050_9Axis_MotionApps41::dmpProcessFIFOPacket(const unsigned char *dmpData) {
(void)dmpData; // suppress unused variable compiler warning
/*for (uint8_t k = 0; k < dmpPacketSize; k++) {
if (dmpData[k] < 0x10) Serial.print("0");
Serial.print(dmpData[k], HEX);
Serial.print(" ");
}
Serial.print("\n");*/
//Serial.println((uint16_t)dmpPacketBuffer);
return 0;
}
uint8_t MPU6050_9Axis_MotionApps41::dmpReadAndProcessFIFOPacket(uint8_t numPackets, uint8_t *processed) {
uint8_t status;
uint8_t buf[dmpPacketSize];
for (uint8_t i = 0; i < numPackets; i++) {
// read packet from FIFO
getFIFOBytes(buf, dmpPacketSize);
// process packet
if ((status = dmpProcessFIFOPacket(buf)) > 0) return status;
// increment external process count variable, if supplied
if (processed != 0) (*processed)++;
}
return 0;
}
// uint8_t MPU6050_9Axis_MotionApps41::dmpSetFIFOProcessedCallback(void (*func) (void));
// uint8_t MPU6050_9Axis_MotionApps41::dmpInitFIFOParam();
// uint8_t MPU6050_9Axis_MotionApps41::dmpCloseFIFO();
// uint8_t MPU6050_9Axis_MotionApps41::dmpSetGyroDataSource(uint_fast8_t source);
// uint8_t MPU6050_9Axis_MotionApps41::dmpDecodeQuantizedAccel();
// uint32_t MPU6050_9Axis_MotionApps41::dmpGetGyroSumOfSquare();
// uint32_t MPU6050_9Axis_MotionApps41::dmpGetAccelSumOfSquare();
// void MPU6050_9Axis_MotionApps41::dmpOverrideQuaternion(long *q);
uint16_t MPU6050_9Axis_MotionApps41::dmpGetFIFOPacketSize() {
return dmpPacketSize;
}

View File

@ -0,0 +1,153 @@
// I2Cdev library collection - MPU6050 I2C device class
// Based on InvenSense MPU-6050 register map document rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
// 10/3/2011 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2021/09/27 - split implementations out of header files, finally
// ... - ongoing debug release
// NOTE: THIS IS ONLY A PARIAL RELEASE. THIS DEVICE CLASS IS CURRENTLY UNDERGOING ACTIVE
// DEVELOPMENT AND IS STILL MISSING SOME IMPORTANT FEATURES. PLEASE KEEP THIS IN MIND IF
// YOU DECIDE TO USE THIS PARTICULAR CODE FOR ANYTHING.
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
#ifndef _MPU6050_6AXIS_MOTIONAPPS41_H_
#define _MPU6050_6AXIS_MOTIONAPPS41_H_
// take ownership of the "MPU6050" typedef
#define I2CDEVLIB_MPU6050_TYPEDEF
#include "MPU6050.h"
class MPU6050_9Axis_MotionApps41 : public MPU6050_Base {
public:
MPU6050_9Axis_MotionApps41(uint8_t address=MPU6050_DEFAULT_ADDRESS, void *wireObj=0) : MPU6050_Base(address, wireObj) { }
uint8_t dmpInitialize();
bool dmpPacketAvailable();
uint8_t dmpSetFIFORate(uint8_t fifoRate);
uint8_t dmpGetFIFORate();
uint8_t dmpGetSampleStepSizeMS();
uint8_t dmpGetSampleFrequency();
int32_t dmpDecodeTemperature(int8_t tempReg);
// Register callbacks after a packet of FIFO data is processed
//uint8_t dmpRegisterFIFORateProcess(inv_obj_func func, int16_t priority);
//uint8_t dmpUnregisterFIFORateProcess(inv_obj_func func);
uint8_t dmpRunFIFORateProcesses();
// Setup FIFO for various output
uint8_t dmpSendQuaternion(uint_fast16_t accuracy);
uint8_t dmpSendGyro(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendAccel(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendLinearAccel(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendLinearAccelInWorld(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendControlData(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendExternalSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendGravity(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendPacketNumber(uint_fast16_t accuracy);
uint8_t dmpSendQuantizedAccel(uint_fast16_t elements, uint_fast16_t accuracy);
uint8_t dmpSendEIS(uint_fast16_t elements, uint_fast16_t accuracy);
// Get Fixed Point data from FIFO
uint8_t dmpGetAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetQuaternion(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuaternion(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuaternion(Quaternion *q, const uint8_t* packet=0);
uint8_t dmpGet6AxisQuaternion(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGet6AxisQuaternion(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGet6AxisQuaternion(Quaternion *q, const uint8_t* packet=0);
uint8_t dmpGetRelativeQuaternion(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetRelativeQuaternion(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetRelativeQuaternion(Quaternion *data, const uint8_t* packet=0);
uint8_t dmpGetGyro(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyro(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyro(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetMag(int16_t *data, const uint8_t* packet=0);
uint8_t dmpSetLinearAccelFilterCoefficient(float coef);
uint8_t dmpGetLinearAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetLinearAccel(VectorInt16 *v, VectorInt16 *vRaw, VectorFloat *gravity);
uint8_t dmpGetLinearAccelInWorld(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccelInWorld(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetLinearAccelInWorld(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetLinearAccelInWorld(VectorInt16 *v, VectorInt16 *vReal, Quaternion *q);
uint8_t dmpGetGyroAndAccelSensor(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroAndAccelSensor(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroAndAccelSensor(VectorInt16 *g, VectorInt16 *a, const uint8_t* packet=0);
uint8_t dmpGetGyroSensor(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroSensor(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGyroSensor(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetControlData(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetTemperature(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGravity(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetGravity(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetGravity(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetGravity(VectorFloat *v, Quaternion *q);
uint8_t dmpGetUnquantizedAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetUnquantizedAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetUnquantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetQuantizedAccel(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuantizedAccel(int16_t *data, const uint8_t* packet=0);
uint8_t dmpGetQuantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
uint8_t dmpGetExternalSensorData(int32_t *data, uint16_t size, const uint8_t* packet=0);
uint8_t dmpGetEIS(int32_t *data, const uint8_t* packet=0);
uint8_t dmpGetEuler(float *data, Quaternion *q);
uint8_t dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity);
// Get Floating Point data from FIFO
uint8_t dmpGetAccelFloat(float *data, const uint8_t* packet=0);
uint8_t dmpGetQuaternionFloat(float *data, const uint8_t* packet=0);
uint8_t dmpProcessFIFOPacket(const unsigned char *dmpData);
uint8_t dmpReadAndProcessFIFOPacket(uint8_t numPackets, uint8_t *processed=NULL);
uint8_t dmpSetFIFOProcessedCallback(void (*func) (void));
uint8_t dmpInitFIFOParam();
uint8_t dmpCloseFIFO();
uint8_t dmpSetGyroDataSource(uint8_t source);
uint8_t dmpDecodeQuantizedAccel();
uint32_t dmpGetGyroSumOfSquare();
uint32_t dmpGetAccelSumOfSquare();
void dmpOverrideQuaternion(long *q);
uint16_t dmpGetFIFOPacketSize();
private:
uint8_t *dmpPacketBuffer;
uint16_t dmpPacketSize;
};
typedef MPU6050_9Axis_MotionApps41 MPU6050;
#endif /* _MPU6050_6AXIS_MOTIONAPPS41_H_ */

View File

@ -0,0 +1,216 @@
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class, 3D math helper
// 6/5/2012 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2012-06-05 - add 3D math helper file to DMP6 example sketch
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg
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.
===============================================
*/
#ifndef _HELPER_3DMATH_H_
#define _HELPER_3DMATH_H_
class Quaternion {
public:
float w;
float x;
float y;
float z;
Quaternion() {
w = 1.0f;
x = 0.0f;
y = 0.0f;
z = 0.0f;
}
Quaternion(float nw, float nx, float ny, float nz) {
w = nw;
x = nx;
y = ny;
z = nz;
}
Quaternion getProduct(Quaternion q) {
// Quaternion multiplication is defined by:
// (Q1 * Q2).w = (w1w2 - x1x2 - y1y2 - z1z2)
// (Q1 * Q2).x = (w1x2 + x1w2 + y1z2 - z1y2)
// (Q1 * Q2).y = (w1y2 - x1z2 + y1w2 + z1x2)
// (Q1 * Q2).z = (w1z2 + x1y2 - y1x2 + z1w2
return Quaternion(
w*q.w - x*q.x - y*q.y - z*q.z, // new w
w*q.x + x*q.w + y*q.z - z*q.y, // new x
w*q.y - x*q.z + y*q.w + z*q.x, // new y
w*q.z + x*q.y - y*q.x + z*q.w); // new z
}
Quaternion getConjugate() {
return Quaternion(w, -x, -y, -z);
}
float getMagnitude() {
return sqrt(w*w + x*x + y*y + z*z);
}
void normalize() {
const float im = 1.0f / getMagnitude();
w *= im;
x *= im;
y *= im;
z *= im;
}
Quaternion getNormalized() {
Quaternion r(w, x, y, z);
r.normalize();
return r;
}
};
class VectorInt16 {
public:
int16_t x;
int16_t y;
int16_t z;
VectorInt16() {
x = 0;
y = 0;
z = 0;
}
VectorInt16(int16_t nx, int16_t ny, int16_t nz) {
x = nx;
y = ny;
z = nz;
}
float getMagnitude() {
return sqrt(x*x + y*y + z*z);
}
void normalize() {
const float im = 1.0f / getMagnitude();
x *= im;
y *= im;
z *= im;
}
VectorInt16 getNormalized() {
VectorInt16 r(x, y, z);
r.normalize();
return r;
}
void rotate(Quaternion *q) {
// http://www.cprogramming.com/tutorial/3d/quaternions.html
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/index.htm
// http://content.gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation
// ^ or: http://webcache.googleusercontent.com/search?q=cache:xgJAp3bDNhQJ:content.gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation&hl=en&gl=us&strip=1
// P_out = q * P_in * conj(q)
// - P_out is the output vector
// - q is the orientation quaternion
// - P_in is the input vector (a*aReal)
// - conj(q) is the conjugate of the orientation quaternion (q=[w,x,y,z], q*=[w,-x,-y,-z])
Quaternion p(0, x, y, z);
// quaternion multiplication: q * p, stored back in p
p = q -> getProduct(p);
// quaternion multiplication: p * conj(q), stored back in p
p = p.getProduct(q -> getConjugate());
// p quaternion is now [0, x', y', z']
x = p.x;
y = p.y;
z = p.z;
}
VectorInt16 getRotated(Quaternion *q) {
VectorInt16 r(x, y, z);
r.rotate(q);
return r;
}
};
class VectorFloat {
public:
float x;
float y;
float z;
VectorFloat() {
x = 0;
y = 0;
z = 0;
}
VectorFloat(float nx, float ny, float nz) {
x = nx;
y = ny;
z = nz;
}
float getMagnitude() {
return sqrt(x*x + y*y + z*z);
}
void normalize() {
const float m = 1.0f / getMagnitude();
x *= m;
y *= m;
z *= m;
}
VectorFloat getNormalized() {
VectorFloat r(x, y, z);
r.normalize();
return r;
}
void rotate(Quaternion *q) {
Quaternion p(0, x, y, z);
// quaternion multiplication: q * p, stored back in p
p = q -> getProduct(p);
// quaternion multiplication: p * conj(q), stored back in p
p = p.getProduct(q -> getConjugate());
// p quaternion is now [0, x', y', z']
x = p.x;
y = p.y;
z = p.z;
}
VectorFloat getRotated(Quaternion *q) {
VectorFloat r(x, y, z);
r.rotate(q);
return r;
}
};
#endif /* _HELPER_3DMATH_H_ */

395
lib/OSC/API.md 100644
View File

@ -0,0 +1,395 @@
# OSCMessage
An OSCMessage is an address followed by any number of data. Messages can have mixed data types like an integer followed by a string followed by a float, etc.
## Constructor
OSCMessages can be constructed with or without an address.
### `OSCMessage(const char *)`
Set the address of the message in the constructor
```C++
OSCMessage msg("/address");
```
### `OSCMessage()`
An OSCMessage constructed without an address is not valid until it is given an address.
## Add/Set Data
### `OSCMessage& add(int i)`
Append an integer to the OSCMessage.
```C++
msg.add(1);
```
### `OSCMessage& add(float f)`
Append a float to the OSCMessage.
### `OSCMessage& add(bool b)`
Append a boolean to the OSCMessage.
### `OSCMessage& add(const char * str)`
Append a string to the OSCMessage.
```C++
msg.add("hello");
```
### `OSCMessage& add(uint8_t * blob, int length)`
Append a [blob](https://en.wikipedia.org/wiki/Binary_large_object) to the OSCMessage. Pass in the length of the blob as the second argument.
### `OSCMessage& set(int position, Type data)`
Replace the data at the given position with the data. `Type` can be any of the supported data types.
```C++
//replace the data at the 0th position with a string
msg.set(0, "string");
```
### `OSCMessage& set(int position, uint8_t * data, int length)`
Set the data at the given position to be a blob of the given length.
### `OSCMessage& add(double d)`
Append a double precision floating point value to the OSCMessage. NOTE: double is not supported on most Arduino platforms. It will fall back to float, when double is not supported.
## Get Data
### `int getInt(int position)`
Returns the integer at the given position
```C++
//returns the integer at the third position
msg.getInt(2);
```
### `float getFloat(int position)`
Returns the float at the given position
### `bool getBoolean(int position)`
Returns the boolean at the given position
### `double getDouble(int position)`
Returns the double at the given position. NOTE: double is not supported by most Arduino platforms. This will fail silently if double is not supported.
### `int getString(int position, char * strBuffer)`
Copy the strings characters into the `strBuffer`, without any safety check.
Returns the number of copied characters.
### `int getString(int position, char * strBuffer, int length)`
Copy the strings characters into the `strBuffer`, after checking that this doesnt exceed the buffers `length`.
Returns the number of copied characters. NOTE that if the string length is greater than the available buffer length, then NO characters are copied.
### `int getString(int position, char * strBuffer, int length, int offset, int size)`
Copy `size` number of characters from the given `offset` into the `strBuffer`, after checking that this doesnt exceed the buffers `length`. Returns `size`, even if the number of copied characters is lower.
```C++
char str[8];
//fill str with 8 characters from the 0th datum
msg.getString(0, str, 8, 0, 8);
```
### `int getBlob(int position, uint8_t * blobBuffer)`
Directly copy the blobs bytes into the `blob` buffer (without safety-check).
Returns the number of bytes from the blob.
### `int getBlob(int position, uint8_t * blobBuffer, int length)`
Copy the blob's bytes into the given `blobBuffer`, if the blob's size doesnt exceed the blobBuffer's `length`.
Returns the number of bytes copied from the blob. NOTE that if the blob length is greater than the available buffer length, then NO bytes are copied.
### `int getBlob(int position, uint8_t * blobBuffer, int length, int offset, int size)`
Copy `size` bytes from the blob, starting from `offset`, into the given `blobBuffer`, if the size doesnt exceed the buffers `length` or the blobs data length.
Returns the number of bytes copied from the blob. NOTE that if the requested size is greater than *either* the available buffer length *or* the (partial) blob length, then NO bytes are copied.
### `const uint8_t* getBlob(int position)`
Get a pointer to blob data.
### `int getBlobLength(int position)`
Returns the length of the blob in bytes.
### `char getType(int position)`
Returns the type of the data at the given position.
```C++
OSCMessage msg("/address");
msg.add(1);
msg.getType(0); //-> returns 'i'
```
## Query Data
### `bool isInt(int position)`
Returns `true` when the data at the given position is an integer.
### `bool isFloat(int position)`
Returns `true` when the data at the given position is a float.
### `bool isBoolean(int position)`
Returns `true` when the data at the given position is a boolean.
### `bool isString(int position)`
Returns `true` when the data at the given position is a string.
### `bool isBlob(int position)`
Returns `true` when the data at the given position is a blob.
### `bool isDouble(int position)`
Returns `true` when the data at the given position is a double.
### `int size()`
Returns the number of data the OSCMessage has.
### `int bytes()`
Returns the size of the OSCMessage in bytes (if everything is 32-bit aligned).
## Address
### `OSCMessage& setAddress(const char * address)`
Set the address of the OSCMessage.
### `int getAddress(char * str, int offset=0)`
Copy the address of the OSCMessage into the `str` buffer. Copy after the given address `offset` (defaults to 0). Returns the length of the resulting string. If the offset is past the end of the address an empty string / zero length are returned.
### `int getAddress(char * str, int offset, int len)`
Copy a maximum of len characters of the address of the OSCMessage into the `str` buffer, starting at at the given address `offset`. Returns the length of the resulting string. If the offset is past the end of the address an empty string / zero length are returned.
### `int getAddressLength(int offset=0)`
Returns the length of the OSCMessage's address, starting after the given address `offset` (defaults to 0). If the offset is
greater than the address length then it returns zero.
### `const char* getAddress()`
Get a pointer to the address as a C string.
## Send Receive
### `OSCMessage& send(Print &p)`
Output the message to the given transport layer which extends Arduino's [Print class](http://playground.arduino.cc/Code/Printclass) like the `Serial` out.
```C++
msg.send(SLIPSerial);
```
### `OSCMessage& fill(uint8_t incomingByte)`
Add the incoming byte to the OSCMessage where it will be decoded.
### `OSCMessage& fill(uint8_t * bytes, int length)`
Add and decode the array of `bytes` as an OSCMessage.
## Matching / Routing
### `bool fullMatch( const char * pattern, int offset = 0)`
Returns true if the message's address is a full match to the given `pattern` after the `offset`.
```C++
OSCMessage msg("/a/0");
msg.fullMatch("/0", 2); // ->returns true
```
### `int match( const char * pattern, int offset = 0)`
Returns the number of matched characters of the message's address against the given `pattern` (optionally with an `offset`). Unlike `fullMatch`, `match` allows for partial matches
```C++
OSCMessage msg("/a/0");
msg.match("/a"); // ->returns 2
```
### `bool dispatch(const char * pattern, void (*callback)(OSCMessage &), int offset = 0)`
Invoke the given `callback` if the address is a full match with the `pattern` (after the `offset`). The message is passed into the callback function. Returns true if the pattern was a match and the callback function was invoked.
### `bool route(const char * pattern, void (*callback)(OSCMessage &, int), int offset = 0)`
Invoke the given `callback` if the address if a match with the `pattern` (after the `offset`). The OSCMessage and the address offset is passed into the callback function. Returns true if the pattern was a match and the callback function was invoked.
```C++
//define a callback function for matching messages
void routeCallback(OSCMessage & message, int addressOffset){
//do something with the message...
//with the message below, the addressOffset will equal 2.
}
OSCMessage msg("/a/0");
msg.route("/a", routeCallback);
```
## Address Patterns
OSCMessages can be constructed with patterns and later routed or dispatched against addresses.
```C++
OSCMessage msg("/{a,b}/[0-9]");
msg.route("/a/0", a0_callback); //matches the address
msg.route("/b/2", b2_callback); //matches the address
msg.route("/c/11", c11_callback); //not invoked
```
# OSCBundle
A bundle is a group of OSCMessages with a timetag.
## Constructor
### `OSCBundle()`
Construct an empty OSCBundle.
### `OSCBundle(osctime_t = zerotime)`
Construct the bundle with a timetag. timetag defaults to 0 (immediate).
## Add OSCMessage
### `OSCMessage & add(char * address)`
Create a new message with the given `address` in the bundle. Returns the newly created OSCMessage.
```C++
//create a new OSCMessage and add some data to it
bundle.add("/message").add("data");
```
## Get OSCMessage
### `OSCMessage * getOSCMessage(int position)`
Return the OSCMessage in the bundle at the given `position`.
```C++
OSCBundle bundle
bundle.add("/a");
bundle.add("/b");
bundle.getOSCMessage(0);//returns the OSCMessage with the address "/a".
```
### `OSCMessage * getOSCMessage(char * address)`
Return the OSCMessage in the bundle which matches the given address.
```C++
OSCBundle bundle
bundle.add("/a");
bundle.add("/b");
bundle.getOSCMessage("/b");//returns the second OSCMessage in the bundle
```
## Routing
### `bool dispatch(const char * pattern, void (*callback)(OSCMessage&), int offset = 0)`
Invoke the `callback` function with all messages in the bundle which match the given pattern after the offset.
```C++
bundle.add("/a/0");
bundle.add("/b/0");
bundle.dispatch("/0", dispatchZero, 2);
```
### `bool route(const char * pattern, void (*callback)(OSCMessage &, int), int offset = 0)`
Invoke the `callback` with all the OSCMessages in the bundle which match the given `pattern`. `route` allows for partial matches.
## Send/Receive
### `OSCBundle& send(Print &p)`
Output the bundle to the given transport layer which extends Arduino's [Print class](http://playground.arduino.cc/Code/Printclass) (such as `SLIPSerial` out).
```C++
bundle.send(SLIPSerial);
```
### `OSCBundle& fill(uint8_t incomingByte)`
Add the incoming byte to the OSCBundle where it will be decoded.
### `OSCBundle& fill(uint8_t * bytes, int length)`
Add and decode the array of bytes as an OSCBundle.
# Chaining
Many methods return `this` which enables you to string together multiple commands.
This technique allows multiple lines to be condensed into one:
```C++
bundle.add("/address").add("data").add(0).send(SLIPSerial).empty();
```

View File

@ -0,0 +1,306 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 7,
"minor" : 0,
"revision" : 4,
"architecture" : "x86",
"modernui" : 1
}
,
"rect" : [ 130.0, 174.0, 983.0, 623.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 12.0,
"default_fontface" : 0,
"default_fontname" : "Arial",
"gridonopen" : 1,
"gridsize" : [ 15.0, 15.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"fontface" : 0,
"fontsize" : 12.0,
"id" : "obj-5",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 141.0, 266.0, 150.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-3",
"linecount" : 6,
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 422.5, 125.0, 158.0, 101.0 ],
"text" : "/port : \"usbmodemOSCes41\",\n/rate/output : 0,\n/rate/input : 0,\n/mediansize/received : -1,\n/baud",
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-2",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 389.5, -32.5, 170.0, 33.0 ],
"style" : "",
"text" : "Look for your device in the menu list of serial USB"
}
}
, {
"box" : {
"bgmode" : 0,
"border" : 0,
"clickthrough" : 0,
"enablehscroll" : 0,
"enablevscroll" : 0,
"id" : "obj-7",
"lockeddragscroll" : 0,
"maxclass" : "bpatcher",
"name" : "o.io.serial.display.maxpat",
"numinlets" : 1,
"numoutlets" : 1,
"offset" : [ 3.0, 0.0 ],
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 81.5, 29.0, 340.5, 25.0 ],
"viewvisibility" : 1
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-23",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 2,
"outlettype" : [ "FullPacket", "FullPacket" ],
"patching_rect" : [ 20.5, 68.0, 80.0, 22.0 ],
"style" : "",
"text" : "o.io.slipserial"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-11",
"linecount" : 3,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 471.0, 29.0, 150.0, 54.0 ],
"style" : "",
"text" : "stats on serial OSC communications"
}
}
, {
"box" : {
"fontface" : 0,
"fontsize" : 12.0,
"id" : "obj-6",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 214.0, 285.0, 150.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontsize" : 12.0,
"id" : "obj-4",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 23.0, 285.0, 150.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-1",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 3,
"outlettype" : [ "", "", "FullPacket" ],
"patching_rect" : [ 23.0, 176.0, 119.0, 22.0 ],
"style" : "",
"text" : "o.route /raw /cooked"
}
}
],
"lines" : [ {
"patchline" : {
"destination" : [ "obj-4", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-1", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-6", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-1", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-1", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-23", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-3", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 91.0, 109.0, 432.0, 109.0 ],
"source" : [ "obj-23", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-5", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-23", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-7", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 91.0, 95.0, 433.0, 95.0, 433.0, 5.0, 91.0, 5.0 ],
"source" : [ "obj-23", 1 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-23", 1 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-7", 0 ]
}
}
],
"dependency_cache" : [ {
"name" : "o.io.slipserial.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.righttoleft.maxpat",
"bootpath" : "~/Documents/Max/Packages/odot/patchers/ordering",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.io.serial.display.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.route.mxo",
"type" : "iLaX"
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
, {
"name" : "o.pack.mxo",
"type" : "iLaX"
}
, {
"name" : "o.union.mxo",
"type" : "iLaX"
}
, {
"name" : "o.validate.mxo",
"type" : "iLaX"
}
, {
"name" : "o.print.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.encode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.decode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.if.mxo",
"type" : "iLaX"
}
],
"embedsnapshot" : 0
}
}

View File

@ -0,0 +1,974 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 7,
"minor" : 0,
"revision" : 4,
"architecture" : "x86",
"modernui" : 1
}
,
"rect" : [ 140.0, 78.0, 1266.0, 737.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 14.0,
"default_fontface" : 0,
"default_fontname" : "Andale Mono",
"gridonopen" : 1,
"gridsize" : [ 5.0, 5.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-6",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 725.5, 158.0, 170.0, 33.0 ],
"style" : "",
"text" : "Look for your device in the menu list of serial USB"
}
}
, {
"box" : {
"bgmode" : 0,
"border" : 0,
"clickthrough" : 0,
"enablehscroll" : 0,
"enablevscroll" : 0,
"id" : "obj-9",
"lockeddragscroll" : 0,
"maxclass" : "bpatcher",
"name" : "o.io.serial.display.maxpat",
"numinlets" : 1,
"numoutlets" : 1,
"offset" : [ 3.0, 0.0 ],
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 338.5, 162.0, 340.5, 25.0 ],
"viewvisibility" : 1
}
}
, {
"box" : {
"fontface" : 0,
"fontsize" : 14.0,
"id" : "obj-8",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 240.5, 252.0, 150.0, 36.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontsize" : 14.0,
"id" : "obj-5",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 491.0, 252.0, 150.0, 36.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-7",
"maxclass" : "o.message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 521.0, 81.0, 150.0, 20.0 ],
"text" : "/analog/{2,3}/u",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-1",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 524.5, 16.0, 222.0, 38.0 ],
"style" : "",
"text" : "read analog pins 2 and 3 with pullup turned on"
}
}
, {
"box" : {
"id" : "obj-78",
"maxclass" : "toggle",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "int" ],
"parameter_enable" : 0,
"patching_rect" : [ 504.5, 15.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-79",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 504.5, 46.0, 86.0, 24.0 ],
"style" : "",
"text" : "qmetro 20"
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-55",
"maxclass" : "o.message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 266.0, 81.0, 150.0, 20.0 ],
"text" : "/analog/[0-3]/u",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-28",
"maxclass" : "o.message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 19.0, 81.0, 150.0, 20.0 ],
"text" : "/analog/*",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"id" : "obj-56",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 174.0, 455.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-64",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 172.0, 350.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[37]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[25]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-13",
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 3.0, 493.0, 145.0, 22.0 ],
"style" : "",
"text" : "analog readings"
}
}
, {
"box" : {
"id" : "obj-110",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 135.0, 454.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"id" : "obj-109",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 102.0, 454.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"id" : "obj-108",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 69.0, 454.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"id" : "obj-107",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 36.0, 454.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-105",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 135.0, 350.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[19]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[4]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-104",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 102.0, 350.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[20]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[3]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-103",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 69.0, 350.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[21]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[2]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-102",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 36.0, 350.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[22]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[1]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-101",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 3.0, 350.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[23]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a"
}
}
, {
"box" : {
"id" : "obj-84",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 3.0, 454.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-81",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 7,
"outlettype" : [ "", "", "", "", "", "", "FullPacket" ],
"patching_rect" : [ 8.0, 310.0, 221.0, 24.0 ],
"style" : "",
"text" : "o.route /0 /1 /2 /3 /4 /5"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-45",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "FullPacket" ],
"patching_rect" : [ 3.0, 252.0, 137.0, 24.0 ],
"style" : "",
"text" : "o.route /analog"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-15",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 269.5, 17.0, 187.0, 38.0 ],
"style" : "",
"text" : "read analog pins 0-3 with pullup turned on"
}
}
, {
"box" : {
"id" : "obj-18",
"maxclass" : "toggle",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "int" ],
"parameter_enable" : 0,
"patching_rect" : [ 249.5, 17.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-22",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 249.5, 47.0, 86.0, 24.0 ],
"style" : "",
"text" : "qmetro 20"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-46",
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 32.5, 18.0, 187.0, 22.0 ],
"style" : "",
"text" : "read all analog pins"
}
}
, {
"box" : {
"id" : "obj-60",
"maxclass" : "toggle",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "int" ],
"parameter_enable" : 0,
"patching_rect" : [ 12.5, 18.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-61",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 12.5, 47.0, 95.0, 24.0 ],
"style" : "",
"text" : "qmetro 100"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-4",
"linecount" : 3,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 702.5, 243.0, 150.0, 54.0 ],
"style" : "",
"text" : "stats on serial OSC communications"
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-26",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 2,
"outlettype" : [ "FullPacket", "FullPacket" ],
"patching_rect" : [ 220.5, 201.0, 137.0, 24.0 ],
"style" : "",
"text" : "o.io.slipserial"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-91",
"maxclass" : "newobj",
"numinlets" : 0,
"numoutlets" : 0,
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 7,
"minor" : 0,
"revision" : 4,
"architecture" : "x86",
"modernui" : 1
}
,
"rect" : [ 34.0, 78.0, 738.0, 421.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 14.0,
"default_fontface" : 0,
"default_fontname" : "Andale Mono",
"gridonopen" : 1,
"gridsize" : [ 5.0, 5.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-2",
"linecount" : 25,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 15.0, 20.0, 768.0, 400.0 ],
"style" : "",
"text" : "/*\n Written by Yotam Mann and Adrian freed,\n The Center for New Music and Audio Technologies,\n University of California, Berkeley. Copyright (c) 2012, The Regents of\n the University of California (Regents).\n \n Permission to use, copy, modify, distribute, and distribute modified versions\n of this software and its documentation without fee and without a signed\n licensing agreement, is hereby granted, provided that the above copyright\n notice, this paragraph and the following two paragraphs appear in all copies,\n modifications, and distributions.\n \n IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,\n SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING\n OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS\n BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED\n HEREUNDER IS PROVIDED \"AS IS\". REGENTS HAS NO OBLIGATION TO PROVIDE\n MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.\n \n For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu\n */"
}
}
],
"lines" : [ ]
}
,
"patching_rect" : [ 8.0, 570.0, 111.0, 24.0 ],
"saved_object_attributes" : {
"description" : "",
"digest" : "",
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"globalpatchername" : "",
"style" : "",
"tags" : ""
}
,
"style" : "",
"text" : "p disclaimer"
}
}
],
"lines" : [ {
"patchline" : {
"destination" : [ "obj-84", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-101", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-107", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-102", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-108", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-103", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-109", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-104", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-110", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-105", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-22", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-18", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-55", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-22", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-45", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-5", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-8", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-9", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 348.0, 229.0, 717.0, 229.0, 717.0, 131.0, 348.0, 131.0 ],
"source" : [ "obj-26", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-26", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-28", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-81", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-45", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-26", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-55", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-61", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-60", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-28", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-61", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-56", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-64", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-26", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-7", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-79", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-78", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-7", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-79", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-101", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-102", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-103", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 2 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-104", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 3 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-105", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 4 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-64", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 5 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-26", 1 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-9", 0 ]
}
}
],
"parameters" : {
"obj-105" : [ "a[19]", "a", 0 ],
"obj-104" : [ "a[20]", "a", 0 ],
"obj-103" : [ "a[21]", "a", 0 ],
"obj-64" : [ "a[37]", "a", 0 ],
"obj-102" : [ "a[22]", "a", 0 ],
"obj-101" : [ "a[23]", "a", 0 ]
}
,
"dependency_cache" : [ {
"name" : "o.io.slipserial.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.righttoleft.maxpat",
"bootpath" : "~/Documents/Max/Packages/odot/patchers/ordering",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.io.serial.display.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.pack.mxo",
"type" : "iLaX"
}
, {
"name" : "o.route.mxo",
"type" : "iLaX"
}
, {
"name" : "o.union.mxo",
"type" : "iLaX"
}
, {
"name" : "o.validate.mxo",
"type" : "iLaX"
}
, {
"name" : "o.print.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.encode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.decode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.if.mxo",
"type" : "iLaX"
}
, {
"name" : "o.message.mxo",
"type" : "iLaX"
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
],
"embedsnapshot" : 0
}
}

View File

@ -0,0 +1,304 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 6,
"minor" : 1,
"revision" : 6,
"architecture" : "x86"
}
,
"rect" : [ 608.0, 81.0, 1202.0, 749.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 14.0,
"default_fontface" : 0,
"default_fontname" : "Andale Mono",
"gridonopen" : 0,
"gridsize" : [ 5.0, 5.0 ],
"gridsnaponopen" : 0,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"boxanimatetime" : 200,
"imprint" : 0,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"boxes" : [ {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-1",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 218.0, 295.0, 95.0, 22.0 ],
"text" : "o.downcast"
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-18",
"linecount" : 10,
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 28.5, 425.0, 267.0, 155.0 ],
"text" : "/ping : 100,\n/thing : [2., 3.04, 1242., 23., \"thing\"],\n/stuff : [1, 2, 3, 4, 5],\n/fsakjfskfsdkasfk : [234, 242, 234, 234, 4],\n/decision : 1,\n/notdecision : 0,\n/micros : 616229100,\n/sequencenumber : 20557,\n/digital/5 : false,\n/lsb : false",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-3",
"linecount" : 5,
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 404.5, 425.0, 158.0, 88.0 ],
"text" : "/port : \"usbmodem12341\",\n/rate/output : 32,\n/rate/input : 39,\n/mediansize/received : -1,\n/baud",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"frgb" : 0.0,
"id" : "obj-19",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 424.5, 269.5, 170.0, 33.0 ],
"text" : "Look for your device in the menu list of serial USB"
}
}
, {
"box" : {
"id" : "obj-20",
"maxclass" : "bpatcher",
"name" : "o.io.serial.display.maxpat",
"numinlets" : 1,
"numoutlets" : 1,
"offset" : [ 3.0, 0.0 ],
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 404.5, 340.0, 164.0, 24.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-23",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 2,
"outlettype" : [ "FullPacket", "FullPacket" ],
"patching_rect" : [ 343.5, 379.0, 80.0, 20.0 ],
"text" : "o.io.slipserial"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-2",
"linecount" : 6,
"maxclass" : "o.compose",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 45.0, 90.166656, 964.0, 105.0 ],
"text" : "/ping : 100,\n/thing : [2., 3.04, 1242., 23., \"thing\"],\n/stuff : [1, 2, 3, 4, 5],\n/fsakjfskfsdkasfk : [234, 242, 234, 234, 4],\n/decision : true,\n/notdecision : false",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"frgb" : 0.0,
"id" : "obj-4",
"linecount" : 3,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 595.0, 415.0, 150.0, 54.0 ],
"text" : "stats on serial OSC communications"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-61",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 45.0, 38.166656, 162.0, 22.0 ],
"text" : "metro 22 @active 1"
}
}
],
"lines" : [ {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-23", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-1", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-1", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-2", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-23", 1 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-20", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-18", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-23", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-20", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 414.0, 406.0, 583.0, 406.0, 583.0, 316.0, 414.0, 316.0 ],
"source" : [ "obj-23", 1 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-3", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 414.0, 420.0, 414.0, 420.0 ],
"source" : [ "obj-23", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-2", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-61", 0 ]
}
}
],
"dependency_cache" : [ {
"name" : "o.io.slipserial.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/CNMAT-MMJSS/patchers/esplora",
"patcherrelativepath" : "../../../../../Documents/Max/Packages/CNMAT-MMJSS/patchers/esplora",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.righttoleft.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/CNMAT-odot/patchers/ordering",
"patcherrelativepath" : "../../../../../Documents/Max/Packages/CNMAT-odot/patchers/ordering",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.io.serial.display.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/CNMAT-MMJSS/patchers/esplora",
"patcherrelativepath" : "../../../../../Documents/Max/Packages/CNMAT-MMJSS/patchers/esplora",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.compose.mxo",
"type" : "iLaX"
}
, {
"name" : "o.pack.mxo",
"type" : "iLaX"
}
, {
"name" : "o.route.mxo",
"type" : "iLaX"
}
, {
"name" : "o.union.mxo",
"type" : "iLaX"
}
, {
"name" : "o.validate.mxo",
"type" : "iLaX"
}
, {
"name" : "o.print.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.encode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.decode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.if.mxo",
"type" : "iLaX"
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
, {
"name" : "o.downcast.mxo",
"type" : "iLaX"
}
]
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,428 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 7,
"minor" : 0,
"revision" : 4,
"architecture" : "x86",
"modernui" : 1
}
,
"rect" : [ 378.0, 174.0, 792.0, 490.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 12.0,
"default_fontface" : 0,
"default_fontname" : "Arial",
"gridonopen" : 1,
"gridsize" : [ 15.0, 15.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"fontface" : 0,
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-5",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 68.0, 374.0, 267.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-12",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 164.0, 202.0, 69.0, 22.0 ],
"style" : "",
"text" : "o.pack /led"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-1",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 164.0, 244.0, 95.0, 24.0 ],
"style" : "",
"text" : "o.downcast"
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-18",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 164.0, 314.0, 92.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-3",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 350.5, 374.0, 158.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-2",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 370.5, 218.5, 170.0, 33.0 ],
"style" : "",
"text" : "Look for your device in the menu list of serial USB"
}
}
, {
"box" : {
"bgmode" : 0,
"border" : 0,
"clickthrough" : 0,
"enablehscroll" : 0,
"enablevscroll" : 0,
"id" : "obj-4",
"lockeddragscroll" : 0,
"maxclass" : "bpatcher",
"name" : "o.io.serial.display.maxpat",
"numinlets" : 1,
"numoutlets" : 1,
"offset" : [ 3.0, 0.0 ],
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 350.5, 289.0, 340.5, 25.0 ],
"viewvisibility" : 1
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-23",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 2,
"outlettype" : [ "FullPacket", "FullPacket" ],
"patching_rect" : [ 289.5, 328.0, 80.0, 22.0 ],
"style" : "",
"text" : "o.io.slipserial"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-11",
"linecount" : 3,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 541.0, 364.0, 150.0, 54.0 ],
"style" : "",
"text" : "stats on serial OSC communications"
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-19",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 43.5, 42.0, 156.0, 33.0 ],
"style" : "",
"text" : "PWM control of brightness of LED"
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-15",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 114.0, 151.0, 32.5, 22.0 ],
"style" : "",
"text" : "on"
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-13",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 56.0, 151.0, 32.5, 22.0 ],
"style" : "",
"text" : "off"
}
}
, {
"box" : {
"contdata" : 1,
"id" : "obj-9",
"maxclass" : "multislider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "" ],
"parameter_enable" : 0,
"patching_rect" : [ 220.5, 31.0, 20.0, 140.0 ],
"setminmax" : [ 0.0, 1.0 ],
"style" : ""
}
}
, {
"box" : {
"id" : "obj-8",
"maxclass" : "toggle",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "int" ],
"parameter_enable" : 0,
"patching_rect" : [ 164.0, 151.0, 20.0, 20.0 ],
"style" : ""
}
}
],
"lines" : [ {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-18", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-1", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-23", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-1", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-1", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-12", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-12", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-13", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-12", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-15", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-3", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 360.0, 369.0, 360.0, 369.0 ],
"source" : [ "obj-23", 1 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-4", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 360.0, 355.0, 702.0, 355.0, 702.0, 265.0, 360.0, 265.0 ],
"source" : [ "obj-23", 1 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-5", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-23", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-23", 1 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-4", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-12", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-8", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-12", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-9", 0 ]
}
}
],
"dependency_cache" : [ {
"name" : "o.io.slipserial.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.righttoleft.maxpat",
"bootpath" : "~/Documents/Max/Packages/odot/patchers/ordering",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.io.serial.display.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.pack.mxo",
"type" : "iLaX"
}
, {
"name" : "o.route.mxo",
"type" : "iLaX"
}
, {
"name" : "o.union.mxo",
"type" : "iLaX"
}
, {
"name" : "o.validate.mxo",
"type" : "iLaX"
}
, {
"name" : "o.print.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.encode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.decode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.if.mxo",
"type" : "iLaX"
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
, {
"name" : "o.downcast.mxo",
"type" : "iLaX"
}
],
"embedsnapshot" : 0
}
}

View File

@ -0,0 +1,297 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 7,
"minor" : 0,
"revision" : 4,
"architecture" : "x86",
"modernui" : 1
}
,
"rect" : [ 125.0, 78.0, 1072.0, 480.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 12.0,
"default_fontface" : 0,
"default_fontname" : "Arial",
"gridonopen" : 1,
"gridsize" : [ 15.0, 15.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"fontface" : 0,
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-12",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 27.5, 386.0, 158.0, 34.0 ],
"presentation_rect" : [ 534.5, 418.0, 0.0, 0.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"id" : "obj-6",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 137.5, 194.0, 82.0, 22.0 ],
"style" : "",
"text" : "o.pack /servo"
}
}
, {
"box" : {
"contdata" : 1,
"id" : "obj-11",
"maxclass" : "multislider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "" ],
"parameter_enable" : 0,
"patching_rect" : [ 139.0, 27.0, 20.0, 140.0 ],
"setminmax" : [ 0.0, 180.0 ],
"settype" : 0,
"style" : ""
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-3",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 198.5, 386.0, 158.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-1",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 218.5, 230.5, 170.0, 33.0 ],
"style" : "",
"text" : "Look for your device in the menu list of serial USB"
}
}
, {
"box" : {
"bgmode" : 0,
"border" : 0,
"clickthrough" : 0,
"enablehscroll" : 0,
"enablevscroll" : 0,
"id" : "obj-20",
"lockeddragscroll" : 0,
"maxclass" : "bpatcher",
"name" : "o.io.serial.display.maxpat",
"numinlets" : 1,
"numoutlets" : 1,
"offset" : [ 3.0, 0.0 ],
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 198.5, 301.0, 164.0, 24.0 ],
"viewvisibility" : 1
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-23",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 2,
"outlettype" : [ "FullPacket", "FullPacket" ],
"patching_rect" : [ 137.5, 337.0, 80.0, 22.0 ],
"style" : "",
"text" : "o.io.slipserial"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-5",
"linecount" : 3,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 389.0, 376.0, 150.0, 54.0 ],
"style" : "",
"text" : "stats on serial OSC communications"
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-19",
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 335.0, 151.0, 156.0, 20.0 ],
"style" : "",
"text" : "Servo control (from 0-180)"
}
}
],
"lines" : [ {
"patchline" : {
"destination" : [ "obj-6", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-11", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-23", 1 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-20", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-12", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-23", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-20", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 208.0, 367.0, 377.0, 367.0, 377.0, 277.0, 208.0, 277.0 ],
"source" : [ "obj-23", 1 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-3", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 208.0, 381.0, 208.0, 381.0 ],
"source" : [ "obj-23", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-23", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-6", 0 ]
}
}
],
"dependency_cache" : [ {
"name" : "o.io.slipserial.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.righttoleft.maxpat",
"bootpath" : "~/Documents/Max/Packages/odot/patchers/ordering",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.io.serial.display.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.pack.mxo",
"type" : "iLaX"
}
, {
"name" : "o.route.mxo",
"type" : "iLaX"
}
, {
"name" : "o.union.mxo",
"type" : "iLaX"
}
, {
"name" : "o.validate.mxo",
"type" : "iLaX"
}
, {
"name" : "o.print.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.encode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.decode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.if.mxo",
"type" : "iLaX"
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
],
"embedsnapshot" : 0
}
}

View File

@ -0,0 +1,227 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 6,
"minor" : 1,
"revision" : 9,
"architecture" : "x86"
}
,
"rect" : [ 196.0, 152.0, 1072.0, 480.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 12.0,
"default_fontface" : 0,
"default_fontname" : "Arial",
"gridonopen" : 0,
"gridsize" : [ 15.0, 15.0 ],
"gridsnaponopen" : 0,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"boxanimatetime" : 200,
"imprint" : 0,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"boxes" : [ {
"box" : {
"fontsize" : 12.0,
"id" : "obj-8",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 572.0, 228.0, 207.0, 34.0 ],
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontsize" : 12.0,
"id" : "obj-6",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 95.0, 228.0, 394.0, 34.0 ],
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontsize" : 12.0,
"id" : "obj-9",
"maxclass" : "o.expr.codebox",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "FullPacket", "FullPacket" ],
"patching_rect" : [ 95.0, 172.0, 251.0, 37.0 ],
"text" : " /bundle/time = gettimetag()",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"id" : "obj-7",
"maxclass" : "bpatcher",
"name" : "o.io.serial.display.maxpat",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 271.0, 58.0, 331.0, 28.0 ]
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"frgb" : 0.0,
"id" : "obj-4",
"linecount" : 3,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 592.0, 119.0, 150.0, 54.0 ],
"text" : "stats on serial OSC communications"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-26",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 2,
"outlettype" : [ "FullPacket", "FullPacket" ],
"patching_rect" : [ 95.0, 119.0, 195.0, 22.0 ],
"text" : "o.io.slipserial f 9600"
}
}
],
"lines" : [ {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-7", 0 ],
"disabled" : 0,
"hidden" : 0,
"midpoints" : [ 280.5, 141.0, 300.0, 141.0, 300.0, 96.0, 258.0, 96.0, 258.0, 54.0, 280.5, 54.0 ],
"source" : [ "obj-26", 1 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-8", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 1 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-9", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-26", 1 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-7", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-6", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-9", 0 ]
}
}
],
"dependency_cache" : [ {
"name" : "o.io.slipserial.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"patcherrelativepath" : "../../../../../../Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.righttoleft.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/CNMAT-odot/patchers/ordering",
"patcherrelativepath" : "../../../../../../Documents/Max/Packages/CNMAT-odot/patchers/ordering",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.io.serial.display.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/o.io/experimental/Protocols/serial",
"patcherrelativepath" : "../../../../../../Documents/Max/Packages/o.io/experimental/Protocols/serial",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.pack.mxo",
"type" : "iLaX"
}
, {
"name" : "o.route.mxo",
"type" : "iLaX"
}
, {
"name" : "o.union.mxo",
"type" : "iLaX"
}
, {
"name" : "o.validate.mxo",
"type" : "iLaX"
}
, {
"name" : "o.print.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.encode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.slip.decode.mxo",
"type" : "iLaX"
}
, {
"name" : "o.if.mxo",
"type" : "iLaX"
}
, {
"name" : "o.expr.codebox.mxo",
"type" : "iLaX"
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
]
}
}

View File

@ -0,0 +1,947 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 7,
"minor" : 0,
"revision" : 4,
"architecture" : "x86",
"modernui" : 1
}
,
"rect" : [ 140.0, 78.0, 982.0, 632.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 14.0,
"default_fontface" : 0,
"default_fontname" : "Andale Mono",
"gridonopen" : 1,
"gridsize" : [ 5.0, 5.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-10",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 246.5, 265.0, 128.0, 24.0 ],
"style" : "",
"text" : "o.betweentimes"
}
}
, {
"box" : {
"fontface" : 0,
"fontsize" : 14.0,
"id" : "obj-9",
"maxclass" : "o.compose",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 699.5, 158.0, 157.0, 26.0 ],
"saved_bundle_data" : [ 35, 98, 117, 110, 100, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 47, 97, 110, 97, 108, 111, 103, 47, 123, 50, 44, 51, 125, 47, 117, 0, 44, 0, 0, 0 ],
"saved_bundle_length" : 40,
"text" : "/analog/{2,3}/u",
"textcolor" : [ 0.188, 0.188, 0.188, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontsize" : 14.0,
"id" : "obj-8",
"maxclass" : "o.compose",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 448.5, 159.0, 150.0, 26.0 ],
"saved_bundle_data" : [ 35, 98, 117, 110, 100, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 47, 97, 110, 97, 108, 111, 103, 47, 91, 48, 45, 51, 93, 47, 117, 0, 44, 0, 0, 0 ],
"saved_bundle_length" : 40,
"text" : "/analog/[0-3]/u",
"textcolor" : [ 0.188, 0.188, 0.188, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontsize" : 14.0,
"id" : "obj-6",
"maxclass" : "o.compose",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 246.5, 159.0, 150.0, 26.0 ],
"saved_bundle_data" : [ 35, 98, 117, 110, 100, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 47, 97, 110, 97, 108, 111, 103, 47, 42, 0, 0, 0, 44, 0, 0, 0 ],
"saved_bundle_length" : 36,
"text" : "/analog/*",
"textcolor" : [ 0.188, 0.188, 0.188, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontsize" : 14.0,
"id" : "obj-4",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 246.5, 308.0, 265.0, 36.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-3",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 246.5, 55.0, 95.0, 24.0 ],
"style" : "",
"text" : "loadmess 1"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-1",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 726.5, 77.0, 222.0, 38.0 ],
"style" : "",
"text" : "read analog pins 2 and 3 with pullup turned on"
}
}
, {
"box" : {
"id" : "obj-78",
"maxclass" : "toggle",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "int" ],
"parameter_enable" : 0,
"patching_rect" : [ 699.5, 95.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-79",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 699.5, 126.0, 86.0, 24.0 ],
"style" : "",
"text" : "qmetro 20"
}
}
, {
"box" : {
"id" : "obj-56",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 179.333328, 500.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-64",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 179.333328, 396.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[37]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[25]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-13",
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 11.0, 542.0, 137.0, 22.0 ],
"style" : "",
"text" : "analog readings"
}
}
, {
"box" : {
"id" : "obj-110",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 145.666672, 500.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"id" : "obj-109",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 112.0, 500.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"id" : "obj-108",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 78.333336, 500.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"id" : "obj-107",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 44.666668, 500.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-105",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 145.666672, 396.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[19]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[4]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-104",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 112.0, 396.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[20]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[3]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-103",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 78.333336, 396.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[21]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[2]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-102",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 44.666668, 396.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[22]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a[1]"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"id" : "obj-101",
"maxclass" : "live.slider",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "float" ],
"parameter_enable" : 1,
"patching_rect" : [ 11.0, 396.0, 34.0, 95.0 ],
"saved_attribute_attributes" : {
"valueof" : {
"parameter_longname" : "a[23]",
"parameter_shortname" : "a",
"parameter_type" : 0,
"parameter_mmax" : 1023.0,
"parameter_unitstyle" : 0
}
}
,
"varname" : "a"
}
}
, {
"box" : {
"id" : "obj-84",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 11.0, 500.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-81",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 7,
"outlettype" : [ "", "", "", "", "", "", "FullPacket" ],
"patching_rect" : [ 11.0, 323.0, 221.0, 24.0 ],
"style" : "",
"text" : "o.route /0 /1 /2 /3 /4 /5"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-45",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "", "FullPacket" ],
"patching_rect" : [ 11.0, 265.0, 137.0, 24.0 ],
"style" : "",
"text" : "o.route /analog"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-15",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 475.5, 86.0, 187.0, 38.0 ],
"style" : "",
"text" : "read analog pins 0-3 with pullup turned on"
}
}
, {
"box" : {
"id" : "obj-18",
"maxclass" : "toggle",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "int" ],
"parameter_enable" : 0,
"patching_rect" : [ 448.5, 95.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-22",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 448.5, 125.0, 86.0, 24.0 ],
"style" : "",
"text" : "qmetro 20"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-46",
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 261.5, 95.0, 187.0, 22.0 ],
"style" : "",
"text" : "read all analog pins"
}
}
, {
"box" : {
"id" : "obj-60",
"maxclass" : "toggle",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "int" ],
"parameter_enable" : 0,
"patching_rect" : [ 246.5, 95.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-61",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 246.5, 124.0, 95.0, 24.0 ],
"style" : "",
"text" : "qmetro 100"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-26",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 246.5, 214.0, 288.0, 24.0 ],
"style" : "",
"text" : "o.io.udp 128.32.122.252 8888 9999"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-91",
"maxclass" : "newobj",
"numinlets" : 0,
"numoutlets" : 0,
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 7,
"minor" : 0,
"revision" : 4,
"architecture" : "x86",
"modernui" : 1
}
,
"rect" : [ 34.0, 78.0, 738.0, 421.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 14.0,
"default_fontface" : 0,
"default_fontname" : "Andale Mono",
"gridonopen" : 1,
"gridsize" : [ 5.0, 5.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-2",
"linecount" : 25,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 15.0, 20.0, 768.0, 400.0 ],
"style" : "",
"text" : "/*\n Written by Yotam Mann and Adrian Freed,\n The Center for New Music and Audio Technologies,\n University of California, Berkeley. Copyright (c) 2012, The Regents of\n the University of California (Regents).\n \n Permission to use, copy, modify, distribute, and distribute modified versions\n of this software and its documentation without fee and without a signed\n licensing agreement, is hereby granted, provided that the above copyright\n notice, this paragraph and the following two paragraphs appear in all copies,\n modifications, and distributions.\n \n IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,\n SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING\n OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS\n BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED\n HEREUNDER IS PROVIDED \"AS IS\". REGENTS HAS NO OBLIGATION TO PROVIDE\n MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.\n \n For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu\n */"
}
}
],
"lines" : [ ]
}
,
"patching_rect" : [ 666.5, 494.0, 111.0, 24.0 ],
"saved_object_attributes" : {
"description" : "",
"digest" : "",
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"globalpatchername" : "",
"style" : "",
"tags" : ""
}
,
"style" : "",
"text" : "p disclaimer"
}
}
],
"lines" : [ {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-4", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-10", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-84", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-101", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-107", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-102", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-108", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-103", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-109", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-104", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-110", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-105", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-22", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-18", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-8", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-22", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-10", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-45", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-60", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-3", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-81", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-45", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-26", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-6", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-61", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-60", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-6", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-61", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-56", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-64", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-79", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-78", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-9", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-79", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-26", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-8", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-101", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-102", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-103", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 2 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-104", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 3 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-105", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 4 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-64", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-81", 5 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-26", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-9", 0 ]
}
}
],
"parameters" : {
"obj-105" : [ "a[19]", "a", 0 ],
"obj-104" : [ "a[20]", "a", 0 ],
"obj-103" : [ "a[21]", "a", 0 ],
"obj-64" : [ "a[37]", "a", 0 ],
"obj-102" : [ "a[22]", "a", 0 ],
"obj-101" : [ "a[23]", "a", 0 ]
}
,
"dependency_cache" : [ {
"name" : "o.io.udp.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/udp",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.betweentimes.maxpat",
"bootpath" : "~/Documents/Max/Packages/odot/patchers/time",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.was.maxpat",
"bootpath" : "~/Documents/Max/Packages/odot/dev",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.righttoleft.maxpat",
"bootpath" : "~/Documents/Max/Packages/odot/patchers/ordering",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.route.mxo",
"type" : "iLaX"
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
, {
"name" : "o.compose.mxo",
"type" : "iLaX"
}
, {
"name" : "o.timetag.mxo",
"type" : "iLaX"
}
, {
"name" : "o.prepend.mxo",
"type" : "iLaX"
}
, {
"name" : "o.intersection.mxo",
"type" : "iLaX"
}
, {
"name" : "o.union.mxo",
"type" : "iLaX"
}
, {
"name" : "o.var.mxo",
"type" : "iLaX"
}
, {
"name" : "o.collect.mxo",
"type" : "iLaX"
}
, {
"name" : "o.if.mxo",
"type" : "iLaX"
}
, {
"name" : "o.expr.codebox.mxo",
"type" : "iLaX"
}
],
"embedsnapshot" : 0
}
}

View File

@ -0,0 +1,215 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 6,
"minor" : 1,
"revision" : 9,
"architecture" : "x86"
}
,
"rect" : [ 153.0, 100.0, 758.0, 531.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 14.0,
"default_fontface" : 0,
"default_fontname" : "Andale Mono",
"gridonopen" : 0,
"gridsize" : [ 5.0, 5.0 ],
"gridsnaponopen" : 0,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"boxanimatetime" : 200,
"imprint" : 0,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"boxes" : [ {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-8",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "FullPacket" ],
"patching_rect" : [ 20.5, 240.0, 128.0, 22.0 ],
"text" : "o.betweentimes"
}
}
, {
"box" : {
"fontsize" : 14.0,
"id" : "obj-7",
"linecount" : 2,
"maxclass" : "o.compose",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 20.5, 112.0, 510.0, 42.0 ],
"saved_bundle_data" : [ 35, 98, 117, 110, 100, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 47, 112, 105, 110, 103, 0, 0, 0, 44, 105, 0, 0, 0, 0, 0, 100, 0, 0, 0, 76, 47, 116, 104, 105, 110, 103, 0, 0, 44, 100, 105, 105, 105, 105, 105, 105, 105, 105, 115, 0, 64, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 98, 105, 103, 103, 101, 114, 32, 112, 97, 99, 107, 101, 116, 0, 0, 0 ],
"saved_bundle_length" : 116,
"text" : "/ping : 100,\n/thing : [100., 100, 1, 2, 3, 4, 4, 4, 4, \"bigger packet\"]",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontsize" : 14.0,
"id" : "obj-5",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 20.5, 296.0, 517.0, 36.0 ],
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-61",
"maxclass" : "newobj",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 20.5, 22.0, 153.0, 22.0 ],
"text" : "metro 2 @active 1"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-26",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 20.5, 191.0, 288.0, 22.0 ],
"text" : "o.io.udp 128.32.122.252 8888 9999"
}
}
],
"lines" : [ {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-8", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-7", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-61", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-26", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-7", 0 ]
}
}
, {
"patchline" : {
"color" : [ 1.0, 0.8, 0.4, 1.0 ],
"destination" : [ "obj-5", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-8", 0 ]
}
}
],
"dependency_cache" : [ {
"name" : "o.io.udp.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/o.io/experimental/Protocols/udp",
"patcherrelativepath" : "../../../../../../Documents/Max/Packages/o.io/experimental/Protocols/udp",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.betweentimes.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/CNMAT-odot/patchers/time",
"patcherrelativepath" : "../../../../../../Documents/Max/Packages/CNMAT-odot/patchers/time",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.was.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/CNMAT-odot/dev",
"patcherrelativepath" : "../../../../../../Documents/Max/Packages/CNMAT-odot/dev",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.righttoleft.maxpat",
"bootpath" : "/Users/adrian2013/Documents/Max/Packages/CNMAT-odot/patchers/ordering",
"patcherrelativepath" : "../../../../../../Documents/Max/Packages/CNMAT-odot/patchers/ordering",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
, {
"name" : "o.compose.mxo",
"type" : "iLaX"
}
, {
"name" : "o.timetag.mxo",
"type" : "iLaX"
}
, {
"name" : "o.prepend.mxo",
"type" : "iLaX"
}
, {
"name" : "o.intersection.mxo",
"type" : "iLaX"
}
, {
"name" : "o.union.mxo",
"type" : "iLaX"
}
, {
"name" : "o.var.mxo",
"type" : "iLaX"
}
, {
"name" : "o.collect.mxo",
"type" : "iLaX"
}
, {
"name" : "o.if.mxo",
"type" : "iLaX"
}
, {
"name" : "o.expr.codebox.mxo",
"type" : "iLaX"
}
]
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,319 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 7,
"minor" : 0,
"revision" : 4,
"architecture" : "x86",
"modernui" : 1
}
,
"rect" : [ 334.0, 78.0, 1072.0, 480.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 12.0,
"default_fontface" : 0,
"default_fontname" : "Arial",
"gridonopen" : 1,
"gridsize" : [ 15.0, 15.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"fontface" : 0,
"fontsize" : 12.0,
"id" : "obj-5",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 183.5, 341.0, 150.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-18",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 498.0, 91.0, 150.0, 33.0 ],
"style" : "",
"text" : "control Arduino square wave tone on pin 3"
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-15",
"maxclass" : "o.message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 406.0, 168.0, 150.0, 22.0 ],
"text" : "/tone/3",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-12",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 134.0, 127.0, 34.0, 22.0 ],
"style" : "",
"text" : "mtof"
}
}
, {
"box" : {
"id" : "obj-11",
"maxclass" : "kslider",
"numinlets" : 2,
"numoutlets" : 2,
"outlettype" : [ "int", "int" ],
"parameter_enable" : 0,
"patching_rect" : [ 132.0, 65.0, 336.0, 53.0 ],
"presentation_rect" : [ 0.0, 0.0, 336.0, 53.0 ],
"style" : "",
"varname" : "kslider"
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-9",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 242.0, 140.0, 32.5, 22.0 ],
"style" : "",
"text" : "220"
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-8",
"maxclass" : "message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 184.0, 137.0, 34.0, 22.0 ],
"style" : "",
"text" : "440."
}
}
, {
"box" : {
"id" : "obj-4",
"maxclass" : "button",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "bang" ],
"patching_rect" : [ 402.0, 137.0, 20.0, 20.0 ],
"style" : ""
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-3",
"linecount" : 3,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 489.0, 279.0, 154.0, 47.0 ],
"style" : "",
"text" : "8888 is the port sent to on the Arduino node 128.32.122.252"
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-20",
"maxclass" : "o.message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 235.0, 234.0, 150.0, 22.0 ],
"text" : "/tone/3 130.813 \n",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-6",
"maxclass" : "o.message",
"numinlets" : 2,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 185.0, 191.0, 150.0, 22.0 ],
"text" : "/tone/3 \"$1\" ",
"textcolor" : [ 0.0, 0.0, 0.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-26",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 183.5, 290.0, 288.0, 24.0 ],
"style" : "",
"text" : "o.io.udp 128.32.122.252 8888 9999"
}
}
],
"lines" : [ {
"patchline" : {
"destination" : [ "obj-12", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-11", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-6", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-12", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-26", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-15", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-5", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-15", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-4", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-20", 1 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-6", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-26", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-6", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-6", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-8", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-6", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-9", 0 ]
}
}
],
"dependency_cache" : [ {
"name" : "o.io.udp.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/udp",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.message.mxo",
"type" : "iLaX"
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
],
"embedsnapshot" : 0
}
}

View File

@ -0,0 +1,159 @@
{
"patcher" : {
"fileversion" : 1,
"appversion" : {
"major" : 7,
"minor" : 0,
"revision" : 4,
"architecture" : "x86",
"modernui" : 1
}
,
"rect" : [ 443.0, 218.0, 1072.0, 480.0 ],
"bglocked" : 0,
"openinpresentation" : 0,
"default_fontsize" : 12.0,
"default_fontface" : 0,
"default_fontname" : "Arial",
"gridonopen" : 1,
"gridsize" : [ 15.0, 15.0 ],
"gridsnaponopen" : 1,
"objectsnaponopen" : 1,
"statusbarvisible" : 2,
"toolbarvisible" : 1,
"lefttoolbarpinned" : 0,
"toptoolbarpinned" : 0,
"righttoolbarpinned" : 0,
"bottomtoolbarpinned" : 0,
"toolbars_unpinned_last_save" : 0,
"tallnewobj" : 0,
"boxanimatetime" : 200,
"enablehscroll" : 1,
"enablevscroll" : 1,
"devicewidth" : 0.0,
"description" : "",
"digest" : "",
"tags" : "",
"style" : "",
"subpatcher_template" : "",
"boxes" : [ {
"box" : {
"fontface" : 0,
"fontsize" : 12.0,
"id" : "obj-8",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 277.0, 243.0, 150.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontface" : 0,
"fontsize" : 12.0,
"id" : "obj-6",
"maxclass" : "o.display",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 91.0, 243.0, 150.0, 34.0 ],
"textcolor" : [ 1.0, 1.0, 1.0, 1.0 ]
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-2",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 2,
"outlettype" : [ "FullPacket", "FullPacket" ],
"patching_rect" : [ 91.0, 149.0, 97.0, 22.0 ],
"style" : "",
"text" : "o.if exists(/units)"
}
}
, {
"box" : {
"fontname" : "Arial",
"fontsize" : 12.0,
"id" : "obj-4",
"linecount" : 2,
"maxclass" : "comment",
"numinlets" : 1,
"numoutlets" : 0,
"patching_rect" : [ 95.0, 62.0, 150.0, 33.0 ],
"style" : "",
"text" : "Set udp port, send and receive port respectively"
}
}
, {
"box" : {
"fontname" : "Andale Mono",
"fontsize" : 14.0,
"id" : "obj-26",
"maxclass" : "newobj",
"numinlets" : 1,
"numoutlets" : 1,
"outlettype" : [ "" ],
"patching_rect" : [ 91.0, 107.0, 288.0, 24.0 ],
"style" : "",
"text" : "o.io.udp 128.32.122.26 8888 9999"
}
}
],
"lines" : [ {
"patchline" : {
"destination" : [ "obj-6", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-2", 0 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-8", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-2", 1 ]
}
}
, {
"patchline" : {
"destination" : [ "obj-2", 0 ],
"disabled" : 0,
"hidden" : 0,
"source" : [ "obj-26", 0 ]
}
}
],
"dependency_cache" : [ {
"name" : "o.io.udp.maxpat",
"bootpath" : "~/Documents/Max/Packages/o.io/experimental/Protocols/udp",
"type" : "JSON",
"implicit" : 1
}
, {
"name" : "o.if.mxo",
"type" : "iLaX"
}
, {
"name" : "o.display.mxo",
"type" : "iLaX"
}
],
"embedsnapshot" : 0
}
}

View File

@ -0,0 +1,312 @@
#N canvas 33 23 1015 763 10;
#X msg 272 58 /a/*;
#X msg 612 30 /s/a;
#X msg 569 30 /s/d;
#X msg 675 30 /s/m;
#X obj 169 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 189 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 210 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 231 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X msg 439 45 /d/[1-3];
#X obj 27 451 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 272 10 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 107 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 47 451 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 87 451 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 67 451 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 127 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 147 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 167 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 187 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 267 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 207 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 247 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 227 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 327 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 307 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 287 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 212 18 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X msg 212 37 /s/l \$1;
#X obj 252 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 273 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 294 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 314 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 335 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 356 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 377 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 398 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 419 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 440 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 460 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 481 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 333 117 o.io.slipserial;
#X obj 502 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 523 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 544 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 565 339 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 694 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 774 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 714 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 754 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 734 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 794 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 814 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 834 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 854 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 874 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 914 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 894 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X msg 786 80 /c/*;
#X obj 360 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 439 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 380 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 420 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 400 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 459 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 479 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 499 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 519 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 599 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 539 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 579 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 559 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 659 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 639 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X obj 619 452 vsl 15 128 0 1023 0 0 empty empty empty 0 -9 0 10 -262144
-1 -1 0 1;
#X msg 333 64 /a/*/u;
#X text 340 48 Pull up;
#X text 567 10 How many pins?;
#X text 675 9 How many milliseconds ?;
#X text 215 -1 LED;
#X text 749 369 Touch Pins on Teensy 3;
#X text 341 211 System message responses;
#X text 356 370 Analog Values;
#X text 27 369 Analog Values with Pullups Enabled;
#N canvas 0 50 450 278 (subpatch) 0;
#X array AnalogArray 16 float 2 black black;
#X coords 0 1023 16 0 200 140 1;
#X restore 31 605 graph;
#X obj 272 35 metro 60;
#X obj 786 39 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 786 59 metro 60;
#X obj 200 214 print;
#X obj 253 115 print;
#X msg 459 107 devicename /dev/tty.usbmodem122611 \, baud 9600 \, pollintervall
4 \, verbose 1;
#X obj 333 96 mrpeach/packOSC;
#X obj 333 138 mrpeach/unpackOSC;
#X obj 333 159 mrpeach/routeOSC /a /d /s /c;
#X obj 169 297 mrpeach/routeOSC /1 /2 /3 /4 /5 /6 /7 /8 /9 /10 /11
/12 /13 /14 /15 /16 /17 /18 /19 /20, f 70;
#X obj 694 387 mrpeach/routeOSC /0 /1 /16 /17 /18 /19 /22 /23 /25 /32
/33 /15, f 40;
#X obj 359 387 mrpeach/routeOSC /1 /2 /3 /4 /5 /6 /7 /8 /9 /10 /11
/12 /13 /14 /15 /16, f 54;
#X obj 27 387 mrpeach/routeOSC /0/u /1/u /2/u /3/u /4/u /5/u /6/u /7/u
/8/u /9/u /10/u /11/u /12/u /13/u /14/u /15/u, f 54;
#X obj 346 229 cyclone/prepend set;
#X obj 536 206 cyclone/prepend set;
#X text 291 8 Retrieve analog value each 60ms, f 15;
#X text 436 2 get digital pins 1 to 3 status, f 11;
#X text 741 25 get Teensy 3 Touch each 60ms;
#N canvas 0 94 450 300 fillArray 0;
#X obj 60 223 send AnalogArray;
#X obj 60 142 mrpeach/routeOSC /1 /2 /3 /4 /5 /6 /7 /8 /9 /10 /11 /12
/13 /14 /15 /16, f 54;
#X obj 60 194 cyclone/funnel 16;
#X obj 60 120 inlet;
#X connect 1 0 2 0;
#X connect 1 1 2 1;
#X connect 1 2 2 2;
#X connect 1 3 2 3;
#X connect 1 4 2 4;
#X connect 1 5 2 5;
#X connect 1 6 2 6;
#X connect 1 7 2 7;
#X connect 1 8 2 8;
#X connect 1 9 2 9;
#X connect 1 10 2 10;
#X connect 1 11 2 11;
#X connect 1 12 2 12;
#X connect 1 13 2 13;
#X connect 1 14 2 14;
#X connect 1 15 2 15;
#X connect 2 0 0 0;
#X connect 3 0 1 0;
#X restore 348 423 pd fillArray;
#X msg 536 226;
#X msg 346 252;
#X text 211 279 Digital pins state;
#X obj 200 194 spigot;
#X obj 234 171 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
1;
#X obj 668 651 cnv 15 400 80 empty empty empty 20 12 0 14 -258113 -66577
0;
#X text 26 71 Oscuino Serial Adrian Freed 2013;
#X text 762 229 - comport;
#X text 763 213 - cyclone;
#X obj 530 148 import mrpeach;
#X text 763 197 - mrpeach osc slipenc and slipdec;
#X text 650 153 This patch depends on several third party externals
available in PD-extended (deprecated?) \, Purr \, or through deken
plugin (Help -> Find externals):;
#X connect 0 0 90 0;
#X connect 1 0 90 0;
#X connect 2 0 90 0;
#X connect 3 0 90 0;
#X connect 8 0 90 0;
#X connect 10 0 84 0;
#X connect 26 0 27 0;
#X connect 27 0 90 0;
#X connect 40 0 91 0;
#X connect 40 0 106 0;
#X connect 57 0 90 0;
#X connect 74 0 90 0;
#X connect 84 0 0 0;
#X connect 85 0 86 0;
#X connect 86 0 57 0;
#X connect 89 0 40 1;
#X connect 90 0 40 0;
#X connect 91 0 92 0;
#X connect 92 0 96 0;
#X connect 92 1 93 0;
#X connect 92 2 97 0;
#X connect 92 3 94 0;
#X connect 92 4 98 0;
#X connect 93 0 4 0;
#X connect 93 1 5 0;
#X connect 93 2 6 0;
#X connect 93 3 7 0;
#X connect 93 4 28 0;
#X connect 93 5 29 0;
#X connect 93 6 30 0;
#X connect 93 7 31 0;
#X connect 93 8 32 0;
#X connect 93 9 33 0;
#X connect 93 10 34 0;
#X connect 93 11 35 0;
#X connect 93 12 36 0;
#X connect 93 13 37 0;
#X connect 93 14 38 0;
#X connect 93 15 39 0;
#X connect 93 16 41 0;
#X connect 93 17 42 0;
#X connect 93 18 43 0;
#X connect 93 19 44 0;
#X connect 94 0 45 0;
#X connect 94 1 47 0;
#X connect 94 2 49 0;
#X connect 94 3 48 0;
#X connect 94 4 46 0;
#X connect 94 5 50 0;
#X connect 94 6 51 0;
#X connect 94 7 52 0;
#X connect 94 8 53 0;
#X connect 94 9 54 0;
#X connect 94 10 56 0;
#X connect 94 11 55 0;
#X connect 95 0 58 0;
#X connect 95 1 60 0;
#X connect 95 2 62 0;
#X connect 95 3 61 0;
#X connect 95 4 59 0;
#X connect 95 5 63 0;
#X connect 95 6 64 0;
#X connect 95 7 65 0;
#X connect 95 8 66 0;
#X connect 95 9 68 0;
#X connect 95 10 70 0;
#X connect 95 11 69 0;
#X connect 95 12 67 0;
#X connect 95 13 73 0;
#X connect 95 14 72 0;
#X connect 95 15 71 0;
#X connect 96 0 9 0;
#X connect 96 1 12 0;
#X connect 96 2 14 0;
#X connect 96 3 13 0;
#X connect 96 4 11 0;
#X connect 96 5 15 0;
#X connect 96 6 16 0;
#X connect 96 7 17 0;
#X connect 96 8 18 0;
#X connect 96 9 20 0;
#X connect 96 10 22 0;
#X connect 96 11 21 0;
#X connect 96 12 19 0;
#X connect 96 13 25 0;
#X connect 96 14 24 0;
#X connect 96 15 23 0;
#X connect 96 16 95 0;
#X connect 96 16 102 0;
#X connect 97 0 104 0;
#X connect 98 0 103 0;
#X connect 106 0 87 0;
#X connect 107 0 106 1;

View File

@ -0,0 +1,22 @@
#N canvas 618 358 756 268 10;
#X obj 95 179 mrpeach/slipdec 65536;
#X obj 95 47 mrpeach/slipenc 65536;
#X obj 359 20 loadbang;
#X obj 95 22 inlet;
#X obj 95 206 outlet;
#X msg 359 83 baud 115200;
#X obj 261 46 inlet;
#X msg 318 46 devicename /dev/tty.usbserial-A5002rKU \, pollintervall
1;
#X obj 95 135 comport;
#X obj 134 157 print errors;
#X connect 0 0 4 0;
#X connect 1 0 8 0;
#X connect 2 0 7 0;
#X connect 2 0 5 0;
#X connect 3 0 1 0;
#X connect 5 0 8 0;
#X connect 6 0 8 0;
#X connect 7 0 8 0;
#X connect 8 0 0 0;
#X connect 8 1 9 0;

View File

@ -0,0 +1,148 @@
ControlP5 cp5;
void setupGUI() {
//the ControlP5 object
cp5 = new ControlP5(this);
//start button
cp5.addButton("START")
.setPosition(width/2 - 100, height-30)
.setSize(200, 20);
//stop button
cp5.addButton("STOP")
.setPosition(width/2 - 100, height-30)
.setSize(200, 20)
.hide();
//setup the baud list
DropdownList baudRate = cp5.addDropdownList("BaudRate")
.setPosition(50, 130)
.setSize(200, 90)
.setItemHeight(20)
.setBarHeight(20)
.setId(4).close();
ControllerStyle baudRateStyle = baudRate.getCaptionLabel().getStyle();
baudRate.getCaptionLabel().set("SELECT THE BAUD RATE");
baudRateStyle.marginTop = baudRateStyle.marginLeft = baudRateStyle.marginTop = 3;
//the baud options
for (int i=0; i<serialRateStrings.length; i++) {
String baudString = serialRateStrings[i];
baudRate.addItem(baudString, i);
}
//Serial Port selector
DropdownList serialddl = cp5.addDropdownList("SerialPort")
.setPosition(50, 30)
.setSize(200, 90)
.setItemHeight(20)
.setBarHeight(20)
.setId(0).close();
ControllerStyle serialStyle = serialddl.getCaptionLabel().getStyle();
serialddl.getCaptionLabel().set("SELECT ARDUINO SERIAL PORT");
serialStyle.marginTop = serialStyle.marginLeft = serialStyle.marginTop = 3;
//set the serial options
String SerialList[] = Serial.list();
for (int i=0; i<SerialList.length; i++) {
serialddl.addItem(SerialList[i], i);
}
//udp IP/port
cp5.addTextfield("IP address")
.setPosition(300, 30)
.setAutoClear(false)
.setText(ipAddress);
cp5.addTextfield("Incoming Port Number")
.setPosition(300, 80)
.setAutoClear(false)
.setText(str(inPort));
cp5.addTextfield("Outgoing Port Number")
.setPosition(300, 130)
.setAutoClear(false)
.setText(str(outPort));
//text labels
cp5.addTextlabel("arduinoLabel")
.setText("Serial")
.setPosition(50, 10)
.setColorValue(0xffffff00)
.setFont(createFont("SansSerif", 11));
cp5.addTextlabel("UDPLabel")
.setText("UDP")
.setPosition(300, 10)
.setColorValue(0xffffff00)
.setFont(createFont("SansSerif", 11));
cp5.addTextlabel("incomingPacketLabel")
.setText("Incoming Packet")
.setPosition(210, 100)
.setColorValue(0xffffff00)
.setFont(createFont("SansSerif", 10))
.hide();
}
void controlEvent(ControlEvent theEvent) {
String eventName = theEvent.getName();
if (eventName == "SerialPort") {
//set the serial port
serialListNumber = int(theEvent.getValue());
} else if (eventName == "BaudRate") {
int index = int(theEvent.getValue());
baud = Integer.parseInt(serialRateStrings[index]);
} else if (eventName == "IP address") {
cp5.get(Textfield.class, eventName).setFocus(false);
ipAddress = theEvent.getStringValue();
} else if (eventName == "Incoming Port Number") {
cp5.get(Textfield.class, eventName).setFocus(false);
inPort = Integer.parseInt(theEvent.getStringValue());
} else if (eventName == "Outgoing Port Number") {
cp5.get(Textfield.class, eventName).setFocus(false);
outPort = Integer.parseInt(theEvent.getStringValue());
}
}
//hide all the controls and show the stop button
void hideControls() {
//HIDE
cp5.get(Button.class, "START").hide();
cp5.get(Textfield.class, "IP address").hide();
cp5.get(DropdownList.class, "BaudRate").hide();
cp5.get(DropdownList.class, "SerialPort").hide();
cp5.get(Textfield.class, "Outgoing Port Number").hide();
cp5.get(Textfield.class, "Incoming Port Number").hide();
//SHOW
cp5.get(Button.class, "STOP").show();
cp5.get(Textlabel.class, "incomingPacketLabel").show();
}
void showControls() {
//SHOW
cp5.get(Button.class, "START").show();
cp5.get(Textfield.class, "IP address").show();
cp5.get(DropdownList.class, "BaudRate").show();
cp5.get(DropdownList.class, "SerialPort").show();
cp5.get(Textfield.class, "Outgoing Port Number").show();
cp5.get(Textfield.class, "Incoming Port Number").show();
//HIDE
cp5.get(Button.class, "STOP").hide();
cp5.get(Textlabel.class, "incomingPacketLabel").hide();
}
//start everything
public void START(int theValue) {
setupUDP();
setupSerial();
hideControls();
applicationRunning = true;
}
public void STOP() {
stopSerial();
stopUDP();
showControls();
applicationRunning = false;
}

View File

@ -0,0 +1,56 @@
import processing.serial.*;
//download at http://ubaa.net/shared/processing/udp/
import hypermedia.net.*;
//download at www.sojamo.de/libraries/controlp5
import controlP5.*;
boolean applicationRunning = false;
void setup() {
// configure the screen size and frame rate
size(550, 350, P3D);
frameRate(30);
setupGUI();
}
void draw() {
background(128);
if (applicationRunning) {
drawIncomingPackets();
}
}
/************************************************************************************
VISUALIZING INCOMING PACKETS
************************************************************************************/
int lastSerialPacket = 0;
int lastUDPPacket = 0;
void drawIncomingPackets() {
//the serial packet
fill(0);
rect(75, 50, 100, 100);
//the udp packet
rect(325, 50, 100, 100);
int now = millis();
int lightDuration = 75;
if (now - lastSerialPacket < lightDuration) {
fill(255);
rect(85, 60, 80, 80);
}
if (now - lastUDPPacket < lightDuration) {
fill(255);
rect(335, 60, 80, 80);
}
}
void drawIncomingSerial() {
lastSerialPacket = millis();
}
void drawIncomingUDP() {
lastUDPPacket = millis();
}

View File

@ -0,0 +1,101 @@
//the Serial communication to the Arduino
Serial serial;
String[] serialRateStrings = {
"300", "1200", "2400", "4800", "9600", "14400",
"19200", "28800", "38400", "57600", "115200"
};
int baud = 9600;
int serialListNumber = 3;
ArrayList<Byte> serialBuffer = new ArrayList<Byte>();
void setupSerial() {
serial = new Serial(this, Serial.list()[serialListNumber], baud);
}
void stopSerial() {
serial.stop();
}
void serialEvent(Serial serial) {
//decode the message
while (serial.available () > 0) {
slipDecode(byte(serial.read()));
}
}
void SerialSendToUDP() {
byte [] buffer = new byte[serialBuffer.size()];
//copy the buffer over
for (int i = 0; i < serialBuffer.size(); i++) {
buffer[i] = serialBuffer.get(i);
}
//send it off
UDPSendBuffer(buffer);
//clear the buffer
serialBuffer.clear();
//light up the indicator
drawIncomingSerial();
}
void serialSend(byte[] data) {
//encode the message and send it
for (int i = 0; i < data.length; i++){
slipEncode(data[i]);
}
//write the eot
serial.write(eot);
println("");
}
/************************************************************************************
SLIP ENCODING
************************************************************************************/
byte eot = byte(192);
byte slipesc = byte(219);
byte slipescend = byte(220);
byte slipescesc = byte(221);
byte previousByte;
void slipDecode(byte incoming) {
byte previous = previousByte;
previousByte = incoming;
//if the previous was the escape char
if (previous == slipesc) {
//if this one is the esc eot
if (incoming==slipescend) {
serialBuffer.add(eot);
}
else if (incoming==slipescesc) {
serialBuffer.add(slipesc);
}
}
else if (incoming==eot) {
//if it's the eot
//send off the packet
SerialSendToUDP();
}
else if (incoming != slipesc) {
serialBuffer.add(incoming);
}
}
void slipEncode(byte incoming) {
if(incoming == eot){
serial.write(slipesc);
serial.write(slipescend);
} else if(incoming==slipesc) {
serial.write(slipesc);
serial.write(slipescesc);
} else {
serial.write(incoming);
}
print((char)incoming);
print(" ");
println(incoming);
}

View File

@ -0,0 +1,27 @@
//UDP communication
UDP udp;
int inPort = 9000;
int outPort = 9001;
String ipAddress = "127.0.0.1";
void setupUDP() {
udp = new UDP( this, inPort );
//udp.log( true ); // <-- printout the connection activity
udp.listen( true );
}
void stopUDP() {
udp.close();
}
void UDPSendBuffer(byte[] data) {
udp.send( data, ipAddress, outPort );
}
//called when UDP receives some data
void receive( byte[] data) {
drawIncomingUDP();
//send it over to serial
serialSend(data);
}

View File

@ -0,0 +1,375 @@
import processing.serial.*;
//download at http://ubaa.net/shared/processing/udp/
import hypermedia.net.*;
//download at www.sojamo.de/libraries/controlp5
import controlP5.*;
/************************************************************************************
GUI
************************************************************************************/
ControlP5 cp5;
DropdownList serialddl;
DropdownList baudddl;
Textlabel arduinoLabel;
Textlabel UDPLabel;
Textlabel incomingPacket;
Button startButton;
Button stopButton;
Textfield ipAddressField;
Textfield incomingPortField;
Textfield outgoingPortField;
void setupGUI() {
//the ControlP5 object
cp5 = new ControlP5(this);
//start button
startButton = cp5.addButton("START")
.setPosition(200, 200)
.setSize(200, 19)
;
//stop button
stopButton = cp5.addButton("STOP")
.setPosition(200, 200)
.setSize(200, 19)
;
stopButton.hide();
//Serial Port selector
serialddl = cp5.addDropdownList("SerialPort")
.setPosition(50, 100)
.setSize(200, 200)
;
serialddl.setItemHeight(20);
serialddl.setBarHeight(15);
serialddl.setCaptionLabel("SELECT ARDUINO SERIAL PORT");
//serialddl.captionLabel().style().marginTop = 3;
//serialddl.captionLabel().style().marginLeft = 3;
//serialddl.valueLabel().style().marginTop = 3;
//set the serial options
String SerialList[] = Serial.list();
for (int i=0;i<SerialList.length;i++) {
String portName = SerialList[i];
serialddl.addItem(portName, i);
}
//serialddl.setIndex(0);
//setup the baud list
baudddl = cp5.addDropdownList("BaudRate")
.setPosition(50, 50)
.setSize(200, 200)
;
baudddl.setItemHeight(20);
baudddl.setBarHeight(15);
baudddl.setCaptionLabel("SELECT THE BAUD RATE");
//baudddl.captionLabel().style().marginTop = 3;
//baudddl.captionLabel().style().marginLeft = 3;
//baudddl.valueLabel().style().marginTop = 3;
//the baud options
for (int i=0;i<serialRateStrings.length;i++) {
String baudString = serialRateStrings[i];
baudddl.addItem(baudString, i);
}
//baudddl.setIndex(4);
//udp IP/port
ipAddressField = cp5.addTextfield("IP address")
.setPosition(300, 30)
.setAutoClear(false)
.setText(ipAddress)
;
incomingPortField = cp5.addTextfield("Incoming Port Number")
.setPosition(300, 80)
.setAutoClear(false)
.setText(str(inPort))
;
outgoingPortField = cp5.addTextfield("Outgoing Port Number")
.setPosition(300, 130)
.setAutoClear(false)
.setText(str(outPort))
;
//text labels
arduinoLabel = cp5.addTextlabel("arduinoLabel")
.setText("Serial")
.setPosition(50, 10)
.setColorValue(0xffffff00)
.setFont(createFont("SansSerif", 11))
;
UDPLabel = cp5.addTextlabel("UDPLabel")
.setText("UDP")
.setPosition(300, 10)
.setColorValue(0xffffff00)
.setFont(createFont("SansSerif", 11))
;
incomingPacket = cp5.addTextlabel("incomingPacketLabel")
.setText("Incoming Packet")
.setPosition(210, 100)
.setColorValue(0xffffff00)
.setFont(createFont("SansSerif", 10))
;
incomingPacket.hide();
}
void controlEvent(ControlEvent theEvent) {
String eventName = theEvent.getName();
if (theEvent.isGroup()) {
if (eventName == "SerialPort") {
//set the serial port
serialListNumber = int(theEvent.getValue());
}
else if (eventName == "BaudRate") {
int index = int(theEvent.getValue());
baud = Integer.parseInt(serialRateStrings[index]);
}
else {
}
}
else if (theEvent.isAssignableFrom(Textfield.class)) {
if (eventName == "IP address") {
ipAddressField.setFocus(false);
ipAddress = theEvent.getStringValue();
}
else if (eventName == "Incoming Port Number") {
incomingPortField.setFocus(false);
inPort = Integer.parseInt(theEvent.getStringValue());
}
else if (eventName == "Outgoing Port Number") {
outgoingPortField.setFocus(false);
outPort = Integer.parseInt(theEvent.getStringValue());
}
}
}
boolean applicationRunning = false;
//start everything
public void START(int theValue) {
setupUDP();
setupSerial();
hideControls();
applicationRunning = true;
}
//hide all the controls and show the stop button, cuando se da start
void hideControls() {
serialddl.hide();
baudddl.hide();
startButton.hide();
outgoingPortField.hide();
incomingPortField.hide();
ipAddressField.hide();
incomingPacket.show(); // se ve incomingPacket
//show the stop button
stopButton.show();
}
void showControls() {
serialddl.show();
baudddl.show();
startButton.show();
outgoingPortField.show();
incomingPortField.show();
ipAddressField.show();
incomingPacket.hide();
//hide the stop button
stopButton.hide();
}
public void STOP() {
stopSerial();
stopUDP();
showControls();
applicationRunning = false;
}
/************************************************************************************
SERIAL
************************************************************************************/
//the Serial communication to the Arduino
Serial serial;
String[] serialRateStrings = { //less baudrates, only hi speeds
"19200", "28800", "38400", "57600", "115200", "230400", "345600", "460800"
};
int baud = 460800;
int serialListNumber = 0;
ArrayList<Byte> serialBuffer = new ArrayList<Byte>();
void setupSerial() {
serial = new Serial(this, Serial.list()[serialListNumber], baud);
}
void stopSerial() {
serial.stop();
}
void serialEvent(Serial serial) {
//decode the message
//println (serial.read());
while (serial.available () > 0) {
slipDecode(byte(serial.read()));
}
}
void SerialSendToUDP() {
byte [] buffer = new byte[serialBuffer.size()];
//copy the buffer over
for (int i = 0; i < serialBuffer.size(); i++) {
buffer[i] = serialBuffer.get(i);
}
//send it off
UDPSendBuffer(buffer);
//clear the buffer
serialBuffer.clear();
//light up the indicator
drawIncomingSerial();
}
void serialSend(byte[] data) {
//encode the message and send it
for (int i = 0; i < data.length; i++){
slipEncode(data[i]);
}
//write the eot
serial.write(eot);
}
/************************************************************************************
SLIP ENCODING
************************************************************************************/
byte eot = byte(192);
byte slipesc = byte(219);
byte slipescend = byte(220);
byte slipescesc = byte(221);
byte previousByte;
void slipDecode(byte incoming) {
byte previous = previousByte;
previousByte = incoming;
//if the previous was the escape char
if (previous == slipesc) {
//if this one is the esc eot
if (incoming==slipescend) {
serialBuffer.add(eot);
}
else if (incoming==slipescesc) {
serialBuffer.add(slipesc);
}
}
else if (incoming==eot) {
//if it's the eot
//send off the packet
SerialSendToUDP();
}
else {
serialBuffer.add(incoming);
}
}
void slipEncode(byte incoming) {
if(incoming == eot){
serial.write(slipesc);
serial.write(slipescend);
} else if(incoming==slipesc) {
serial.write(slipesc);
serial.write(slipescesc);
} else {
serial.write(incoming);
}
}
/************************************************************************************
UDP
************************************************************************************/
//UDP communication
UDP udp;
int inPort = 9000;
int outPort = 10001;
String ipAddress = "192.168.0.12";
void setupUDP() {
udp = new UDP( this, inPort );
udp.log( true ); // <-- printout the connection activity
udp.listen( true );
}
void stopUDP() {
udp.close();
}
void UDPSendBuffer(byte[] data) {
udp.send( data, ipAddress, outPort );
}
//called when UDP receives some data
void receive( byte[] data) {
drawIncomingUDP();
//send it over to serial
serialSend(data);
}
/************************************************************************************
SETUP/DRAW
************************************************************************************/
void setup() {
// configure the screen size and frame rate
size(550, 250, P3D);
frameRate(30);
setupGUI();
}
void draw() {
background(128);
if (applicationRunning) {
drawIncomingPackets();
}
}
/************************************************************************************
VISUALIZING INCOMING PACKETS
************************************************************************************/
int lastSerialPacket = 0;
int lastUDPPacket = 0;
void drawIncomingPackets() {
//the serial packet
fill(0);
rect(75, 50, 100, 100);
//the udp packet
rect(325, 50, 100, 100);
int now = millis();
int lightDuration = 75;
if (now - lastSerialPacket < lightDuration) {
fill(255);
rect(85, 60, 80, 80);
}
if (now - lastUDPPacket < lightDuration) {
fill(255);
rect(335, 60, 80, 80);
}
}
void drawIncomingSerial() {
lastSerialPacket = millis();
}
void drawIncomingUDP() {
lastUDPPacket = millis();
}

View File

@ -0,0 +1,74 @@
/*
Receives and visualizes OSCBundles sent over UDP
Use with /examples/UDPSendBundle
or with /examples/SerialSendBundle in conjunction
with /Applications/Processing/SLIPSerialToUDP
*/
import oscP5.*;
import netP5.*;
OscP5 oscP5;
void setup() {
size(600,300);
frameRate(30);
//set this to the receiving port
oscP5 = new OscP5(this,9001);
}
void draw() {
background(0);
//draw the analog values
float analog0Height = map(analogValue0, 0, 1024, 0, 200);
float analog1Height = map(analogValue1, 0, 1024, 0, 200);
fill(255);
rect(50, 250, 50, -analog0Height);
rect(150, 250, 50, -analog1Height);
//and the labels
textSize(12);
text("/analog/0", 50, 270);
text("/analog/1", 150, 270);
//and the digital pin label
text("/digital/5", 250, 270);
textSize(25);
text(digitalValue5, 250, 250);
//now do the mouse part
//add the label
textSize(12);
text("/mouse/step", 350, 270);
//make a box where it should go
noFill();
stroke(255);
rect(350, 50, 200, 200);
//and a square where the mouse is
fill(255);
float mouseXPos = map(mouseStepX, 0, 1024, 350, 530);
float mouseYPos = map(mouseStepY, 0, 1024, 50, 230);
rect(mouseXPos, mouseYPos, 20, 20);
}
int analogValue0 = 50;
int analogValue1 = 50;
String digitalValue5 = "LOW";
int mouseStepX = 0;
int mouseStepY = 0;
// incoming osc message are forwarded to the oscEvent method.
void oscEvent(OscMessage theOscMessage) {
//println(theOscMessage.addrPattern());
if (theOscMessage.addrPattern().equals("/analog/0")){
analogValue0 = theOscMessage.get(0).intValue();
} else if(theOscMessage.addrPattern().equals("/analog/1")){
analogValue1 = theOscMessage.get(0).intValue();
} else if(theOscMessage.addrPattern().equals("/digital/5")){
digitalValue5 = theOscMessage.get(0).stringValue();
} else if(theOscMessage.addrPattern().equals("/mouse/step")){
mouseStepX = theOscMessage.get(0).intValue();
mouseStepY = theOscMessage.get(1).intValue();
}
}

View File

@ -0,0 +1,42 @@
/*
Receives and visualizes OSCBundles sent over UDP
Use with /examples/UDPSendMessage
or with /examples/SerialSendMessage in conjunction
with /Applications/Processing/SLIPSerialToUDP
*/
import oscP5.*;
import netP5.*;
OscP5 oscP5;
void setup() {
size(150,300);
frameRate(30);
//set this to the receiving port
oscP5 = new OscP5(this,9001);
}
void draw() {
background(0);
//draw the analog values
float analog0Height = map(analogValue0, 0, 1024, 0, 200);
fill(255);
rect(50, 250, 50, -analog0Height);
//and the labels
textSize(12);
text("/analog/0", 50, 270);
}
int analogValue0 = 50;
// incoming osc message are forwarded to the oscEvent method.
void oscEvent(OscMessage theOscMessage) {
//println(theOscMessage.addrPattern());
if (theOscMessage.addrPattern().equals("/analog/0")){
analogValue0 = theOscMessage.get(0).intValue();
}
}

View File

@ -0,0 +1,50 @@
import oscP5.*;
import netP5.*;
OscP5 oscP5;
NetAddress arduinoAddress;
//the number of analog pins on this controller
int analogPins = 16;
//an array of all of the pin values
int[] pinVals = new int[analogPins];
void setup() {
frameRate(60);
size(320, 100);
background(0);
//initialize the listening port
oscP5 = new OscP5(this, 9999);
//the outgoing communication to the arduino
arduinoAddress = new NetAddress("128,32.122.252", 8888);
}
void draw() {
//clear the previous bars
fill(0);
rect(0, 0, width, height);
//draw each of the bars showing the pin value
for (int i = 0; i < analogPins; i++) {
int value = pinVals[i];
int barWidth = width/analogPins;
float barHeight = (value/1024.)*height;
//draws the new bar in white
fill(255);
rect(barWidth*i, height - barHeight, barWidth, barHeight);
}
}
// incoming osc message are forwarded to the oscEvent method.
void oscEvent(OscMessage msg) {
String address = msg.addrPattern();
if (address.startsWith("/analog/")) {
//then it's an analog reading
//split the address
String[] splitAddr = address.split("/");
//the third element should be the number
int pinNum = Integer.parseInt(splitAddr[2]);
int val = msg.get(0).intValue();
pinVals[pinNum] = val;
}
}

View File

@ -0,0 +1 @@
mode=Android

20
lib/OSC/LICENSE 100644
View File

@ -0,0 +1,20 @@
Written by Yotam Mann and Adrian Freed, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2013, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

View File

@ -0,0 +1,191 @@
/*
Written by Adrian Freed, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2013, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
*/
#include <Arduino.h>
#include "OSCBoards.h"
#ifndef analogInputToDigitalPin
int analogInputToDigitalPin(int i)
{
switch(i)
{
#ifdef A0
case 0: return A0;
#endif
#ifdef A1
case 1: return A1;
#endif
#ifdef A2
case 2: return A2;
#endif
#ifdef A3
case 3: return A3;
#endif
#ifdef A4
case 4: return A4;
#endif
#ifdef A5
case 5: return A5;
#endif
#ifdef A6
case 6: return A6;
#endif
#ifdef A7
case 7: return A7;
#endif
#ifdef A8
case 8: return A8;
#endif
#ifdef A9
case 9: return A9;
#endif
#ifdef A10
case 10: return A10;
#endif
#ifdef A11
case 11: return A11;
#endif
#ifdef A12
case 12: return A12;
#endif
#ifdef A13
case 13: return A13;
#endif
#ifdef A14
case 14: return A14;
#endif
#ifdef A15
case 15: return A15;
#endif
#ifdef A16
case 16: return A16;
#endif
}
return -1;
}
#endif
#ifdef BOARD_HAS_DIE_POWER_SUPPLY_MEASUREMENT
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK64FX512V__) || defined(__MK66FX1M0__)
float getSupplyVoltage()
{
analogReference(DEFAULT);
analogReadResolution(12);
analogReadAveraging(32);
PMC_REGSC |= PMC_REGSC_BGBE; // 39=bandgap ref (PMC_REGSC |= PMC_REGSC_BGBE);
delay(1);
#if defined(__MKL26Z64__)
// Teensy 3 LC
int val = analogRead(39);
return val>0? (1.0f*4095/val):0.0f;
#elif defined(__MK64FX512V__) || defined(__MK66FX1M0__)
int val = analogRead(71);
return val>0? (1.195f*4095/val):0.0f;
#else
int val = analogRead(39);
return val>0? (1.195f*4095/val):0.0f;
#endif
}
#else
// power supply measurement on some Arduinos
float getSupplyVoltage(){
// powersupply
int result;
// Read 1.1V reference against AVcc
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || defined(__AVR_ATmega1280__)
ADMUX = 0x40| _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) ;
ADCSRB = 0;
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delayMicroseconds(300); // wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
float supplyvoltage = 1.1264f *1023 / result;
return supplyvoltage;
}
#endif
#endif
#ifdef BOARD_HAS_DIE_TEMPERATURE_SENSOR
#if defined(__MK20DX128__) || defined(__MK20DX256__)|| defined(__MKL26Z64__) || defined(__MK66FX1M0__) || defined(__MK64FX512V__)
float getTemperature()
{
#if defined(__MK64FX512V__) || defined(__MK66FX1M0__)
const int temppin = 70 ;
#else
const int temppin = 38;
#endif
// untested on all teensy 3.x
analogReference(INTERNAL);
analogReadResolution(12);
analogReadAveraging(32);
delay(2);
float val = 25.0 + 0.17083 * (2454.19 - analogRead(temppin));
analogReference(DEFAULT);
return val;
}
#else
// temperature
float getTemperature(){
int result;
#if defined(__AVR_ATmega32U4__)
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0);
ADCSRB = _BV(MUX5);
#else
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);
#endif
delayMicroseconds(200); // wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
analogReference(DEFAULT);
return result/1023.0f;
}
#endif
#endif

View File

@ -0,0 +1,56 @@
//
// OSCBoards.h
//
//
// Created by AdrianFreed on 5/26/13.
//
//
#ifndef _OSCBoards_h
#define _OSCBoards_h
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK66FX1M0__)
// Teensy 3.0 3.1 3.1LC 3.2 3.6
#define BOARD_HAS_CAPACITANCE_SENSING
#endif
#if defined(__AVR_ATmega32U4__) || defined(__MKL26Z64__) || defined(__MK20DX128__)|| defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__AVR_ATmega328_) || defined(__AVR_ATmega128__)
#define BOARD_HAS_DIE_TEMPERATURE_SENSOR
#endif
#if defined(__AVR_ATmega32U4__) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK66FX1M0__) || defined(__MKL26Z64__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega328_) || defined(__AVR_ATmega128__)
#define BOARD_HAS_DIE_POWER_SUPPLY_MEASUREMENT
#endif
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega328_) || defined(__AVR_ATmega128__)
#define BOARD_HAS_ANALOG_PULLUP
#endif
// missing specs for PIC32
#if (defined(__PIC32MX__) || defined(__PIC32MZ__))
#define NUM_ANALOG_INPUTS NUM_ANALOG_PINS
#define NUM_DIGITAL_INPUTS NUM_DIGITAL_PINS
#define LED_BUILTIN PIN_LED1
#endif
#ifndef analogInputToDigitalPin
int analogInputToDigitalPin(int i);
#endif
#ifdef BOARD_HAS_DIE_TEMPERATURE_SENSOR
float getTemperature();
#endif
#ifdef BOARD_HAS_DIE_POWER_SUPPLY_MEASUREMENT
float getSupplyVoltage();
#endif
#endif

View File

@ -0,0 +1,357 @@
/*
Written by Yotam Mann, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2012, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
*/
#include "OSCBundle.h"
#include <stdlib.h>
/*=============================================================================
CONSTRUCTORS / DESTRUCTOR
=============================================================================*/
OSCBundle::OSCBundle(osctime_t _timetag){
setTimetag(_timetag);
numMessages = 0;
error = OSC_OK;
messages = NULL;
incomingBuffer = NULL;
incomingBufferSize = 0;
decodeState = STANDBY;
}
OSCBundle::~OSCBundle(){
for (int i = 0; i < numMessages; i++){
OSCMessage * msg = getOSCMessage(i);
delete msg;
}
free(messages);
free(incomingBuffer);
}
//clears all of the OSCMessages inside
OSCBundle& OSCBundle::empty(){
error = OSC_OK;
for (int i = 0; i < numMessages; i++){
OSCMessage * msg = getOSCMessage(i);
delete msg;
}
free(messages);
messages = NULL;
clearIncomingBuffer();
numMessages = 0;
return *this;
}
/*=============================================================================
SETTERS
=============================================================================*/
OSCMessage & OSCBundle::add(const char * _address){
OSCMessage * msg = new OSCMessage(_address);
if (!msg->hasError()){
//realloc the array to fit the message
OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
if (messageMem != NULL){
messages = messageMem;
messages[numMessages] = msg;
numMessages++;
} else {
error = ALLOCFAILED;
}
}
return *msg;
}
OSCMessage & OSCBundle::add(){
OSCMessage * msg = new OSCMessage();
//realloc the array to fit the message
OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
if (messageMem != NULL){
messages = messageMem;
messages[numMessages] = msg;
numMessages++;
} else {
error = ALLOCFAILED;
}
return *msg;
}
OSCMessage & OSCBundle::add(OSCMessage & _msg){
OSCMessage * msg = new OSCMessage(&_msg);
if (!msg->hasError()){
//realloc the array to fit the message
OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
if (messageMem != NULL){
messages = messageMem;
messages[numMessages] = msg;
numMessages++;
} else {
error = ALLOCFAILED;
}
}
return *msg;
}
/*=============================================================================
GETTERS
=============================================================================*/
//returns the first fullMatch.
OSCMessage * OSCBundle::getOSCMessage( char * addr){
for (int i = 0; i < numMessages; i++){
OSCMessage * msg = getOSCMessage(i);
if (msg->fullMatch(addr)){
return msg;
}
}
return NULL;
}
//the position is the same as the order they were declared in
OSCMessage * OSCBundle::getOSCMessage(int pos){
if (pos < numMessages){
return messages[pos];
}
return NULL;
}
/*=============================================================================
PATTERN MATCHING
=============================================================================*/
bool OSCBundle::dispatch(const char * pattern, void (*callback)(OSCMessage&), int initial_offset){
bool called = false;
for (int i = 0; i < numMessages; i++){
OSCMessage msg = getOSCMessage(i);
called = msg.dispatch(pattern, callback, initial_offset) || called ;
}
return called;
}
bool OSCBundle::route(const char * pattern, void (*callback)(OSCMessage&, int), int initial_offset){
bool called = false;
for (int i = 0; i < numMessages; i++){
OSCMessage msg = getOSCMessage(i);
called = msg.route(pattern, callback, initial_offset) || called;
}
return called;
}
/*=============================================================================
SIZE
=============================================================================*/
int OSCBundle::size(){
return numMessages;
}
/*=============================================================================
ERROR HANDLING
=============================================================================*/
bool OSCBundle::hasError(){
bool retError = error != OSC_OK;
//test each of the data
for (int i = 0; i < numMessages; i++){
OSCMessage * msg = getOSCMessage(i);
retError |= msg->hasError();
}
return retError;
}
OSCErrorCode OSCBundle::getError(){
return error;
}
/*=============================================================================
SENDING
=============================================================================*/
OSCBundle& OSCBundle::send(Print &p){
//don't send a bundle with errors
if (hasError()){
return *this;
}
//write the bundle header
static uint8_t header[] = {'#', 'b', 'u', 'n', 'd', 'l', 'e', 0};
p.write(header, 8);
//write the timetag
{
osctime_t time = timetag;
uint32_t d = BigEndian(time.seconds);
uint8_t * ptr = (uint8_t *) &d;
p.write(ptr, 4);
d = BigEndian(time.fractionofseconds);
ptr = (uint8_t *) &d;
p.write(ptr, 4);
}
//send the messages
for (int i = 0; i < numMessages; i++){
OSCMessage * msg = getOSCMessage(i);
int msgSize = msg->bytes();
//turn the message size into a pointer
uint32_t s32 = BigEndian((uint32_t) msgSize);
uint8_t * sptr = (uint8_t *) &s32;
//write the message size
p.write(sptr, 4);
msg->send(p);
}
return *this;
}
/*=============================================================================
FILLING
=============================================================================*/
OSCBundle& OSCBundle::fill(uint8_t incomingByte){
decode(incomingByte);
return *this;
}
OSCBundle& OSCBundle::fill(const uint8_t * incomingBytes, int length){
while (length--){
decode(*incomingBytes++);
}
return *this;
}
/*=============================================================================
DECODING
=============================================================================*/
void OSCBundle::decodeTimetag(){
//parse the incoming buffer as a uint64
setTimetag(incomingBuffer);
//make sure the endianness is right
//xxx time tag timetag = BigEndian(timetag);
decodeState = MESSAGE_SIZE;
clearIncomingBuffer();
}
void OSCBundle::decodeHeader(){
const char * header = "#bundle";
if (strcmp(header, (char *) incomingBuffer)!=0){
//otherwise go back to the top and wait for a new bundle header
decodeState = STANDBY;
error = INVALID_OSC;
} else {
decodeState = TIMETAG;
}
clearIncomingBuffer();
}
void OSCBundle::decodeMessage(uint8_t incomingByte){
//get the current message
if (numMessages > 0){
OSCMessage * lastMessage = messages[numMessages - 1];
//put the bytes in there
lastMessage->fill(incomingByte);
//if it's all done
if (incomingBufferSize == incomingMessageSize){
//move onto the next message
decodeState = MESSAGE_SIZE;
clearIncomingBuffer();
} else if (incomingBufferSize > incomingMessageSize){
error = INVALID_OSC;
}
}
}
//does not validate the incoming OSC for correctness
void OSCBundle::decode(uint8_t incomingByte){
addToIncomingBuffer(incomingByte);
switch (decodeState){
case STANDBY:
if (incomingByte == '#'){
decodeState = HEADER;
} else if (incomingByte == '/'){
add();//add a simple message to the bundle
decodeMessage(incomingByte);
decodeState = MESSAGE;
}
break;
case HEADER:
if (incomingBufferSize == 8){
decodeHeader();
decodeState = TIMETAG;
}
break;
case TIMETAG:
if (incomingBufferSize == 8){
decodeTimetag();
decodeState = MESSAGE_SIZE;
}
break;
case MESSAGE_SIZE:
if (incomingBufferSize == 4){
//make sure the message size is valid
int32_t msgSize;
memcpy(&msgSize, incomingBuffer, 4);
msgSize = BigEndian(msgSize);
if (msgSize % 4 != 0 || msgSize == 0){
error = INVALID_OSC;
} else {
//add a message to the buffer
decodeState = MESSAGE;
incomingMessageSize = msgSize;
clearIncomingBuffer();
//add a new empty message
add();
}
}
break;
case MESSAGE:
decodeMessage(incomingByte);
break;
}
}
/*=============================================================================
INCOMING BUFFER MANAGEMENT
=============================================================================*/
void OSCBundle::addToIncomingBuffer(uint8_t incomingByte){
//realloc some space for the new byte and stick it on the end
incomingBuffer = (uint8_t *) realloc ( incomingBuffer, incomingBufferSize + 1);
if (incomingBuffer != NULL){
incomingBuffer[incomingBufferSize++] = incomingByte;
} else {
error = ALLOCFAILED;
}
}
void OSCBundle::clearIncomingBuffer(){
incomingBufferSize = 0;
free(incomingBuffer);
incomingBuffer = NULL;
}

175
lib/OSC/OSCBundle.h 100644
View File

@ -0,0 +1,175 @@
/*
Written by Yotam Mann, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2012, 2013, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef OSCBUNDLE_h
#define OSCBUNDLE_h
#include "OSCMessage.h"
extern osctime_t zerotime;
class OSCBundle
{
private:
/*=============================================================================
PRIVATE VARIABLES
=============================================================================*/
//the array of messages contained in the bundle
OSCMessage ** messages;
//the number of messages in the array
int numMessages;
osctime_t timetag;
//error codes
OSCErrorCode error;
/*=============================================================================
DECODING INCOMING BYTES
=============================================================================*/
//the decoding states for incoming bytes
enum DecodeState {
STANDBY,
HEADER,
TIMETAG,
MESSAGE_SIZE,
MESSAGE,
} decodeState;
//stores incoming bytes until they can be decoded
uint8_t * incomingBuffer;
int incomingBufferSize;
//the size of the incoming message
int incomingMessageSize;
//adds a byte to the buffer
void addToIncomingBuffer(uint8_t);
//clears the incoming buffer
void clearIncomingBuffer();
//decoding functions
void decode(uint8_t);
void decodeTimetag();
void decodeHeader();
void decodeMessage(uint8_t);
//just a placeholder while filling
OSCMessage & add();
public:
/*=============================================================================
CONSTRUCTORS / DESTRUCTOR
=============================================================================*/
//default timetag of
OSCBundle(osctime_t = zerotime);
//DESTRUCTOR
~OSCBundle();
//clears all of the OSCMessages inside
OSCBundle& empty();
/*=============================================================================
SETTERS
=============================================================================*/
//start a new OSC Message in the bundle
OSCMessage & add(const char * address);
//add with nothing in it produces an invalid osc message
//copies an existing message into the bundle
OSCMessage & add(OSCMessage & msg);
template <typename T>
OSCBundle& setTimetag(T t){
timetag = (osctime_t) t;
return *this;
}
//sets the timetag from a buffer
OSCBundle& setTimetag(uint8_t * buff){
memcpy(&timetag, buff, 8);
return *this;
}
/*=============================================================================
GETTERS
=============================================================================*/
//gets the message the matches the address string
//will do regex matching
OSCMessage * getOSCMessage(char * addr);
//get message by position
OSCMessage * getOSCMessage(int position);
/*=============================================================================
MATCHING
=============================================================================*/
//if the bundle contains a message that matches the pattern,
//call the function callback on that message
bool dispatch(const char * pattern, void (*callback)(OSCMessage&), int = 0);
//like dispatch, but allows for partial matches
//the address match offset is sent as an argument to the callback
bool route(const char * pattern, void (*callback)(OSCMessage&, int), int = 0);
/*=============================================================================
SIZE
=============================================================================*/
//returns the number of messages in the bundle;
int size();
/*=============================================================================
ERROR
=============================================================================*/
bool hasError();
OSCErrorCode getError();
/*=============================================================================
SENDING
=============================================================================*/
OSCBundle& send(Print &p);
/*=============================================================================
FILLING
=============================================================================*/
OSCBundle& fill(uint8_t incomingByte);
OSCBundle& fill(const uint8_t * incomingBytes, int length);
};
#endif

335
lib/OSC/OSCData.cpp 100644
View File

@ -0,0 +1,335 @@
#include "OSCData.h"
osctime_t zerotime = {0,0};
/*=============================================================================
CONSTRUCTORS
overloaded methods for each of the types which will
set the type flag, the size (in bytes), and the data
=============================================================================*/
OSCData::OSCData(const char * s){
error = OSC_OK;
type = 's';
bytes = (strlen(s) + 1);
//own the data
char * mem = (char *) malloc(bytes);
if (mem == NULL){
error = ALLOCFAILED;
} else {
strcpy(mem, s);
data.s = mem;
}
}
OSCData::OSCData(int32_t i){
error = OSC_OK;
type = 'i';
bytes = 4;
data.i = i;
}
#ifndef ESPxx
OSCData::OSCData(int i){
error = OSC_OK;
type = 'i';
bytes = 4;
data.i = i;
}
#endif
OSCData::OSCData(unsigned int i){
error = OSC_OK;
type = 'i';
bytes = 4;
data.i = i;
}
#if defined(__SAM3X8E__)
OSCData::OSCData(int16_t i){
error = OSC_OK;
type = 'i';
bytes = 4;
data.i = i;
}
#endif
OSCData::OSCData(float f){
error = OSC_OK;
type = 'f';
bytes = 4;
data.f = f;
}
OSCData::OSCData(osctime_t t){
error = OSC_OK;
type = 't';
bytes = 8;
data.time = t;
}
OSCData::OSCData(boolean b){
error = OSC_OK;
type = b?'T':'F';
bytes = 0;
}
OSCData::OSCData(double d){
error = OSC_OK;
bytes = sizeof(double);
//if it's not 8 bytes it's not a true double
if (bytes == 8){
type = 'd';
data.d = d;
} else {
type = 'f';
data.f = d;
}
}
OSCData::OSCData(uint8_t * b, int len){
error = OSC_OK;
type = 'b';
bytes = len + 4;
//add the size to the front of the blob
uint32_t len32 = (uint32_t) len;
//make sure the length is endian-safe
len32 = BigEndian(len32);
uint8_t * lenPtr = (uint8_t *) (& len32);
//own the data
if(bytes>0)
{
uint8_t * mem = (uint8_t * ) malloc(bytes);
if (mem == NULL){
error = ALLOCFAILED;
} else {
//copy over the blob length
memcpy(mem, lenPtr, 4);
//copy over the blob data
memcpy(mem + 4, b, len);
data.b = mem;
}
}
else
data.b = 0;
}
OSCData::OSCData (OSCData * datum){
error = OSC_OK;
type = datum->type;
bytes = datum->bytes;
if ( (type == 'i') || (type == 'f') || (type == 'd') || (type == 't')
|| (type == 'h') || (type == 'c') || (type == 'r') || (type == 'm')
)
{
data = datum->data;
} else if ((type == 's') || (type == 'b')){
//allocate a new piece of memory
uint8_t * mem = (uint8_t * ) malloc(bytes);
if (mem == NULL){
error = ALLOCFAILED;
} else {
//copy over the blob length
memcpy(mem, datum->data.b, bytes);
data.b = mem;
}
}
}
//DESTRUCTOR
OSCData::~OSCData(){
//if there are no bytes, there is nothing to free
if (bytes>0){
//if the data is of type 's' or 'b', need to free that memory
if (type == 's'){
free(data.s);
}else if( type == 'b'){
free(data.b);
}
}
}
//sets just the type as a message placeholder
//no data
OSCData::OSCData(char t){
error = (t == 'T' || t == 'F') ? OSC_OK : INVALID_OSC;
type = t;
bytes = 0;
}
/*=============================================================================
GETTERS
perform a safety check to make sure the data type matches the request
otherwise returns NULL
=============================================================================*/
int32_t OSCData::getInt(){
if (type == 'i'){
return data.i;
} else {
#ifndef ESPxx
return (int32_t)NULL;
#else
return -1;
#endif
}
}
osctime_t OSCData::getTime(){
if (type == 't'){
return data.time;
} else {
return zerotime;
}
}
float OSCData::getFloat(){
if (type == 'f'){
return data.f;
} else {
#ifndef ESPxx
return (float)NULL;
#else
return -1;
#endif
}
}
double OSCData::getDouble(){
if (type == 'd'){
return data.d;
} else {
#ifndef ESPxx
return (double)NULL;
#else
return -1;
#endif
}
}
bool OSCData::getBoolean(){
if (type == 'T'){
return true;
} else if (type=='F'){
return false;
}
else
#ifndef ESPxx
return NULL;
#else
return -1;
#endif
}
// no-safety-check straightforward way to fill the passed buffer
// with the received string
int OSCData::getString(char * strBuffer){
if (type == 's'){
strncpy(strBuffer, data.s, bytes);
return bytes;
} else {
#ifndef ESPxx
return (int)NULL;
#else
return -1;
#endif
}
}
// it's possible to pass strBuffer's size as argument (length)
// in order to check that it won't be overflown
int OSCData::getString(char * strBuffer, int length){
if (type == 's' && bytes <= length){
strncpy(strBuffer, data.s, bytes);
return bytes;
} else {
#ifndef ESPxx
return (int)NULL;
#else
return -1;
#endif
}
}
// Here we can get only a part of the string
int OSCData::getString(char * strBuffer, int length, int offset, int size)
{
int maxLen = bytes - offset;
if (type == 's' && maxLen >= 0 && size <= maxLen && size <= length){
strncpy(strBuffer, data.s + offset, size);
return size;
} else {
#ifndef ESPxx
return (int)NULL;
#else
return -1;
#endif
}
}
// no-safety-check straightforward way to fill the passed buffer
// with the contents of the received blob
int OSCData::getBlob(uint8_t * blobBuffer){
// read the blob length
int blobLength = getBlobLength();
if (type == 'b'){
memcpy(blobBuffer, data.b + 4, blobLength);
return blobLength;
} else {
#ifndef ESPxx
return (int)NULL;
#else
return -1;
#endif
}
}
// it's possible to pass blobBuffer's size as argument (length)
// in order to check that it won't be overflown
int OSCData::getBlob(uint8_t * blobBuffer, int length){
//jump over the first 4 bytes which encode the length
int blobLength = bytes-4;
if (type == 'b' && blobLength <= length){
memcpy(blobBuffer, data.b + 4, blobLength);
return blobLength;
} else {
#ifndef ESPxx
return (int)NULL;
#else
return -1;
#endif
}
}
// Here we can get only a part of the blob
int OSCData::getBlob(uint8_t * blobBuffer, int length, int offset, int size){
//jump over the first 4 bytes which encode the length
int blobLength = bytes-4-offset;
if (type == 'b' && blobLength >= 0 && size <= blobLength && size <= length){
memcpy(blobBuffer, data.b + 4 + offset, size);
return size;
} else {
#ifndef ESPxx
return (int)NULL;
#else
return -1;
#endif
}
}
const uint8_t* OSCData::getBlob() {
return type == 'b' ? data.b + 4 : NULL;
}
int OSCData::getBlobLength(){
if (type == 'b'){
//jump over the first 4 bytes which encode the length
return bytes-4;
}
return -1;
}

156
lib/OSC/OSCData.h 100644
View File

@ -0,0 +1,156 @@
/*
Written by Yotam Mann, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2013, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
*/
#ifndef OSCDATA_h
#define OSCDATA_h
#include "Arduino.h"
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include "OSCTiming.h"
#if (defined(TEENSYDUINO) && defined(USB_SERIAL)) || (!defined(TEENSYDUINO) && defined(__AVR_ATmega32U4__)) || defined(__SAM3X8E__) || (defined(_USB) && defined(_USE_USB_FOR_SERIAL_)) || defined(BOARD_maple_mini)
#define BOARD_HAS_USB_SERIAL
#if defined(__SAM3X8E__)
#define thisBoardsSerialUSB SerialUSB
#else
#define thisBoardsSerialUSB Serial
#endif
#endif
#if defined(ESP8266) || defined(ESP32)
#define ESPxx
#endif
//ERRORS/////////////////////////////////////////////////
typedef enum { OSC_OK = 0,
BUFFER_FULL, INVALID_OSC, ALLOCFAILED, INDEX_OUT_OF_BOUNDS
} OSCErrorCode;
class OSCData
{
private:
//friends
friend class OSCMessage;
//should only be used while decoding
//leaves an invalid OSCMessage with a type, but no data
OSCData(char t);
public:
//an error flag
OSCErrorCode error;
//the size (in bytes) of the data
int bytes;
//the type of the data
int type;
//the data
union {
char * s; //string
int32_t i; //int
float f; //float
double d; //double
uint64_t l; //long
uint8_t * b; //blob
osctime_t time;
} data;
//overload the constructor to account for all the types and sizes
OSCData(const char * s);
#if defined(__SAM3X8E__)
OSCData (int16_t);
#endif
OSCData (int32_t);
#ifndef ESPxx
OSCData (int);
#endif
OSCData (unsigned int);
OSCData (float);
OSCData (double);
OSCData (uint8_t *, int);
//accepts another OSCData objects and clones it
OSCData (OSCData *);
OSCData (boolean);
OSCData (osctime_t);
//destructor
~OSCData();
//GETTERS
int32_t getInt();
float getFloat();
double getDouble();
int getString(char *);
int getString(char *, int);
int getString(char *, int, int, int);
int getBlob(uint8_t *);
int getBlob(uint8_t *, int);
int getBlob(uint8_t *, int, int, int);
const uint8_t* getBlob();
int getBlobLength();
bool getBoolean();
osctime_t getTime();
//constructor from byte array with type and length
OSCData(char, uint8_t *, int);
//fill the passed in buffer with the data
//uint8_t * asByteArray();
};
/*
based on http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c
if the system is little endian, it will flip the bits
if the system is big endian, it'll do nothing
*/
template<typename T>
static inline T BigEndian(const T& x)
{
const int one = 1;
const char sig = *(char*)&one;
if (sig == 0) return x; // for big endian machine just return the input
T ret;
int size = sizeof(T);
char* src = (char*)&x + sizeof(T) - 1;
char* dst = (char*)&ret;
while (size-- > 0){
*dst++ = *src--;
}
return ret;
}
#endif

307
lib/OSC/OSCMatch.c 100644
View File

@ -0,0 +1,307 @@
#define OSC_MATCH_ENABLE_2STARS 1
#define OSC_MATCH_ENABLE_NSTARS 1
/*
Written by John MacCallum, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2009, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#include <string.h>
#include "OSCMatch.h"
static int osc_match_star(const char *pattern, const char *address);
static int osc_match_star_r(const char *pattern, const char *address);
static int osc_match_single_char(const char *pattern, const char *address);
static int osc_match_bracket(const char *pattern, const char *address);
static int osc_match_curly_brace(const char *pattern, const char *address);
int osc_match(const char *pattern, const char *address, int *pattern_offset, int *address_offset)
{
if(!strcmp(pattern, address)){
*pattern_offset = strlen(pattern);
*address_offset = strlen(address);
return OSC_MATCH_ADDRESS_COMPLETE | OSC_MATCH_PATTERN_COMPLETE;
}
const char *pattern_start;
const char *address_start;
pattern_start = pattern;
address_start = address;
*pattern_offset = 0;
*address_offset = 0;
while(*address != '\0' && *pattern != '\0'){
if(*pattern == '*'){
if(!osc_match_star(pattern, address)){
return 0;
}
while(*pattern != '/' && *pattern != '\0'){
pattern++;
}
while(*address != '/' && *address != '\0'){
address++;
}
}else if(*address == '*'){
while(*pattern != '/' && *pattern != '\0'){
pattern++;
}
while(*address != '/' && *address != '\0'){
address++;
}
}else{
int n = 0;
if(!(n = osc_match_single_char(pattern, address))){
return 0;
}
if(*pattern == '['){
while(*pattern != ']'){
pattern++;
}
pattern++;
address++;
}else if(*pattern == '{'){
while(*pattern != '}'){
pattern++;
}
pattern++;
address += n;
}else{
pattern++;
address++;
}
}
}
*pattern_offset = pattern - pattern_start;
*address_offset = address - address_start;
int r = 0;
if(*address == '\0') {
r |= OSC_MATCH_ADDRESS_COMPLETE;
}
if(*pattern == '\0') {
r |= OSC_MATCH_PATTERN_COMPLETE;
}
return r;
}
static int osc_match_star(const char *pattern, const char *address)
{
const char *address_start = address;
const char *pattern_start = pattern;
int num_stars = 0;
if(*address == '\0') { return 0; }
while(*address != '/' && *address != '\0'){
address++;
}
while(*pattern != '/' && *pattern != '\0'){
if(*pattern == '*'){
num_stars++;
}
pattern++;
}
pattern--;
address--;
switch(num_stars){
case 1:
{
const char *pp = pattern, *aa = address;
while(*pp != '*'){
if(!(osc_match_single_char(pp, aa))){
return 0;
}
if(*pp == ']' || *pp == '}'){
while(*pp != '[' && *pp != '{'){
pp--;
}
}
pp--;
aa--;
}
}
break;
case 2:
#if (OSC_MATCH_ENABLE_2STARS == 1)
{
const char *pp = pattern, *aa = address;
while(*pp != '*'){
if(!(osc_match_single_char(pp, aa))){
return 0;
}
if(*pp == ']' || *pp == '}'){
while(*pp != '[' && *pp != '{'){
pp--;
}
}
pp--;
aa--;
}
aa++; // we want to start one character forward to allow the star to match nothing
const char *star2 = pp;
const char *test = aa;
int i = 0;
while(test > address_start){
pp = star2 - 1;
aa = test - 1;
i++;
while(*pp != '*'){
if(!osc_match_single_char(pp, aa)){
break;
}
if(*pp == ']' || *pp == '}'){
while(*pp != '[' && *pp != '{'){
pp--;
}
}
pp--;
aa--;
}
if(pp == pattern_start){
return 1;
}
test--;
}
return 0;
}
break;
#else
return 0;
#endif
default:
#if (OSC_MATCH_ENABLE_NSTARS == 1)
return osc_match_star_r(pattern_start, address_start);
break;
#else
return 0;
#endif
}
return 1;
}
#if (OSC_MATCH_ENABLE_NSTARS == 1)
static int osc_match_star_r(const char *pattern, const char *address)
{
if(*address == '/' || *address == '\0'){
if(*pattern == '/' || *pattern == '\0' || (*pattern == '*' && ((*(pattern + 1) == '/') || *(pattern + 1) == '\0'))){
return 1;
}else{
return 0;
}
}
if(*pattern == '*'){
if(osc_match_star_r(pattern + 1, address)){
return 1;
}else{
return osc_match_star_r(pattern, address + 1);
}
}else{
if(!osc_match_single_char(pattern, address)){
return 0;
}
if(*pattern == '[' || *pattern == '{'){
while(*pattern != ']' && *pattern != '}'){
pattern++;
}
}
return osc_match_star_r(pattern + 1, address + 1);
}
}
#endif
static int osc_match_single_char(const char *pattern, const char *address)
{
switch(*pattern){
case '[':
return osc_match_bracket(pattern, address);
case ']':
while(*pattern != '['){
pattern--;
}
return osc_match_bracket(pattern, address);
case '{':
return osc_match_curly_brace(pattern, address);
case '}':
while(*pattern != '{'){
pattern--;
}
return osc_match_curly_brace(pattern, address);
case '?':
return 1;
default:
if(*pattern == *address){
return 1;
}else{
return 0;
}
}
return 0;
}
static int osc_match_bracket(const char *pattern, const char *address)
{
pattern++;
int val = 1;
if(*pattern == '!'){
pattern++;
val = 0;
}
int matched = !val;
while(*pattern != ']' && *pattern != '\0'){
// the character we're on now is the beginning of a range
if(*(pattern + 1) == '-'){
if(*address >= *pattern && *address <= *(pattern + 2)){
matched = val;
break;
}else{
pattern += 3;
}
}else{
// just test the character
if(*pattern == *address){
matched = val;
break;
}
pattern++;
}
}
return matched;
}
static int osc_match_curly_brace(const char *pattern, const char *address)
{
pattern++;
const char *ptr = pattern;
while(*ptr != '}' && *ptr != '\0' && *ptr != '/'){
while(*ptr != '}' && *ptr != '\0' && *ptr != '/' && *ptr != ','){
ptr++;
}
int n = ptr - pattern;
if(!strncmp(pattern, address, n)){
return n;
}else{
ptr++;
pattern = ptr;
}
}
return 0;
}

78
lib/OSC/OSCMatch.h 100644
View File

@ -0,0 +1,78 @@
/*
Written by John MacCallum, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2009, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef __OSC_MATCH_H__
#define __OSC_MATCH_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* Switch this off to disable matching against a pattern with 2 stars
*/
//#define OSC_MATCH_ENABLE_2STARS 1
/**
* Switch this off to disable matching against a pattern with more than 2 stars which will
* be done recursively.
*/
//#define OSC_MATCH_ENABLE_NSTARS 1
/**
* Return code for osc_match() that indicates that the entire address was successfully matched
*/
#define OSC_MATCH_ADDRESS_COMPLETE 1
/**
* Return code for osc_match() that indicates that the entire pattern was successfully matched
*/
#define OSC_MATCH_PATTERN_COMPLETE 2
/*
typedef struct _osc_callback {
const char* address; // Address
struct _osc_callback *child; // RAM
struct _osc_callback *sibling; // RAM
struct _osc_callback *parent; // RAM
int callback; // ROM
} osc_callback;
*/
/**
* Match a pattern against an address. In the case of a partial match, pattern_offset
* and address_offset will contain the number of bytes into their respective strings
* where the match failed.
*
* @param pattern The pattern to match
* @param address The address to match
* @param pattern_offset The number of bytes into the pattern that were matched successfully
* @param address_offset The number of bytes into the address that were matched successfully
* @return 0 if the match failed altogether, or an or'd combination of OSC_MATCH_ADDRESS_COMPLETE and
* OSC_MATCH_PATTERN_COMPLETE.
*/
int osc_match(const char *pattern, const char *address, int *pattern_offset, int *address_offset);
#ifdef __cplusplus
}
#endif
#endif // __OSC_MATCH_H__

View File

@ -0,0 +1,791 @@
/*
Written by Yotam Mann, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2012, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
*/
#include "OSCMessage.h"
#include "OSCMatch.h"
#include "OSCTiming.h"
extern osctime_t zerotime;
/*=============================================================================
CONSTRUCTORS / DESTRUCTOR
=============================================================================*/
//constructor with address
OSCMessage::OSCMessage(const char * _address){
setupMessage();
setAddress(_address);
}
//constructor with nothing
//just a placeholder since the message is invalid
OSCMessage::OSCMessage(){
setupMessage();
error = INVALID_OSC;
}
//variable length constructor
//for example OSCMessage msg("/address", "isf", 1, "two", 3.0);
/*
OSCMessage::OSCMessage(const char * _address, char * types, ... ){
setupMessage(_address);
}
*/
//sets up a new message
void OSCMessage::setupMessage(){
address = NULL;
//setup the attributes
dataCount = 0;
error = OSC_OK;
//setup the space for data
data = NULL;
//setup for filling the message
incomingBuffer = NULL;
incomingBufferSize = 0;
incomingBufferFree = 0;
clearIncomingBuffer();
//set the decode state
decodeState = STANDBY;
}
//DESTRUCTOR
OSCMessage::~OSCMessage(){
//free everything that needs to be freed
//free the address
free(address);
//free the data
empty();
//free the filling buffer
free(incomingBuffer);
}
OSCMessage& OSCMessage::empty(){
error = OSC_OK;
//free each of the data in the array
for (int i = 0; i < dataCount; i++){
const auto datum = getOSCData(i);
//explicitly destruct the data
//datum->~OSCData();
delete datum;
}
//and free the array
free(data);
data = NULL;
dataCount = 0;
decodeState = STANDBY;
clearIncomingBuffer();
return *this;
}
//COPY
OSCMessage::OSCMessage(OSCMessage * msg){
//start with a message with the same address
setupMessage();
setAddress(msg->address);
//add each of the data to the other message
for (int i = 0; i < msg->dataCount; i++){
add(msg->data[i]);
}
}
/*=============================================================================
GETTING DATA
=============================================================================*/
OSCData * OSCMessage::getOSCData(int position){
if (position < dataCount){
const auto datum = data[position];
return datum;
} else {
error = INDEX_OUT_OF_BOUNDS;
return nullptr;
}
}
int32_t OSCMessage::getInt(int position){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getInt();
} else {
return 0;
}
}
osctime_t OSCMessage::getTime(int position){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getTime();
} else {
return zerotime;
}
}
float OSCMessage::getFloat(int position){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getFloat();
} else {
return 0.0f;
}
}
double OSCMessage::getDouble(int position){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getDouble();
} else {
return 0.0;
}
}
bool OSCMessage::getBoolean(int position){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getBoolean();
} else {
return false;
}
}
int OSCMessage::getString(int position, char * buffer){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getString(buffer, datum->bytes);
} else {
return -1;
}
}
int OSCMessage::getString(int position, char * buffer, int bufferSize){
const auto datum = getOSCData(position);
if (!hasError()){
//the number of bytes to copy is the smaller between the buffer size and the datum's byte length
int copyBytes = bufferSize < datum->bytes? bufferSize : datum->bytes;
return datum->getString(buffer, copyBytes);
} else {
return -1;
}
}
int OSCMessage::getString(int position, char * buffer, int bufferSize, int offset, int size){
const auto datum = getOSCData(position);
if (!hasError()){
//the number of bytes to copy is the smaller between the buffer size and the datum's byte length
int copyBytes = bufferSize < datum->bytes? bufferSize : datum->bytes;
return datum->getString(buffer, copyBytes, offset, size);
} else {
return -1;
}
}
int OSCMessage::getBlob(int position, uint8_t * buffer){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getBlob(buffer);
} else {
return -1;
}
}
int OSCMessage::getBlob(int position, uint8_t * buffer, int bufferSize){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getBlob(buffer, bufferSize);
} else {
return -1;
}
}
int OSCMessage::getBlob(int position, uint8_t * buffer, int bufferSize, int offset, int size){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getBlob(buffer, bufferSize, offset, size);
} else {
return -1;
}
}
const uint8_t* OSCMessage::getBlob(int position) {
const auto datum = getOSCData(position);
if(!hasError()) {
return datum->getBlob();
} else {
return nullptr;
}
}
uint32_t OSCMessage::getBlobLength(int position)
{
const auto datum = getOSCData(position);
if (!hasError()){
return datum->getBlobLength();
} else {
return 0;
}
}
char OSCMessage::getType(int position){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->type;
} else {
return '\0';
}
}
int OSCMessage::getDataLength(int position){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->bytes;
} else {
return 0;
}
}
/*=============================================================================
TESTING DATA
=============================================================================*/
bool OSCMessage::testType(int position, char type){
const auto datum = getOSCData(position);
if (!hasError()){
return datum->type == type;
} else {
return false;
}
}
bool OSCMessage::isInt(int position){
return testType(position, 'i');
}
bool OSCMessage::isTime(int position){
return testType(position, 't');
}
bool OSCMessage::isFloat(int position){
return testType(position, 'f');
}
bool OSCMessage::isBlob(int position){
return testType(position, 'b');
}
bool OSCMessage::isChar(int position){
return testType(position, 'c');
}
bool OSCMessage::isString(int position){
return testType(position, 's');
}
bool OSCMessage::isDouble(int position){
return testType(position, 'd');
}
bool OSCMessage::isBoolean(int position){
return testType(position, 'T') || testType(position, 'F');
}
/*=============================================================================
PATTERN MATCHING
=============================================================================*/
int OSCMessage::match(const char * pattern, int addr_offset){
int pattern_offset;
int address_offset;
int ret = osc_match(address + addr_offset, pattern, &pattern_offset, &address_offset);
char * next = (char *) (address + addr_offset + pattern_offset);
if (ret==3){
return pattern_offset;
} else if (pattern_offset > 0 && *next == '/'){
return pattern_offset;
} else {
return 0;
}
}
bool OSCMessage::fullMatch( const char * pattern, int addr_offset){
int pattern_offset;
int address_offset;
int ret = osc_match(address + addr_offset, pattern, &pattern_offset, &address_offset );
return (ret==3);
}
bool OSCMessage::dispatch(const char * pattern, void (*callback)(OSCMessage &), int addr_offset){
if (fullMatch(pattern, addr_offset)){
callback(*this);
return true;
} else {
return false;
}
}
bool OSCMessage::route(const char * pattern, void (*callback)(OSCMessage &, int), int initial_offset){
int match_offset = match(pattern, initial_offset);
if (match_offset>0){
callback(*this, match_offset + initial_offset);
return true;
} else {
return false;
}
}
/*=============================================================================
ADDRESS
=============================================================================*/
int OSCMessage::getAddress(char * buffer, int offset){
int result = strlen(address);
if (result > offset)
strcpy(buffer, address+offset);
else
*buffer = 0;
return result - offset; // could be negative!
}
int OSCMessage::getAddress(char * buffer, int offset, int len){
int result = strlen(address);
if (result > offset)
{
strncpy(buffer, address+offset, len); // N.B. NOT guaranteed to null-terminate! So...
buffer[len-1] = 0; // ...prevent strlen() blowing up
}
else
*buffer = 0;
return strlen(buffer);
}
const char* OSCMessage::getAddress(){
return address;
}
int OSCMessage::getAddressLength(int offset)
{
int result = (int) strlen(address) - offset;
if (result < 0) // offset past end!
result = 0; // do the best we can
return result;
}
OSCMessage& OSCMessage::setAddress(const char * _address){
//free the previous address
free(address); // are we sure address was allocated?
//copy the address
char * addressMemory = (char *) malloc( (strlen(_address) + 1) * sizeof(char) );
if (addressMemory == NULL){
error = ALLOCFAILED;
address = NULL;
} else {
strcpy(addressMemory, _address);
address = addressMemory;
}
return *this;
}
/*=============================================================================
SIZE
=============================================================================*/
#ifdef SLOWpadcalculation
int OSCMessage::padSize(int _bytes){
int space = (_bytes + 3) / 4;
space *= 4;
return space - _bytes;
}
#else
static inline int padSize(int bytes) { return (4- (bytes&03))&3; }
#endif
//returns the number of OSCData in the OSCMessage
int OSCMessage::size(){
return dataCount;
}
int OSCMessage::bytes(){
int messageSize = 0;
//send the address
int addrLen = strlen(address) + 1;
messageSize += addrLen;
//padding amount
int addrPad = padSize(addrLen);
messageSize += addrPad;
//add the comma separator
messageSize += 1;
//add the types
messageSize += dataCount;
//pad the types
int typePad = padSize(dataCount + 1); //for the comma
if (typePad == 0){
typePad = 4; // to make sure the type string is null terminated
}
messageSize+=typePad;
//then the data
for (int i = 0; i < dataCount; i++){
const auto datum = getOSCData(i);
messageSize+=datum->bytes;
messageSize += padSize(datum->bytes);
}
return messageSize;
}
/*=============================================================================
ERROR HANDLING
=============================================================================*/
bool OSCMessage::hasError(){
if(error != OSC_OK) return true;
//test each of the data
for (int i = 0; i < dataCount; i++){
if(getOSCData(i)->error) return true;
}
return false;
}
OSCErrorCode OSCMessage::getError(){
return error;
}
/*=============================================================================
SENDING
=============================================================================*/
OSCMessage& OSCMessage::send(Print &p){
//don't send a message with errors
if (hasError()){
return *this;
}
uint8_t nullChar = '\0';
//send the address
int addrLen = strlen(address) + 1;
//padding amount
int addrPad = padSize(addrLen);
//write it to the stream
p.write((uint8_t *) address, addrLen);
//add the padding
while(addrPad--){
p.write(nullChar);
}
//add the comma separator
p.write((uint8_t) ',');
//add the types
#ifdef PAULSSUGGESTION
// Paul suggested buffering on the stack
// to improve performance. The problem is this could exhaust the stack
// for long complex messages
{
uint8_t typstr[dataCount];
for (int i = 0; i < dataCount; i++){
typstr[i] = getType(i);
}
p.write(typstr,dataCount);
}
#else
for (int i = 0; i < dataCount; i++){
p.write((uint8_t) getType(i));
}
#endif
//pad the types
int typePad = padSize(dataCount + 1); // 1 is for the comma
if (typePad == 0){
typePad = 4; // This is because the type string has to be null terminated
}
while(typePad--){
p.write(nullChar);
}
//write the data
for (int i = 0; i < dataCount; i++){
const auto datum = getOSCData(i);
if ((datum->type == 's') || (datum->type == 'b')){
p.write(datum->data.b, datum->bytes);
int dataPad = padSize(datum->bytes);
while(dataPad--){
p.write(nullChar);
}
} else if (datum->type == 'd'){
double d = BigEndian(datum->data.d);
uint8_t * ptr = (uint8_t *) &d;
p.write(ptr, 8);
} else if (datum->type == 't'){
osctime_t time = datum->data.time;
uint32_t d = BigEndian(time.seconds);
uint8_t * ptr = (uint8_t *) &d;
p.write(ptr, 4);
d = BigEndian(time.fractionofseconds);
ptr = (uint8_t *) &d;
p.write(ptr, 4);
} else if (datum->type == 'T' || datum->type == 'F')
{ }
else { // float or int
uint32_t i = BigEndian(datum->data.i);
uint8_t * ptr = (uint8_t *) &i;
p.write(ptr, datum->bytes);
}
}
return *this;
}
/*=============================================================================
FILLING
=============================================================================*/
OSCMessage& OSCMessage::fill(uint8_t incomingByte){
decode(incomingByte);
return *this;
}
OSCMessage& OSCMessage::fill(uint8_t * incomingBytes, int length){
while (length--){
decode(*incomingBytes++);
}
return *this;
}
/*=============================================================================
DECODING
=============================================================================*/
void OSCMessage::decodeAddress(){
setAddress((char *) incomingBuffer);
//change the error from invalid message
error = OSC_OK;
clearIncomingBuffer();
}
void OSCMessage::decodeType(uint8_t incomingByte){
char type = incomingByte;
add(type);
}
void OSCMessage::decodeData(uint8_t incomingByte){
//get the first OSCData to re-set
for (int i = 0; i < dataCount; i++){
const auto datum = getOSCData(i);
if (datum->error == INVALID_OSC){
//set the contents of datum with the data received
switch (datum->type){
case 'i':
if (incomingBufferSize == 4){
//parse the buffer as an int
union {
int32_t i;
uint8_t b[4];
} u;
memcpy(u.b, incomingBuffer, 4);
int32_t dataVal = BigEndian(u.i);
set(i, dataVal);
clearIncomingBuffer();
}
break;
case 'f':
if (incomingBufferSize == 4){
//parse the buffer as a float
union {
float f;
uint8_t b[4];
} u;
memcpy(u.b, incomingBuffer, 4);
float dataVal = BigEndian(u.f);
set(i, dataVal);
clearIncomingBuffer();
}
break;
case 'd':
if (incomingBufferSize == 8){
//parse the buffer as a double
union {
double d;
uint8_t b[8];
} u;
memcpy(u.b, incomingBuffer, 8);
double dataVal = BigEndian(u.d);
set(i, dataVal);
clearIncomingBuffer();
}
break;
case 't':
if (incomingBufferSize == 8){
//parse the buffer as a timetag
union {
osctime_t t;
uint8_t b[8];
} u;
memcpy(u.b, incomingBuffer, 8);
u.t.seconds = BigEndian(u.t.seconds);
u.t.fractionofseconds = BigEndian(u.t.fractionofseconds);
set(i, u.t);
clearIncomingBuffer();
}
break;
case 's':
if (incomingByte == 0){
char * str = (char *) incomingBuffer;
set(i, str);
clearIncomingBuffer();
decodeState = DATA_PADDING;
}
break;
case 'b':
if (incomingBufferSize > 4){
//compute the expected blob size
union {
uint32_t i;
uint8_t b[4];
} u;
memcpy(u.b, incomingBuffer, 4);
uint32_t blobLength = BigEndian(u.i);
if (incomingBufferSize == (int)(blobLength + 4)){
set(i, incomingBuffer + 4, blobLength);
clearIncomingBuffer();
decodeState = DATA_PADDING;
}
}
break;
}
//break out of the for loop once we've selected the first invalid message
break;
}
}
}
//does not validate the incoming OSC for correctness
void OSCMessage::decode(uint8_t incomingByte){
addToIncomingBuffer(incomingByte);
switch (decodeState){
case STANDBY:
if (incomingByte == '/'){
decodeState = ADDRESS;
}
break;
case ADDRESS:
if (incomingByte == 0){
//end of the address
//decode the address
decodeAddress();
//next state
decodeState = ADDRESS_PADDING;
}
break;
case ADDRESS_PADDING:
//it does not count the padding
if (incomingByte==','){
//next state
decodeState = TYPES;
clearIncomingBuffer();
}
break;
case TYPES:
if (incomingByte != 0){
//next state
decodeType(incomingByte);
} else {
decodeState = TYPES_PADDING;
}
//FALL THROUGH to test if it should go to the data state
case TYPES_PADDING: {
//compute the padding size for the types
//to determine the start of the data section
int typePad = padSize(dataCount + 1); // 1 is the comma
if (typePad == 0){
typePad = 4; // to make sure it will be null terminated
}
if (incomingBufferSize == (typePad + dataCount)){
clearIncomingBuffer();
decodeState = DATA;
}
}
break;
case DATA:
decodeData(incomingByte);
break;
case DATA_PADDING:{
//get the last valid data
for (int i = dataCount - 1; i >= 0; i--){
const auto datum = getOSCData(i);
if (datum->error == OSC_OK){
//compute the padding size for the data
int dataPad = padSize(datum->bytes);
// if there is no padding required, switch back to DATA, and don't clear the incomingBuffer because it holds next data
if (dataPad == 0){
decodeState = DATA;
}
else if (incomingBufferSize == dataPad){
clearIncomingBuffer();
decodeState = DATA;
}
break;
}
}
}
break;
case DONE:
break; // TODO: is this correct? - was missing from original code, it did this by default
}
}
/*=============================================================================
INCOMING BUFFER MANAGEMENT
=============================================================================*/
#define OSCPREALLOCATEIZE 16
void OSCMessage::addToIncomingBuffer(uint8_t incomingByte){
//realloc some space for the new byte and stick it on the end
if(incomingBufferFree>0)
{
incomingBuffer[incomingBufferSize++] = incomingByte;
incomingBufferFree--;
}
else
{
incomingBuffer = (uint8_t *) realloc ( incomingBuffer, incomingBufferSize + 1 + OSCPREALLOCATEIZE);
if (incomingBuffer != NULL){
incomingBuffer[incomingBufferSize++] = incomingByte;
incomingBufferFree = OSCPREALLOCATEIZE;
} else {
error = ALLOCFAILED;
}
}
}
void OSCMessage::clearIncomingBuffer(){
incomingBuffer = (uint8_t *) realloc ( incomingBuffer, OSCPREALLOCATEIZE);
if (incomingBuffer != NULL){
incomingBufferFree = OSCPREALLOCATEIZE;
} else {
error = ALLOCFAILED;
incomingBuffer = NULL;
}
incomingBufferSize = 0;
}

View File

@ -0,0 +1,350 @@
/*
Written by Yotam Mann, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2012, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
*/
#ifndef OSCMESSAGE_h
#define OSCMESSAGE_h
#include "OSCData.h"
#include <Print.h>
class OSCMessage
{
private:
//friends
friend class OSCBundle;
/*=============================================================================
PRIVATE VARIABLES
=============================================================================*/
//the address
char * address;
//the data
OSCData ** data;
//the number of OSCData in the data array
int dataCount;
//error codes for potential runtime problems
OSCErrorCode error;
/*=============================================================================
DECODING INCOMING BYTES
=============================================================================*/
//the decoding states for incoming bytes
enum DecodeState {
STANDBY,
ADDRESS,
ADDRESS_PADDING,
TYPES,
TYPES_PADDING,
DATA,
DATA_PADDING,
DONE,
} decodeState;
//stores incoming bytes until they can be decoded
uint8_t * incomingBuffer;
int incomingBufferSize; // how many bytes are stored
int incomingBufferFree; // how many bytes are allocated but unused
//adds a byte to the buffer
void addToIncomingBuffer(uint8_t);
//clears the incoming buffer
void clearIncomingBuffer();
//decoding function
void decode(uint8_t);
void decodeAddress();
void decodeType(uint8_t);
void decodeData(uint8_t);
/*=============================================================================
HELPER FUNCTIONS
=============================================================================*/
void setupMessage();
//compares the OSCData's type char to a test char
bool testType(int position, char type);
//returns the number of bytes to pad to make it 4-bit aligned
// int padSize(int bytes);
public:
//returns the OSCData at that position
OSCData * getOSCData(int);
/*=============================================================================
CONSTRUCTORS / DESTRUCTOR
=============================================================================*/
//new constructor needs an address
OSCMessage (const char * _address);
//no address
//placeholder since it's invalid OSC
OSCMessage();
//can optionally accept all of the data after the address
//OSCMessage(const char * _address, char * types, ... );
//created from another OSCMessage
OSCMessage (OSCMessage *);
//DESTRUCTOR
~OSCMessage();
//empties all of the data
OSCMessage& empty();
/*=============================================================================
SETTING DATA
=============================================================================*/
//returns the OSCMessage so that multiple 'add's can be strung together
template <typename T>
OSCMessage& add(T datum){
//make a piece of data
OSCData * d = new OSCData(datum);
//check if it has any errors
if (d->error == ALLOCFAILED){
error = ALLOCFAILED;
} else {
//resize the data array
OSCData ** dataMem = (OSCData **) realloc(data, sizeof(OSCData *) * (dataCount + 1));
if (dataMem == NULL){
error = ALLOCFAILED;
} else {
data = dataMem;
//add data to the end of the array
data[dataCount] = d;
//increment the data size
dataCount++;
}
}
return *this;
}
//blob specific add
OSCMessage& add(uint8_t * blob, int length){
//make a piece of data
OSCData * d = new OSCData(blob, length);
//check if it has any errors
if (d->error == ALLOCFAILED){
error = ALLOCFAILED;
} else {
//resize the data array
OSCData ** dataMem = (OSCData **) realloc(data, sizeof(OSCData *) * (dataCount + 1));
if (dataMem == NULL){
error = ALLOCFAILED;
} else {
data = dataMem;
//add data to the end of the array
data[dataCount] = d;
//increment the data size
dataCount++;
}
}
return *this;
}
//sets the data at a position
template <typename T>
OSCMessage& set(int position, T datum){
if (position < dataCount){
//replace the OSCData with a new one
OSCData * oldDatum = getOSCData(position);
//destroy the old one
delete oldDatum;
//make a new one
OSCData * newDatum = new OSCData(datum);
//test if there was an error
if (newDatum->error == ALLOCFAILED){
error = ALLOCFAILED;
} else {
//otherwise, put it in the data array
data[position] = newDatum;
}
} else if (position == (dataCount)){
//add the data to the end
add(datum);
} else {
//else out of bounds error
error = INDEX_OUT_OF_BOUNDS;
}
return *this;
}
//blob specific setter
OSCMessage& set(int position, uint8_t * blob, int length){
if (position < dataCount){
//replace the OSCData with a new one
OSCData * oldDatum = getOSCData(position);
//destroy the old one
delete oldDatum;
//make a new one
OSCData * newDatum = new OSCData(blob, length);
//test if there was an error
if (newDatum->error == ALLOCFAILED){
error = ALLOCFAILED;
} else {
//otherwise, put it in the data array
data[position] = newDatum;
}
} else if (position == (dataCount)){
//add the data to the end
add(blob, length);
} else {
//else out of bounds error
error = INDEX_OUT_OF_BOUNDS;
}
return *this;
}
OSCMessage& setAddress(const char *);
/*=============================================================================
GETTING DATA
getters take a position as an argument
=============================================================================*/
int32_t getInt(int);
osctime_t getTime(int);
float getFloat(int);
double getDouble(int);
bool getBoolean(int);
//return the copied string's length
int getString(int, char *);
//check that it won't overflow the passed buffer's size with a third argument
int getString(int, char *, int);
//offset and size can be defined in order to only query a part of the string
int getString(int, char *, int, int, int);
//returns the number of unsigned int8's copied into the buffer
int getBlob(int, uint8_t *);
//check that it won't overflow the passed buffer's size with a third argument
int getBlob(int, uint8_t *, int);
//offset and size can be defined in order to only query a part of the blob's content
int getBlob(int, uint8_t *, int, int, int);
//get pointer to blob
const uint8_t* getBlob(int);
// returns the length of blob
uint32_t getBlobLength(int position);
//returns the number of bytes of the data at that position
int getDataLength(int);
//returns the type at the position
char getType(int);
//put the address in the buffer
int getAddress(char * buffer, int offset = 0);
int getAddress(char * buffer, int offset, int len);
const char* getAddress();
// Find out address length so we can create a buffer
int getAddressLength(int offset = 0);
/*=============================================================================
TESTING DATA
testers take a position as an argument
=============================================================================*/
bool isInt(int);
bool isFloat(int);
bool isBlob(int);
bool isChar(int);
bool isString(int);
bool isDouble(int);
bool isBoolean(int);
bool isTime(int);
/*=============================================================================
PATTERN MATCHING
=============================================================================*/
//match the pattern against the address
//returns true only for a complete match
bool fullMatch( const char * pattern, int = 0);
//returns the number of characters matched in the address
int match( const char * pattern, int = 0);
//calls the function with the message as the arg if it was a full match
bool dispatch(const char * pattern, void (*callback)(OSCMessage &), int = 0);
//like dispatch, but allows for partial matches
//the address match offset is sent as an argument to the callback
//also room for an option address offset to allow for multiple nested routes
bool route(const char * pattern, void (*callback)(OSCMessage &, int), int = 0);
/*=============================================================================
SIZE
=============================================================================*/
//the number of data that the message contains
int size();
//computes the number of bytes the OSCMessage occupies if everything is 32-bit aligned
int bytes();
/*=============================================================================
TRANSMISSION
=============================================================================*/
//send the message
OSCMessage& send(Print &p);
//fill the message from a byte stream
OSCMessage& fill(uint8_t);
OSCMessage& fill(uint8_t *, int);
/*=============================================================================
ERROR
=============================================================================*/
bool hasError();
OSCErrorCode getError();
};
#endif

View File

@ -0,0 +1,178 @@
/*
Written by Adrian Freed, The Center for New Music and Audio Technologies,
University of California, Berkeley. Copyright (c) 2013, The Regents of
the University of California (Regents).
Permission to use, copy, modify, distribute, and distribute modified versions
of this software and its documentation without fee and without a signed
licensing agreement, is hereby granted, provided that the above copyright
notice, this paragraph and the following two paragraphs appear in all copies,
modifications, and distributions.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
*/
#include "OSCTiming.h"
#if defined(TEENSYDUINO) && defined(__arm__)
extern volatile uint32_t systick_millis_count;
static uint32_t savedcount, savedcurrent;
static void latchOscTime()
{
uint32_t istatus;
uint32_t count, current;
__disable_irq();
current = SYST_CVR;
count = systick_millis_count;
istatus = SCB_ICSR; // bit 26 indicates if systick exception pending
__enable_irq();
//systick_current = current;
//systick_count = count;
//systick_istatus = istatus & SCB_ICSR_PENDSTSET ? 1 : 0;
if ((istatus & SCB_ICSR_PENDSTSET) && current > 50) count++;
current = ((F_CPU / 1000) - 1) - current;
savedcount=count; savedcurrent=current;
}
static osctime_t computeOscTime()
{ //4,294,967,296
osctime_t t;
t.seconds = (( uint64_t)(savedcount/1000)) ;
t.fractionofseconds = ( (uint64_t)(4294967295) * ( (savedcount * 1000 + (uint64_t)savedcurrent / (F_CPU / 1000000UL)) % 1000000) ) /1000000;
return t;
}
osctime_t oscTime()
{
latchOscTime();
return computeOscTime();
}
#elif defined(CORE_TEENSY)
extern volatile uint32_t timer0_millis_count;
static uint32_t savedcount, savedmicros;
static void latchOscTime()
{
noInterrupts();
savedcount = timer0_millis_count;
savedmicros = micros();
interrupts();
}
static osctime_t computeOscTime()
{ //4,294,967,296
osctime_t t;
savedmicros %= 1000000;
t.fractionofseconds= (67108864ULL * savedmicros) / 15625 ; // 2^32/1000000
t.seconds = savedcount/1000;
return t;
#ifdef ddfgsdfgsdfgsdfg
return ((savedcount/1000)<<32) + ( (4294967295ULL) * ( (savedcount * 1000ULL + savedmicros) % 1000000ULL) ) /1000000ULL
;
#endif
}
osctime_t oscTime()
{
latchOscTime();
return computeOscTime();
}
#elif defined(AVR) || defined(__AVR_ATmega32U4__) || defined(__SAM3X8E__) || defined(_SAMD21_) || defined(__ARM__)
static uint32_t savedcount, savedmicros;
static void latchOscTime()
{
noInterrupts();
//cli();
savedcount = millis();
savedmicros = micros();
interrupts();
//sei();
}
osctime_t computeOscTime()
{ //4,294,967,296
osctime_t t;
savedmicros %= 1000000UL;
// t.fractionofseconds = (67108864ULL * (uint64_t)savedmicros) / 15625ULL ; // 2^32/1000000
t.fractionofseconds= (67108864UL * savedmicros)/ 15625ULL ; // 2^32/1000000
t.seconds = savedcount/1000;
return t;
}
osctime_t oscTime()
{
latchOscTime();
return computeOscTime();
}
#else
static void latchOscTime()
{
}
osctime_t oscTime()
{
osctime_t t;
t.fractionofseconds = 1;
return t;
}
#endif
int adcRead(int pin, osctime_t *t)
{
latchOscTime();
int v =analogRead(pin);
*t = oscTime();
return v;
}
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK66FX1M0__)
int capacitanceRead(int pin, osctime_t *t)
{
latchOscTime();
int v = touchRead(pin);
*t = oscTime();
return v;
}
#endif
int inputRead(int pin, osctime_t *t)
{
int v =digitalRead(pin);
*t = oscTime();
return v;
}

View File

@ -0,0 +1,30 @@
//
// OSCTiming.h
//
//
// Created by AdrianFreed on 11/10/13.
//
//
#ifndef ____OSCTiming__
#define ____OSCTiming__
#include "Arduino.h"
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
typedef struct
{
uint32_t seconds;
uint32_t fractionofseconds;
} osctime_t;
osctime_t oscTime();
int adcRead(int pin, osctime_t *t);
int capacitanceRead(int pin, osctime_t *t);
int inputRead(int pin, uint64_t *t);
#endif /* defined(____OSCTiming__) */

235
lib/OSC/README.md 100644
View File

@ -0,0 +1,235 @@
# OSC for Arduino
This is an Arduino and Teensy library implementation of the [OSC](http://opensoundcontrol.org) (Open Sound Control) encoding.It was developed primarily by Yotam Mann and Adrian Freed at CNMAT where OSC was invented. It benefits from contributions from John MacCallum, Matt Wright, Jeff Lubow and Andy Schmeder and many beta testers.
Features:
* Supports the four basic OSC data types (32-bit integers, 32-bit floats, strings, and blobs - arbitrary length byte sequences)
* Supports the optional 64-bit timetag data type and Booleans
* Address pattern matching
* Dynamic memory allocation
* Sends and receives OSC packets over transport layers that implements the Arduino Stream Class such as Serial and Ethernet UDP
# Installation
We recommend Arduino 1.8.5 and a compatible Teensyduino overlay if you use the Teensy. Install using the library manager.
Additional information about installing libraries on [Arduino's website](https://www.arduino.cc/en/Guide/Libraries).
# Examples
The `Applications` folder contains examples for Max/MSP and PD and Processing that work with the example sketches. This will be expanded to include other applications like TouchOSC and Processing. For the Max/MSP examples you will need to download the CNMAT max externals package that includes the "o." objects available [here](http://cnmat.berkeley.edu/downloads).
# API
OSC for Arduino supports creating, sending and receiving OSCMessages individually and wrapped into OSCBundles.
The full API is available [here](./API.md).
### Sending Data
Create a new `OSCMessage` with an address in the constructor:
```C++
OSCMessage msg("/address");
```
add some data to it:
```C++
msg.add(1);
msg.add(2.0);
msg.add("three");
```
`add` will infer the type of the data and encode it correctly. The API also supports chaining, so multiple calls to `add` can be strung together:
```C++
msg.add(1).add(2.0f).add("three");
```
Then send it over any transport layer that extends Arduino's [Print class](http://playground.arduino.cc/Code/Printclass) like the `Serial` out.
```C++
msg.send(Serial);
```
### Receiving Data
In a typical Serial stream, there is no way to know where one message ends and another begins. That's why we recommend using `SLIPSerial` (which also comes in the OSC for Arduino Package). Read more about the lightweight [SLIP encoding](https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol).
To receive an OSCMessage, wait for the end of SLIP Stream, and fill an empty OSCMessage with the available bytes:
```C++
//make an empty message to fill with the incoming data
OSCMessage msg;
//wait for the end of the packet to be received
while(!SLIPSerial.endofPacket()){
int size = SLIPSerial.available();
if (size > 0){
//fill the msg with all of the available bytes
while(size--){
msg.fill(SLIPSerial.read());
}
}
}
```
Now you can query and use the data you received:
```C++
//returns true if the data in the first position is an integer
if (msg.isInt(0)){
//get that integer
int data = msg.getInt(0);
}
```
### Routing / Dispatching
OSCMessages can be routed to a specific function by matching their address exactly or with an OSC pattern.
`dispatch` will do a full match on the OSCMessage's address or patterned address.
```C++
OSCMessage msg("/a/1");
msg.dispatch("/a/1", dispatchAddress);
```
And the function definition of `dispatchAddress` could be as follows:
```C++
//called whenever an OSCMessage's address matches "/a/1"
void dispatchAddress(OSCMessage &msg){
//do something with the OSCMessage...
if (msg.isFloat(0)){
float val = msg.getFloat(0);
}
}
```
`route` does the same thing as `dispatch` but allows for partial address matching as long as they are aligned to a `/` character.
```C++
OSCMessage msg("/b/2");
msg.route("/b", routeAddress);
```
```C++
//called whenever an OSCMessage's address matches "/b"
void routeAddress(OSCMessage &msg, int addressOffset){
//do something with the OSCMessage...
if (msg.isBoolean(0)){
bool val = msg.getBoolean(0);
}
}
```
### OSCBundles
An OSCBundle is a group of OSCMessage that can be sent and received together.
```C++
OSCBundle bundle;
//add a new OSCMessage to the bundle with the address "/a"
OSCMessage msgA = bundle.add("/a");
//add some data to that message
msgA.add("some data");
//append another OSCMessage, this time chaining 'add' calls
bundle.add("/b").add("some more data").add("even more data");
```
Now send the OSCBundle over SLIPSerial
```C++
//start a new SLIP Packet
SLIPSerial.beginPacket();
//send the data
bundle.send(SLIPSerial);
//end the packet
SLIPSerial.endPacket();
```
### SLIP Serial
The OSC for Arduino library includes extensions of the USB serial and Hardware serial functions of the Arduino core that sends and receives data using the SLIP encoding. This makes Max/MSP and PD integration very simple using CNMAT's o.io.slipserial. The SLIPSerial library implements the same methods as the Serial object with additional `beginPacket` and `endPacket` methods to mark the boundaries of each packet in a serial stream.
When sending data, begin each packet with `SLIPSerial.beginPacket()`, then write any data to the SLIPSerial and signify the end of the packet using `SLIPSerial.endPacket()`.
On the receiving side, in addition to the normal `read` and `available` methods of the Serial object, SLIPSerial includes `SLIPSerial.endofPacket()` which returns true when the EOT (End Of Transmission) character is received, marking the end of the data packet.
# Oscuino
As well as many small examples illustrating the API, there is a larger application called "oscuino" that illustrates how to use OSC to simplify situations Firmata and Maxuino are typically used in.
# Support
### IDEs
Arduino 1.8.5
Best Supported Board:
ARM boards such M0, Zero, Teensy 3.0 and 3.1 and LC have the performance and memory that afford rich OSC implementations.
Our primary test platform for new development is the Teensy 3.x series which currently offers the best performance
of any of the Arduinos and variants. We greatly appreciate Paul Stoffregen's ongoing work
with "best practice" engineering of high performance micro-controllers.
### Unsupported boards
Arduino Yun and related openwrt/arduino hybrids (e.g. Draguino):
Marco Brianza is exploring these interesting approaches to running this OSC library on the Atmel 32u4 in the Yun:
https://github.com/cylinderlight/udp2serial
https://github.com/cylinderlight/udp2serialSPI
The Yun still lacks the Linux-side support to reliably move data between the 32u4 and the router's cpu. We recommend that you add a Teensy to the USB port of an OpenWrt router to get good performance and reliability with our library.
# Testing
OSC for Arduino comes with a small suite of tests to validate its functionality and test compatibility when new platforms come out. The tests are broken into a number of individual `.ino` files located in the `test` folder.
The tests require [ArduinoUnit](https://github.com/mmurdoch/arduinounit) to be installed in the `libraries` folder. The results of the test are printed to the Serial console.
Tested on:
* Esplora
* Leonardo
* Teensy 3.x
* Mega 2560
# Performance
Currently best performance is achieved with Arduinos with built-in USB Serial, i.e. Teensy 3.0, Teensy 2.0 and 2.0++ and Leanardo variants (12Mbps max).
This is because the Wiznet 5100 used in the Ethernet Arduino and shields uses really slow SPI (0.3Mbps). This will change as people retool to use the much faster Wiznet 5200 which has been measured with the Due at 6Mbps.
References:
* http://forum.pjrc.com/threads/17951-WIZ820io-Ethernet-and-2nd-power-supply-with-teensy-3-0
* http://arduino.cc/forum/index.php?topic=139147.0
The serial examples use a 9600 baud rate which is reliable on most of the FTDI based Arduinos. The slow rate is required for Arduino's without clock chips such as the TinyLili. Once you have established that things work at 9600 baud you will find it very beneficial to increase the rate. e.g. `Serial.begin(345600); // !! 115200, 230400, 345600, 460800 X`
# Future development ideas
* WIFI examples
* STM32 support
* Intel Galileo support
* HiFive Support
* Photon Support
* support for special OSC types in CNMAT's "o." especially subbundles
* examples for recent OSC support in node.js and Node Red
* nested bundles
* performance tuning
* Photon spark core examples
* Better Time Tags that avoid the overflow limitation of Arduino timer code
* Time Tag synchronization
* Bluetooth LE
* TCP/IP Examples
* examples for more applications (i.e. TouchOSC, Processing with SLIP)
* deadline scheduling of OSC 64-bit timetags
* ADK support
We welcome and appreciate your contributions and feedback.
# New in this release
ESPxx, M0, PIC32

View File

@ -0,0 +1,292 @@
/*
Extends the Serial class to encode SLIP over serial
*/
#include "Arduino.h"
#ifndef SLIPEncodedSerial_h
#define SLIPEncodedSerial_h
#include <Stream.h>
#ifdef ARDUINO_API_VERSION
#include <api/HardwareSerial.h>
#else
#include <HardwareSerial.h>
#endif
#if (defined(TEENSYDUINO) && (defined(USB_SERIAL) || defined(USB_DUAL_SERIAL) || defined(USB_TRIPLE_SERIAL) || defined(USB_SERIAL_HID) || defined(USB_MIDI_SERIAL) || defined(USB_MIDI_AUDIO_DUAL_SERIAL) || defined(USB_MIDI4_SERIAL) || defined(USB_MIDI16_SERIAL) || defined(USB_MIDI_AUDIO_SERIAL) || defined(USB_MIDI16_AUDIO_SERIAL))) || (!defined(TEENSYDUINO) && defined(__AVR_ATmega32U4__)) || defined(__SAM3X8E__) || (defined(_USB) && defined(_USE_USB_FOR_SERIAL_)) || defined(_SAMD21_) || defined(__PIC32MX__) || defined(__PIC32MZ__) || defined(ARDUINO_USB_CDC_ON_BOOT) || defined(ARDUINO_ARCH_RP2040)
#define BOARD_HAS_USB_SERIAL
//import the serial USB object
#if defined(TEENSYDUINO) && defined (__arm__)
#if !defined(USB_HOST_TEENSY36_)
#include <usb_serial.h>
#endif
#elif defined(TEENSYDUINO) && defined (__AVR__)
#include <usb_api.h>
#elif defined(__SAM3X8E__) || defined(_SAMD21_)
#include <USB/USBAPI.h>
#elif (defined(__PIC32MX__) || defined(__PIC32MZ__) || defined(ARDUINO_USB_CDC_ON_BOOT))
#include <USB.h>
#elif defined(__AVR_ATmega32U4__)
#include "USBAPI.h"
#include <avr/wdt.h>
#elif defined(ARDUINO_ARCH_RP2040)
#include <SerialUSB.h>
#else
#error Unknown USB port
#endif
#endif
template <class T>
class _SLIPSerial: public Stream{
private:
// state machine for SLIP escape characters
enum erstate {CHAR, FIRSTEOT, SECONDEOT, SLIPESC } rstate;
//the serial port used
T * serial;
public:
_SLIPSerial(T &s)
{
serial = &s;
rstate = CHAR;
}
static const uint8_t eot = 0300;
static const uint8_t slipesc = 0333;
static const uint8_t slipescend = 0334;
static const uint8_t slipescesc = 0335;
/*
SERIAL METHODS
*/
bool endofPacket()
{
if(rstate == SECONDEOT)
{
rstate = CHAR;
return true;
}
if (rstate==FIRSTEOT)
{
if(serial->available())
{
uint8_t c =serial->peek();
if(c==eot)
{
serial->read(); // throw it on the floor
}
}
rstate = CHAR;
return true;
}
return false;
}
int available(){
back:
uint8_t cnt = serial->available();
if(cnt==0)
return 0;
if(rstate==CHAR)
{
uint8_t c =serial->peek();
if(c==slipesc)
{
rstate = SLIPESC;
serial->read(); // throw it on the floor
goto back;
}
else if( c==eot)
{
rstate = FIRSTEOT;
serial->read(); // throw it on the floor
goto back;
}
return 1; // we may have more but this is the only sure bet
}
else if(rstate==SLIPESC)
return 1;
else if(rstate==FIRSTEOT)
{
if(serial->peek()==eot)
{
rstate = SECONDEOT;
serial->read(); // throw it on the floor
return 0;
}
rstate = CHAR;
}else if (rstate==SECONDEOT) {
rstate = CHAR;
}
return 0;
}
//reads a byte from the buffer
int read(){
back:
uint8_t c = serial->read();
if(rstate==CHAR)
{
if(c==slipesc)
{
rstate=SLIPESC;
goto back;
}
else if(c==eot){
return -1; // xxx this is an error
}
return c;
}
else
if(rstate==SLIPESC)
{
rstate=CHAR;
if(c==slipescend)
return eot;
else if(c==slipescesc)
return slipesc;
else {
// insert some error code here
return -1;
}
}
else
return -1;
}
size_t readBytes( uint8_t *buffer, size_t size)
{
size_t count = 0;
while(!endofPacket() && available() && (size>0))
{
int c = read();
if(c>=0)
{
*buffer++ = c;
++count;
--size;
}
else
break;
}
return count;
}
// as close as we can get to correct behavior
int peek(){
uint8_t c = serial->peek();
if(rstate==SLIPESC)
{
if(c==slipescend)
return eot;
else if(c==slipescesc)
return slipesc;
}
return c;
}
//encode SLIP
size_t write(uint8_t b){
if(b == eot){
serial->write(slipesc);
return serial->write(slipescend);
} else if(b==slipesc) {
serial->write(slipesc);
return serial->write(slipescesc);
} else {
return serial->write(b);
}
}
size_t write(const uint8_t *buffer, size_t size)
{
size_t result=0;
while(size--)
{
result = write(*buffer++);
}
return result;
}
void begin(unsigned long baudrate){
serial->begin(baudrate);
}
// for bluetooth
void begin(char *name){
serial->begin(name);
}
//SLIP specific method which begins a transmitted packet
void beginPacket() { serial->write(eot); }
//signify the end of the packet with an EOT
void endPacket(){
serial->write(eot);
}
void flush(){
serial->flush();
}
};
using SLIPEncodedSerial = _SLIPSerial<HardwareSerial> ;
// template <> void _SLIPSerial<HardwareSerial>::endPacket(){
// serial->write(eot);
// }
#ifdef BOARD_HAS_USB_SERIAL
#if defined(_SAMD21_)
// Required for Serial on Zero based boards
#if defined(ARDUINO_SAMD_ZERO)
// Adafruit breaks with tradition here
#define thisBoardsSerialUSB Serial
typedef decltype(Serial) actualUSBtype;
#else
#define thisBoardsSerialUSB SerialUSB
typedef decltype(SerialUSB) actualUSBtype;
#endif
#elif defined(__SAM3X8E__)
// Required for Serial on Zero based boards
#define thisBoardsSerialUSB SerialUSB
typedef decltype(SerialUSB) actualUSBtype;
// defined(__SAM3X8E__)
#elif defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_USB_CDC_ON_BOOT) || defined(CORE_TEENSY) || defined(__AVR_ATmega32U4__) || (defined(__PIC32MX__) || defined(__PIC32MZ__))
#define thisBoardsSerialUSB Serial
typedef decltype(Serial) actualUSBtype;
#endif
using SLIPEncodedUSBSerial = _SLIPSerial<actualUSBtype>;
#if defined(CORE_TEENSY)
template <> void _SLIPSerial<actualUSBtype>::endPacket(){
serial->write(eot);
serial->send_now();
}
#endif
#endif
// Bluetooth Example
// #if BOARD_HAS_BLUETOOTH_SERIAL
// #include "BluetoothSerial.h"
// BluetoothSerial bluetoothserialinstance;
// SLIPEncodedBluetoothSerial SLIPSerial(bluetoothserialinstance);
#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
#include "BluetoothSerial.h"
using SLIPEncodedBluetoothSerial = _SLIPSerial<BluetoothSerial>;
#define BOARD_HAS_BLUETOOTH_SERIAL
#endif
#endif

View File

@ -0,0 +1,103 @@
/*---------------------------------------------------------------------------------------------
Open Sound Control (OSC) library for the ESP8266/ESP32
Example for receiving open sound control (OSC) bundles on the ESP8266/ESP32
Send integers '0' or '1' to the address "/led" to turn on/off the built-in LED of the esp8266.
This example code is in the public domain.
--------------------------------------------------------------------------------------------- */
#ifdef ESP8266
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <WiFiUdp.h>
#include <OSCMessage.h>
#include <OSCBundle.h>
#include <OSCData.h>
char ssid[] = "*****************"; // your network SSID (name)
char pass[] = "*******"; // your network password
// A UDP instance to let us send and receive packets over UDP
WiFiUDP Udp;
const IPAddress outIp(10,40,10,105); // remote IP (not needed for receive)
const unsigned int outPort = 9999; // remote port (not needed for receive)
const unsigned int localPort = 8888; // local port to listen for UDP packets (here's where we send the packets)
OSCErrorCode error;
unsigned int ledState = LOW; // LOW means led is *on*
#ifndef BUILTIN_LED
#ifdef LED_BUILTIN
#define BUILTIN_LED LED_BUILTIN
#else
#define BUILTIN_LED 13
#endif
#endif
void setup() {
pinMode(BUILTIN_LED, OUTPUT);
digitalWrite(BUILTIN_LED, ledState); // turn *on* led
Serial.begin(115200);
// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.print("Local port: ");
#ifdef ESP32
Serial.println(localPort);
#else
Serial.println(Udp.localPort());
#endif
}
void led(OSCMessage &msg) {
ledState = msg.getInt(0);
digitalWrite(BUILTIN_LED, ledState);
Serial.print("/led: ");
Serial.println(ledState);
}
void loop() {
OSCBundle bundle;
int size = Udp.parsePacket();
if (size > 0) {
while (size--) {
bundle.fill(Udp.read());
}
if (!bundle.hasError()) {
bundle.dispatch("/led", led);
} else {
error = bundle.getError();
Serial.print("error: ");
Serial.println(error);
}
}
}

View File

@ -0,0 +1,100 @@
/*---------------------------------------------------------------------------------------------
Open Sound Control (OSC) library for the ESP8266/ESP32
Example for receiving open sound control (OSC) messages on the ESP8266/ESP32
Send integers '0' or '1' to the address "/led" to turn on/off the built-in LED of the esp8266.
This example code is in the public domain.
--------------------------------------------------------------------------------------------- */
#ifdef ESP8266
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <WiFiUdp.h>
#include <OSCMessage.h>
#include <OSCBundle.h>
#include <OSCData.h>
char ssid[] = "*****************"; // your network SSID (name)
char pass[] = "*******"; // your network password
// A UDP instance to let us send and receive packets over UDP
WiFiUDP Udp;
const IPAddress outIp(10,40,10,105); // remote IP (not needed for receive)
const unsigned int outPort = 9999; // remote port (not needed for receive)
const unsigned int localPort = 8888; // local port to listen for UDP packets (here's where we send the packets)
OSCErrorCode error;
unsigned int ledState = LOW; // LOW means led is *on*
#ifndef BUILTIN_LED
#ifdef LED_BUILTIN
#define BUILTIN_LED LED_BUILTIN
#else
#define BUILTIN_LED 13
#endif
#endif
void setup() {
pinMode(BUILTIN_LED, OUTPUT);
digitalWrite(BUILTIN_LED, ledState); // turn *on* led
Serial.begin(115200);
// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.print("Local port: ");
#ifdef ESP32
Serial.println(localPort);
#else
Serial.println(Udp.localPort());
#endif
}
void led(OSCMessage &msg) {
ledState = msg.getInt(0);
digitalWrite(BUILTIN_LED, ledState);
Serial.print("/led: ");
Serial.println(ledState);
}
void loop() {
OSCMessage msg;
int size = Udp.parsePacket();
if (size > 0) {
while (size--) {
msg.fill(Udp.read());
}
if (!msg.hasError()) {
msg.dispatch("/led", led);
} else {
error = msg.getError();
Serial.print("error: ");
Serial.println(error);
}
}
}

View File

@ -0,0 +1,66 @@
/*---------------------------------------------------------------------------------------------
Open Sound Control (OSC) library for the ESP8266/ESP32
Example for sending messages from the ESP8266/ESP32 to a remote computer
The example is sending "hello, osc." to the address "/test".
This example code is in the public domain.
--------------------------------------------------------------------------------------------- */
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <WiFiUdp.h>
#include <OSCMessage.h>
char ssid[] = "*****************"; // your network SSID (name)
char pass[] = "*******"; // your network password
WiFiUDP Udp; // A UDP instance to let us send and receive packets over UDP
const IPAddress outIp(10,40,10,105); // remote IP of your computer
const unsigned int outPort = 9999; // remote port to receive OSC
const unsigned int localPort = 8888; // local port to listen for OSC packets (actually not used for sending)
void setup() {
Serial.begin(115200);
// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.print("Local port: ");
#ifdef ESP32
Serial.println(localPort);
#else
Serial.println(Udp.localPort());
#endif
}
void loop() {
OSCMessage msg("/test");
msg.add("hello, osc.");
Udp.beginPacket(outIp, outPort);
msg.send(Udp);
Udp.endPacket();
msg.empty();
delay(500);
}

View File

@ -0,0 +1,287 @@
/*
Bidirectional Esplora OSC communications using SLIP
Adrian Freed, Jeff Lubow 2013
Includes some examples of common "best practices" for OSC name space and parameter
mapping design.
*/
#include <Esplora.h>
#include <OSCBundle.h>
//Teensy and Leonardo variants have special USB serial
#include <SLIPEncodedSerial.h>
#if !defined(__AVR_ATmega32U4__)
#error select Arduino Esplora in board menu
#endif
// temperature
float getTemperature(){
int result;
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0);
ADCSRB = _BV(MUX5);
delayMicroseconds(200); // wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
analogReference(DEFAULT);
return result/1023.0f;
}
float getSupplyVoltage(){
// powersupply
int result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delayMicroseconds(300); // wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
float supplyvoltage = 1.1264f *1023 / result;
return supplyvoltage;
}
// Esplora has a dinky green led at the top left and a big RGB led at the bottom right
void routeLed(OSCMessage &msg, int addrOffset ){
if(msg.match("/red", addrOffset)) {
if (msg.isInt(0)) Esplora.writeRed( (byte)msg.getInt(0));
}
else
if(msg.match("/green", addrOffset)) {
if (msg.isInt(0)) Esplora.writeGreen( (byte)msg.getInt(0));
}
else
if(msg.match("/blue", addrOffset)) {
if (msg.isInt(0)) Esplora.writeBlue( (byte)msg.getInt(0));
}
else
if(msg.match("/rgb", addrOffset)) {
if (msg.isInt(0)&&msg.isInt(1)&&msg.isInt(2))
{
Esplora.writeRGB((byte)msg.getInt(0),(byte)msg.getInt(1),(byte)msg.getInt(2));
}
}
else
{
if (msg.isInt(0))
{
digitalWrite(13, msg.getInt(0)>0?HIGH:LOW);
}
}
}
// Esplora has a dinky green led at the top left and a big RGB led at the bottom right
void routeOut(OSCMessage &msg, int addrOffset ){
if(msg.match("/B", addrOffset) || msg.match("/b", addrOffset)) {
if (msg.isInt(0)) {
pinMode(11,OUTPUT);
digitalWrite(11, msg.getInt(0)>0?HIGH:LOW);
}
else
pinMode(11,INPUT); // add pull up logic some day
}
else
if(msg.match("/A", addrOffset) ||msg.match("/a", addrOffset)) {
if (msg.isInt(0)) {
pinMode(3,OUTPUT);
digitalWrite(3, msg.getInt(0)>0?HIGH:LOW);
}
else
pinMode(3,INPUT); // add pull up logic some day
}
}
/**
* TONE
*
* square wave output "/tone"
*
* format:
* /tone
* (no value) = notome
* float or int = frequency
* optional length of time as an integer in milliseconds afterwards
*
**/
void routeTone(OSCMessage &msg, int addrOffset ){
unsigned int frequency = 0;
if (msg.isInt(0)){
frequency = msg.getInt(0);
}
else if(msg.isFloat(0)){
frequency = msg.getFloat(0); // this doesn't work due to problems with double to float conversion?
}
else
Esplora.noTone();
if(frequency>0)
{
if(msg.isInt(1))
Esplora.tone(frequency, msg.getInt(1));
else
Esplora.tone( frequency);
}
}
const char *released = "released";
const char *pressed = "pressed";
const byte MUX_ADDR_PINS[] = {
A0, A1, A2, A3 };
const byte MUX_COM_PIN = A4;
unsigned int myReadChannel(byte channel) {
digitalWrite(MUX_ADDR_PINS[0], (channel & 1) ? HIGH : LOW);
digitalWrite(MUX_ADDR_PINS[1], (channel & 2) ? HIGH : LOW);
digitalWrite(MUX_ADDR_PINS[2], (channel & 4) ? HIGH : LOW);
digitalWrite(MUX_ADDR_PINS[3], (channel & 8) ? HIGH : LOW);
return analogRead(MUX_COM_PIN);
}
SLIPEncodedUSBSerial SLIPSerial(Serial);
void setup() {
SLIPSerial.begin(115200); // set this as high as you can reliably run on your platform
}
int32_t counter = 0;
int32_t serialnumber = 2; //hard coded; beware
int32_t num_components = 3; //currently break the bundle up into 3 components
void loop(){
OSCBundle bndl;
int32_t manifest_count = 1;
if(!SLIPSerial.available())
{
// The RAW OSC address space and parameter mappngs try to capture
// the data at lowest level without calibration or scaling
// The names are chosen to match what is on the silkscreen of the board where it is found
#define RAW
#ifdef RAW
SLIPSerial.beginPacket();
bndl.add("/mic").add((int32_t)Esplora.readMicrophone());
bndl.add("/temp/sensor/celsius").add((int32_t)Esplora.readTemperature(DEGREES_C));
bndl.add("/temp/sensor/fahrenheit").add((int32_t)Esplora.readTemperature(DEGREES_F));
bndl.add("/linear/potentiometer").add((int32_t)Esplora.readSlider());
bndl.add("/light/sensor").add((int32_t)Esplora.readLightSensor());
bndl.add("/switch/1").add((int32_t)Esplora.readButton(SWITCH_1));
bndl.add("/switch/2").add((int32_t)Esplora.readButton(SWITCH_2));
bndl.add("/switch/3").add((int32_t)Esplora.readButton(SWITCH_3));
bndl.add("/switch/4").add((int32_t)Esplora.readButton(SWITCH_4));
bndl.add("/joystick/X").add((int32_t)Esplora.readJoystickX());
bndl.add("/joystick/Y").add((int32_t)Esplora.readJoystickY());
bndl.add("/joystick/switch").add((int32_t)Esplora.readJoystickSwitch());
bndl.add("/joystick/switch/1").add((int32_t)Esplora.readButton(JOYSTICK_DOWN));
bndl.add("/joystick/switch/2").add((int32_t)Esplora.readButton(JOYSTICK_LEFT));
bndl.add("/joystick/switch/3").add((int32_t)Esplora.readButton(JOYSTICK_UP));
bndl.add("/joystick/switch/4").add((int32_t)Esplora.readButton(JOYSTICK_RIGHT));
bndl.add("/accelerometer/x").add(Esplora.readAccelerometer(X_AXIS));
bndl.add("/accelerometer/y").add(Esplora.readAccelerometer(Y_AXIS));
bndl.add("/accelerometer/z").add(Esplora.readAccelerometer(Z_AXIS));
bndl.send(SLIPSerial); // send the bytes to the SLIP stream
SLIPSerial.endPacket(); // mark the end of the OSC Packet
bndl.empty();
#endif //RAW
// The COOKED OSC address space and parameter mappings
// encode data for ease of use and legibility at the host. Unit intervals replace integers
// The names are chosen to clarify usage rather than adherence to the silkscreen
// also values are acquired as close together as reasonably possible to increase
// their usability in sensor fusion contexts, i.e. in this case with the accelerometer
SLIPSerial.beginPacket(); // mark the beginning of the OSC Packet
//bundle 1
bndl.add("/acceleration/x").add(Esplora.readAccelerometer(X_AXIS)/512.0f);
bndl.add("/acceleration/y").add(Esplora.readAccelerometer(Y_AXIS)/512.0f);
bndl.add("/acceleration/z").add(Esplora.readAccelerometer(Z_AXIS)/512.0f);
bndl.add("/photoresistor").add(Esplora.readLightSensor()/1023.0f);
bndl.add("/joystick/horizontal").add(-1.0 * (int32_t)Esplora.readJoystickX()/512.0f);
bndl.add("/joystick/vertical").add(-1.0 * (int32_t)Esplora.readJoystickY()/512.0f);
bndl.add("/joystick/button").add(Esplora.readJoystickSwitch()>0? released:pressed);
bndl.add("/joystick/backward").add((int32_t)Esplora.readButton(JOYSTICK_DOWN)?released:pressed);
bndl.add("/joystick/left").add((int32_t)Esplora.readButton(JOYSTICK_LEFT)?released:pressed);
bndl.add("/joystick/forward").add((int32_t)Esplora.readButton(JOYSTICK_UP)?released:pressed);
bndl.add("/joystick/right").add((int32_t)Esplora.readButton(JOYSTICK_RIGHT)?released:pressed);
bndl.add("/serialnumber").add(serialnumber);
//bndl.add("/manifest").add(manifest_count++).add(num_components).add(counter);
bndl.send(SLIPSerial); // send the bytes to the SLIP stream
SLIPSerial.endPacket(); // mark the end of the OSC Packet
bndl.empty(); //bundle ending early due to current memory limitations
//bundle 2
bndl.add("/diamond/backward").add((int32_t)Esplora.readButton(SWITCH_1)?released:pressed);
bndl.add("/diamond/left").add((int32_t)Esplora.readButton(SWITCH_2)?released:pressed);
bndl.add("/diamond/forward").add((int32_t)Esplora.readButton(SWITCH_3)?released:pressed);
bndl.add("/diamond/right").add((int32_t)Esplora.readButton(SWITCH_4)?released:pressed);
bndl.add("/microphone/loudness").add(Esplora.readMicrophone()/1023.0f);
bndl.add("/temperature/fahrenheit").add((float)Esplora.readTemperature(DEGREES_F));
bndl.add("/temperature/celsius").add((float)Esplora.readTemperature(DEGREES_C));
bndl.add("/slider/horizontal").add(1.0f - ((float)Esplora.readSlider()/1023.0f));
bndl.add("/serialnumber").add(serialnumber);
//bndl.add("/manifest").add(manifest_count++).add(num_components).add(counter);
bndl.send(SLIPSerial); // send the bytes to the SLIP stream
SLIPSerial.endPacket(); // mark the end of the OSC Packet
bndl.empty(); //bundle ending early due to current memory limitations
//bundle 3
bndl.add("/connector/white/left").add(myReadChannel(CH_MIC +1)/1023.0);
bndl.add("/connector/white/right").add(myReadChannel(CH_MIC +2)/1023.0);
bndl.add("/led/red").add((int32_t)Esplora.readRed());
bndl.add("/led/green").add((int32_t)Esplora.readGreen());
bndl.add("/led/blue").add((int32_t)Esplora.readBlue());
bndl.add("/led/rgb").add((int32_t)Esplora.readRed()).add((int32_t)Esplora.readGreen()).add((int32_t)Esplora.readBlue());
bndl.add("/connector/orange/right").add((digitalRead(3)==HIGH)?1:0);
bndl.add("/connector/orange/left").add((digitalRead(11)==HIGH)?1:0);
bndl.add("/vendor").add("Arduino");
bndl.add("/productname").add("Esplora");
bndl.add("/serialnumber").add(serialnumber);
//bndl.add("/manifest").add(manifest_count++).add(num_components).add(counter);
bndl.send(SLIPSerial); // send the bytes to the SLIP stream
SLIPSerial.endPacket(); // mark the end of the OSC Packet
bndl.empty();
counter += 1;
// bndl.add("/32u4/supplyVoltage").add(getSupplyVoltage());
// bndl.add("/32u4/temperature").add(getTemperature());
}
else
{
OSCBundle bundleIN;
int size;
while(!SLIPSerial.endofPacket())
if ((size =SLIPSerial.available()) > 0)
{
while(size--)
bundleIN.fill(SLIPSerial.read());
}
{
if(!bundleIN.hasError())
{
bundleIN.route("/led", routeLed);
bundleIN.route("/L", routeLed); // this is how it is marked on the silkscreen
bundleIN.route("/out", routeOut); // for the TinkerIt output connectors
bundleIN.route("/tone", routeTone);
bundleIN.route("/squarewave", routeTone);
bundleIN.route("/notone", routeTone);
}
}
}
}

View File

@ -0,0 +1,91 @@
/*
The library has four methods for doing pattern matching on address.
'match' and 'fullMatch' are specific to OSCMessages while route and dispatch work on both messages and bundles.
OSCMessage:
match - matches the message's address pattern against an address. returns the number of characters matched from the address passed in.
fullMatch - returns true if the pattern was a complete match against the address
OSCMessage && OSCBundle:
route - calls a function with the matched OSCMessage(s) and the number of matched characters in the address as the parameters
dispatch - calls a function with each OSCMessage which was fully matched by the pattern
///////////////////////////////////////////////////////////////////////////////////////////////////
OSC Regular expression pattern matching rules from http://opensoundcontrol.org/spec-1_0
1. '?' in the OSC Address Pattern matches any single character
2. '*' in the OSC Address Pattern matches any sequence of zero or more characters
3. A string of characters in square brackets (e.g., "[string]") in the OSC Address Pattern matches any character in the string.
Inside square brackets, the minus sign (-) and exclamation point (!) have special meanings:
two characters separated by a minus sign indicates the range of characters between the given two in ASCII collating sequence.
An exclamation point at the beginning of a bracketed string negates the sense of the list, meaning that the list matches any character not in the list.
4. A comma-separated list of strings enclosed in curly braces (e.g., "{foo,bar}") in the OSC Address Pattern matches any of the strings in the list.
5. Any other character in an OSC Address Pattern can match only the same character.
///////////////////////////////////////////////////////////////////////////////////////////////////
*/
#include <OSCBundle.h>
void setup() {
Serial.begin(38400);
}
void loop(){
//a heavily patterned message address
OSCMessage msg0("/{input,output}/[0-2]/[!ab]/*");
//match will traverse as far as it can in the pattern
//it returns the number of characters matched from the pattern
int patternOffset = msg0.match("/input/1");
if (patternOffset>0){
//string multiple 'match' methods together using the pattern offset parameter to continue matching where it left off
//use 'fullMatch' to test if the entire pattern was matched.
if(msg0.fullMatch("/c/anything", patternOffset)){
Serial.println("Match: '/input/1/c/anything' against the pattern '/{input,output}/[0-2]/[abc]/*'");
}
}
//write over the other message address
OSCMessage msg1("/partialMatch");
//match will return 0 if it did not reach the end or a '/'
if(!msg1.match("/partial")){
Serial.println("No Match: '/partial' against the pattern '/partialMatch'");
}
OSCMessage msg2("/output/[0-2]");
//'route' is uses 'match' to allow for partial matches
//it invokes the callback with the matched message and the pattern offset as parameters to the callback
msg2.route("/output", routeOutput);
//'dispatch' uses 'fullMatch' so it does not allow for partial matches
//invokes the callback with only one argument which is the matched message
msg2.dispatch("/output/1", routeOutputOne);
delay(1000);
}
//called after matching '/output'
//the matched message and the number of matched characters as the parameters
void routeOutput(OSCMessage &msg, int patternOffset){
Serial.println("Match: '/output'");
//string multiple 'route' methods together using the pattern offset parameter.
msg.route("/0", routeZero, patternOffset);
}
//called after matching '/0'
void routeZero(OSCMessage &msg, int addressOffset){
Serial.println("Match: '/output/0'");
}
//called after matching '/output/1'
void routeOutputOne(OSCMessage &msg){
Serial.println("Match: '/output/1'");
}
//
// TROUBLESHOOTING:
// Because of a bug in the Arduino IDE, it sometimes thinks that the '*' in combination with '/' is the opening or closing of a multiline comment
// This can be fixed by escaping the '/' with '\' or using the octal value of '*' which is '\052'
// for example:
// "/*" == "/\052" == "\/*"
//

View File

@ -0,0 +1,108 @@
/*
Serial Call Response
Send responses to calls for information from a remote host
*/
#include <OSCBundle.h>
#include <OSCBoards.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
OSCBundle bundleOUT;
/**
* ANALOG
*
* called when the address matches "/a"
*
* format:
* /analog/(pin)
* /u = analogRead with pullup
*
**/
void routeAnalog(OSCMessage &msg, int addrOffset ){
int pinMatched;
pinMatched = msg.match("/0", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(0), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/0").add((int32_t)analogRead(0));
}
pinMatched = msg.match("/1", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(1), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/1").add((int32_t)analogRead(1));
}
pinMatched = msg.match("/2", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(2), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/2").add((int32_t)analogRead(2));
}
pinMatched = msg.match("/3", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(3), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/3").add((int32_t)analogRead(3));
}
pinMatched = msg.match("/4", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(4), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/4").add((int32_t)analogRead(4));
}
pinMatched = msg.match("/5", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(5), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/5").add((int32_t)analogRead(5));
}
}
/**
* MAIN METHODS
*
* setup and loop, bundle receiving/sending, initial routing
*/
void setup() {
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
}
//reads and routes the incoming messages
void loop(){
OSCBundle bundleIN;
int size;
while(!SLIPSerial.endofPacket())
if ((size =SLIPSerial.available()) > 0)
{
while(size--)
bundleIN.fill(SLIPSerial.read());
}
if(!bundleIN.hasError())
{
bundleIN.route("/analog", routeAnalog);
//send the outgoing response message
SLIPSerial.beginPacket();
bundleOUT.send(SLIPSerial);
SLIPSerial.endPacket();
bundleOUT.empty(); // empty the bundle ready to use for new messages
}
}

View File

@ -0,0 +1,48 @@
/*
Serial USB ports are bidirectional.
This example can be extended to build routers and forwarders of OSC packets
*/
#include <OSCBundle.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
void setup() {
//begin SLIPSerial just like Serial
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
}
void loop(){
OSCBundle bndl;
int size;
//receive a bundle
while(!SLIPSerial.endofPacket())
if( (size =SLIPSerial.available()) > 0)
{
while(size--)
bndl.fill(SLIPSerial.read());
}
if(!bndl.hasError())
{
static int32_t sequencenumber=0;
// we can sneak an addition onto the end of the bundle
bndl.add("/micros").add((int32_t)micros()); // (int32_t) is the type of OSC Integers
bndl.add("/sequencenumber").add(sequencenumber++);
bndl.add("/digital/5").add(digitalRead(5)==HIGH);
bndl.add("/lsb").add((sequencenumber &1)==1);
SLIPSerial.beginPacket(); // mark the beginning of the OSC Packet
bndl.send(SLIPSerial);
SLIPSerial.endPacket();
}
}

View File

@ -0,0 +1,332 @@
#include <OSCBundle.h>
#include <OSCBoards.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
//outgoing messages
OSCBundle bundleOUT;
//converts the pin to an osc address
char * numToOSCAddress( int pin){
static char s[10];
int i = 9;
s[i--]= '\0';
do
{
s[i] = "0123456789"[pin % 10];
--i;
pin /= 10;
}
while(pin && i);
s[i] = '/';
return &s[i];
}
/**
* ROUTES
*
* these are where the routing functions go
*
*/
/**
* DIGITAL
*
* called when address matched "/d"
* expected format:
* /d/(pin)
* /u = digitalRead with pullup
* (no value) = digitalRead without pullup
* (value) = digital write on that pin
*
*/
void routeDigital(OSCMessage &msg, int addrOffset ){
//match input or output
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(pin, OUTPUT);
digitalWrite(pin, (msg.getInt(0)>0) ? HIGH:LOW);
}
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
//otherwise it's an digital read
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(pin, INPUT_PULLUP);
//setup the output address which should be /d/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the digital read and send the results
bundleOUT.add(outputAddress).add(digitalRead(pin));
} //else without a pullup
else {
//set the pinmode
pinMode(pin, INPUT);
//setup the output address which should be /d/(pin)
char outputAddress[6];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
//do the digital read and send the results
bundleOUT.add(outputAddress).add(digitalRead(pin));
}
}
}
}
/**
* ANALOG
*
* called when the address matches "/a"
*
* format:
* /a/(pin)
* /u = analogRead with pullup
* (no value) = analogRead without pullup
* (digital value) = digital write on that pin
* (float value) = analogWrite on that pin
*
**/
void routeAnalog(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_ANALOG_INPUTS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(analogInputToDigitalPin(pin), OUTPUT);
digitalWrite(analogInputToDigitalPin(pin), (msg.getInt(0) > 0)? HIGH: LOW);
}
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
#ifdef BOARD_HAS_ANALOG_PULLUP
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(analogInputToDigitalPin(pin), INPUT_PULLUP);
//setup the output address which should be /a/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the analog read and send the results
bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
} //else without a pullup
#endif
else {
//otherwise it's an analog read
//set the pinmode
pinMode(analogInputToDigitalPin(pin), INPUT);
//setup the output address which should be /a/(pin)
char outputAddress[6];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
//do the analog read and send the results
bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
}
}
}
}
#ifdef BOARD_HAS_TONE
/**
* TONE
*
* square wave output "/tone"
*
* format:
* /tone/pin
*
* (digital value) (float value) = frequency in Hz
* (no value) disable tone
*
**/
void routeTone(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
unsigned int frequency = 0;
//if it has an int, then it's an integers frequency in Hz
if (msg.isInt(0)){
frequency = msg.getInt(0);
} //otherwise it's a floating point frequency in Hz
else if(msg.isFloat(0)){
frequency = msg.getFloat(0);
}
else
noTone(pin);
if(frequency>0)
{
if(msg.isInt(1))
tone(pin, frequency, msg.getInt(1));
else
tone(pin, frequency);
}
}
}
}
#endif
#ifdef BOARD_HAS_CAPACITANCE_SENSING
#if defined(__MKL26Z64__)
// teensy 3.0LC
#define NTPINS 11
const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,3,4 };
#elif defined(__MK66FX1M0__)
// teensy 3.6
#define NTPINS 12
const int cpins[NTPINS] = {0,1,14,15,16,17,18,19,22,23,29,30 };
#else
//Teensy 3.1 3.2
#define NTPINS 12
const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,25,32, 33 };
#endif
void routeTouch(OSCMessage &msg, int addrOffset )
{
for(int i=0;i<NTPINS;++i)
{
const char *name = numToOSCAddress(cpins[i]);
int pinMatched = msg.match(name, addrOffset);
if(pinMatched)
{
char outputAddress[9];
strcpy(outputAddress, "/c");
strcat(outputAddress, name);
bundleOUT.add(outputAddress).add(touchRead(cpins[i]));
}
}
}
#endif
/**
* SYSTEM MESSAGES
*
* expected format:
* /s
* /m = microseconds
* /d = number of digital pins
* /a = number of analog pins
* /l integer = set the led
* /t = temperature
* /s = power supply voltage
*/
//
void routeSystem(OSCMessage &msg, int addrOffset ){
#ifdef BOARD_HAS_DIE_TEMPERATURE_SENSOR
if (msg.fullMatch("/t", addrOffset)){
bundleOUT.add("/s/t").add(getTemperature());
}
#endif
#ifdef BOARD_HAS_DIE_POWER_SUPPLY_MEASUREMENT
if (msg.fullMatch("/s", addrOffset)){
bundleOUT.add("/s/s").add(getSupplyVoltage());
}
#endif
if (msg.fullMatch("/m", addrOffset)){
bundleOUT.add("/s/m").add((int32_t)micros());
}
if (msg.fullMatch("/d", addrOffset)){
bundleOUT.add("/s/d").add(NUM_DIGITAL_PINS);
}
if (msg.fullMatch("/a", addrOffset)){
bundleOUT.add("/s/a").add(NUM_ANALOG_INPUTS);
}
if (msg.fullMatch("/l", addrOffset)){
if (msg.isInt(0)){
pinMode(LED_BUILTIN, OUTPUT);
int i = msg.getInt(0);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, (i > 0)? HIGH: LOW);
bundleOUT.add("/s/l").add(i);
}
}
}
/**
* MAIN METHODS
*
* setup and loop, bundle receiving/sending, initial routing
*/
void setup() {
SLIPSerial.begin(115200); // set this as high as you can reliably run on your platform
#if ARDUINO >= 100
while(!Serial)
; // Leonardo bug
#endif
}
//reads and routes the incoming messages
void loop(){
OSCBundle bundleIN;
int size;
while(!SLIPSerial.endofPacket())
if ((size =SLIPSerial.available()) > 0)
{
while(size--)
bundleIN.fill(SLIPSerial.read());
}
if(!bundleIN.hasError())
{
bundleIN.route("/s", routeSystem);
bundleIN.route("/a", routeAnalog);
bundleIN.route("/d", routeDigital);
#ifdef BOARD_HAS_TONE
bundleIN.route("/tone", routeTone);
#endif
#ifdef BOARD_HAS_CAPACITANCE_SENSING
bundleIN.route("/c", routeTouch);
#endif
}
bundleIN.empty();
//send the outgoing message
SLIPSerial.beginPacket();
bundleOUT.send(SLIPSerial);
SLIPSerial.endPacket();
bundleOUT.empty();
}

View File

@ -0,0 +1,292 @@
#include <OSCBundle.h>
#include <OSCBoards.h>
// Fubarino MINI
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
OSCBundle bundleOUT;
//converts the pin to an osc address
char * numToOSCAddress( int pin){
static char s[10];
int i = 9;
s[i--]= '\0';
do
{
s[i] = "0123456789"[pin % 10];
--i;
pin /= 10;
}
while(pin && i);
s[i] = '/';
return &s[i];
}
/**
* ROUTES
*
* these are where the routing functions go
*
*/
/**
* DIGITAL
*
* called when address matched "/d"
* expected format:
* /d/(pin)
* /u = digitalRead with pullup
* (no value) = digitalRead without pullup
* (value) = digital write on that pin
*
*/
void routeDigital(OSCMessage &msg, int addrOffset ){
//match input or output
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
switch(pin)
{
// fubarino MINI
// these are used for clocks and USB and Program switch and shouldn't be written to
// unless you know what you are doing
case 3: case 14: case 15: case 23: case 16: case 31:case 32: goto out;
}
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(pin, OUTPUT);
digitalWrite(pin, (msg.getInt(0)>0) ? HIGH:LOW);
} //otherwise it's an digital read
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(pin, INPUT_PULLUP);
//setup the output address which should be /d/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the digital read and send the results
{
OSCMessage msgOut(outputAddress); msgOut.add(digitalRead(pin));
SLIPSerial.beginPacket(); msgOut.send(SLIPSerial); SLIPSerial.endPacket();
}
} //else without a pullup
else {
//set the pinmode
pinMode(pin, INPUT);
//setup the output address which should be /d/(pin)
char outputAddress[6];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
//do the digital read and send the results
{
OSCMessage msgOut(outputAddress); msgOut.add(digitalRead(pin));
SLIPSerial.beginPacket(); msgOut.send(SLIPSerial); SLIPSerial.endPacket();
}
}
}
out: ;
}
}
/**
* ANALOG
*
* called when the address matches "/a"
*
* format:
* /a/(pin)
* /u = analogRead with pullup
* (no value) = analogRead without pullup
* (digital value) = digital write on that pin
* (float value) = analogWrite on that pin
*
**/
void routeAnalog(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_ANALOG_INPUTS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(analogInputToDigitalPin(pin), OUTPUT);
digitalWrite(analogInputToDigitalPin(pin), (msg.getInt(0) > 0)? HIGH: LOW);
} //otherwise it's an analog read
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
#ifdef BOARD_HAS_ANALOG_PULLUP
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(analogInputToDigitalPin(pin), INPUT_PULLUP);
//setup the output address which should be /a/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the analog read and send the results
{
OSCMessage msgOut(outputAddress); msgOut.add((int32_t)analogRead(pin));
SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket();
}
} //else without a pullup
#endif
else {
//set the pinmode
// This fails on Arduino 1.04 on Leanardo, I added this to fix it: #define analogInputToDigitalPin(p) (p+18)
pinMode(analogInputToDigitalPin(pin), INPUT);
//setup the output address which should be /a/(pin)
char outputAddress[6];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
//do the analog read and send the results
{
OSCMessage msgOut(outputAddress); msgOut.add((int32_t)analogRead(pin));
SLIPSerial.beginPacket(); msgOut.send(SLIPSerial); SLIPSerial.endPacket();
}
}
}
}
}
#ifdef BOARD_HAS_TONE
/**
* TONE
*
* square wave output "/tone"
*
* format:
* /tone/pin
*
* (digital value) (float value) = frequency in Hz
* (no value) disable tone
*
**/
void routeTone(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
unsigned int frequency = 0;
//if it has an int, then it's an integers frequency in Hz
if (msg.isInt(0)){
frequency = msg.getInt(0);
} //otherwise it's a floating point frequency in Hz
else if(msg.isFloat(0)){
frequency = msg.getFloat(0);
}
else
noTone(pin);
if(frequency>0)
{
if(msg.isInt(1))
tone(pin, frequency, msg.getInt(1));
else
tone(pin, frequency);
}
}
}
}
#endif
/**
* SYSTEM MESSAGES
*
* expected format:
* /s
* /m = microseconds
* /d = number of digital pins
* /a = number of analog pins
* /l integer = set the led
* /t = temperature
* /s = power supply voltage
*/
//
void routeSystem(OSCMessage &msg, int addrOffset ){
#ifdef BOARD_HAS_DIE_TEMPERATURE_SENSOR
if (msg.fullMatch("/t", addrOffset)){
{ OSCMessage msgOut("/s/t"); msgOut.add(getTemperature()); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
#endif
#ifdef BOARD_HAS_DIE_POWER_SUPPLY_MEASUREMENT
if (msg.fullMatch("/s", addrOffset)){
{ OSCMessage msgOut("/s/s"); msgOut.add(getSupplyVoltage()); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
#endif
if (msg.fullMatch("/m", addrOffset)){
{ OSCMessage msgOut("/s/m"); msgOut.add((int32_t)micros()); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
if (msg.fullMatch("/d", addrOffset)){
{ OSCMessage msgOut("/s/d"); msgOut.add(NUM_DIGITAL_PINS); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
if (msg.fullMatch("/a", addrOffset)){
{ OSCMessage msgOut("/s/a"); msgOut.add(NUM_ANALOG_INPUTS); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
if (msg.fullMatch("/l", addrOffset)){
if (msg.isInt(0)){
pinMode(LED_BUILTIN, OUTPUT);
int i = msg.getInt(0);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, (i > 0)? HIGH: LOW);
{ OSCMessage msgOut("/s/l"); msgOut.add(i); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
}
}
/**
* MAIN METHODS
*
* setup and loop, bundle receiving/sending, initial routing
*/
void setup() {
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
}
//reads and routes the incoming messages
void loop(){
OSCBundle bundleIN;
int size;
while(!SLIPSerial.endofPacket())
if ((size =SLIPSerial.available()) > 0)
{
while(size--)
bundleIN.fill(SLIPSerial.read());
}
if(!bundleIN.hasError())
{
bundleIN.route("/s", routeSystem);
bundleIN.route("/a", routeAnalog);
bundleIN.route("/d", routeDigital);
#ifdef BOARD_HAS_TONE
bundleIN.route("/tone", routeTone);
#endif
#ifdef BOARD_HAS_CAPACITANCE_SENSING
bundleIN.route("/c", routeTouch);
#endif
}
}

View File

@ -0,0 +1,311 @@
#include <OSCBundle.h>
#include <OSCBoards.h>
#include "Adafruit_FreeTouch.h"
#include <SLIPEncodedSerial.h>
Adafruit_FreeTouch qt_0 = Adafruit_FreeTouch(A0, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE);
Adafruit_FreeTouch qt_1 = Adafruit_FreeTouch(A1, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE);
Adafruit_FreeTouch qt_2 = Adafruit_FreeTouch(A2, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE);
Adafruit_FreeTouch *p[3] = { &qt_0, &qt_1, &qt_2 };
#undef NUM_DIGITAL_PINS
#define NUM_DIGITAL_PINS 3
#undef NUM_ANALOG_PINS
#define NUM_ANALOG_PINS 3
SLIPEncodedUSBSerial SLIPSerial( Serial );
//outgoing messages
OSCBundle bundleOUT;
//converts the pin to an osc address
char * numToOSCAddress( int pin){
static char s[10];
int i = 9;
s[i--]= '\0';
do
{
s[i] = "0123456789"[pin % 10];
--i;
pin /= 10;
}
while(pin && i);
s[i] = '/';
return &s[i];
}
/**
* ROUTES
*
* these are where the routing functions go
*
*/
/**
* DIGITAL
*
* called when address matched "/d"
* expected format:
* /d/(pin)
* /u = digitalRead with pullup
* (no value) = digitalRead without pullup
* (value) = digital write on that pin
*
*/
void routeDigital(OSCMessage &msg, int addrOffset ){
//match input or output
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(pin, OUTPUT);
digitalWrite(pin, (msg.getInt(0)>0) ? HIGH:LOW);
}
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
//otherwise it's an digital read
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(pin, INPUT_PULLUP);
//setup the output address which should be /d/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the digital read and send the results
bundleOUT.add(outputAddress).add(digitalRead(pin));
} //else without a pullup
else {
//set the pinmode
pinMode(pin, INPUT);
//setup the output address which should be /d/(pin)
char outputAddress[6];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
//do the digital read and send the results
bundleOUT.add(outputAddress).add(digitalRead(pin));
}
}
}
}
/**
* ANALOG
*
* called when the address matches "/a"
*
* format:
* /a/(pin)
* /u = analogRead with pullup
* (no value) = analogRead without pullup
* (digital value) = digital write on that pin
* (float value) = analogWrite on that pin
*
**/
void routeAnalog(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_ANALOG_INPUTS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(analogInputToDigitalPin(pin), OUTPUT);
digitalWrite(analogInputToDigitalPin(pin), (msg.getInt(0) > 0)? HIGH: LOW);
}
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
#ifdef BOARD_HAS_ANALOG_PULLUP
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(analogInputToDigitalPin(pin), INPUT_PULLUP);
//setup the output address which should be /a/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the analog read and send the results
bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
} //else without a pullup
#endif
else {
//otherwise it's an analog read
//set the pinmode
pinMode(analogInputToDigitalPin(pin), INPUT);
//setup the output address which should be /a/(pin)
char outputAddress[6];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
//do the analog read and send the results
bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
}
}
}
}
#if 1
/**
* TONE
*
* square wave output "/tone"
*
* format:
* /tone/pin
*
* (digital value) (float value) = frequency in Hz
* (no value) disable tone
*
**/
void routeTone(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
unsigned int frequency = 0;
//if it has an int, then it's an integers frequency in Hz
if (msg.isInt(0)){
frequency = msg.getInt(0);
} //otherwise it's a floating point frequency in Hz
else if(msg.isFloat(0)){
frequency = msg.getFloat(0);
}
else
noTone(pin);
if(frequency>0)
{
if(msg.isInt(1))
tone(pin, frequency, msg.getInt(1));
else
tone(pin, frequency);
}
}
}
}
#endif
void routeTouch(OSCMessage &msg, int addrOffset )
{
for(int i=0;i<3;++i)
{
const char *name = numToOSCAddress(i);
int pinMatched = msg.match(name, addrOffset);
if(pinMatched && p[i])
{
char outputAddress[9];
strcpy(outputAddress, "/c");
strcat(outputAddress, name);
bundleOUT.add(outputAddress).add(p[i]->measure());
}
}
}
/**
* SYSTEM MESSAGES
*
* expected format:
* /s
* /m = microseconds
* /d = number of digital pins
* /a = number of analog pins
* /l integer = set the led
* /t = temperature
* /s = power supply voltage
*/
//
void routeSystem(OSCMessage &msg, int addrOffset ){
if (msg.fullMatch("/m", addrOffset)){
bundleOUT.add("/s/m").add((int32_t)micros());
}
if (msg.fullMatch("/d", addrOffset)){
bundleOUT.add("/s/d").add(NUM_DIGITAL_PINS);
}
if (msg.fullMatch("/a", addrOffset)){
bundleOUT.add("/s/a").add(NUM_ANALOG_INPUTS);
}
if (msg.fullMatch("/l", addrOffset)){
if (msg.isInt(0)){
pinMode(LED_BUILTIN, OUTPUT);
int i = msg.getInt(0);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, (i > 0)? HIGH: LOW);
bundleOUT.add("/s/l").add(i);
}
}
}
/**
* MAIN METHODS
*
* setup and loop, bundle receiving/sending, initial routing
*/
void setup() {
SLIPSerial.begin(115200); // set this as high as you can reliably run on your platform
for(int i=0; i<3; ++i)
if(!p[i]->begin())
p[i] =0;
}
//reads and routes the incoming messages
void loop(){
OSCBundle bundleIN;
int size;
while(!SLIPSerial.endofPacket())
if ((size =SLIPSerial.available()) > 0)
{
while(size--)
bundleIN.fill(SLIPSerial.read());
}
if(!bundleIN.hasError())
{
bundleIN.route("/s", routeSystem);
bundleIN.route("/a", routeAnalog);
bundleIN.route("/d", routeDigital);
bundleIN.route("/tone", routeTone);
bundleIN.route("/c", routeTouch);
}
bundleIN.empty();
//send the outgoing message
SLIPSerial.beginPacket();
bundleOUT.send(SLIPSerial);
SLIPSerial.endPacket();
bundleOUT.empty();
}

View File

@ -0,0 +1,323 @@
#include <OSCBundle.h>
#include <OSCBoards.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
//outgoing messages
OSCBundle bundleOUT;
//converts the pin to an osc address
char * numToOSCAddress( int pin){
static char s[10];
int i = 9;
s[i--]= '\0';
do
{
s[i] = "0123456789"[pin % 10];
--i;
pin /= 10;
}
while(pin && i);
s[i] = '/';
return &s[i];
}
/**
* ROUTES
*
* these are where the routing functions go
*
*/
/**
* DIGITAL
*
* called when address matched "/d"
* expected format:
* /d/(pin)
* /u = digitalRead with pullup
* (no value) = digitalRead without pullup
* (value) = digital write on that pin
*
*/
void routeDigital(OSCMessage &msg, int addrOffset ){
//match input or output
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(pin, OUTPUT);
digitalWrite(pin, (msg.getInt(0)>0) ? HIGH:LOW);
}
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
//otherwise it's an digital read
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(pin, INPUT_PULLUP);
//setup the output address which should be /d/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the digital read and send the results
bundleOUT.add(outputAddress).add(digitalRead(pin));
} //else without a pullup
else {
//set the pinmode
pinMode(pin, INPUT);
//setup the output address which should be /d/(pin)
char outputAddress[6];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
//do the digital read and send the results
bundleOUT.add(outputAddress).add(digitalRead(pin));
}
}
}
}
/**
* ANALOG
*
* called when the address matches "/a"
*
* format:
* /a/(pin)
* /u = analogRead with pullup
* (no value) = analogRead without pullup
* (digital value) = digital write on that pin
* (float value) = analogWrite on that pin
*
**/
void routeAnalog(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_ANALOG_INPUTS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(analogInputToDigitalPin(pin), OUTPUT);
digitalWrite(analogInputToDigitalPin(pin), (msg.getInt(0) > 0)? HIGH: LOW);
}
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
#ifdef BOARD_HAS_ANALOG_PULLUP
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(analogInputToDigitalPin(pin), INPUT_PULLUP);
//setup the output address which should be /a/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the analog read and send the results
bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
} //else without a pullup
#endif
else {
//otherwise it's an analog read
//set the pinmode
pinMode(analogInputToDigitalPin(pin), INPUT);
//setup the output address which should be /a/(pin)
char outputAddress[6];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
//do the analog read and send the results
bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
}
}
}
}
#ifdef BOARD_HAS_TONE
/**
* TONE
*
* square wave output "/tone"
*
* format:
* /tone/pin
*
* (digital value) (float value) = frequency in Hz
* (no value) disable tone
*
**/
void routeTone(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
unsigned int frequency = 0;
//if it has an int, then it's an integers frequency in Hz
if (msg.isInt(0)){
frequency = msg.getInt(0);
} //otherwise it's a floating point frequency in Hz
else if(msg.isFloat(0)){
frequency = msg.getFloat(0);
}
else
noTone(pin);
if(frequency>0)
{
if(msg.isInt(1))
tone(pin, frequency, msg.getInt(1));
else
tone(pin, frequency);
}
}
}
}
#endif
#ifdef BOARD_HAS_CAPACITANCE_SENSING
#if defined(__MKL26Z64__)
#define NTPINS 11
const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,3,4 };
#else
#define NTPINS 12
const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,25,32, 33 };
#endif
void routeTouch(OSCMessage &msg, int addrOffset )
{
for(int i=0;i<NTPINS;++i)
{
const char *name = numToOSCAddress(cpins[i]);
int pinMatched = msg.match(name, addrOffset);
if(pinMatched)
{
char outputAddress[9];
strcpy(outputAddress, "/c");
strcat(outputAddress, name);
bundleOUT.add(outputAddress).add(touchRead(cpins[i]));
}
}
}
#endif
/**
* SYSTEM MESSAGES
*
* expected format:
* /s
* /m = microseconds
* /d = number of digital pins
* /a = number of analog pins
* /l integer = set the led
* /t = temperature
* /s = power supply voltage
*/
//
void routeSystem(OSCMessage &msg, int addrOffset ){
#ifdef BOARD_HAS_DIE_TEMPERATURE_SENSOR
if (msg.fullMatch("/t", addrOffset)){
bundleOUT.add("/s/t").add(getTemperature());
}
#endif
#ifdef BOARD_HAS_DIE_POWER_SUPPLY_MEASUREMENT
if (msg.fullMatch("/s", addrOffset)){
bundleOUT.add("/s/s").add(getSupplyVoltage());
}
#endif
if (msg.fullMatch("/m", addrOffset)){
bundleOUT.add("/s/m").add((int32_t)micros());
}
if (msg.fullMatch("/d", addrOffset)){
bundleOUT.add("/s/d").add(NUM_DIGITAL_PINS);
}
if (msg.fullMatch("/a", addrOffset)){
bundleOUT.add("/s/a").add(NUM_ANALOG_INPUTS);
}
if (msg.fullMatch("/l", addrOffset)){
if (msg.isInt(0)){
pinMode(LED_BUILTIN, OUTPUT);
int i = msg.getInt(0);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, (i > 0)? HIGH: LOW);
bundleOUT.add("/s/l").add(i);
}
}
}
/**
* MAIN METHODS
*
* setup and loop, bundle receiving/sending, initial routing
*/
void setup() {
SLIPSerial.begin(115200); // set this as high as you can reliably run on your platform
}
//reads and routes the incoming messages
void loop(){
OSCBundle bundleIN;
int size;
while(!SLIPSerial.endofPacket())
if ((size =SLIPSerial.available()) > 0)
{
while(size--)
bundleIN.fill(SLIPSerial.read());
}
if(!bundleIN.hasError())
{
bundleIN.route("/s", routeSystem);
bundleIN.route("/a", routeAnalog);
bundleIN.route("/d", routeDigital);
#ifdef BOARD_HAS_TONE
bundleIN.route("/tone", routeTone);
#endif
#ifdef BOARD_HAS_CAPACITANCE_SENSING
bundleIN.route("/c", routeTouch);
#endif
}
bundleIN.empty();
//send the outgoing message
SLIPSerial.beginPacket();
bundleOUT.send(SLIPSerial);
SLIPSerial.endPacket();
bundleOUT.empty();
}

View File

@ -0,0 +1,338 @@
#include <OSCBundle.h>
#include <OSCBoards.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
//converts the pin to an osc address
char * numToOSCAddress( int pin){
static char s[10];
int i = 9;
s[i--]= '\0';
do
{
s[i] = "0123456789"[pin % 10];
--i;
pin /= 10;
}
while(pin && i);
s[i] = '/';
return &s[i];
}
/**
* ROUTES
*
* these are where the routing functions go
*
*/
/**
* DIGITAL
*
* called when address matched "/d"
* expected format:
* /d/(pin)
* /u = digitalRead with pullup
* (no value) = digitalRead without pullup
* (value) = digital write on that pin
*
*/
void routeDigital(OSCMessage &msg, int addrOffset ){
//match input or output
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(pin, OUTPUT);
digitalWrite(pin, (msg.getInt(0)>0) ? HIGH:LOW);
} //otherwise it's an analog read
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
//otherwise it's an digital read
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(pin, INPUT_PULLUP);
//setup the output address which should be /d/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the digital read and send the results
{
OSCMessage msgOut(outputAddress); msgOut.add(digitalRead(pin));
SLIPSerial.beginPacket(); msgOut.send(SLIPSerial); SLIPSerial.endPacket();
}
} //else without a pullup
else {
//set the pinmode
pinMode(pin, INPUT);
//setup the output address which should be /d/(pin)
char outputAddress[6];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
//do the digital read and send the results
{
OSCMessage msgOut(outputAddress); msgOut.add(digitalRead(pin));
SLIPSerial.beginPacket(); msgOut.send(SLIPSerial); SLIPSerial.endPacket();
}
}
}
}
}
/**
* ANALOG
*
* called when the address matches "/a"
*
* format:
* /a/(pin)
* /u = analogRead with pullup
* (no value) = analogRead without pullup
* (digital value) = digital write on that pin
* (float value) = analogWrite on that pin
*
**/
void routeAnalog(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_ANALOG_INPUTS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(analogInputToDigitalPin(pin), OUTPUT);
digitalWrite(analogInputToDigitalPin(pin), (msg.getInt(0) > 0)? HIGH: LOW);
} //otherwise it's an analog read
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
#ifdef BOARD_HAS_ANALOG_PULLUP
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(analogInputToDigitalPin(pin), INPUT_PULLUP);
//setup the output address which should be /a/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the analog read and send the results
{
OSCMessage msgOut(outputAddress); msgOut.add((int32_t)analogRead(pin));
SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket();
}
} //else without a pullup
#endif
else {
//set the pinmode
// This fails on Arduino 1.04 on Leanardo, I added this to fix it: #define analogInputToDigitalPin(p) (p+18)
pinMode(analogInputToDigitalPin(pin), INPUT);
//setup the output address which should be /a/(pin)
char outputAddress[6];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
//do the analog read and send the results
{
OSCMessage msgOut(outputAddress); msgOut.add((int32_t)analogRead(pin));
SLIPSerial.beginPacket(); msgOut.send(SLIPSerial); SLIPSerial.endPacket();
}
}
}
}
}
#ifdef BOARD_HAS_TONE
/**
* TONE
*
* square wave output "/tone"
*
* format:
* /tone/pin
*
* (digital value) (float value) = frequency in Hz
* (no value) disable tone
*
**/
void routeTone(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
unsigned int frequency = 0;
//if it has an int, then it's an integers frequency in Hz
if (msg.isInt(0)){
frequency = msg.getInt(0);
} //otherwise it's a floating point frequency in Hz
else if(msg.isFloat(0)){
frequency = msg.getFloat(0);
}
else
noTone(pin);
if(frequency>0)
{
if(msg.isInt(1))
tone(pin, frequency, msg.getInt(1));
else
tone(pin, frequency);
}
}
}
}
#endif
#ifdef BOARD_HAS_CAPACITANCE_SENSING
#if defined(__MKL26Z64__)
// teensy 3.0LC
#define NTPINS 11
const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,3,4 };
#elif defined(__MK66FX1M0__)
// teensy 3.6
#define NTPINS 12
const int cpins[NTPINS] = {0,1,14,15,16,17,18,19,22,23,29,30 };
#else
//Teensy 3.1 3.2
#define NTPINS 12
const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,25,32, 33 };
#endif
void routeTouch(OSCMessage &msg, int addrOffset )
{
for(int i=0;i<NTPINS;++i)
{
const char *name = numToOSCAddress(cpins[i]);
int pinMatched = msg.match(name, addrOffset);
if(pinMatched)
{
char outputAddress[9];
strcpy(outputAddress, "/c");
strcat(outputAddress, name);
{
OSCMessage msgOut(outputAddress); msgOut.add(touchRead(cpins[i]));
SLIPSerial.beginPacket(); msgOut.send(SLIPSerial); SLIPSerial.endPacket();
}
}
}
}
#endif
/**
* SYSTEM MESSAGES
*
* expected format:
* /s
* /m = microseconds
* /d = number of digital pins
* /a = number of analog pins
* /l integer = set the led
* /t = temperature
* /s = power supply voltage
*/
//
void routeSystem(OSCMessage &msg, int addrOffset ){
#ifdef BOARD_HAS_DIE_TEMPERATURE_SENSOR
if (msg.fullMatch("/t", addrOffset)){
{ OSCMessage msgOut("/s/t"); msgOut.add(getTemperature()); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
#endif
#ifdef BOARD_HAS_DIE_POWER_SUPPLY_MEASUREMENT
if (msg.fullMatch("/s", addrOffset)){
{ OSCMessage msgOut("/s/s"); msgOut.add(getSupplyVoltage()); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
#endif
if (msg.fullMatch("/m", addrOffset)){
{ OSCMessage msgOut("/s/m"); msgOut.add((int32_t)micros()); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
if (msg.fullMatch("/d", addrOffset)){
{ OSCMessage msgOut("/s/d"); msgOut.add(NUM_DIGITAL_PINS); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
if (msg.fullMatch("/a", addrOffset)){
{ OSCMessage msgOut("/s/a"); msgOut.add(NUM_ANALOG_INPUTS); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
if (msg.fullMatch("/l", addrOffset)){
if (msg.isInt(0)){
pinMode(LED_BUILTIN, OUTPUT);
int i = msg.getInt(0);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, (i > 0)? HIGH: LOW);
{ OSCMessage msgOut("/s/l"); msgOut.add(i); SLIPSerial.beginPacket();msgOut.send(SLIPSerial); SLIPSerial.endPacket(); }
}
}
}
/**
* MAIN METHODS
*
* setup and loop, bundle receiving/sending, initial routing
*/
void setup() {
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
}
//reads and routes the incoming messages
void loop(){
OSCBundle bundleIN;
int size;
while(!SLIPSerial.endofPacket())
if ((size =SLIPSerial.available()) > 0)
{
while(size--)
bundleIN.fill(SLIPSerial.read());
}
if(!bundleIN.hasError())
{
bundleIN.route("/s", routeSystem);
bundleIN.route("/a", routeAnalog);
bundleIN.route("/d", routeDigital);
#ifdef BOARD_HAS_TONE
bundleIN.route("/tone", routeTone);
#endif
#ifdef BOARD_HAS_CAPACITANCE_SENSING
bundleIN.route("/c", routeTouch);
#endif
}
}

View File

@ -0,0 +1,66 @@
/*
* Set the LED according to incoming OSC control
*/
#include <OSCBundle.h>
#include <OSCBoards.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
void LEDcontrol(OSCMessage &msg)
{
if (msg.isInt(0))
{
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, (msg.getInt(0) > 0)? HIGH: LOW);
}
else if(msg.isString(0))
{
int length=msg.getDataLength(0);
if(length<5)
{
char str[length];
msg.getString(0,str,length);
if((strcmp("on", str)==0)|| (strcmp("On",str)==0))
{
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
}
else if((strcmp("Of", str)==0)|| (strcmp("off",str)==0))
{
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
}
}
}
}
void setup() {
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
}
//reads and dispatches the incoming message
void loop(){
OSCBundle bundleIN;
int size;
while(!SLIPSerial.endofPacket())
if( (size =SLIPSerial.available()) > 0)
{
while(size--)
bundleIN.fill(SLIPSerial.read());
}
if(!bundleIN.hasError())
bundleIN.dispatch("/led", LEDcontrol);
}

View File

@ -0,0 +1,77 @@
/*
* Blink the LED according to incoming OSC on/off rates in quasi-asynchronous way
*/
#include <OSCBoards.h>
#include <OSCBundle.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
constexpr unsigned long blinkInterval = 2500;
unsigned long blinkNow;
unsigned long blinkRateOn = 50;
unsigned long blinkRateOff = 50;
void LEDcontrol(OSCMessage& msg)
{
if (msg.isInt(0)) {
blinkRateOn = msg.getInt(0);
}
if (msg.isInt(1)) {
blinkRateOff = msg.getInt(1);
}
}
void setup()
{
Serial.begin(9600);
const unsigned long startNow = millis() + 5000;
while(!Serial && millis() < startNow);
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
blinkNow = millis() + blinkInterval;
}
//reads and dispatches the incoming message
void loop()
{
OSCBundle bundleIN;
int size;
if (SLIPSerial.available())
while (!SLIPSerial.endofPacket())
while (SLIPSerial.available())
bundleIN.fill(SLIPSerial.read());
if (!bundleIN.hasError())
bundleIN.dispatch("/led", LEDcontrol);
if (millis() >= blinkNow) {
pinMode(LED_BUILTIN, OUTPUT);
Serial.print("Blinking at ");
Serial.print(blinkRateOn);
Serial.print("/");
Serial.print(blinkRateOff);
Serial.println();
for (auto i = 0; i <= 5; i ++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(blinkRateOn);
digitalWrite(LED_BUILTIN, LOW);
delay(blinkRateOff);
}
// blinkNow = millis() + blinkInterval;
blinkNow = millis() + blinkInterval - 5 * (blinkRateOn + blinkRateOff);
}
}

View File

@ -0,0 +1,67 @@
/*
* Control a servo according to incoming OSC control
*
*/
#include <OSCBundle.h>
#include <OSCBoards.h>
#include <Servo.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
Servo myservo;
void servoControl(OSCMessage &msg)
{
if (msg.isInt(0))
{
myservo.write(msg.getInt(0));
}
#ifdef TEMPoraray
else if (msg.isFloat(0))
{
//test if that pin is a PWM
if (digitalPinHasPWM(LED_BUILTIN))
{
pinMode(LED_BUILTIN, OUTPUT);
analogWrite(LED_BUILTIN, (int)(msg.getFloat(0)*127.0f));
}
else
SoftPWMSet(LED_BUILTIN, (int)(msg.getFloat(0)*127.0f));
}
#endif
}
void setup() {
SLIPSerial.begin(9600);
myservo.attach(13);
myservo.write(90);
}
//reads and dispatches the incoming message
void loop(){
OSCBundle bundleIN;
int size;
while(!SLIPSerial.endofPacket())
if( (size =SLIPSerial.available()) > 0)
{
while(size--)
bundleIN.fill(SLIPSerial.read());
}
if(!bundleIN.hasError())
bundleIN.dispatch("/servo", servoControl);
}

View File

@ -0,0 +1,47 @@
/*
Make an OSC bundle and send it over SLIP serial
OSCBundles allow OSCMessages to be grouped together to preserve the order and completeness of related messages.
They also allow for timetags to be carried to represent the presentation time of the messages.
*/
#include <OSCBundle.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
void setup() {
//begin SLIPSerial just like Serial
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
}
void loop(){
//declare the bundle
OSCBundle bndl;
//BOSCBundle's add' returns the OSCMessage so the message's 'add' can be composed together
bndl.add("/analog/0").add((int32_t)analogRead(0));
bndl.add("/analog/1").add((int32_t)analogRead(1));
bndl.add("/digital/5").add((digitalRead(5)==HIGH)?"HIGH":"LOW");
SLIPSerial.beginPacket();
bndl.send(SLIPSerial); // send the bytes to the SLIP stream
SLIPSerial.endPacket(); // mark the end of the OSC Packet
bndl.empty(); // empty the bundle to free room for a new one
bndl.add("/mouse/step").add((int32_t)analogRead(0)).add((int32_t)analogRead(1));
bndl.add("/units").add("pixels");
SLIPSerial.beginPacket();
bndl.send(SLIPSerial); // send the bytes to the SLIP stream
SLIPSerial.endPacket(); // mark the end of the OSC Packet
bndl.empty(); // empty the bundle to free room for a new one
delay(100);
}

View File

@ -0,0 +1,47 @@
/*
Make an OSC bundle and send it over SLIP serial
OSCBundles allow OSCMessages to be grouped together to preserve the order and completeness of related messages.
They also allow for timetags to be carried to represent the presentation time of the messages.
*/
#include <OSCBundle.h>
#include <OSCBoards.h>
#include <OSCTiming.h>
#include <SLIPEncodedSerial.h>
#ifdef BOARD_HAS_USB_SERIAL
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
void setup() {
//begin SLIPSerial just like Serial
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
}
void loop(){
//declare the bundle
OSCBundle bndl;
osctime_t timetag;
//OSCBundle's add' returns the OSCMessage so the message's 'add' can be composed together
bndl.add("/analog/0").add((int32_t)adcRead(0, &timetag));
bndl.add("/analog/0/time").add(timetag);
bndl.add("/analog/1").add((int32_t)adcRead(1, &timetag));
bndl.add("/analog/1/time").add(timetag);
bndl.add("/digital/5").add((digitalRead(5)==HIGH)?"HIGH":"LOW");
SLIPSerial.beginPacket();
bndl.setTimetag(oscTime());
bndl.send(SLIPSerial); // send the bytes to the SLIP stream
SLIPSerial.endPacket(); // mark the end of the OSC Packet
bndl.empty(); // empty the bundle to free room for a new one
delay(100);
}

View File

@ -0,0 +1,33 @@
#include <OSCMessage.h>
#include <OSCBoards.h>
/*
Make an OSC message and send it over serial
*/
#ifdef BOARD_HAS_USB_SERIAL
#include <SLIPEncodedUSBSerial.h>
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
#else
#include <SLIPEncodedSerial.h>
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
void setup() {
//begin SLIPSerial just like Serial
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
}
void loop(){
//the message wants an OSC address as first argument
OSCMessage msg("/analog/0");
msg.add((int32_t)analogRead(0));
SLIPSerial.beginPacket();
msg.send(SLIPSerial); // send the bytes to the SLIP stream
SLIPSerial.endPacket(); // mark the end of the OSC Packet
msg.empty(); // free space occupied by message
delay(20);
}

View File

@ -0,0 +1,44 @@
/*
* Make an OSC message for controlling a remote LED blinking rates.
*/
#include <OSCBoards.h>
#include <OSCMessage.h>
#ifdef BOARD_HAS_USB_SERIAL
#include <SLIPEncodedUSBSerial.h>
SLIPEncodedUSBSerial SLIPSerial(thisBoardsSerialUSB);
#else
#include <SLIPEncodedSerial.h>
SLIPEncodedSerial SLIPSerial(Serial1); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that dont have Serial
#endif
constexpr auto blinkRatesSize = 8;
int blinkRates[blinkRatesSize] = { 25, 50, 100, 125, 150, 175, 200, 225 };
void setup()
{
//begin SLIPSerial just like Serial
SLIPSerial.begin(9600); // set this as high as you can reliably run on your platform
}
void loop()
{
//the message wants an OSC address as first argument
OSCMessage msg("/led");
auto i = rand() % (blinkRatesSize - 1);
auto blinkRateOn = blinkRates[i];
auto j = rand() % (blinkRatesSize - 1);
auto blinkRateOff = blinkRates[j];
msg.add(blinkRateOn).add(blinkRateOff);
SLIPSerial.beginPacket();
msg.send(SLIPSerial); // send the bytes to the SLIP stream
SLIPSerial.endPacket(); // mark the end of the OSC Packet
msg.empty(); // free space occupied by message
delay(20);
}

View File

@ -0,0 +1,164 @@
/*
UDP Call Response
Send responses to calls for information from a remote host
*/
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>
#include <OSCBundle.h>
#include <OSCBoards.h>
//UDP communication
EthernetUDP Udp;
//the Arduino's IP
IPAddress ip(128, 32, 122, 252);
//port numbers
const unsigned int inPort = 8888;
const unsigned int outPort = 9999;
//everything on the network needs a unique MAC
#if defined(__MK20DX128__)
// Teensy 3 has MAC burned in
static byte mac[6];
void read(uint8_t word, uint8_t *mac, uint8_t offset) {
FTFL_FCCOB0 = 0x41; // Selects the READONCE command
FTFL_FCCOB1 = word; // read the given word of read once area
// launch command and wait until complete
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF));
*(mac+offset) = FTFL_FCCOB5; // collect only the top three bytes,
*(mac+offset+1) = FTFL_FCCOB6; // in the right orientation (big endian).
*(mac+offset+2) = FTFL_FCCOB7; // Skip FTFL_FCCOB4 as it's always 0.
}
void read_mac() {
read(0xe,mac,0);
read(0xf,mac,3);
}
#else
void read_mac() {}
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // you can find this written on the board of some Arduino Ethernets or shields
#endif
//outgoing messages
OSCBundle bundleOUT;
//converts the pin to an osc address
char * numToOSCAddress( int pin){
static char s[10];
int i = 9;
s[i--]= '\0';
do
{
s[i] = "0123456789"[pin % 10];
--i;
pin /= 10;
}
while(pin && i);
s[i] = '/';
return &s[i];
}
/**
* ANALOG
*
* called when the address matches "/a"
*
* format:
* /analog/(pin)
* /u = analogRead with pullup
*
**/
void routeAnalog(OSCMessage &msg, int addrOffset ){
int pinMatched;
pinMatched = msg.match("/0", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(0), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/0").add((int32_t)analogRead(0));
}
pinMatched = msg.match("/1", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(1), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/1").add((int32_t)analogRead(1));
}
pinMatched = msg.match("/2", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(2), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/2").add((int32_t)analogRead(2));
}
pinMatched = msg.match("/3", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(3), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/3").add((int32_t)analogRead(3));
}
pinMatched = msg.match("/4", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(4), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/4").add((int32_t)analogRead(4));
}
pinMatched = msg.match("/5", addrOffset);
if(pinMatched){
if (msg.fullMatch("/u", pinMatched+addrOffset)) pinMode(analogInputToDigitalPin(5), INPUT_PULLUP); //set the pullup
//do the analog read and send the results
bundleOUT.add("/analog/5").add((int32_t)analogRead(5));
}
}
/**
* MAIN METHODS
*
* setup and loop, bundle receiving/sending, initial routing
*/
void setup() {
//setup ethernet part
read_mac();
Ethernet.begin(mac,ip);
Udp.begin(inPort);
}
//reads and routes the incoming messages
void loop(){
OSCBundle bundleIN;
int size;
if( (size = Udp.parsePacket())>0)
{
// unsigned int outPort = Udp.remotePort();
while(size--)
bundleIN.fill(Udp.read());
if(!bundleIN.hasError())
bundleIN.route("/analog", routeAnalog);
// send the response bundle back to where the request came from
Udp.beginPacket(Udp.remoteIP(), outPort);
bundleOUT.send(Udp);
Udp.endPacket();
bundleOUT.empty(); // empty the bundle ready to use for new messages
}
}

View File

@ -0,0 +1,84 @@
/*
Leverage the UDP source IP and port calls to
return OSC information back
This example can be extended to build routers and forwarders of OSC packets
*/
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>
#include <OSCBundle.h>
EthernetUDP Udp;
//the Arduino's IP
IPAddress ip(128, 32, 122, 252);
//port numbers
const unsigned int inPort = 8888;
const unsigned int outPort = 9999;
//everything on the network needs a unique MAC
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
// Teensy 3.x has MAC burned in
static byte mac[6];
void read(uint8_t word, uint8_t *mac, uint8_t offset) {
  FTFL_FCCOB0 = 0x41;             // Selects the READONCE command
  FTFL_FCCOB1 = word;             // read the given word of read once area
  // launch command and wait until complete
  FTFL_FSTAT = FTFL_FSTAT_CCIF;
  while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF));
  *(mac+offset) =   FTFL_FCCOB5;       // collect only the top three bytes,
  *(mac+offset+1) = FTFL_FCCOB6;       // in the right orientation (big endian).
  *(mac+offset+2) = FTFL_FCCOB7;       // Skip FTFL_FCCOB4 as it's always 0.
}
void read_mac() {
  read(0xe,mac,0);
  read(0xf,mac,3);
}
#else
void read_mac() {}
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // you can find this written on the board of some Arduino Ethernets or shields
#endif
void setup() {
Ethernet.begin(mac,ip);
Udp.begin(inPort);
}
void loop(){
OSCBundle bndl;
int size;
//receive a bundle
if( (size = Udp.parsePacket())>0)
{
// unsigned int outPort = Udp.remotePort();
while(size--)
bndl.fill(Udp.read());
if(!bndl.hasError())
{
//and echo it back
if(bndl.size() > 0)
{
static int32_t sequencenumber=0;
// we can sneak an addition onto the end of the bundle
bndl.add("/micros").add((int32_t)micros()); // (int32_t) is the type of OSC Integers
bndl.add("/sequencenumber").add(sequencenumber++);
Udp.beginPacket(Udp.remoteIP(), outPort);
bndl.send(Udp);
Udp.endPacket();
}
}
}
}

View File

@ -0,0 +1,378 @@
// UDP OSCuino
// system, analog and digital pin control and monitoring for Arduino
// Yotam Mann and Adrian Freed
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>
#include <OSCBundle.h>
#include <OSCBoards.h>
EthernetUDP Udp;
//the Arduino's IP
IPAddress ip(128, 32, 122, 252);
//port numbers
const unsigned int inPort = 8888;
const unsigned int outPort = 9999;
//everything on the network needs a unique MAC
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK66FX1M0__)
// Teensy 3 has MAC burned in
static byte mac[6];
void read(uint8_t word, uint8_t *mac, uint8_t offset) {
FTFL_FCCOB0 = 0x41; // Selects the READONCE command
FTFL_FCCOB1 = word; // read the given word of read once area
// launch command and wait until complete
FTFL_FSTAT = FTFL_FSTAT_CCIF;
while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF));
*(mac+offset) = FTFL_FCCOB5; // collect only the top three bytes,
*(mac+offset+1) = FTFL_FCCOB6; // in the right orientation (big endian).
*(mac+offset+2) = FTFL_FCCOB7; // Skip FTFL_FCCOB4 as it's always 0.
}
void read_mac() {
read(0xe,mac,0);
read(0xf,mac,3);
}
#else
void read_mac() {}
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // you can find this written on the board of some Arduino Ethernets or shields
#endif
//outgoing messages
OSCBundle bundleOUT;
//converts the pin to an osc address
char * numToOSCAddress( int pin){
static char s[10];
int i = 9;
s[i--]= '\0';
do
{
s[i] = "0123456789"[pin % 10];
--i;
pin /= 10;
}
while(pin && i);
s[i] = '/';
return &s[i];
}
/**
* ROUTES
*
* these are where the routing functions go
*
*/
/**
* DIGITAL
*
* called when address matched "/d"
* expected format:
* /d/(pin)
* /u = digitalRead with pullup
* (no value) = digitalRead without pullup
* (value) = digital write on that pin
*
*/
void routeDigital(OSCMessage &msg, int addrOffset ){
//match input or output
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(pin, OUTPUT);
digitalWrite(pin, (msg.getInt(0)>0) ? HIGH:LOW);
} //otherwise it's an analog read
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
//otherwise it's an digital read
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(pin, INPUT_PULLUP);
//setup the output address which should be /d/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
//do the digital read and send the results
bundleOUT.add(outputAddress).add(digitalRead(pin));
} //else without a pullup
else {
//set the pinmode
pinMode(pin, INPUT);
//setup the output address which should be /d/(pin)
char outputAddress[6];
strcpy(outputAddress, "/d");
strcat(outputAddress, numToOSCAddress(pin));
//do the digital read and send the results
bundleOUT.add(outputAddress).add(digitalRead(pin));
}
}
}
}
/**
* ANALOG
*
* called when the address matches "/a"
*
* format:
* /a/(pin)
* /u = analogRead with pullup
* (no value) = analogRead without pullup
* (digital value) = digital write on that pin
* (float value) = analogWrite on that pin
*
**/
void routeAnalog(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_ANALOG_INPUTS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
//if it has an int, then it's a digital write
if (msg.isInt(0)){
pinMode(analogInputToDigitalPin(pin), OUTPUT);
digitalWrite(analogInputToDigitalPin(pin), (msg.getInt(0) > 0)? HIGH: LOW);
} //otherwise it's an analog read
else if(msg.isFloat(0)){
analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
}
#ifdef BOARD_HAS_ANALOG_PULLUP
//with a pullup?
else if (msg.fullMatch("/u", pinMatched+addrOffset)){
//set the pullup
pinMode(analogInputToDigitalPin(pin), INPUT_PULLUP);
//setup the output address which should be /a/(pin)/u
char outputAddress[9];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
strcat(outputAddress,"/u");
strcat(outputAddress,"/u");
//do the analog read and send the results
bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
} //else without a pullup
#endif
else {
//set the pinmode
pinMode(analogInputToDigitalPin(pin), INPUT);
//setup the output address which should be /a/(pin)
char outputAddress[6];
strcpy(outputAddress, "/a");
strcat(outputAddress, numToOSCAddress(pin));
//do the analog read and send the results
bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
}
}
}
}
#ifdef BOARD_HAS_TONE
/**
* TONE
*
* square wave output "/tone"
*
* format:
* /tone/pin
*
* (digital value) (float value) = frequency in Hz
* (no value) disable tone
*
**/
void routeTone(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
unsigned int frequency = 0;
//if it has an int, then it's an integers frequency in Hz
if (msg.isInt(0)){
frequency = msg.getInt(0);
} //otherwise it's a floating point frequency in Hz
else if(msg.isFloat(0)){
frequency = msg.getFloat(0);
}
else
noTone(pin);
if(frequency>0)
{
if(msg.isInt(1))
tone(pin, frequency, msg.getInt(1));
else
tone(pin, frequency);
}
}
}
}
#endif
#ifdef BOARD_HAS_CAPACITANCE_SENSING
#if defined(__MKL26Z64__)
// teensy 3.0LC
#define NTPINS 11
const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,3,4 };
#elif defined(__MK66FX1M0__)
// teensy 3.6
#define NTPINS 12
const int cpins[NTPINS] = {0,1,14,15,16,17,18,19,22,23,29,30 };
#else
//Teensy 3.1 3.2
#define NTPINS 12
const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,25,32, 33 };
#endif
void routeTouch(OSCMessage &msg, int addrOffset )
{
for(int i=0;i<NTPINS;++i)
{
const char *name = numToOSCAddress(cpins[i]);
int pinMatched = msg.match(name, addrOffset);
if(pinMatched)
{
char outputAddress[9];
strcpy(outputAddress, "/c");
strcat(outputAddress, name);
bundleOUT.add(outputAddress).add(touchRead(cpins[i]));
}
}
}
#endif
/**
* SYSTEM MESSAGES
*
* expected format:
* /s
* /m = microseconds
* /d = number of digital pins
* /a = number of analog pins
* /l integer = set the led
* /t = temperature
* /s = power supply voltage
*/
//
void routeSystem(OSCMessage &msg, int addrOffset ){
#ifdef BOARD_HAS_DIE_TEMPERATURE_SENSOR
if (msg.fullMatch("/t", addrOffset)){
bundleOUT.add("/s/t").add(getTemperature());
}
#endif
#ifdef BOARD_HAS_DIE_POWER_SUPPLY_MEASUREMENT
if (msg.fullMatch("/s", addrOffset)){
bundleOUT.add("/s/s").add(getSupplyVoltage());
}
#endif
if (msg.fullMatch("/m", addrOffset)){
bundleOUT.add("/s/m").add((int32_t)micros());
}
if (msg.fullMatch("/d", addrOffset)){
bundleOUT.add("/s/d").add(NUM_DIGITAL_PINS);
}
if (msg.fullMatch("/a", addrOffset)){
bundleOUT.add("/s/a").add(NUM_ANALOG_INPUTS);
}
// this is disabled because many ethernet boards use the
// LED pin for ethernet pin 13
#if LED_BUILTIN!=13
if (msg.fullMatch("/l", addrOffset)){
if (msg.isInt(0)){
pinMode(LED_BUILTIN, OUTPUT);
int i = msg.getInt(0);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, (i > 0)? HIGH: LOW);
bundleOUT.add("/s/l").add(i);
}
}
#endif
}
/**
* MAIN METHODS
*
* setup and loop, bundle receiving/sending, initial routing
*/
void setup() {
//setup ethernet port
read_mac();
Ethernet.begin(mac,ip);
Udp.begin(inPort);
}
//reads and routes the incoming messages
void loop(){
OSCBundle bundleIN;
int size;
if( (size = Udp.parsePacket())>0)
{
// unsigned int outPort = Udp.remotePort();
while(size--)
bundleIN.fill(Udp.read());
if(!bundleIN.hasError())
{
bundleIN.route("/s", routeSystem);
bundleIN.route("/a", routeAnalog);
bundleIN.route("/d", routeDigital);
#ifdef BOARD_HAS_TONE
bundleIN.route("/tone", routeTone);
#endif
#ifdef TOUCHSUPPORT
bundleIN.route("/c", routeTouch);
#endif
}
// send the response bundle back to where the request came from
Udp.beginPacket(Udp.remoteIP(),outPort);
bundleOUT.send(Udp);
Udp.endPacket();
bundleOUT.empty(); // empty the bundle ready to use for new messages
}
}

View File

@ -0,0 +1,106 @@
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>
#include <OSCBundle.h>
#include <OSCBoards.h>
/*
* UDPReceiveOSC
* Set a tone according to incoming OSC control
* Adrian Freed
*/
//UDP communication
EthernetUDP Udp;
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // you can find this written on the board of some Arduino Ethernets or shields
//the Arduino's IP
IPAddress ip(128, 32, 122, 252);
//port numbers
const unsigned int inPort = 8888;
//converts the pin to an osc address
char * numToOSCAddress( int pin){
static char s[10];
int i = 9;
s[i--]= '\0';
do
{
s[i] = "0123456789"[pin % 10];
--i;
pin /= 10;
}
while(pin && i);
s[i] = '/';
return &s[i];
}
/**
* TONE
*
* square wave output "/tone"
*
* format:
* /tone/pin
*
* (digital value) (float value) = frequency in Hz
* (no value) disable tone
*
**/
void routeTone(OSCMessage &msg, int addrOffset ){
//iterate through all the analog pins
for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
//match against the pin number strings
int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
if(pinMatched){
unsigned int frequency = 0;
//if it has an int, then it's an integers frequency in Hz
if (msg.isInt(0)){
frequency = msg.getInt(0);
} //otherwise it's a floating point frequency in Hz
else if(msg.isFloat(0)){
frequency = msg.getFloat(0);
}
else
noTone(pin);
if(frequency>0)
{
if(msg.isInt(1))
tone(pin, frequency, msg.getInt(1));
else
tone(pin, frequency);
}
}
}
}
void setup() {
//setup ethernet part
Ethernet.begin(mac,ip);
Udp.begin(inPort);
}
//reads and dispatches the incoming message
void loop(){
OSCBundle bundleIN;
int size;
if( (size = Udp.parsePacket())>0)
{
while(size--)
bundleIN.fill(Udp.read());
if(!bundleIN.hasError())
bundleIN.route("/tone", routeTone);
}
}

View File

@ -0,0 +1,55 @@
/*
Make an OSC bundle and send it over UDP
OSCBundles allow OSCMessages to be grouped together
to preserve the order and completeness of related messages.
They also allow for timetags to be carried to represent the presentation time
of the messages.
*/
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>
#include <OSCBundle.h>
EthernetUDP Udp;
//the Arduino's IP
IPAddress ip(128, 32, 122, 252);
//destination IP
IPAddress outIp(128, 32, 122, 125);
const unsigned int outPort = 9999;
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // you can find this written on the board of some Arduino Ethernets or shields
void setup() {
Ethernet.begin(mac,ip);
Udp.begin(8888);
}
void loop(){
//declare the bundle
OSCBundle bndl;
//BOSCBundle's add' returns the OSCMessage so the message's 'add' can be composed together
bndl.add("/analog/0").add((int32_t)analogRead(0));
bndl.add("/analog/1").add((int32_t)analogRead(1));
bndl.add("/digital/5").add((digitalRead(5)==HIGH)?"HIGH":"LOW");
Udp.beginPacket(outIp, outPort);
bndl.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
bndl.empty(); // empty the bundle to free room for a new one
bndl.add("/mouse/step").add((int32_t)analogRead(0)).add((int32_t)analogRead(1));
bndl.add("/units").add("pixels");
Udp.beginPacket(outIp, outPort);
bndl.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
bndl.empty(); // empty the bundle to free room for a new one
delay(1000);
}

View File

@ -0,0 +1,62 @@
/*
Make an OSC bundle and send it over UDP
OSCBundles allow OSCMessages to be grouped together
to preserve the order and completeness of related messages.
They also allow for timetags to be carried to represent the presentation time
of the messages.
*/
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>
#include <OSCBundle.h>
#include <OSCTiming.h>
EthernetUDP Udp;
//the Arduino's IP
IPAddress ip(128, 32, 122, 26);
//destination IP
IPAddress outIp(128, 32, 122, 25);
const unsigned int outPort = 9999;
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // you can find this written on the board of some Arduino Ethernets or shields
void setup() {
Ethernet.begin(mac,ip);
Udp.begin(8888);
}
void loop(){
//declare the bundle
OSCBundle bndl;
osctime_t timetag;
//OSCBundle's add' returns the OSCMessage so the message's 'add' can be composed together
bndl.add("/analog/0").add((int32_t)adcRead(0, &timetag));
bndl.add("/analog/0/time").add(timetag);
bndl.add("/analog/1").add((int32_t)adcRead(1, &timetag));
bndl.add("/analog/1/time").add(timetag);
Udp.beginPacket(outIp, outPort);
bndl.setTimetag(oscTime());
bndl.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
bndl.empty(); // empty the bundle to free room for a new one
bndl.add("/mouse/step").add((int32_t)analogRead(0)).add((int32_t)analogRead(1));
bndl.add("/units").add("pixels");
Udp.beginPacket(outIp, outPort);
bndl.setTimetag(oscTime());
bndl.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
bndl.empty(); // empty the bundle to free room for a new one
delay(100);
}

View File

@ -0,0 +1,41 @@
#include <OSCMessage.h>
/*
Make an OSC message and send it over UDP
Adrian Freed
*/
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>
#include <OSCMessage.h>
EthernetUDP Udp;
//the Arduino's IP
IPAddress ip(128, 32, 122, 252);
//destination IP
IPAddress outIp(128, 32, 122, 125);
const unsigned int outPort = 9999;
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // you can find this written on the board of some Arduino Ethernets or shields
void setup() {
Ethernet.begin(mac,ip);
Udp.begin(8888);
}
void loop(){
//the message wants an OSC address as first argument
OSCMessage msg("/analog/0");
msg.add((int32_t)analogRead(0));
Udp.beginPacket(outIp, outPort);
msg.send(Udp); // send the bytes to the SLIP stream
Udp.endPacket(); // mark the end of the OSC Packet
msg.empty(); // free space occupied by message
delay(20);
}

Some files were not shown because too many files have changed in this diff Show More