diff --git a/README.md b/README.md index 9dc98c1..2a8fbca 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -Extra examples for TI BLE-Stack SDK -=================================== +Extra examples for TI BLE-Stack 2.2.x SDK +========================================= -This repository contains additional sample applications and components for the Texas Instruments *Bluetooth®* Low Energy software development kit. All Github sample apps are compatible with the latest BLE-Stack SDK. +This repository contains additional sample applications and components for the Texas Instruments *Bluetooth®* Low Energy software development kit. All Github sample apps are compatible with BLE-Stack 2.2.x. To use the examples and tools in this repository, please [download and install the SDK](http://www.ti.com/ble-stack) first, and if necessary [buy an evaluation kit](https://store.ti.com/Search.aspx?k=CC2650). For other hardware and software resources, [please visit our wiki](http://www.ti.com/ble-wiki). If you have any questions please refer to the [FAQ page](docs/faq.md). -**Note:** Not all additional sample projects are migrated to GitHub - please refer to the Examples List below. +**Note:** Not all additional sample projects are migrated to GitHub. Additionally all examples on this page are targeted for the **`CC2650R1`** device - please refer to the Examples List below. Installation ============ @@ -39,10 +39,12 @@ By default, TI\_BLE\_SDK\_BASE points to `C:\ti\simplelink\ble_sdk_2_02_01_18\`. Required Tools ============== -Similar to the BLE-Stack SDK, the examples in this repository support the IAR and CCS toolchains. Please pay careful attention to versions of these tools, the supported version are listed below. Using a non supported version is untested and may result in unexpected behavior. +Similar to the BLE-Stack SDK, the examples in this repository support the IAR and CCS toolchains. Please pay careful attention to versions of these tools, the supported version are listed below. **Using a non supported version is untested and may result in unexpected behavior.** - IAR for ARM v7.70.2 - CCS v6.2.0 with TI ARM Compiler v5.2.6 + +TI ARM Compiler is no longer installed by default in CCS v6.2.0. For instructions on installing TI ARM Compiler v5.2.6, please refer to the [Installing a Specific TI ARM Compiler](http://software-dl.ti.com/lprf/sdg-latest/html/cc2640/platform.html#installing-a-specific-ti-arm-compiler) of the TI BLE Software Developer's Guide. For more information on toolchain setup, please refer to our [FAQ page](docs/faq.md). @@ -54,6 +56,8 @@ The [FAQ page](docs/faq.md) will try to address some of the common questions rel Examples List ============= +**Note: All of the sample applications below run on CC2650R1 based devopment kits. These examples will not work on CC2640R2 devices. For R2 examples, please ble_examples-3.0.** + The following examples are currently supported: ### beacon\_rfdriver @@ -86,12 +90,23 @@ The following examples are currently supported:     [docs](docs/simple_beacon.md) | [project files ](examples/cc2650lp/simple_beacon) | [src](src/examples/simple_beacon) +### simple\_central\_lp +    SimpleBLECentral for CC2650 LaunchPad + +    [docs](docs/simple_central_lp.md) | [Launchpad project files](examples/cc2650lp/simple_central) | [src](src/examples/simple_central) + ### simple\_central\_audio\_receiver -    Receive and decode a voice stream over BLE using CC2650 central device and SensorTag or
-    HID Advanced Remote peripheral device +    Receive and decode a voice stream over BLE using CC2650 central device and SensorTag,
+    HID Advanced Remote or CC2650 LaunchPad with CC3200AUDBOOST peripheral device     [docs](docs/simple_central_audio_receiver.md) | [project files](examples/cc2650lp/simple_central_audio_receiver) | [src](src/examples/simple_central_audio_receiver) +### simple\_peripheral\_audio\_transmitter +    Encode and transmit an audio stream over BLE using CC2650 peripheral device on LaunchPad with CC3200AUDBOOST
+    booster pack + +    [docs](docs/simple_peripheral_audio_transmitter.md) | [project files](examples/cc2650lp/simple_peripheral_audio_transmitter) | [src](src/examples/simple_peripheral_audio_transmitter) + ### simple\_eddystone     Demonstrate an implementation of a beacon that uses the Eddystone beacon format diff --git a/ble_examples_X.X_manifest.html b/ble_examples_X.X_manifest.html index d2e1304..a5af6bc 100644 --- a/ble_examples_X.X_manifest.html +++ b/ble_examples_X.X_manifest.html @@ -121,14 +121,14 @@

-06-07-2016 +02-06-2017

-Manifest ID - SRAS00002949 +Manifest ID - SRAS00003660

@@ -249,7 +249,7 @@

Open Source License References

Export Information

ECCN for Software included in this release:

-Publicly Available - Open Source or TI TSPA License +Publicly Available
@@ -316,13 +316,106 @@

+ + + + +

+ mSBC_audio_codec_cc26xx_cc13xx Manifest Table +

+ + +

+ + See the Legend above for a description of these columns. + +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Software NameVersionLicense TypeDelivered AsModified by TI
+ mSBC_audio_codec_cc26xx_cc13xx + + 1.0 + + LGPLv2.1 + + Binary + + Yes + Location + https://github.com/ti-simplelink/ble_examples/examples/util/mSBClibrary/bin +
Obtained from + +
+ mSBC_audio_codec_cc26xx_cc13xx + + 1.0 + + LGPLv2.1 + + Source + + Yes + Location + https://github.com/ti-simplelink/ble_examples/src/util/sbc +
Obtained from + http://www.bluez.org/sbc-12/ +
+ +

+

+

Credits

-




+









Licenses

-

ble_examples Licenses





/*
* Filename: filename.c
*
* Description: This file provides…
*
*
* Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/


+

ble_examples Licenses





/*
* Filename: filename.c
*
* Description: This file provides…
*
*
* Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/



mSBC_audio_codec_cc26xx_cc13xx License




GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999

Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]

Preamble

The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.

This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.

When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.

To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.

For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.

We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.

To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.

Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.

Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.

When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.

We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.

For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.

In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.

Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.

The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.

GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".

A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.

The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)

"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.

1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.

You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.

2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

a) The modified work must itself be a software library.

b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.

c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.

d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.

(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)

These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.

In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.

Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.

This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.

4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.

If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.

5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.

However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.

When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.

If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)

Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.

6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.

You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:

a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)

b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.

c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.

d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.

e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.

For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.

It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.

7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:

a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.

b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.

8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.

9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.

10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.

11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.

13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.

14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.

NO WARRANTY

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.

END OF TERMS AND CONDITIONS

How to Apply These Terms to Your New Libraries

If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).

To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.

<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Also add information on how to contact you by electronic and paper mail.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.

<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice

That's all there is to it!




\ No newline at end of file diff --git a/docs/simple_central_audio_receiver.md b/docs/simple_central_audio_receiver.md index a36d52f..a662f4e 100644 --- a/docs/simple_central_audio_receiver.md +++ b/docs/simple_central_audio_receiver.md @@ -2,27 +2,29 @@ Purpose / Scope =============== This page will document how to demonstrate an end to end BLE voice solution using two CC2650 devices. -Emphasis will be placed on the central device which is reponsible for recieving and decoding the voice stream. +Emphasis will be placed on the central device which is responsible for receieving and decoding the voice stream. -TI's voice system supports streaming voice data from the Pulse Density Modulation (PDM) microphone on the CC2650 SensorTag and HID Advanced Remote kits. -Voice data is transferred over BLE using the TI audio\_profile which is a Voice Over GATT Profile (VoGP) design. +TI's voice system has long supported streaming voice data from the Pulse Density Modulation (PDM) microphone on the CC2650 SensorTag and HID Advanced Remote kits. Now support for the CC3200AUDBOOST boosterpack and another compression algorithm, mSBC, is added. +Voice data is transferred over BLE using the TI audio\_profile which is a Voice Over GATT Profile (VoGP) design. This profile has been update to add an additional start byte. This new start byte indicates that the following stream uses mSBC compression. In this demo, data flows unidirectionally between a streamer (GATT server) and a receiver (GATT client) device. -The supported streamer examples from the BLE-Stack SDK are: +In addition to the `simple_peripheral_audio_transmitter`, the following streamer examples from the BLE-Stack SDK are supported: - `hid_adv_remote` - `sensortag_audio` -The streaming devices are the ones containing the PDM microphone on board. These are the devices the user will ultimately be speaking into. -These devkits and firmware examples can be found within the BLE-Stack SDK release. +The streaming devices are the ones containing the PDM microphone on board, and CC2650 LaunchPad with CC3200AUDBOOST boosterpack. These are the devices the user will ultimately be speaking into, or send audio to via 3.5mm jack. +The PDM microphone based devkits and firmware examples can be found within the BLE-Stack SDK release. Simple Central Audio Receiver is designed to demonstrate receiving and decoding (for playback or cloud based speech recognition) the voice stream from one of the supported streamer examples above. This example is based on the simple\_central project from the **BLE-Stack v2.2.1** installer. The central project was slightly modified to: - Run on the CC2650 LaunchPad - - Automatically connect to CC2650 SensorTag or CC2650RC based on advertisement data + - Automatically connect to CC2650 SensorTag, CC2650RC or CC2650 LaunchPad with CC3200AUDBOOST based on advertisement data - Receive voice stream using the TI VoGP audio\_profile - - Send the voice stream to the PC over UART for post processing (Python script included) + - Decode the voice stream and output to headphone/line out on CC3200AUDBOOST. Connect this to headphones, or speaker + - [Optional] Stream audio data with IMA-ADPCM mechanism using Data Length Extension feature + - [Optional] Send the voice stream to the PC over UART for post processing (Python script included) Streaming Voice over BLE ======================== @@ -35,12 +37,12 @@ _Note: The above links also apply to sensortag\_audio projects as well. They emp Some quick facts about voice over BLE: - - Input device: `Pulse Density Modulation (PDM) Microphone` + - Input device: `Pulse Density Modulation (PDM) Microphone` or `CC3200AUDBOOST boosterpack` - Sample rate: `16kHz` - Bit Depth: `16 bits` - - Compression mechanism: `4:1 IMA-ADPCM` - - Required application throughput: `66.67kbps` - - Voice quality has been qualified by Nuance and is sufficient for voice recognition solutions + - Compression mechanism: `4:1 IMA-ADPCM` or `mSBC` + - Required application throughput: `66.67kbps` or `60.8kpbs` + - Voice quality (IMA-ADPCM) has been qualified by Nuance and is sufficient for voice recognition solutions Prerequisites @@ -50,21 +52,27 @@ Prerequisites Before running the demo, the user will need the following components: -- CC2650 voice enabled development kit (SensorTag or HID Advanced Remote) +- CC2650 voice enabled development kit (SensorTag, HID Advanced Remote or CC2650 LaunchPad with CC3200AUDBOOST) - [CC2650 RC](http://www.ti.com/tool/cc2650rc) - [CC2650 STK](http://www.ti.com/tool/cc2650stk) + - [CC2650 LaunchPad](http://www.ti.com/tool/launchxl-cc2650) + with [CC3200AUDBOOST](http://www.ti.com/tool/cc3200audboost) - [BLE-Stack v2.2.1](http://www.ti.com/ble-stack) - [CC2650 LaunchPad](http://www.ti.com/tool/launchxl-cc2650) -- A PC that supports `.wav` file playback. +- A device to output audio over a 3.5mm jack (connected to the LINE-IN, 3.5mm stereo jack, of the CC3200AUDBOOST boosterpack) +- **OPTIONAL:** A PC that supports `.wav` file playback, and/or view logging via UART-over-USB, @460800 baudrate - **OPTIONAL:** [Sharp LCD BoosterPack](http://www.ti.com/tool/430boost-sharp96) #### Firmware Requirements +_Note: Apple headphones will not work with the CC3200 boosterpack_ + 1. Load the voice streaming device with it's proper firmware image from the BLE-Stack SDK * For the CC2650 STK this is the `sensortag_audio` project * For the CC2650 RC this is the `hid_adv_remote` project + * For the CC2650 LaunchPad with CC3200AUDBOOST this is the `simple_peripheral_audio_transmitter` project 2. Load the `simple_central_audio_reciever` project onto the CC2650 LaunchPad -3. Handle Python dependencies for `audio_frame_serial_print.py` from [tools/scripts/audio folder](../tools/scripts/audio) +3. **OPTIONAL** Handle Python dependencies for `audio_frame_serial_print.py` from [tools/scripts/audio folder](../tools/scripts/audio) * Requires [Python 2.7](https://www.python.org/download/releases/2.7/) * The script also requires the following Python modules: struct, wave, serial, time, winsound * See the [FAQ](faq.md) for more info @@ -73,29 +81,150 @@ Before running the demo, the user will need the following components: Running the Demo ================ -After building the firmware required for the voice streamer and receiver, you are ready to demo the voice capabilites of the CC2650. +#### A Note for SensorTag Users + + * In order for the `sensortag_audio` project to run standalone (without a debugger attached), a BIM project must be loaded. + * BIM can be loaded using the project in `\examples\util\bim_extflash`, be sure to use the `FlashOnly_ST` configuration. + + * Additionally the `sensortag_audio` project for CCS will need to have a target configration added to the app project. + * The target config can be added to the app project by copying the `CC2650F128.ccxml` file from the /targetConfigs folder of the stack project to into the app project. + + * `sensortag_audio` for CCS in BLE 2.2.1 does not have pairing and bonding enabled by default. You may see "pairing failed" on the screen. This is safe to ignore, the + demo will proceed correctly. + +#### Voice Streaming on the CC2650 + +After building the firmware required for the voice transmitter and receiver, you are ready to demo the voice capabilities of the CC2650. + +1. Power up the transmitter launchpad + * If the serial port is attached it will log + ``` + Audio Tx Peripheral + + Initialized + Advertising + ``` + +2. Power up the audio\_receiver device + * If the serial port is attached it will log + ``` + Audio Central + + Initialized + Idle... + ``` +3. Start Discovery on the central device by pressing the left key on the LaunchPad. Scanning is indicated by blinking green LED on the LaunchPad. + * The Central device will scan the peripheral's advertisement data for either the TI\_COMPANY\_ID (SensorTag), the HID\_SERV\_UUID (HID Advanced Remote) or SIMPLEPROFILE\_SERV\_UUID (Audio Tx Peripheral). + * After finding devices that list these services their advertisement payloads it will scan for the following device names: + ```c + static uint8 remoteNameST[] = + { + 'C', 'C', '2', '6', '5', '0', ' ', + 'S', 'e', 'n', 's', 'o', 'r', 'T', 'a', 'g', + }; + ... + static uint8 remoteNameRC[] = + { + 'H', 'I', 'D', ' ', 'A', 'd', 'v', 'R', 'e', 'm', 'o', 't', 'e' + }; + ... + static uint8 remoteNameTx[] = + { + 'S', 'i', 'm', 'p', 'l', 'e', + 'B', 'L', 'E', + 'A', 'u', 'd', 'i', 'o', 'T', 'x', + }; + ``` +4. If an acceptable voice streaming device is found (STK, CC2650RC or CC2650LP) then the central will connect, pair, and bond to the device. If attached the serial port will log: + * Audio Central + ``` + Discovering... + Pairing started + Connected + + Pairing success + Bond Saved OR Param Update: 0 + ``` + * Audio Tx Peripheral + ``` + Connected + + ``` +5. The devices are now ready to stream voice over BLE. + * Press and hold the MIC button to start streaming voice from the HID Advanced Remote + * Press and hold the right key on the SensorTag to start streaming voice from the SensorTag + * If using the launchpad press: + * Right button to start transmitting with ADPCM compression + * Left button to start transmitting with mSBC compression + * Press both buttons simultaneously to stop transmitting +6. The demo is written such that, once a sensortag, remote control or transmitting launchpad is discovered, the audio\_receiver project will pair and bond to it. Scanning/connecting to other devices is not allowed while bonded. (i.e. left button is disabled). In order to "forget the devices" you should: + * Power off your audio transmitting device. Wait for link to be terminated. Red LED will turn on. + * Press the right key to erase the bonds from the audio\_receiver project. Green LED will blink 1x while red LED stays on. + * The bonds are now erased, you can discover and connect to another device. + +Optional demo : Stream audio data with IMA-ADPCM mechanism using Data Length Extension feature +------------ + +The Data Length Extension feature for this stack projet is enabled by adding -DBLE_V42_FEATURES=EXT_DATA_LEN_CFG into build_config.opt file +The needed modification for the application project is wrapped around in the DLE_ENABLED predefine symbol. +The MAX_PDU_SIZE has been modified to be 107. + +To enable the application to send 100 bytes audio data in one frame, you simply need to enable DLE_ENABLED in the predefine symbol. + +_Note: Data Length Extension feature only supports ADPCM format for now_ + +Once Data Length Extension feature is enabled, the attached serial port will log: + * Audio Central with DLE + ``` + Discovering... + Pairing started + Connected + + Pairing success + Bond Saved + ``` + * Audio Tx Peripheral with DLE + ``` + Connected + + ``` + +Optional demo : Send the voice stream to the PC over UART for post processing (Python script included) +------------ + +It is possible to send the stream to a PC. In this case there will be no logging via UART, for logging please mount LCD on top of CC3200AUDBOOST. To enable this one must rebuild the `simple_central_audio_reciever` project with the following modifications in Project-->C/C++ Compiler-->Preprocessor-->Defined symbols: +``` +xSTREAM_TO_AUDBOOST +STREAM_TO_PC +BOARD_DISPLAY_EXCLUDE_UART +xBOARD_DISPLAY_EXCLUDE_LCD +``` + +There are two python scripts for decoding and recording audio. `audio_frame_serial_print` is used for ADPCM stream, and `pySBC27` is used for mSBC format. The instructions below are written for the `audio_frame_serial_print`. To decode mSBC simply replace all references to `audio_frame_serial_print` below with `pySBC27`. 1. Connect the audio\_receiver (CC2650 LaunchPad) device to your PC. Use windows device manager to note the COM port, it is the User/UART port (COM4 in picture below) ![Connecting the COM Port](doc_resources/dev_mgr_xds110.png) -2. Make note of the COM port from step #1 and update the Python script to use that port by replacing COM38 the following line: +2. Make note of the COM port from step #1 and update the Python script to use that port by replacing COM91 the following line: ```Python - ser = Serial("COM38", 400000, timeout=0.1) + ser = Serial("COM91", 460800, timeout=0.1) ``` + * The python script requires pyserial and other dependencies to be installed please see the [FAQ](faq.md) for more info. 3. Run `audio_frame_serial_print.py` 4. Power up the voice streaming device. * The SensorTag will advertise out of the box, this is indicated by the green blinking LED. * The HID Advanced Remote will advertise after any button press. + * The CC2650 LaunchPad with CC3200AUDBOOST will always advertise when not in connection 5. Power up the audio\receiver device - * If the LCD is attached it will display + * If the LCD is mounted it will display ``` Audio central Idle... ``` 6. Start Discovery on the central device by pressing the left key on the LaunchPad. Scanning is indicated by blinking green LED on the LaunchPad. - * The Central device will scan the peripheral's advertisement data for either the TI\_COMPANY\_ID (SensorTag) or the HID\_SERV\_UUID (HID Advanced Remote). + * The Central device will scan the peripheral's advertisement data for either the TI\_COMPANY\_ID (SensorTag), the HID\_SERV\_UUID (HID Advanced Remote) or SIMPLEPROFILE\_SERV\_UUID (Audio Tx Peripheral). * After finding devices that list these services their advertisement payloads it will scan for the following device names: ```c static uint8 remoteNameST[] = @@ -108,17 +237,36 @@ After building the firmware required for the voice streamer and receiver, you ar { 'H', 'I', 'D', ' ', 'A', 'd', 'v', 'R', 'e', 'm', 'o', 't', 'e' }; + ... + static uint8 remoteNameTx[] = + { + 'S', 'i', 'm', 'p', 'l', 'e', + 'B', 'L', 'E', + 'A', 'u', 'd', 'i', 'o', 'T', 'x', + }; ``` -7. If an acceptable voice streaming device is found (STK or CC2650RC) then the central will connect, pair, and bond to the device. If attached the Sharp LCD will display: +7. If an acceptable voice streaming device is found (STK, CC2650RC or CC2650LP) then the central will connect, pair, and bond to the device. If attached the serial port will log: + * Audio Central ``` - Audio central - + Discovering... + Pairing started + Connected + + Pairing success Bond Saved OR Param Update: 0 + ``` + * Audio Tx Peripheral + ``` + Connected ``` 8. The devices are now ready to stream voice over BLE * Press and hold the MIC button to start streaming voice from the HID Advanced Remote * Press and hold the right key on the SensorTag to start streaming voice from the SensorTag + * On the transmitting launchpad press: + * Right button to start transmitting with ADPCM compression + * Left button to start transmitting with mSBC compression + * Press both buttons simultaneously to stop transmitting 9. The Python script will read the voice frames from the CC2650 and decode them into `.wav` files. These files can be played back on the PC. * The files are saved in the format: `pdm_test_%Y-%m-%d_%H-%M-%S_adpcm` where Y, m, d, H, M, S are used to store the time stamp when the file was saved. @@ -138,6 +286,25 @@ The following states of the device can be described by the red and green LEDs on * Device connected and bonded + streaming voice: Red LED blinks on both LP and STK or Remote. * Bonds forgotten: Green LED blinks 1x while red LED is on. +Useful tip +========== + +To make more RAM available to HEAP some variables can be placed in AUX_RAM. This ram is available when the Sensor Controller is not in use. The following code shows this placement: + +IAR: +``` +#pragma default_variable_attributes = @ "AUX_RAM_SECTION" +``` + +CCS: +``` +#pragma DATA_SECTION(i2sContMgtBuffer, ".aux_ram") +#pragma DATA_SECTION(audio_encoded, ".aux_ram") +#pragma DATA_SECTION(sbc, ".aux_ram") +#pragma DATA_SECTION(written, ".aux_ram") +#pragma DATA_SECTION(streamVariables, ".aux_ram") +``` + References ========== * [CC2650 Remote Control User's Guide](http://processors.wiki.ti.com/index.php/CC2650RC_UG) diff --git a/docs/simple_central_lp.md b/docs/simple_central_lp.md new file mode 100644 index 0000000..5fb1bb1 --- /dev/null +++ b/docs/simple_central_lp.md @@ -0,0 +1,45 @@ +Purpose +=============== + +This example project configures the Simple BLE Central for the CC2650 LaunchPad. The simple central is a Bluetooth low energy central device with GATT client functionality. To accommodate the CC2650 LaunchPad, two buttons are used to navigate through the menu. + +By default, the simple central application is configured to filter and connect to peripheral devices with the TI Simple Profile Service UUID, such as Simple Peripheral. To modify this behavior, set DEFAULT_DEV_DISC_BY_SVC_UUID to FALSE in simple_central.c. + +The application can be used with a LCD screen, or a terminal program such as PuTTY can be used to display over UART. + +Requirements +============= + +#### Hardware + +- [CC2650 LaunchPad](http://www.ti.com/tool/launchxl-cc2650) +- **OPTIONAL:** [Sharp LCD BoosterPack](http://www.ti.com/tool/430boost-sharp96) +- Device to connect to + +##### Software +- simple_central_lp project from this GIT page +- [BLE-Stack v2.2.1](http://www.ti.com/ble-stack) +- **OPTIONAL:** Terminal program such as [PuTTY](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html) +- CCS 6.2.x **or** IAR 7.70.x + + +User Interface +================ + +#### Choosing Display + +By default, the project will use a UART display. To use LCD to display (instead of UART), go to the project Predefines (Properties -> Build -> ARM Compiler -> Predefined Symbols) and delete the `BOARD_DISPLAY_EXCLUDE_LCD` entry. Then add `BOARD_DISPLAY_EXCLUDE_UART`. + +For instructions on using PuTTY with the CC2650 LaunchPad, please see the [FAQ page](faq.md). + +#### Running the Project + +Upon powering the device, press the right button (BTN-2) to scan for devices. The central will display both address and name of the devices found. To browse through the found devices press the left button (BTN-1). To scan for devices, press the right button. When browsing through devices, press the right button to connect. + +When connected, the bottom row displays the possible actions. Press left to toggle which option is selected, and right to execute. +- Param upd req: Send a parameter update request, toggling between the "initial" and "default" set of connection parameters. (By default, this toggles between a connection interval of 400 and 200 ms.) +- Start/stop RSSI poll: Start or cancel RSSI polling. +- Read/write req: Send a read or write request for the Simple Service characteristic 1. +- Disconnect. + +When disconnected, press right to scan for devices. diff --git a/docs/simple_peripheral_audio_transmitter.md b/docs/simple_peripheral_audio_transmitter.md new file mode 100644 index 0000000..016082e --- /dev/null +++ b/docs/simple_peripheral_audio_transmitter.md @@ -0,0 +1,204 @@ +Purpose / Scope +=============== + +This page will document how to demonstrate an end to end BLE voice solution using two CC2650 LaunchPads with CC3200AUDBOOST boosterpacks. +Emphasis will be placed on the peripheral device which is responsible for coding and transmitting the voice stream. + +TI's voice system has long supported streaming voice data from the Pulse Density Modulation (PDM) microphone on the CC2650 SensorTag and HID Advanced Remote kits. This page documents an addition. The addition is the usage of the CC3200AUDBOOST boosterpack. It also adds another compression algorithm, mSBC. +Voice data is transferred over BLE using the TI audio\_profile which is a Voice Over GATT Profile (VoGP) design. This profile has been update to add an additional start byte. This new start byte indicates that the following stream uses mSBC compression. +In this demo, data flows unidirectionally between a streamer (GATT server) and a receiver (GATT client) device. + +Other supported streamer examples from the BLE-Stack SDK are: + - `hid_adv_remote` + - `sensortag_audio` + +Simple Peripheral Audio Transmitter is designed to demonstrate coding and transmitting the audio stream from the CC3200AUDBOOST boosterpack. This example is based on the simple\_peripheral project from the **BLE-Stack v2.2.1** installer. + +The peripheral project was modified as follows: + + - Run on the CC2650 LaunchPad + - Always advertise and attempt to connect to CC2650 LaunchPad Audio Central + - Change scan response data to 'SimpleBLEAudioTx' and device name to 'Simple BLE AudioTx' + - Transmit audio stream using the TI VoGP audio\_profile + - Switch between ADPCM and mSBC compression + - [Optional] Stream audio data with IMA-ADPCM mechanism using Data Length Extension feature + +Streaming Voice over BLE +======================== + +For more information about the technical details of TI's Voice Over BLE Solution please see: + - [Voice Streaming on CC2650](http://processors.wiki.ti.com/index.php/CC2650RC_Getting_Started_with_Development#Voice_Streaming_on_the_CC2650RC) + - [Voice Over BLE](http://processors.wiki.ti.com/index.php/BLESDK-2.2.x-CC2650RC_Developers_Guide#Voice_Over_BLE) + +_Note: The above links also apply to sensortag\_audio projects as well. They employ the same firmware components (PDM driver, audio\_profile, etc) as the Remote Control solutions, but deploy on a different dev board._ + +Some quick facts about voice over BLE: + + - Input device: `Pulse Density Modulation (PDM) Microphone` or `CC3200AUDBOOST boosterpack` + - Sample rate: `16kHz` + - Bit Depth: `16 bits` + - Compression mechanism: `4:1 IMA-ADPCM` or `mSBC` + - Required application throughput: `66.67kbps` or `60.8kpbs` + - Voice quality (IMA-ADPCM) has been qualified by Nuance and is sufficient for voice recognition solutions + + +Prerequisites +============= + +#### Hardware Requirements + +_Note: Apple headphones will not work with the CC3200 boosterpack_ + +Before running the demo, the user will need the following components: + +- [CC2650 LaunchPad](http://www.ti.com/tool/launchxl-cc2650) +- [CC3200AUDBOOST](http://www.ti.com/tool/cc3200audboost) +- [BLE-Stack v2.2.1](http://www.ti.com/ble-stack) +- A device to output audio over a 3.5mm jack (connected to the LINE-IN, 3.5mm stereo jack, of the CC3200AUDBOOST boosterpack) +- **OPTIONAL:** A PC to view logging via UART-over-USB, @460800 baudrate +- **OPTIONAL:** [Sharp LCD BoosterPack](http://www.ti.com/tool/430boost-sharp96) + +#### Firmware Requirements + +1. Load the `simple_peripheral_audio_transmitter` project onto one CC2650 LaunchPad +2. Load the `simple_central_audio_reciever` project onto the other CC2650 LaunchPad + + +Running the Demo +================ + +After building the firmware required for the voice transmitter and receiver, you are ready to demo the voice capabilities of the CC2650. Before following the steps below, +be sure that an audio source (i.e. line out from a PC is connected to the LINE_IN jack of the `CC3200AUDBOOST`). + +1. Power up the transmitter launchpad + * If the serial port is attached it will log + ``` + Audio Tx Peripheral + + Initialized + Advertising + ``` +2. Power up the audio\_receiver device + * If the serial port is attached it will log + ``` + Audio Central + + Initialized + Idle... + ``` +3. Start Discovery on the central device by pressing the left key on the LaunchPad. Scanning is indicated by blinking green LED on the LaunchPad. + * The Central device will scan the peripheral's advertisement data for either the TI\_COMPANY\_ID (SensorTag), the HID\_SERV\_UUID (HID Advanced Remote) or SIMPLEPROFILE\_SERV\_UUID (Audio Tx Peripheral). + * After finding devices that list these services their advertisement payloads it will scan for the following device names: + ```c + static uint8 remoteNameST[] = + { + 'C', 'C', '2', '6', '5', '0', ' ', + 'S', 'e', 'n', 's', 'o', 'r', 'T', 'a', 'g', + }; + ... + static uint8 remoteNameRC[] = + { + 'H', 'I', 'D', ' ', 'A', 'd', 'v', 'R', 'e', 'm', 'o', 't', 'e' + }; + ... + static uint8 remoteNameTx[] = + { + 'S', 'i', 'm', 'p', 'l', 'e', + 'B', 'L', 'E', + 'A', 'u', 'd', 'i', 'o', 'T', 'x', + }; + ``` +4. If an acceptable voice streaming device is found (STK, CC2650RC or CC2650LP) then the central will connect, pair, and bond to the device. If attached the serial port will log: + * Audio Central + ``` + Discovering... + Pairing started + Connected + + Pairing success + Bond Saved OR Param Update: 0 + ``` + * Audio Tx Peripheral + ``` + Connected + + ``` +5. The devices are now ready to stream voice over BLE. On the transmitting launchpad press: + * Right button to start transmitting with ADPCM compression + * Left button to start transmitting with mSBC compression +6. The demo is written such that, once a sensortag, remote control or transmitting launchpad is discovered, the audio\_receiver project will pair and bond to it. Scanning/connecting to other devices is not allowed while bonded. (i.e. left button is disabled). In order to "forget the devices" you should: + * Power off your audio transmitting device. Wait for link to be terminated. Red LED will turn on. + * Press the right key to erase the bonds from the audio\_receiver project. Green LED will blink 1x while red LED stays on. + * The bonds are now erased, you can discover and connect to another device. + +Optional demo : Stream audio data with IMA-ADPCM mechanism using Data Length Extension feature +------------ + +The Data Length Extension feature for this stack projet is enabled by adding -DBLE_V42_FEATURES=EXT_DATA_LEN_CFG into build_config.opt file +The needed modification for the application project is wrapped around in the DLE_ENABLED predefine symbol. +The MAX_PDU_SIZE has been modified to be 107. + +To enable the application to send 100 bytes audio data in one frame, you simply need to enable DLE_ENABLED in the predefine symbol. + +_Note: Data Length Extension feature only supports ADPCM format for now_ + +Once Data Length Extension feature is enabled, the attached serial port will log: + * Audio Central with DLE + ``` + Discovering... + Pairing started + Connected + + Pairing success + Bond Saved + ``` + * Audio Tx Peripheral with DLE + ``` + Connected + + ``` + + +Demo LED states +=============== + +The following states of the device can be described by the red and green LEDs on the LaunchPad. + +Audio Central: +* Idle + bonds forgotten: Red LED is on, solid +* Scanning for devices: Green LED is flashing +* Device connected + bond saved: Green LED is on, solid +* Device connected and bonded + streaming voice: Red LED blinks on both LP and STK or Remote. +* Bonds forgotten: Green LED blinks 1x while red LED is on. + +Audio Tx Peripheral: +* Transmitting mSBC compressed audio: Red LED is active, and on (Green is inactive LED) +* Transmitting ADPCM compressed audio: Green LED is active, and on (Red is inactive LED) +* Fails to add notification to queue: Active LED flicker +* I2S driver fails to get buffer for next frame: Inactive LED flicker + +Useful tip +========== + +To make more RAM available to HEAP some variables are placed in AUX_RAM. This ram is available when the Sensor Controller is not in use. The following code in `simple_peripheral_audio_transmitter.c` shows this placement: + +IAR: +``` +#pragma default_variable_attributes = @ "AUX_RAM_SECTION" +``` + +CCS: +``` +#pragma DATA_SECTION(i2sContMgtBuffer, ".aux_ram") +#pragma DATA_SECTION(audio_encoded, ".aux_ram") +#pragma DATA_SECTION(sbc, ".aux_ram") +#pragma DATA_SECTION(written, ".aux_ram") +#pragma DATA_SECTION(streamVariables, ".aux_ram") +``` + +References +========== + * [CC2650 Remote Control User's Guide](http://processors.wiki.ti.com/index.php/CC2650RC_UG) + * [CC2650 Remote Control Developer's Guide](http://processors.wiki.ti.com/index.php/CC2650RC_Getting_Started_with_Development#Getting_started_with_Development) + * [CC2650 SensorTag User's Guide](http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User%27s_Guide) + * [Voice Over BLE](http://processors.wiki.ti.com/index.php/BLESDK-2.2.x-CC2650RC_Developers_Guide#Voice_Over_BLE) diff --git a/docs/spp_ble.md b/docs/spp_ble.md index fd9fbe5..6ec43e0 100644 --- a/docs/spp_ble.md +++ b/docs/spp_ble.md @@ -51,7 +51,7 @@ Running the demo is as simple and compiling and loading the code, then hooking u - You can use the terminal to send data from your PC to the LaunchPad, and also display the info sent from one device to another. - You will need to open two instances of the terminal program to, one to communicate with each board. - Follow the steps from our [FAQ](faq.md) to connect to the LaunchPad boards - - **Please note that the SPP project uses a baud rate of 921600 not 115200** + - **Please note that the SPP project uses the default baud rate of 115200** 2. Power the boards inividually and verify they are initialized - The client will blink the green LED twice at initialzation. It will also display `Auto connecting...` on the terminal diff --git a/examples/cc2650lp/hid_emu_kbd/ccs/stack/hid_emu_kbd_cc2650lp_stack.projectspec b/examples/cc2650lp/hid_emu_kbd/ccs/stack/hid_emu_kbd_cc2650lp_stack.projectspec index 4cfe995..a9be3e0 100644 --- a/examples/cc2650lp/hid_emu_kbd/ccs/stack/hid_emu_kbd_cc2650lp_stack.projectspec +++ b/examples/cc2650lp/hid_emu_kbd/ccs/stack/hid_emu_kbd_cc2650lp_stack.projectspec @@ -185,6 +185,8 @@ + + diff --git a/examples/cc2650lp/multi_role/ccs/stack/multi_role_cc2650lp_stack.projectspec b/examples/cc2650lp/multi_role/ccs/stack/multi_role_cc2650lp_stack.projectspec index 7420622..82d96a8 100644 --- a/examples/cc2650lp/multi_role/ccs/stack/multi_role_cc2650lp_stack.projectspec +++ b/examples/cc2650lp/multi_role/ccs/stack/multi_role_cc2650lp_stack.projectspec @@ -238,6 +238,8 @@ + + diff --git a/examples/cc2650lp/simple_beacon/ccs/app/simple_beacon_cc2650lp_app.projectspec b/examples/cc2650lp/simple_beacon/ccs/app/simple_beacon_cc2650lp_app.projectspec index 8c33793..2b24407 100644 --- a/examples/cc2650lp/simple_beacon/ccs/app/simple_beacon_cc2650lp_app.projectspec +++ b/examples/cc2650lp/simple_beacon/ccs/app/simple_beacon_cc2650lp_app.projectspec @@ -8,7 +8,7 @@ connection="common/targetdb/connections/TIXDS110_Connection.xml" toolChain="TI" linkerCommandFile="" - compilerBuildOptions="--cmd_file="${TI_BLE_SDK_BASE}/src/config/build_components.opt" --cmd_file="${WORKSPACE_LOC}/simple_beacon_cc2650lp_stack/TOOLS/build_config.opt" --cmd_file="${WORKSPACE_LOC}/simple_beacon_cc2650lp_stack/TOOLS/ccs_compiler_defines.bcfg" -mv7M3 --code_state=16 --abi=eabi -me -g --c99 --gcc --gen_func_subsections=on --display_error_number --diag_warning=255 --diag_wrap=off + compilerBuildOptions="--cmd_file="${TI_BLE_SDK_BASE}/src/config/build_components.opt" --cmd_file="${WORKSPACE_LOC}/simple_beacon_cc2650lp_stack/TOOLS/build_config.opt" --cmd_file="${WORKSPACE_LOC}/simple_beacon_cc2650lp_stack/TOOLS/ccs_compiler_defines.bcfg" -mv7M3 -O4 --opt_for_speed=0 --code_state=16 --abi=eabi -me -g --c99 --gcc --gen_func_subsections=on --display_error_number --diag_warning=255 --diag_wrap=off -DUSE_ICALL -DPOWER_SAVING -DSBP_TASK_STACK_SIZE=700 @@ -49,7 +49,7 @@ -I${TI_BLE_SDK_BASE}/src/inc -I${CC26XXWARE} " - linkerBuildOptions="-l${}libc.a -l${CC26XXWARE}/driverlib/bin/ccs/driverlib.lib -l${TI_BLE_SDK_BASE}/src/rom/common_rom_releases/03282014/common_rom.symbols -l${PROJECT_IMPORT_LOC}/../../ccs/config/ccs_linker_defines.cmd + linkerBuildOptions="-l${}libc.a -l${CC26XXWARE}/driverlib/bin/ccs/driverlib.lib -l${TI_BLE_SDK_BASE}/src/rom/common_rom_releases/03282014/common_rom.symbols -l${PROJECT_ROOT}/../simple_beacon_cc2650lp_stack/TOOLS/ccs_linker_defines.cmd -l${TI_BLE_SDK_BASE}/src/common/cc26xx/ccs/cc26xx_app.cmd -x --diag_suppress=16002-D --diag_suppress=16004-D --diag_suppress=10247-D --diag_suppress=10325-D --diag_suppress=10229-D" description="" launchWizard="false" diff --git a/examples/cc2650lp/simple_beacon/ccs/stack/simple_beacon_cc2650lp_stack.projectspec b/examples/cc2650lp/simple_beacon/ccs/stack/simple_beacon_cc2650lp_stack.projectspec index e3370ab..ac8b660 100644 --- a/examples/cc2650lp/simple_beacon/ccs/stack/simple_beacon_cc2650lp_stack.projectspec +++ b/examples/cc2650lp/simple_beacon/ccs/stack/simple_beacon_cc2650lp_stack.projectspec @@ -8,7 +8,7 @@ connection="common/targetdb/connections/TIXDS110_Connection.xml" toolChain="TI" linkerCommandFile="" - compilerBuildOptions="--cmd_file="${TI_BLE_SDK_BASE}/src/config/build_components.opt" --cmd_file="${PROJECT_ROOT}/TOOLS/build_config.opt" -mv7M3 --code_state=16 --abi=eabi -me -g --c99 --gcc --gen_func_subsections=on --display_error_number --diag_warning=255 --diag_wrap=off + compilerBuildOptions="--cmd_file="${TI_BLE_SDK_BASE}/src/config/build_components.opt" --cmd_file="${PROJECT_ROOT}/TOOLS/build_config.opt" -mv7M3 -O4 --opt_for_speed=0 --code_state=16 --abi=eabi -me -g --c99 --gcc --gen_func_subsections=on --display_error_number --diag_warning=255 --diag_wrap=off -DUSE_ICALL -DOSAL_SNV=1 -DFLASH_ROM_BUILD @@ -33,7 +33,6 @@ -I${TI_BLE_SDK_BASE}/src/examples/simple_peripheral/cc26xx/app -I${TI_BLE_SDK_BASE}/src/common/cc26xx -I${TI_BLE_SDK_BASE}/src/components/hal/src/target/_common - -I${TI_BLE_SDK_BASE}/src/components/hal/src/target/_common -I${TI_BLE_SDK_BASE}/src/components/hal/src/target -I${TI_BLE_SDK_BASE}/src/components/hal/src/target/_common/cc26xx -I${TI_BLE_SDK_BASE}/src/components/hal/src/inc @@ -53,8 +52,8 @@ -I${CC26XXWARE} -I${SRC_BLE_CORE}/rom " - linkerBuildOptions="-l${}libc.a -l${PROJECT_LOC}/TOOLS/lib_linker.cmd -l${TI_BLE_SDK_BASE}/src/rom/enc_lib/cc26xx_ecc_rom_api.a -l${TI_BLE_SDK_BASE}/src/rom/ble_rom_releases/04242014/ble_rom_patch.symbols -l${CC26XXWARE}/driverlib/bin/ccs/driverlib.lib -l${PROJECT_IMPORT_LOC}/../../ccs/config/ccs_linker_defines.cmd - -l${TI_BLE_SDK_BASE}/src/common/cc26xx/ccs/cc26xx_stack.cmd -x --entry_point=startup_entry --diag_suppress=16002-D --diag_suppress=16004-D --diag_suppress=10247-D --diag_suppress=10325-D --diag_suppress=10229-D" + linkerBuildOptions="-l${PROJECT_LOC}/TOOLS/lib_linker.cmd -l${TI_BLE_SDK_BASE}/src/rom/enc_lib/cc26xx_ecc_rom_api.a -l${TI_BLE_SDK_BASE}/src/rom/ble_rom_releases/04242014/ble_rom_patch.symbols -l${CC26XXWARE}/driverlib/bin/ccs/driverlib.lib -l${PROJECT_ROOT}/TOOLS/ccs_linker_defines.cmd + -l${TI_BLE_SDK_BASE}/src/common/cc26xx/ccs/cc26xx_stack.cmd -x --entry_point=startup_entry --diag_suppress=16002-D --diag_suppress=16004-D --diag_suppress=10247-D --diag_suppress=10325-D --diag_suppress=10229-D" description="" launchWizard="false" @@ -151,14 +150,16 @@ - + - + + + @@ -169,7 +170,7 @@ - + diff --git a/examples/cc2650lp/simple_central/ccs/app/simple_central_cc2650lp_app.projectspec b/examples/cc2650lp/simple_central/ccs/app/simple_central_cc2650lp_app.projectspec new file mode 100644 index 0000000..040caa8 --- /dev/null +++ b/examples/cc2650lp/simple_central/ccs/app/simple_central_cc2650lp_app.projectspec @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/cc2650lp/simple_central/ccs/config/app_ble.cfg b/examples/cc2650lp/simple_central/ccs/config/app_ble.cfg new file mode 100644 index 0000000..c2c1cc1 --- /dev/null +++ b/examples/cc2650lp/simple_central/ccs/config/app_ble.cfg @@ -0,0 +1,4 @@ +utils.importFile("src/common/cc26xx/kernel/cc2640/config/cc2640.cfg"); +/* +* Extend the cc2640 configuration +*/ \ No newline at end of file diff --git a/examples/cc2650lp/simple_central/ccs/config/ccs_compiler_defines.bcfg b/examples/cc2650lp/simple_central/ccs/config/ccs_compiler_defines.bcfg new file mode 100644 index 0000000..d133ee9 --- /dev/null +++ b/examples/cc2650lp/simple_central/ccs/config/ccs_compiler_defines.bcfg @@ -0,0 +1,10 @@ +/* +** Stack Frontier Generator 1.1.0 (2017-01-18 09:58:05.054000) +** +** WARNING - Auto-generated file. Modifications could be lost! +*/ + +--define=ICALL_STACK0_ADDR=0xb001 +--define=ICALL_STACK0_START=0xb000 +--define=ICALL_RAM0_START=0x200041d0 + diff --git a/examples/cc2650lp/simple_central/ccs/config/ccs_linker_defines.cmd b/examples/cc2650lp/simple_central/ccs/config/ccs_linker_defines.cmd new file mode 100644 index 0000000..47fd065 --- /dev/null +++ b/examples/cc2650lp/simple_central/ccs/config/ccs_linker_defines.cmd @@ -0,0 +1,10 @@ +/* +** Stack Frontier Generator 1.1.0 (2017-01-18 09:58:05.054000) +** +** WARNING - Auto-generated file. Modifications could be lost! +*/ + +--define=ICALL_RAM0_START=0x200041d0 +--define=ICALL_STACK0_START=0xb000 +--define=ICALL_STACK0_ADDR=0xb001 + diff --git a/examples/cc2650lp/simple_central/ccs/config/lib_linker.cmd b/examples/cc2650lp/simple_central/ccs/config/lib_linker.cmd new file mode 100644 index 0000000..1ca7b72 --- /dev/null +++ b/examples/cc2650lp/simple_central/ccs/config/lib_linker.cmd @@ -0,0 +1,8 @@ +/* + * DO NOT MODIFY. This file is automatically generated during the pre-build + * step by the lib_search utility + */ + +"C:\ti\simplelink\ble_sdk_2_02_01_18\blelib\host\host_xcxx_sc.a" +"C:\ti\simplelink\ble_sdk_2_02_01_18\blelib\ctrl\cc2640\cc2640_ctrl_xcxx_41c_ext_sc.a" +"C:\ti\simplelink\ble_sdk_2_02_01_18\blelib\hci_tl\cc26xx\cc26xx_hci_tl_none_v41_v42.a" diff --git a/examples/cc2650lp/simple_central/ccs/stack/simple_central_cc2650lp_stack.projectspec b/examples/cc2650lp/simple_central/ccs/stack/simple_central_cc2650lp_stack.projectspec new file mode 100644 index 0000000..3cc3b20 --- /dev/null +++ b/examples/cc2650lp/simple_central/ccs/stack/simple_central_cc2650lp_stack.projectspec @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/cc2650lp/simple_central/iar/app/cc2650lp_app.ewd b/examples/cc2650lp/simple_central/iar/app/cc2650lp_app.ewd new file mode 100644 index 0000000..0ae5497 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/app/cc2650lp_app.ewd @@ -0,0 +1,1522 @@ + + + + 2 + + FlashROM + + ARM + + 1 + + C-SPY + 2 + + 27 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ARMSIM_ID + 2 + + 1 + 1 + 1 + + + + + + + + ANGEL_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + + CMSISDAP_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GDBSERVER_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + IARROM_ID + 2 + + 1 + 1 + 1 + + + + + + + + + IJET_ID + 2 + + 6 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JLINK_ID + 2 + + 15 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LMIFTDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + MACRAIGOR_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + PEMICRO_ID + 2 + + 2 + 1 + 1 + + + + + + + + + RDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + + + + + + + STLINK_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + THIRDPARTY_ID + 2 + + 0 + 1 + 1 + + + + + + + + XDS100_ID + 2 + + 4 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $TOOLKIT_DIR$\plugins\middleware\HCCWare\HCCWare.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\middleware\PercepioTraceExporter\PercepioTraceExportPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\AVIX\AVIX.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxTinyArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\embOS\embOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\MQX\MQXRtosPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\OpenRTOS\OpenRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\Quadros\Quadros_EWB7_Plugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SafeRTOS\SafeRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\ThreadX\ThreadXArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\TI-RTOS\tirtosplugin.ewplugin + 1 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-286-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-III\uCOS-III-KA-CSpy.ewplugin + 0 + + + $EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin + 1 + + + $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin + 0 + + + $EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin + 1 + + + $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin + 0 + + + + + + diff --git a/examples/cc2650lp/simple_central/iar/app/cc2650lp_app.ewp b/examples/cc2650lp/simple_central/iar/app/cc2650lp_app.ewp new file mode 100644 index 0000000..18ada4b --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/app/cc2650lp_app.ewp @@ -0,0 +1,1225 @@ + + + + 2 + + FlashROM + + ARM + + 1 + + General + 3 + + 24 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 31 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 9 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + "$XDCROOT$/xs" --xdcpath="$XDCPATH$" iar.tools.configuro -c "$TOOLKIT_DIR$" --cc "$COMPILER_PATH$" --device "$DEVICE$" --compileOptions $COMPILER_ARGS_ROOT_QUOTED$ --linkOptions $LINKER_ARGS_QUOTED$ --profile release --projFile "$PROJ_PATH$" + + + + + ILINK + 0 + + 17 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + + Application + + $SRC_BLE_CORE$\common\cc26xx\board_key.c + + + $SRC_BLE_CORE$\common\cc26xx\board_key.h + + + $PROJ_DIR$\..\..\..\..\..\src\examples\simple_central\cc26xx\app\simple_central.c + + + $SRC_BLE_CORE$\examples\simple_central\cc26xx\app\simple_central.h + + + $SRC_BLE_CORE$\common\cc26xx\util.c + + + $SRC_BLE_CORE$\common\cc26xx\util.h + + + + Drivers + + Display + + $TI_RTOS_DRIVERS_BASE$\ti\mw\display\Display.c + + + $TI_RTOS_DRIVERS_BASE$\ti\mw\display\Display.h + + + $TI_RTOS_DRIVERS_BASE$\ti\mw\display\DisplayDogm1286.h + + + $PROJ_DIR$\..\..\..\..\..\src\components\display_eng\ti\mw\display\DisplaySharp.c + + + $PROJ_DIR$\..\..\..\..\..\src\components\display_eng\ti\mw\display\DisplayUart.c + + + $PROJ_DIR$\..\..\..\..\..\src\components\display_eng\ti\mw\display\DisplayUart.h + + + + ECC + + $SRC_BLE_CORE$\common\cc26xx\ecc\ECCROMCC26XX.c + + + $SRC_BLE_CORE$\common\cc26xx\ecc\ECCROMCC26XX.h + + + + PIN + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\PIN.h + + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\pin\PINCC26XX.c + + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\pin\PINCC26XX.h + + + + RF + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\rf\RF.h + + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\rf\RFCC26XX_singleMode.c + + + + SPI + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\SPI.c + + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\SPI.h + + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\spi\SPICC26XXDMA.c + + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\spi\SPICC26XXDMA.h + + + + TRNG + + $SRC_COMMON$\hal\src\target\_common\TRNGCC26XX.c + + + $SRC_COMMON$\hal\src\target\_common\TRNGCC26XX.h + + + + UDMA + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\dma\UDMACC26XX.c + + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\dma\UDMACC26XX.h + + + + + ICall + + $SRC_COMMON$\heapmgr\heapmgr.h + + + $SRC_COMMON$\icall\src\icall.c + + + $SRC_COMMON$\icall\src\inc\icall.h + + + $SRC_BLE_CORE$\icall\inc\icall_addrs.h + + + $SRC_COMMON$\icall\src\icall_cc2650.c + + + $SRC_COMMON$\icall\src\icall_platform.h + + + + ICallBLE + + $SRC_BLE_CORE$\icall\app\ble_user_config.c + + + $SRC_BLE_CORE$\icall\inc\ble_user_config.h + + + $SRC_BLE_CORE$\icall\app\icall_api.c + + + $SRC_BLE_CORE$\icall\inc\icall_apimsg.h + + + + Include + + $SRC_BLE_CORE$\inc\gap.h + + + $SRC_BLE_CORE$\profiles\roles\gapbondmgr.h + + + $SRC_BLE_CORE$\inc\gapgattserver.h + + + $SRC_BLE_CORE$\inc\gatt.h + + + $SRC_BLE_CORE$\inc\hci.h + + + $SRC_COMMON$\osal\src\common\osal.c + + + $SRC_COMMON$\osal\src\inc\osal_snv.h + + + + Profiles + + $SRC_BLE_CORE$\profiles\roles\cc26xx\central.c + + + $SRC_BLE_CORE$\profiles\roles\cc26xx\central.h + + + + Startup + + $SRC_COMMON$\hal\src\target\board.c + + + $PROJ_DIR$\..\config\ccfg_app_ble.c + + + $SRC_BLE_CORE$\examples\simple_central\cc26xx\app\main.c + + + + Tools + + $PROJ_DIR$\..\config\app_ble.cfg + + FlashROM + + CUSTOM + + .cfg + "$XDCROOT$/bin/stderr" + 0 + + + $PROJ_DIR$\..\config\configPkg\package.mak + + + + + + + + $SRC_BLE_CORE$\common\cc26xx\iar\cc26xx_app.icf + + + $PROJ_DIR$\..\config\iar_boundary.bdef + + + $PROJ_DIR$\..\config\iar_boundary.xcl + + + + + diff --git a/examples/cc2650lp/simple_central/iar/config/app_ble.cfg b/examples/cc2650lp/simple_central/iar/config/app_ble.cfg new file mode 100644 index 0000000..af231cc --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/config/app_ble.cfg @@ -0,0 +1,679 @@ +/****************************************************************************** + + @file app_ble.cfg + + @brief TI RTOS Configuration file for CC26xx + + Imported Symbols + Note: These symbols are defined following the --cfgArgs option. + In IAR this is done at the end of the pre-build step. In CCS, this + is done in Properties->build->XDCtools-Advanced options->Configuration + script arguments. Multiple symbols can be used separating them by a + comma (","). + + By default, TI RTOS builds with RTOS in ROM, interrupt vectors starting + at address 0x0 and uses ROM only kernel modules. + + NO_ROM: When set to a non-zero value, RTOS builds in Flash instead + of ROM + OAD_IMG_A: When set to a non-zero value, interrupt vectors are set to + their expected location for on-chip OAD Image A. + OAD_IMG_B: When set to a non-zero value, interrupt vectors are set to + their expected location for on-chip OAD Image B. + OAD_IMG_E: When set to a non-zero value, interrupt vectors are set to + their expected location for external flash OAD. + USE_EVENTS: Build the RTOS Kernel Event module. + + Group: WCS, BTS + Target Device: CC2650, CC2640, CC1350 + + ****************************************************************************** + + Copyright (c) 2013-2016, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + Release Name: ble_sdk_2_02_00_31 + Release Date: 2016-06-16 18:57:29 + *****************************************************************************/ + + +/* ================ ROM configuration ================ */ +/* + * To use BIOS in flash, comment out the code block below. + */ +if (typeof NO_ROM == 'undefined' || (typeof NO_ROM != 'undefined' && NO_ROM == 0)) +{ + var ROM = xdc.useModule('ti.sysbios.rom.ROM'); + if (Program.cpu.deviceName.match(/CC26/)) { + ROM.romName = ROM.CC2650; + } + else if (Program.cpu.deviceName.match(/CC13/)) { + ROM.romName = ROM.CC1350; + } +} + + + +/* ================ Boot configuration ================ */ +if (typeof NO_ROM == 'undefined' || (typeof NO_ROM != 'undefined' && NO_ROM == 0)) +{ + var Boot = xdc.useModule('ti.sysbios.family.arm.cc26xx.Boot'); +} +/* + * This module contains family specific Boot APIs and configuration settings. + * See the SYS/BIOS API guide for more information. + */ +if (typeof NO_ROM == 'undefined' || (typeof NO_ROM != 'undefined' && NO_ROM == 0)) +{ + Boot.driverlibVersion = 2; + Boot.customerConfig = false; +} + + +/* ================ Clock configuration ================ */ +var Clock = xdc.useModule('ti.sysbios.knl.Clock'); +/* + * When using Power and calibrateRCOSC is set to true, this should be set to 10. + * The timer used by the Clock module supports TickMode_DYNAMIC. This enables us + * to set the tick period to 10 us without generating the overhead of additional + * interrupts. + * + * Note: The calibrateRCOSC parameter is set within the Power configuration + * structure in the "Board.c" file. + */ +Clock.tickPeriod = 10; +Clock.swiPriority = 5; + + +/* ================ Types configuration ================ */ +var Types = xdc.useModule('xdc.runtime.Types'); +/* + * This module defines basic constants and types used throughout the + * xdc.runtime package. + */ + + + +/* ================ Defaults (module) configuration ================ */ +var Defaults = xdc.useModule('xdc.runtime.Defaults'); +/* + * A flag to allow module names to be loaded on the target. Module name + * strings are placed in the .const section for debugging purposes. + * + * Pick one: + * - true (default) + * Setting this parameter to true will include name strings in the .const + * section so that Errors and Asserts are easier to debug. + * - false + * Setting this parameter to false will reduce footprint in the .const + * section. As a result, Error and Assert messages will contain an + * "unknown module" prefix instead of the actual module name. + * + * When using BIOS in ROM: + * This option must be set to false. + */ +//Defaults.common$.namedModule = true; +Defaults.common$.namedModule = false; + +/* Compile out all Assert's */ +//Defaults.common$.diags_ASSERT = Diags.ALWAYS_OFF; + +/* Allow Mod_create() and Mod_construct() but not delete() or destruct() */ +Defaults.common$.memoryPolicy = Types.CREATE_POLICY; + + + +/* ================ Error configuration ================ */ +var Error = xdc.useModule('xdc.runtime.Error'); +/* + * This function is called to handle all raised errors, but unlike + * Error.raiseHook, this function is responsible for completely handling the + * error with an appropriately initialized Error_Block. + * + * Pick one: + * - Error.policyDefault (default) + * Calls Error.raiseHook with an initialized Error_Block structure and logs + * the error using the module's logger. + * - Error.policySpin + * Simple alternative that traps on a while(1) loop for minimized target + * footprint. + * Using Error.policySpin, the Error.raiseHook will NOT called. + */ +//Error.policyFxn = Error.policyDefault; +Error.policyFxn = Error.policySpin; + +/* + * If Error.policyFxn is set to Error.policyDefault, this function is called + * whenever an error is raised by the Error module. + * + * Pick one: + * - Error.print (default) + * Errors are formatted and output via System_printf() for easier + * debugging. + * - null + * Errors are trapped with a while(1) stub function. This option reduces + * code footprint. + * - non-null function + * Errors invoke custom user function. See the Error module documentation + * for more details. + */ +//Error.raiseHook = Error.print; +Error.raiseHook = null; +//Error.raiseHook = "&myErrorFxn"; + +/* + * If Error.policyFxn is set to Error.policyDefault, this option applies to the + * maximum number of times the Error.raiseHook function can be recursively + * invoked. This option limits the possibility of an infinite recursion that + * could lead to a stack overflow. + * The default value is 16. + */ +Error.maxDepth = 2; + + + +/* ================ Hwi configuration ================ */ +var halHwi = xdc.useModule('ti.sysbios.hal.Hwi'); +var m3Hwi = xdc.useModule('ti.sysbios.family.arm.m3.Hwi'); +/* + * Checks for Hwi (system) stack overruns while in the Idle loop. + * + * Pick one: + * - true (default) + * Checks the top word for system stack overflows during the idle loop and + * raises an Error if one is detected. + * - false + * Disabling the runtime check improves runtime performance and yields a + * reduced flash footprint. + */ +//halHwi.checkStackFlag = true; +halHwi.checkStackFlag = false; + +/* + * The following options alter the system's behavior when a hardware exception + * is detected. + * + * Pick one: + * - Hwi.enableException = true + * This option causes the default m3Hwi.excHandlerFunc function to fully + * decode an exception and dump the registers to the system console. + * This option raises errors in the Error module and displays the + * exception in ROV. + * - Hwi.enableException = false + * This option reduces code footprint by not decoding or printing the + * exception to the system console. + * It however still raises errors in the Error module and displays the + * exception in ROV. + * - Hwi.excHandlerFunc = null + * This is the most aggressive option for code footprint savings; but it + * can difficult to debug exceptions. It reduces flash footprint by + * plugging in a default while(1) trap when exception occur. This option + * does not raise an error with the Error module. + */ +//m3Hwi.enableException = true; +//m3Hwi.enableException = false; +m3Hwi.excHandlerFunc = null; + +/* + * Enable hardware exception generation when dividing by zero. + * + * Pick one: + * - 0 (default) + * Disables hardware exceptions when dividing by zero + * - 1 + * Enables hardware exceptions when dividing by zero + */ +m3Hwi.nvicCCR.DIV_0_TRP = 0; +//m3Hwi.nvicCCR.DIV_0_TRP = 1; + +/* + * Enable hardware exception generation for invalid data alignment. + * + * Pick one: + * - 0 (default) + * Disables hardware exceptions for data alignment + * - 1 + * Enables hardware exceptions for data alignment + */ +m3Hwi.nvicCCR.UNALIGN_TRP = 0; +//m3Hwi.nvicCCR.UNALIGN_TRP = 1; + +/* Put reset vector at start of Flash */ +if (typeof OAD_IMG_A != 'undefined' && OAD_IMG_A == 1) +{ + m3Hwi.resetVectorAddress = 0x0610; +} +else if (typeof OAD_IMG_B != 'undefined' && OAD_IMG_B == 1) +{ + m3Hwi.resetVectorAddress = 0x6010; +} +else if (typeof OAD_IMG_E != 'undefined' && OAD_IMG_E == 1) +{ + m3Hwi.resetVectorAddress = 0x1010; +} +else +{ + m3Hwi.resetVectorAddress = 0x0; +} + +/* Put interrupt vector at start of RAM so interrupts can be configured at runtime */ +m3Hwi.vectorTableAddress = 0x20000000; + +/* CC2650 has 50 interrupts */ +m3Hwi.NUM_INTERRUPTS = 50; + + + +/* ================ Idle configuration ================ */ +var Idle = xdc.useModule('ti.sysbios.knl.Idle'); +/* + * The Idle module is used to specify a list of functions to be called when no + * other tasks are running in the system. + * + * Functions added here will be run continuously within the idle task. + * + * Function signature: + * Void func(Void); + */ +//Idle.addFunc("&myIdleFunc"); + + + +/* ================ Kernel (SYS/BIOS) configuration ================ */ +var BIOS = xdc.useModule('ti.sysbios.BIOS'); +/* + * Enable asserts in the BIOS library. + * + * Pick one: + * - true (default) + * Enables asserts for debugging purposes. + * - false + * Disables asserts for a reduced code footprint and better performance. + * + * When using BIOS in ROM: + * This option must be set to false. + */ +//BIOS.assertsEnabled = true; +BIOS.assertsEnabled = false; + +/* + * Specify default heap size for BIOS. + */ +if (typeof NO_ROM == 'undefined' || (typeof NO_ROM != 'undefined' && NO_ROM == 0)) +{ + BIOS.heapSize = 1668; +} + +/* + * A flag to determine if xdc.runtime sources are to be included in a custom + * built BIOS library. + * + * Pick one: + * - false (default) + * The pre-built xdc.runtime library is provided by the respective target + * used to build the application. + * - true + * xdc.runtime library sources are to be included in the custom BIOS + * library. This option yields the most efficient library in both code + * footprint and runtime performance. + */ +//BIOS.includeXdcRuntime = false; +BIOS.includeXdcRuntime = true; + +/* + * The SYS/BIOS runtime is provided in the form of a library that is linked + * with the application. Several forms of this library are provided with the + * SYS/BIOS product. + * + * Pick one: + * - BIOS.LibType_Custom + * Custom built library that is highly optimized for code footprint and + * runtime performance. + * - BIOS.LibType_Debug + * Custom built library that is non-optimized that can be used to + * single-step through APIs with a debugger. + * + */ +BIOS.libType = BIOS.LibType_Custom; +//BIOS.libType = BIOS.LibType_Debug; + +/* + * Runtime instance creation enable flag. + * + * Pick one: + * - true (default) + * Allows Mod_create() and Mod_delete() to be called at runtime which + * requires a default heap for dynamic memory allocation. + * - false + * Reduces code footprint by disallowing Mod_create() and Mod_delete() to + * be called at runtime. Object instances are constructed via + * Mod_construct() and destructed via Mod_destruct(). + * + * When using BIOS in ROM: + * This option must be set to true. + */ +BIOS.runtimeCreatesEnabled = true; +//BIOS.runtimeCreatesEnabled = false; + +/* + * Enable logs in the BIOS library. + * + * Pick one: + * - true (default) + * Enables logs for debugging purposes. + * - false + * Disables logging for reduced code footprint and improved runtime + * performance. + * + * When using BIOS in ROM: + * This option must be set to false. + */ +//BIOS.logsEnabled = true; +BIOS.logsEnabled = false; + +BIOS.swiEnabled = true; + + + +/* ================ Memory configuration ================ */ +var Memory = xdc.useModule('xdc.runtime.Memory'); +/* + * The Memory module itself simply provides a common interface for any + * variety of system and application specific memory management policies + * implemented by the IHeap modules(Ex. HeapMem, HeapBuf). + */ +/* Create a small "alloc-only" heap */ +if (typeof NO_ROM != 'undefined' && NO_ROM != 0) +{ + var HeapMin = xdc.useModule('xdc.runtime.HeapMin'); + var heapMinParams = new HeapMin.Params; + heapMinParams.size = 1668; + var myHeapMin = HeapMin.create(heapMinParams); + Memory.defaultHeapInstance = myHeapMin; +} + + + +/* ================ Program configuration ================ */ +/* + * Program.stack is ignored with IAR. Use the project options in + * IAR Embedded Workbench to alter the system stack size. + */ +if (typeof NO_ROM == 'undefined' || (typeof NO_ROM != 'undefined' && NO_ROM == 0)) +{ + Program.stack = 1024; + Program.argSize = 0; +} +else +{ + Program.stack = 512; +} + + + +/* ================ Semaphore configuration ================ */ +var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore'); +/* + * Enables global support for Task priority pend queuing. + * + * Pick one: + * - true (default) + * This allows pending tasks to be serviced based on their task priority. + * - false + * Pending tasks are services based on first in, first out basis. + * + * When using BIOS in ROM: + * This option must be set to false. + */ +//Semaphore.supportsPriority = true; +Semaphore.supportsPriority = false; + +/* + * Allows for the implicit posting of events through the semaphore, + * disable for additional code saving. + * + * Pick one: + * - true + * This allows the Semaphore module to post semaphores and events + * simultaneously. + * - false (default) + * Events must be explicitly posted to unblock tasks. + * + * When using BIOS in ROM: + * This option must be set to false. + */ +//Semaphore.supportsEvents = true; +Semaphore.supportsEvents = false; + + + + +/* ================ Events configuration ================ */ +if (typeof USE_EVENTS != 'undefined' && USE_EVENTS != 0) +{ + var Events = xdc.useModule('ti.sysbios.knl.Event'); +} + + + +/* ================ Swi configuration ================ */ +var Swi = xdc.useModule('ti.sysbios.knl.Swi'); +/* + * A software interrupt is an object that encapsulates a function to be + * executed and a priority. Software interrupts are prioritized, preempt tasks + * and are preempted by hardware interrupt service routines. + * + * This module is included to allow Swi's in a users' application. + */ +Swi.numPriorities = 6; + + + +/* ================ System configuration ================ */ +var System = xdc.useModule('xdc.runtime.System'); +/* + * The Abort handler is called when the system exits abnormally. + * + * Pick one: + * - System.abortStd (default) + * Call the ANSI C Standard 'abort()' to terminate the application. + * - System.abortSpin + * A lightweight abort function that loops indefinitely in a while(1) trap + * function. + * - A custom abort handler + * A user-defined function. See the System module documentation for + * details. + */ +//System.abortFxn = System.abortStd; +System.abortFxn = System.abortSpin; +//System.abortFxn = "&myAbortSystem"; + +/* + * The Exit handler is called when the system exits normally. + * + * Pick one: + * - System.exitStd (default) + * Call the ANSI C Standard 'exit()' to terminate the application. + * - System.exitSpin + * A lightweight exit function that loops indefinitely in a while(1) trap + * function. + * - A custom exit function + * A user-defined function. See the System module documentation for + * details. + */ +//System.exitFxn = System.exitStd; +System.exitFxn = System.exitSpin; +//System.exitFxn = "&myExitSystem"; + +/* + * Minimize exit handler array in the System module. The System module includes + * an array of functions that are registered with System_atexit() which is + * called by System_exit(). The default value is 8. + */ +System.maxAtexitHandlers = 0; + +/* + * The System.SupportProxy defines a low-level implementation of System + * functions such as System_printf(), System_flush(), etc. + * + * Pick one pair: + * - SysMin + * This module maintains an internal configurable circular buffer that + * stores the output until System_flush() is called. + * The size of the circular buffer is set via SysMin.bufSize. + * - SysCallback + * SysCallback allows for user-defined implementations for System APIs. + * The SysCallback support proxy has a smaller code footprint and can be + * used to supply custom System_printf services. + * The default SysCallback functions point to stub functions. See the + * SysCallback module's documentation. + */ +//var SysMin = xdc.useModule('xdc.runtime.SysMin'); +//SysMin.bufSize = 128; +//System.SupportProxy = SysMin; +var SysCallback = xdc.useModule('xdc.runtime.SysCallback'); +System.SupportProxy = SysCallback; +//SysCallback.abortFxn = "&myUserAbort"; +//SysCallback.exitFxn = "&myUserExit"; +//SysCallback.flushFxn = "&myUserFlush"; +//SysCallback.putchFxn = "&myUserPutch"; +//SysCallback.readyFxn = "&myUserReady"; + + + +/* ================ Task configuration ================ */ +var Task = xdc.useModule('ti.sysbios.knl.Task'); +/* + * Check task stacks for overflow conditions. + * + * Pick one: + * - true (default) + * Enables runtime checks for task stack overflow conditions during + * context switching ("from" and "to") + * - false + * Disables runtime checks for task stack overflow conditions. + * + * When using BIOS in ROM: + * This option must be set to false. + */ +//Task.checkStackFlag = true; +Task.checkStackFlag = false; + +/* + * Set the default task stack size when creating tasks. + * + * The default is dependent on the device being used. Reducing the default stack + * size yields greater memory savings. + */ +Task.defaultStackSize = 512; + +/* + * Enables the idle task. + * + * Pick one: + * - true (default) + * Creates a task with priority of 0 which calls idle hook functions. This + * option must be set to true to gain power savings provided by the Power + * module. + * - false + * No idle task is created. This option consumes less memory as no + * additional default task stack is needed. + * To gain power savings by the Power module without having the idle task, + * add Idle.run as the Task.allBlockedFunc. + */ +Task.enableIdleTask = true; +//Task.enableIdleTask = false; +//Task.allBlockedFunc = Idle.run; + +/* + * If Task.enableIdleTask is set to true, this option sets the idle task's + * stack size. + * + * Reducing the idle stack size yields greater memory savings. + */ +Task.idleTaskStackSize = 512; + +/* + * Reduce the number of task priorities. + * The default is 16. + * Decreasing the number of task priorities yield memory savings. + */ +Task.numPriorities = 6; + + + +/* ================ Text configuration ================ */ +var Text = xdc.useModule('xdc.runtime.Text'); +/* + * These strings are placed in the .const section. Setting this parameter to + * false will save space in the .const section. Error, Assert and Log messages + * will print raw ids and args instead of a formatted message. + * + * Pick one: + * - true (default) + * This option loads test string into the .const for easier debugging. + * - false + * This option reduces the .const footprint. + */ +//Text.isLoaded = true; +Text.isLoaded = false; + + + +/* ================ TI-RTOS middleware configuration ================ */ +var mwConfig = xdc.useModule('ti.mw.Config'); +/* + * Include TI-RTOS middleware libraries + */ + + + +/* ================ TI-RTOS drivers' configuration ================ */ +var driversConfig = xdc.useModule('ti.drivers.Config'); +/* + * Include TI-RTOS drivers + * + * Pick one: + * - driversConfig.LibType_NonInstrumented (default) + * Use TI-RTOS drivers library optimized for footprint and performance + * without asserts or logs. + * - driversConfig.LibType_Instrumented + * Use TI-RTOS drivers library for debugging with asserts and logs enabled. + */ +driversConfig.libType = driversConfig.LibType_NonInstrumented; +//driversConfig.libType = driversConfig.LibType_Instrumented; + + + +// Remaining Modules +var Diags = xdc.useModule('xdc.runtime.Diags'); +var Main = xdc.useModule('xdc.runtime.Main'); +var Reset = xdc.useModule('xdc.runtime.Reset'); diff --git a/examples/cc2650lp/simple_central/iar/config/ccfg_app_ble.c b/examples/cc2650lp/simple_central/iar/config/ccfg_app_ble.c new file mode 100644 index 0000000..63e5297 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/config/ccfg_app_ble.c @@ -0,0 +1,70 @@ +/****************************************************************************** + + @file ccfg_app_ble.c + + @brief Customer Configuration CC26xx PG2 device family. + + Group: WCS, BTS + Target Device: CC2650, CC2640, CC1350 + + ****************************************************************************** + + Copyright (c) 2014-2016, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + Release Name: ble_sdk_2_02_00_31_s + Release Date: 2016-06-16 18:59:11 + *****************************************************************************/ + +// +// ===> READ THIS BEFORE MODIFYING THIS FILE +// +// +// ===> READ THIS BEFORE MODIFYING THIS FILE +// +// +// ===> READ THIS BEFORE MODIFYING THIS FILE +// + +// The customer configuration area (ccfg section) is located at the end of the +// flash and reflect the hw configuration of the device. it is very important +// that it remains align with the version of driverlib you are using. +// all BLE project except sensor tag use the same configuration. +// Keeping the "#include " guarantee that your project using +// driverlib and the ccfg area will be align. + +// you can modify it if you want, the recommend way will be to remove the +// bellow include, copy the content of the file in this +// file and rebuild. + +// ==> KEEP IN MIND that if you do so, be sure that any further update of the +// driverlib must be align with your modified version of ccfg area. +#include diff --git a/examples/cc2650lp/simple_central/iar/config/iar_boundary.bdef b/examples/cc2650lp/simple_central/iar/config/iar_boundary.bdef new file mode 100644 index 0000000..432dff8 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/config/iar_boundary.bdef @@ -0,0 +1,10 @@ +/* +** Stack Frontier Generator 1.1.0 (2016-10-05 10:34:51.136000) +** +** WARNING - Auto-generated file. Modifications could be lost! +*/ + +-D ICALL_STACK0_ADDR=0x0000c001 +-D ICALL_STACK0_START=0x0000c000 +-D ICALL_RAM0_START=0x200041f0 + diff --git a/examples/cc2650lp/simple_central/iar/config/iar_boundary.xcl b/examples/cc2650lp/simple_central/iar/config/iar_boundary.xcl new file mode 100644 index 0000000..8dc1168 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/config/iar_boundary.xcl @@ -0,0 +1,10 @@ +/* +** Stack Frontier Generator 1.1.0 (2016-10-05 10:34:51.136000) +** +** WARNING - Auto-generated file. Modifications could be lost! +*/ + +--config_def ICALL_RAM0_START=0x200041f0 +--config_def ICALL_STACK0_START=0x0000c000 +--config_def ICALL_STACK0_ADDR=0x0000c001 + diff --git a/examples/cc2650lp/simple_central/iar/config/lib_linker.cmd b/examples/cc2650lp/simple_central/iar/config/lib_linker.cmd new file mode 100644 index 0000000..b59a277 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/config/lib_linker.cmd @@ -0,0 +1,8 @@ +/* + * DO NOT MODIFY. This file is automatically generated during the pre-build + * step by the lib_search utility + */ + +"C:\ti\simplelink\ble_sdk_2_02_00_31\blelib\host\host_xcxx_sc.a" +"C:\ti\simplelink\ble_sdk_2_02_00_31\blelib\ctrl\cc2640\cc2640_ctrl_xcxx_41c_ext_sc.a" +"C:\ti\simplelink\ble_sdk_2_02_00_31\blelib\hci_tl\cc26xx\cc26xx_hci_tl_none_v41.a" diff --git a/examples/cc2650lp/simple_central/iar/simple_central.custom_argvars b/examples/cc2650lp/simple_central/iar/simple_central.custom_argvars new file mode 100644 index 0000000..efb80c9 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/simple_central.custom_argvars @@ -0,0 +1,48 @@ + + + + + + TI_RTOS_DRIVERS_BASE + C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\tidrivers_cc13xx_cc26xx_2_20_01_10\packages + + + BIOS_BASE + C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\bios_6_46_01_38\packages + + + XDCPATH + $PROJ_DIR$\..\..\..\..\..\src\components\display_eng;C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\tidrivers_cc13xx_cc26xx_2_20_01_10\packages;C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\bios_6_46_01_38\packages;C:\ti\simplelink\ble_sdk_2_02_01_18 + + + CC26XXWARE + C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\cc26xxware_2_24_02_17393 + + + XDCROOT + C:\ti\xdctools_3_32_00_06_core + + + SRC_EX + C:\ti\simplelink\ble_sdk_2_02_01_18\src + + + SRC_BLE_CORE + C:\ti\simplelink\ble_sdk_2_02_01_18\src + + + SRC_COMMON + C:\ti\simplelink\ble_sdk_2_02_01_18\src\components + + + TOOLS_BLE + C:\ti\simplelink\ble_sdk_2_02_01_18\tools + + + ROM + C:\ti\simplelink\ble_sdk_2_02_01_18\src\rom + + + + + diff --git a/examples/cc2650lp/simple_central/iar/simple_central.eww b/examples/cc2650lp/simple_central/iar/simple_central.eww new file mode 100644 index 0000000..4db5250 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/simple_central.eww @@ -0,0 +1,13 @@ + + + + + $WS_DIR$\app\cc2650lp_app.ewp + + + $WS_DIR$\stack\cc2650lp_stack.ewp + + + + + diff --git a/examples/cc2650lp/simple_central/iar/stack/build_config.opt b/examples/cc2650lp/simple_central/iar/stack/build_config.opt new file mode 100644 index 0000000..28d7886 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/stack/build_config.opt @@ -0,0 +1,144 @@ +/****************************************************************************** + + @file build_config.opt + + @brief This file contains the Bluetooth Low Energy (BLE) build config options. + + Group: WCS, BTS + Target Device: CC2650, CC2640, CC1350 + + ****************************************************************************** + + Copyright (c) 2011-2016, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + Release Name: ble_sdk_2_02_00_31_s + Release Date: 2016-06-16 18:59:11 + *****************************************************************************/ + +/* + The following is a list of all possible build defines and corresponding options + that can be set for each define: + + GATT_DB_OFF_CHIP - Indicates that the GATT database is maintained off the chip on the + Application Processor (AP). + + GAP_BOND_MGR - Used to include the Bond Manager + + HOST_CONFIG (BLE Host Build Configurations) Possible Options: + PERIPHERAL_CFG - Used to include the GAP Peripheral Role support + CENTRAL_CFG - Used to include the GAP Central Role support + OBSERVER_CFG - Used to include the GAP Observer Role support + BROADCASTER_CFG - Used to include the GAP Broadcaster Role support + + BLE_V41_FEATURES Configure the stack to use features from the BLE 4.1 Specification + L2CAP_COC_CFG - Enable L2CAP Connection Oriented Channels + V41_CTRL_CFG - Enable Ping, Slave Feature Exchange, Connection Parameter Request, and + Master Slave connection roles within the Controller + + BLE_V42_FEATURES Configure the stack to use features from the BLE 4.2 Specification + EXT_DATA_LEN_CFG - Enable the Extended Data Length Feature in the Controller + SECURE_CONNS_CFG - Enable Secure Connections Pairing Procedure + PRIVACY_1_2_CFG - Enable Enahnced Privacy + + HCI_TL_FULL - All supported HCI commands are available via the Tranport Layer's NPI. + - Intended for NP solution. + HCI_TL_PTM - Only those HCI commands needed for Production Test Mode are available + via the Transport Layer's NPI + - Intended for SOC solutions where, during production, accesss is temporarily + needed (e.g. for PHY testing using Direct Test Mode, etc.). + HCI_TL_NONE - No supported HCI commands are available via the Transport Layer's NPI. + - Intended for SOC solutions. + + Below is general information for using and/or changing this configuration option file: + + Combo Roles: Combo roles can be set by defining multiple roles for HOST_CONFIG. The possible + combo roles and HOST_CONFIG defines are: + Peirpheral + Observer : PERIPHERAL_CFG+OBSERVER_CFG + Central + Broadcaster : CENTRAL_CFG+BROADCASTER_CFG + Peripheral + Central : PERIPHERAL_CFG+CENTRAL_CFG + Broadcaster + Observer : BROADCASTER_CFG+OBSERVER_CFG + + LibSearch Tool: There is a pre build action for every stack project that runs a tool + lib_search.exe. This tool aims to automatically import the correct library + files into your project based on the defines in this file. + + The locations of all library files and their correspond options are + /ble_core/ble_[host,ctrl]_lib/ for stack libs + and at /ble_core/hci_tl_lib/ for + HCI Transport Layer libs + + If an library is found that was built with matching options, it will be + copied into the project local directory at /../../lib/ and + subsequently linked with the stack. + + If you experience a build error with lib_search.exe, expand the build error + message by clicking Tools->Options->Messages->Show build messages:->All. + The error messages printed out by the LibSearch tool should now appear in + your Build Message window. + +*/ + +/* BLE Host Build Configurations */ +/* -DHOST_CONFIG=PERIPHERAL_CFG */ +-DHOST_CONFIG=CENTRAL_CFG +/* -DHOST_CONFIG=OBSERVER_CFG */ +/* -DHOST_CONFIG=BROADCASTER_CFG */ +/* -DHOST_CONFIG=PERIPHERAL_CFG+OBSERVER_CFG */ +/* -DHOST_CONFIG=CENTRAL_CFG+BROADCASTER_CFG */ +/* -DHOST_CONFIG=PERIPHERAL_CFG+CENTRAL_CFG */ +/* -DHOST_CONFIG=OBSERVER_CFG+BROADCASTER_CFG */ + +/* GATT Database being off chip */ +/* -DGATT_DB_OFF_CHIP */ + +/* Include GAP Bond Manager */ +-DGAP_BOND_MGR + +/* BLE v4.1 Features */ +/* -DBLE_V41_FEATURES=L2CAP_COC_CFG+V41_CTRL_CFG */ +/* -DBLE_V41_FEATURES=L2CAP_COC_CFG */ +-DBLE_V41_FEATURES=V41_CTRL_CFG + +/* BLE v4.2 Features */ +/* -DBLE_V42_FEATURES=SECURE_CONNS_CFG+PRIVACY_1_2_CFG+EXT_DATA_LEN_CFG */ +/* -DBLE_V42_FEATURES=SECURE_CONNS_CFG+PRIVACY_1_2_CFG */ +/* -DBLE_V42_FEATURES=PRIVACY_1_2_CFG+EXT_DATA_LEN_CFG */ +-DBLE_V42_FEATURES=SECURE_CONNS_CFG+EXT_DATA_LEN_CFG +/* -DBLE_V42_FEATURES=SECURE_CONNS_CFG */ +/* -DBLE_V42_FEATURES=PRIVACY_1_2_CFG */ +/*-DBLE_V42_FEATURES=EXT_DATA_LEN_CFG */ + +/* Include Transport Layer (Full or PTM) */ +-DHCI_TL_NONE +/* -DHCI_TL_PTM */ +/* -DHCI_TL_FULL */ + diff --git a/examples/cc2650lp/simple_central/iar/stack/cc2650lp_stack.ewd b/examples/cc2650lp/simple_central/iar/stack/cc2650lp_stack.ewd new file mode 100644 index 0000000..d6e9103 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/stack/cc2650lp_stack.ewd @@ -0,0 +1,1522 @@ + + + + 2 + + FlashROM + + ARM + + 1 + + C-SPY + 2 + + 27 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ARMSIM_ID + 2 + + 1 + 1 + 1 + + + + + + + + ANGEL_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + + CMSISDAP_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GDBSERVER_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + IARROM_ID + 2 + + 1 + 1 + 1 + + + + + + + + + IJET_ID + 2 + + 6 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JLINK_ID + 2 + + 15 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LMIFTDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + MACRAIGOR_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + PEMICRO_ID + 2 + + 2 + 1 + 1 + + + + + + + + + RDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + + + + + + + STLINK_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + THIRDPARTY_ID + 2 + + 0 + 1 + 1 + + + + + + + + XDS100_ID + 2 + + 4 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $TOOLKIT_DIR$\plugins\middleware\HCCWare\HCCWare.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\middleware\PercepioTraceExporter\PercepioTraceExportPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\AVIX\AVIX.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxTinyArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\embOS\embOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\MQX\MQXRtosPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\OpenRTOS\OpenRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\Quadros\Quadros_EWB7_Plugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SafeRTOS\SafeRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\ThreadX\ThreadXArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\TI-RTOS\tirtosplugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-286-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-III\uCOS-III-KA-CSpy.ewplugin + 0 + + + $EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin + 1 + + + $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin + 0 + + + $EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin + 1 + + + $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin + 0 + + + + + + diff --git a/examples/cc2650lp/simple_central/iar/stack/cc2650lp_stack.ewp b/examples/cc2650lp/simple_central/iar/stack/cc2650lp_stack.ewp new file mode 100644 index 0000000..d0e3479 --- /dev/null +++ b/examples/cc2650lp/simple_central/iar/stack/cc2650lp_stack.ewp @@ -0,0 +1,1249 @@ + + + + 2 + + FlashROM + + ARM + + 1 + + General + 3 + + 24 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 31 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 9 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + "$TOOLS_BLE$/lib_search/lib_search.exe" $PROJ_DIR$/build_config.opt "$TOOLS_BLE$/lib_search/params_split_cc2640.xml" $SRC_BLE_CORE$/../blelib $PROJ_DIR$/../config/lib_linker.cmd + "$TOOLS_BLE$/frontier/frontier.exe" iar "$PROJ_DIR$/$CONFIG_NAME$/List/simple_central_cc2650lp_stack.map" "$PROJ_DIR$/../config/iar_boundary.bdef" "$PROJ_DIR$/../config/iar_boundary.xcl" + + + + ILINK + 0 + + 17 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + + HAL + + Common + + $SRC_COMMON$\hal\src\common\hal_assert.c + + + + Include + + $SRC_COMMON$\hal\src\inc\hal_adc.h + + + $SRC_COMMON$\hal\src\inc\hal_assert.h + + + $SRC_COMMON$\hal\src\inc\hal_board.h + + + $SRC_COMMON$\hal\src\inc\hal_defs.h + + + $SRC_COMMON$\hal\src\inc\hal_key.h + + + $SRC_COMMON$\hal\src\inc\hal_lcd.h + + + $SRC_COMMON$\hal\src\inc\hal_led.h + + + $SRC_COMMON$\hal\src\inc\hal_sleep.h + + + $SRC_COMMON$\hal\src\inc\hal_timer.h + + + $SRC_COMMON$\hal\src\inc\hal_uart.h + + + + Target + + CC2650 + + _common + + $SRC_COMMON$\hal\src\target\_common\hal_mcu.h + + + + Config + + $SRC_COMMON$\hal\src\target\_common\hal_board_cfg.h + + + + Drivers + + $SRC_COMMON$\hal\src\target\_common\hal_flash_wrapper.c + + + $SRC_COMMON$\hal\src\target\_common\hal_gpio_wrapper.h + + + $SRC_COMMON$\hal\src\target\_common\hal_rtc_wrapper.c + + + $SRC_COMMON$\hal\src\target\_common\hal_rtc_wrapper.h + + + $SRC_COMMON$\hal\src\target\_common\hal_trng_wrapper.c + + + $SRC_COMMON$\hal\src\target\_common\hal_trng_wrapper.h + + + + + + + ICallBLE + + $SRC_BLE_CORE$\icall\stack\ble_dispatch.c + + + $SRC_BLE_CORE$\icall\inc\ble_dispatch.h + + + + INCLUDE + + $SRC_BLE_CORE$\inc\att.h + + + $SRC_BLE_CORE$\inc\gap.h + + + $SRC_BLE_CORE$\inc\gatt.h + + + $SRC_BLE_CORE$\inc\gatt_uuid.h + + + $SRC_BLE_CORE$\inc\hci.h + + + $SRC_BLE_CORE$\inc\l2cap.h + + + $SRC_BLE_CORE$\inc\linkdb.h + + + $SRC_BLE_CORE$\controller\cc26xx\inc\ll.h + + + $SRC_BLE_CORE$\inc\sm.h + + + + LIB + + $PROJ_DIR$\..\config\lib_linker.cmd + + + + NPI + + $SRC_BLE_CORE$\common\cc26xx\npi\stack\npi.c + + + + OSAL + + $SRC_COMMON$\osal\src\inc\comdef.h + + + $SRC_COMMON$\osal\src\common\osal.c + + + $SRC_COMMON$\osal\src\inc\osal.h + + + $SRC_COMMON$\osal\src\common\osal_bufmgr.c + + + $SRC_COMMON$\osal\src\inc\osal_bufmgr.h + + + $SRC_COMMON$\osal\src\common\osal_cbtimer.c + + + $SRC_COMMON$\osal\src\inc\osal_cbtimer.h + + + $SRC_COMMON$\osal\src\common\osal_clock.c + + + $SRC_COMMON$\osal\src\inc\osal_clock.h + + + $SRC_COMMON$\osal\src\inc\osal_memory.h + + + $SRC_COMMON$\osal\src\common\osal_memory_icall.c + + + $SRC_COMMON$\osal\src\common\osal_pwrmgr.c + + + $SRC_COMMON$\osal\src\inc\osal_pwrmgr.h + + + $SRC_COMMON$\osal\src\inc\osal_snv.h + + + $SRC_COMMON$\osal\src\mcu\cc26xx\osal_snv_wrapper.c + + + $SRC_COMMON$\osal\src\inc\osal_task.h + + + $SRC_COMMON$\osal\src\common\osal_timers.c + + + $SRC_COMMON$\osal\src\inc\osal_timers.h + + + + Profiles + + $SRC_BLE_CORE$\profiles\roles\gap.c + + + $SRC_BLE_CORE$\profiles\roles\gapbondmgr.c + + + $SRC_BLE_CORE$\profiles\roles\gapbondmgr.h + + + $SRC_BLE_CORE$\host\gattservapp_util.c + + + $SRC_BLE_CORE$\host\sm_ecc.c + + + + Startup + + $SRC_BLE_CORE$\icall\stack\ble_user_config.c + + + $SRC_BLE_CORE$\common\cc26xx\icall_startup.c + + + $SRC_BLE_CORE$\examples\simple_central\cc26xx\stack\osal_icall_ble.c + + + $SRC_BLE_CORE$\rom\rom_jt.c + + + + Tools + + $SRC_BLE_CORE$\config\build_components.opt + + + $PROJ_DIR$\build_config.opt + + + $SRC_BLE_CORE$\common\cc26xx\iar\cc26xx_stack.icf + + + $SRC_BLE_CORE$\common\cc26xx\onboard.c + + + $SRC_BLE_CORE$\common\cc26xx\onboard.h + + + + + diff --git a/examples/cc2650lp/simple_central_audio_receiver/ccs/app/simple_central_audio_receiver_cc2650lp_app.projectspec b/examples/cc2650lp/simple_central_audio_receiver/ccs/app/simple_central_audio_receiver_cc2650lp_app.projectspec index b99db8e..2f673e9 100644 --- a/examples/cc2650lp/simple_central_audio_receiver/ccs/app/simple_central_audio_receiver_cc2650lp_app.projectspec +++ b/examples/cc2650lp/simple_central_audio_receiver/ccs/app/simple_central_audio_receiver_cc2650lp_app.projectspec @@ -10,86 +10,99 @@ linkerCommandFile="cc26xx_app.cmd" preBuildStep="" - postBuildStep="${CG_TOOL_HEX} -order MS --memwidth=8 --romwidth=8 --intel -o ${ProjName}.hex ${ProjName}.out" + postBuildStep="${CG_TOOL_HEX} -order MS --memwidth=8 --romwidth=8 --intel -o ${ProjName}.hex ${ProjName}.out"> - compilerBuildOptions=" - --cmd_file=${SRC_EX}/config/build_components.opt - --cmd_file=${PROJECT_IMPORT_LOC}/../../iar/stack/build_config.opt - --cmd_file=${PROJECT_IMPORT_LOC}/../config/ccs_compiler_defines.bcfg - --silicon_version=7M3 - --code_state=16 - --float_support=vfplib - -O4 - --opt_for_speed=0 - --c99 - --relaxed_ansi - --diag_suppress=48 - --diag_warning=225 - --diag_wrap=off - --gen_func_subsections=on - --fp_reassoc=off - --unaligned_access=on - --embedded_constants=on - --wchar_t=16 - --enum_type=packed - --common=on - --sat_reassoc=off - --plain_char=unsigned + + -DUSE_ICALL + -DPOWER_SAVING + -DGAPCENTRALROLE_TASK_STACK_SIZE=700 + -DHEAPMGR_SIZE=0 + -DxDisplay_DISABLE_ALL + -DxBOARD_DISPLAY_EXCLUDE_UART + -DBOARD_DISPLAY_EXCLUDE_LCD + -DAUDIO_RECEIVER + -DSTREAM_TO_AUDBOOST + -DxSTREAM_TO_PC + -DGAPCENTRALROLE_NUM_RSSI_LINKS=1 + -DICALL_MAX_NUM_TASKS=3 + -DICALL_MAX_NUM_ENTITIES=6 + -Dxdc_runtime_Assert_DISABLE_ALL + -Dxdc_runtime_Log_DISABLE_ALL + -DxCC2650DK_7ID + -DCC26XX + -DCC2650_LAUNCHXL + -DMAX_PDU_SIZE=107 + -DxDLE_ENABLED + -I${PROJECT_IMPORT_LOC}/../../../../../src/util/audio_codec + -I${PROJECT_IMPORT_LOC}/../../../../util/mSBClibrary/include + -I${PROJECT_IMPORT_LOC}/../../../../../src/boards/CC2650_LAUNCHXL + -I${PROJECT_IMPORT_LOC}/../../../../../src/profiles/audio + -I${SRC_BLE_CORE}/examples/simple_central/cc26xx/app + -I${SRC_BLE_CORE}/controller/cc26xx/inc + -I${SRC_BLE_CORE}/inc + -I${SRC_EX}/common/cc26xx + -I${SRC_EX}/icall/inc + -I${SRC_EX}/inc + -I${SRC_EX}/profiles/roles + -I${SRC_EX}/profiles/roles/cc26xx + -I${SRC_EX}/profiles/simple_profile + -I${SRC_EX}/target + -I${SRC_COMMON}/hal/src/inc + -I${SRC_COMMON}/hal/src/target/_common + -I${SRC_COMMON}/hal/src/target/_common/cc26xx + -I${SRC_EX}/rom + -I${SRC_COMMON}/heapmgr + -I${SRC_COMMON}/icall/src/inc + -I${SRC_COMMON}/osal/src/inc + -I${SRC_COMMON}/services/src/saddr + -I${SRC_COMMON}/services/src/sdata + -I${CC26XXWARE} + " + linkerBuildOptions=" + -l${PROJECT_IMPORT_LOC}/../config/ccs_linker_defines.cmd + -l${SRC_EX}/common/cc26xx/ccs/cc26xx_app.cmd + --library="libc.a" + --library=${CC26XXWARE}/driverlib/bin/ccs/driverlib.lib + --library=${SRC_BLE_CORE}/rom/common_rom_releases/03282014/common_rom.symbols + --library=${PROJECT_IMPORT_LOC}/../../../../util/mSBClibrary/bin/cc2650_mSBCdecode_library.lib + --diag_wrap=off + --unused_section_elimination=on + --xml_link_info=${ProjName}_linkInfo.xml + --diag_suppress=10247-D + --diag_suppress=16002-D + " + description="" + launchWizard="false"> + + @@ -99,6 +112,7 @@ + @@ -106,10 +120,9 @@ - + - @@ -189,6 +202,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -235,9 +282,13 @@ + + + + - + diff --git a/examples/cc2650lp/simple_central_audio_receiver/ccs/config/ccs_compiler_defines.bcfg b/examples/cc2650lp/simple_central_audio_receiver/ccs/config/ccs_compiler_defines.bcfg index 3dcfbc8..dd1beb4 100644 --- a/examples/cc2650lp/simple_central_audio_receiver/ccs/config/ccs_compiler_defines.bcfg +++ b/examples/cc2650lp/simple_central_audio_receiver/ccs/config/ccs_compiler_defines.bcfg @@ -1,10 +1,10 @@ /* -** Stack Frontier Generator 1.1.0 (2016-10-27 22:33:51.971000) +** Stack Frontier Generator 1.1.0 (2017-03-30 11:36:30.981000) ** ** WARNING - Auto-generated file. Modifications could be lost! */ --define=ICALL_STACK0_ADDR=0xc001 --define=ICALL_STACK0_START=0xc000 ---define=ICALL_RAM0_START=0x20004340 +--define=ICALL_RAM0_START=0x20004318 diff --git a/examples/cc2650lp/simple_central_audio_receiver/ccs/config/ccs_linker_defines.cmd b/examples/cc2650lp/simple_central_audio_receiver/ccs/config/ccs_linker_defines.cmd index d4cd8da..15f6ec3 100644 --- a/examples/cc2650lp/simple_central_audio_receiver/ccs/config/ccs_linker_defines.cmd +++ b/examples/cc2650lp/simple_central_audio_receiver/ccs/config/ccs_linker_defines.cmd @@ -1,10 +1,10 @@ /* -** Stack Frontier Generator 1.1.0 (2016-10-27 22:33:51.971000) +** Stack Frontier Generator 1.1.0 (2017-03-30 11:36:30.981000) ** ** WARNING - Auto-generated file. Modifications could be lost! */ ---define=ICALL_RAM0_START=0x20004340 +--define=ICALL_RAM0_START=0x20004318 --define=ICALL_STACK0_START=0xc000 --define=ICALL_STACK0_ADDR=0xc001 diff --git a/examples/cc2650lp/simple_central_audio_receiver/ccs/config/lib_linker.cmd b/examples/cc2650lp/simple_central_audio_receiver/ccs/config/lib_linker.cmd index 2b073d3..2106e9c 100644 --- a/examples/cc2650lp/simple_central_audio_receiver/ccs/config/lib_linker.cmd +++ b/examples/cc2650lp/simple_central_audio_receiver/ccs/config/lib_linker.cmd @@ -4,5 +4,5 @@ */ "C:\ti\simplelink\ble_sdk_2_02_01_18\blelib\host\host_xcxx.a" -"C:\ti\simplelink\ble_sdk_2_02_01_18\blelib\ctrl\cc2640\cc2640_ctrl_xcxx_41c.a" -"C:\ti\simplelink\ble_sdk_2_02_01_18\blelib\hci_tl\cc26xx\cc26xx_hci_tl_none_v41.a" +"C:\ti\simplelink\ble_sdk_2_02_01_18\blelib\ctrl\cc2640\cc2640_ctrl_xcxx_41c_ext.a" +"C:\ti\simplelink\ble_sdk_2_02_01_18\blelib\hci_tl\cc26xx\cc26xx_hci_tl_none_v41_v42.a" diff --git a/examples/cc2650lp/simple_central_audio_receiver/ccs/stack/simple_central_audio_receiver_cc2650lp_stack.projectspec b/examples/cc2650lp/simple_central_audio_receiver/ccs/stack/simple_central_audio_receiver_cc2650lp_stack.projectspec index 65dc92c..3275ae1 100644 --- a/examples/cc2650lp/simple_central_audio_receiver/ccs/stack/simple_central_audio_receiver_cc2650lp_stack.projectspec +++ b/examples/cc2650lp/simple_central_audio_receiver/ccs/stack/simple_central_audio_receiver_cc2650lp_stack.projectspec @@ -235,6 +235,8 @@ + + diff --git a/examples/cc2650lp/simple_central_audio_receiver/iar/app/cc2650lp_app.ewd b/examples/cc2650lp/simple_central_audio_receiver/iar/app/cc2650lp_app.ewd index 4b7a360..1de7f0d 100644 --- a/examples/cc2650lp/simple_central_audio_receiver/iar/app/cc2650lp_app.ewd +++ b/examples/cc2650lp/simple_central_audio_receiver/iar/app/cc2650lp_app.ewd @@ -12,7 +12,7 @@ C-SPY 2 - 27 + 28 1 1 - + @@ -282,18 +282,47 @@ - CMSISDAP_ID + CADI_ID 2 - 2 + 0 1 1 + + + + + + + + CMSISDAP_ID + 2 + + 4 + 1 + 1 + + + @@ -524,15 +561,15 @@ IJET_ID 2 - 6 + 8 1 1 + + JLINK_ID 2 - 15 + 16 1 1 + - - XDS100_ID + TIFET_ID 2 - 4 + 1 1 1 + + + + + + + + + + + + + + + + + XDS100_ID + 2 + + 6 + 1 + 1 + + + + @@ -1507,10 +1635,6 @@ $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin 0 - - $EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin - 1 - $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin 0 diff --git a/examples/cc2650lp/simple_central_audio_receiver/iar/app/cc2650lp_app.ewp b/examples/cc2650lp/simple_central_audio_receiver/iar/app/cc2650lp_app.ewp index 5059ee8..85aeffd 100644 --- a/examples/cc2650lp/simple_central_audio_receiver/iar/app/cc2650lp_app.ewp +++ b/examples/cc2650lp/simple_central_audio_receiver/iar/app/cc2650lp_app.ewp @@ -77,7 +77,7 @@ @@ -183,10 +183,14 @@ CCDefines USE_ICALL POWER_SAVING + HEAPMGR_METRICS + AUDIO_RECEIVER + STREAM_TO_AUDBOOST + xSTREAM_TO_PC HEAPMGR_SIZE=0 xDisplay_DISABLE_ALL - BOARD_DISPLAY_EXCLUDE_UART - xBOARD_DISPLAY_EXCLUDE_LCD + xBOARD_DISPLAY_EXCLUDE_UART + BOARD_DISPLAY_EXCLUDE_LCD GAPCENTRALROLE_NUM_RSSI_LINKS=1 ICALL_MAX_NUM_TASKS=3 ICALL_MAX_NUM_ENTITIES=6 @@ -194,7 +198,8 @@ xdc_runtime_Log_DISABLE_ALL CC26XX CC2650_LAUNCHXL - AUDIO_SERVICE + MAX_PDU_SIZE=107 + xDLE_ENABLED - - $EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin - 1 - $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin 0 @@ -1514,7 +1642,7 @@ - FlashOnly_OAD_ImgB + FlashROM-CC2650MOD-BP ARM @@ -1523,9 +1651,13 @@ C-SPY 2 - 27 + 28 1 1 + - + @@ -1789,18 +1921,47 @@ - CMSISDAP_ID + CADI_ID 2 - 2 + 0 1 1 + + + + + + + + CMSISDAP_ID + 2 + + 4 + 1 + 1 + + + @@ -2031,15 +2200,15 @@ IJET_ID 2 - 6 + 8 1 1 + + JLINK_ID 2 - 15 + 16 1 1 + - - XDS100_ID + TIFET_ID 2 - 4 + 1 1 1 - + + + + XDS100_ID + 2 + + 6 + 1 + 1 - - - - - - - - - - - - - - - - - - - - - - - - - $TOOLKIT_DIR$\plugins\middleware\HCCWare\HCCWare.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\middleware\PercepioTraceExporter\PercepioTraceExportPlugin.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\AVIX\AVIX.ENU.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\CMX\CmxArmPlugin.ENU.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\CMX\CmxTinyArmPlugin.ENU.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\embOS\embOSPlugin.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\MQX\MQXRtosPlugin.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\OpenRTOS\OpenRTOSPlugin.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\Quadros\Quadros_EWB7_Plugin.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\SafeRTOS\SafeRTOSPlugin.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\ThreadX\ThreadXArmPlugin.ENU.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\TI-RTOS\tirtosplugin.ewplugin - 1 - - - $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-286-KA-CSpy.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-KA-CSpy.ewplugin - 0 - - - $TOOLKIT_DIR$\plugins\rtos\uCOS-III\uCOS-III-KA-CSpy.ewplugin - 0 - - - $EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin - 1 - - - $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin - 0 - - - $EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin - 1 - - - $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin - 0 - - - - - FlashOnly_OAD_ExtFlash - - ARM - - 1 - - C-SPY - 2 - - 27 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ARMSIM_ID - 2 - - 1 - 1 - 1 - - - - - - - - ANGEL_ID - 2 - - 0 - 1 - 1 - - - - - - - - - - - - CMSISDAP_ID - 2 - - 2 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GDBSERVER_ID - 2 - - 0 - 1 - 1 - - - - - - - - - - - IARROM_ID - 2 - - 1 - 1 - 1 - - - - - - - - - IJET_ID - 2 - - 6 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - JLINK_ID - 2 - - 15 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LMIFTDI_ID - 2 - - 2 - 1 - 1 - - - - - - - - - - MACRAIGOR_ID - 2 - - 3 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - PEMICRO_ID - 2 - - 2 - 1 - 1 - - - - - - - - - RDI_ID - 2 - - 2 - 1 - 1 - - - - - - - - - - - - - - - - STLINK_ID - 2 - - 3 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - THIRDPARTY_ID - 2 - - 0 - 1 - 1 - - - - - - - - XDS100_ID - 2 - - 4 - 1 - 1 - + + @@ -4525,10 +3274,6 @@ $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin 0 - - $EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin - 1 - $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin 0 diff --git a/examples/cc2650lp/spp_ble_client/iar/app/cc2650lp_app.ewp b/examples/cc2650lp/spp_ble_client/iar/app/cc2650lp_app.ewp index 3fd5cc1..6b9e7c6 100644 --- a/examples/cc2650lp/spp_ble_client/iar/app/cc2650lp_app.ewp +++ b/examples/cc2650lp/spp_ble_client/iar/app/cc2650lp_app.ewp @@ -77,7 +77,7 @@ @@ -191,6 +191,7 @@ xdc_runtime_Assert_DISABLE_ALL xdc_runtime_Log_DISABLE_ALL CC2650_LAUNCHXL + xBOOSTXL_CC2650MA CC26XX Display_DISABLE_ALL @@ -682,7 +683,7 @@ ILINK 0 - 17 + 18 1 1 + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + + FlashROM-CC2650MOD-BP + + ARM + + 1 + + General + 3 + + 24 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 31 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 9 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + "$XDCROOT$/xs" --xdcpath="$XDCPATH$" iar.tools.configuro -c "$TOOLKIT_DIR$" --cc "$COMPILER_PATH$" --device "$DEVICE$" --compileOptions $COMPILER_ARGS_ROOT_QUOTED$ --linkOptions $LINKER_ARGS_QUOTED$ --profile release --projFile "$PROJ_PATH$" + + + + + ILINK + 0 + + 18 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1023,27 +2033,27 @@ $TI_BLE_SDK_BASE$\src\common\cc26xx\util.h - + Drivers - + RF + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\rf\RF.h + $TI_RTOS_DRIVERS_BASE$\ti\drivers\rf\RFCC26XX_singleMode.c + + + TRNG + + $TI_BLE_SDK_BASE$\src\components\hal\src\target\_common\TRNGCC26XX.c + - $TI_RTOS_DRIVERS_BASE$\ti\drivers\rf\RF.h + $TI_BLE_SDK_BASE$\src\components\hal\src\target\_common\TRNGCC26XX.h - - TRNG - - $SRC_COMMON$\hal\src\target\_common\TRNGCC26XX.c - - - $SRC_COMMON$\hal\src\target\_common\TRNGCC26XX.h - - - + ICall @@ -1163,6 +2173,22 @@ + + FlashROM-CC2650MOD-BP + + CUSTOM + + .cfg + "$XDCROOT$/bin/stderr" + 0 + + + $PROJ_DIR$\..\config\configPkg\package.mak + + + + + $TI_BLE_SDK_BASE$\src\common\cc26xx\iar\cc26xx_app.icf diff --git a/examples/cc2650lp/spp_ble_client/iar/config/iar_boundary.bdef b/examples/cc2650lp/spp_ble_client/iar/config/iar_boundary.bdef index e0690ce..065606a 100644 --- a/examples/cc2650lp/spp_ble_client/iar/config/iar_boundary.bdef +++ b/examples/cc2650lp/spp_ble_client/iar/config/iar_boundary.bdef @@ -1,10 +1,10 @@ /* -** Stack Frontier Generator 1.1.0 (2016-11-02 11:47:45.467000) +** Stack Frontier Generator 1.1.0 (2017-05-19 12:28:56.481000) ** ** WARNING - Auto-generated file. Modifications could be lost! */ --D ICALL_STACK0_ADDR=0x0000e2f5 --D ICALL_STACK0_START=0x0000e2f4 +-D ICALL_STACK0_ADDR=0x0000e2f9 +-D ICALL_STACK0_START=0x0000e2f8 -D ICALL_RAM0_START=0x20004320 diff --git a/examples/cc2650lp/spp_ble_client/iar/config/iar_boundary.xcl b/examples/cc2650lp/spp_ble_client/iar/config/iar_boundary.xcl index 4e412ca..ccbdab9 100644 --- a/examples/cc2650lp/spp_ble_client/iar/config/iar_boundary.xcl +++ b/examples/cc2650lp/spp_ble_client/iar/config/iar_boundary.xcl @@ -1,10 +1,10 @@ /* -** Stack Frontier Generator 1.1.0 (2016-11-02 11:47:45.467000) +** Stack Frontier Generator 1.1.0 (2017-05-19 12:28:56.481000) ** ** WARNING - Auto-generated file. Modifications could be lost! */ --config_def ICALL_RAM0_START=0x20004320 ---config_def ICALL_STACK0_START=0x0000e2f4 ---config_def ICALL_STACK0_ADDR=0x0000e2f5 +--config_def ICALL_STACK0_START=0x0000e2f8 +--config_def ICALL_STACK0_ADDR=0x0000e2f9 diff --git a/examples/cc2650lp/spp_ble_client/iar/stack/cc2650lp_stack.ewd b/examples/cc2650lp/spp_ble_client/iar/stack/cc2650lp_stack.ewd index d8ccc2a..59e3558 100644 --- a/examples/cc2650lp/spp_ble_client/iar/stack/cc2650lp_stack.ewd +++ b/examples/cc2650lp/spp_ble_client/iar/stack/cc2650lp_stack.ewd @@ -12,7 +12,7 @@ C-SPY 2 - 27 + 28 1 1 - + @@ -282,18 +282,47 @@ - CMSISDAP_ID + CADI_ID 2 - 2 + 0 1 1 + + + + + + + + CMSISDAP_ID + 2 + + 4 + 1 + 1 + + + @@ -524,15 +561,15 @@ IJET_ID 2 - 6 + 8 1 1 + + JLINK_ID 2 - 15 + 16 1 1 + - - XDS100_ID + TIFET_ID 2 - 4 + 1 1 1 + + + + + + + + + + + + + + + + + XDS100_ID + 2 + + 6 + 1 + 1 + + + + @@ -1507,10 +1635,6 @@ $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin 0 - - $EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin - 1 - $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin 0 diff --git a/examples/cc2650lp/spp_ble_client/iar/stack/cc2650lp_stack.ewp b/examples/cc2650lp/spp_ble_client/iar/stack/cc2650lp_stack.ewp index 04d50f6..9f211df 100644 --- a/examples/cc2650lp/spp_ble_client/iar/stack/cc2650lp_stack.ewp +++ b/examples/cc2650lp/spp_ble_client/iar/stack/cc2650lp_stack.ewp @@ -77,7 +77,7 @@ + + + + + + @@ -212,11 +219,11 @@ - + - + - + diff --git a/examples/cc2650lp/spp_ble_server/ccs/stack/spp_ble_server_cc2650lp_stack.projectspec b/examples/cc2650lp/spp_ble_server/ccs/stack/spp_ble_server_cc2650lp_stack.projectspec index a0fa0a7..d56c658 100644 --- a/examples/cc2650lp/spp_ble_server/ccs/stack/spp_ble_server_cc2650lp_stack.projectspec +++ b/examples/cc2650lp/spp_ble_server/ccs/stack/spp_ble_server_cc2650lp_stack.projectspec @@ -240,6 +240,8 @@ + + diff --git a/examples/cc2650lp/spp_ble_server/iar/app/cc2650lp_app.ewd b/examples/cc2650lp/spp_ble_server/iar/app/cc2650lp_app.ewd index c8672f5..452a832 100644 --- a/examples/cc2650lp/spp_ble_server/iar/app/cc2650lp_app.ewd +++ b/examples/cc2650lp/spp_ble_server/iar/app/cc2650lp_app.ewd @@ -12,7 +12,7 @@ C-SPY 2 - 27 + 28 1 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ARMSIM_ID + 2 + + 1 + 1 + 1 + + + + + + + + ANGEL_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + + CADI_ID + 2 + + 0 + 1 + 1 + + + + + + + + + CMSISDAP_ID + 2 + + 4 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GDBSERVER_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + IARROM_ID + 2 + + 1 + 1 + 1 + + + + + + + + + IJET_ID + 2 + + 8 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JLINK_ID + 2 + + 16 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LMIFTDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + MACRAIGOR_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + PEMICRO_ID + 2 + + 3 + 1 + 1 + + + + + + + + RDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + + + + + + + STLINK_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + THIRDPARTY_ID + 2 + + 0 + 1 + 1 + + + + + + + + TIFET_ID + 2 + + 1 + 1 + 1 + + + + + + + + + + + + + + + + + + + XDS100_ID + 2 + + 6 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $TOOLKIT_DIR$\plugins\middleware\HCCWare\HCCWare.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\middleware\PercepioTraceExporter\PercepioTraceExportPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\AVIX\AVIX.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxTinyArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\embOS\embOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\MQX\MQXRtosPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\OpenRTOS\OpenRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\Quadros\Quadros_EWB7_Plugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SafeRTOS\SafeRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\ThreadX\ThreadXArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\TI-RTOS\tirtosplugin.ewplugin + 1 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-286-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-III\uCOS-III-KA-CSpy.ewplugin + 0 + + + $EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin + 1 + + + $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin + 0 + + + $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin + 0 + + + + + FlashROM-CC2650MOD-BP + + ARM + + 1 + + C-SPY + 2 + + 28 + 1 + 1 + + + + + + + + + + + + + + + + + + + + @@ -282,18 +1921,47 @@ - CMSISDAP_ID + CADI_ID 2 - 2 + 0 1 1 + + + + + + + + CMSISDAP_ID + 2 + + 4 + 1 + 1 + + + @@ -524,15 +2200,15 @@ IJET_ID 2 - 6 + 8 1 1 + + JLINK_ID 2 - 15 + 16 1 1 + - - XDS100_ID + TIFET_ID 2 - 4 + 1 1 1 + + + + + + + + + + + + + + + + + XDS100_ID + 2 + + 6 + 1 + 1 + + + + @@ -1507,10 +3274,6 @@ $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin 0 - - $EW_DIR$\common\plugins\SymList\SymList.ENU.ewplugin - 1 - $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin 0 diff --git a/examples/cc2650lp/spp_ble_server/iar/app/cc2650lp_app.ewp b/examples/cc2650lp/spp_ble_server/iar/app/cc2650lp_app.ewp index 32911f1..83805ee 100644 --- a/examples/cc2650lp/spp_ble_server/iar/app/cc2650lp_app.ewp +++ b/examples/cc2650lp/spp_ble_server/iar/app/cc2650lp_app.ewp @@ -77,7 +77,7 @@ @@ -191,6 +191,7 @@ xdc_runtime_Assert_DISABLE_ALL xdc_runtime_Log_DISABLE_ALL CC2650_LAUNCHXL + xBOOSTXL_CC2650MA CC26XX Display_DISABLE_ALL @@ -682,7 +683,7 @@ ILINK 0 - 17 + 18 1 1 + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + + FlashROM-CC2650MOD-BP + + ARM + + 1 + + General + 3 + + 24 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 31 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 9 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + "$XDCROOT$/xs" --xdcpath="$XDCPATH$" iar.tools.configuro -c "$TOOLKIT_DIR$" --cc "$COMPILER_PATH$" --device "$DEVICE$" --compileOptions $COMPILER_ARGS_ROOT_QUOTED$ --linkOptions $LINKER_ARGS_QUOTED$ --profile release --projFile "$PROJ_PATH$" + + + + + ILINK + 0 + + 18 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1023,27 +2033,27 @@ $TI_BLE_SDK_BASE$\src\common\cc26xx\util.h - + Drivers - + RF + + $TI_RTOS_DRIVERS_BASE$\ti\drivers\rf\RF.h + $TI_RTOS_DRIVERS_BASE$\ti\drivers\rf\RFCC26XX_singleMode.c + + + TRNG - $TI_RTOS_DRIVERS_BASE$\ti\drivers\rf\RF.h + $TI_BLE_SDK_BASE$\src\components\hal\src\target\_common\TRNGCC26XX.c + + + $TI_BLE_SDK_BASE$\src\components\hal\src\target\_common\TRNGCC26XX.h - - TRNG - - $SRC_COMMON$\hal\src\target\_common\TRNGCC26XX.c - - - $SRC_COMMON$\hal\src\target\_common\TRNGCC26XX.h - - - + ICall @@ -1184,6 +2194,22 @@ + + FlashROM-CC2650MOD-BP + + CUSTOM + + .cfg + "$XDCROOT$/bin/stderr" + 0 + + + $PROJ_DIR$\..\config\configPkg\package.mak + + + + + $TI_BLE_SDK_BASE$\src\common\cc26xx\iar\cc26xx_app.icf diff --git a/examples/cc2650lp/spp_ble_server/iar/config/iar_boundary.bdef b/examples/cc2650lp/spp_ble_server/iar/config/iar_boundary.bdef index abd0dbf..686f8fb 100644 --- a/examples/cc2650lp/spp_ble_server/iar/config/iar_boundary.bdef +++ b/examples/cc2650lp/spp_ble_server/iar/config/iar_boundary.bdef @@ -1,10 +1,10 @@ /* -** Stack Frontier Generator 1.1.0 (2016-11-02 14:24:42.407000) +** Stack Frontier Generator 1.1.0 (2017-05-19 12:13:41.482000) ** ** WARNING - Auto-generated file. Modifications could be lost! */ --D ICALL_STACK0_ADDR=0x0000f811 --D ICALL_STACK0_START=0x0000f810 +-D ICALL_STACK0_ADDR=0x0000f815 +-D ICALL_STACK0_START=0x0000f814 -D ICALL_RAM0_START=0x20004320 diff --git a/examples/cc2650lp/spp_ble_server/iar/config/iar_boundary.xcl b/examples/cc2650lp/spp_ble_server/iar/config/iar_boundary.xcl index 4cc99e3..20a5a59 100644 --- a/examples/cc2650lp/spp_ble_server/iar/config/iar_boundary.xcl +++ b/examples/cc2650lp/spp_ble_server/iar/config/iar_boundary.xcl @@ -1,10 +1,10 @@ /* -** Stack Frontier Generator 1.1.0 (2016-11-02 14:24:42.407000) +** Stack Frontier Generator 1.1.0 (2017-05-19 12:13:41.482000) ** ** WARNING - Auto-generated file. Modifications could be lost! */ --config_def ICALL_RAM0_START=0x20004320 ---config_def ICALL_STACK0_START=0x0000f810 ---config_def ICALL_STACK0_ADDR=0x0000f811 +--config_def ICALL_STACK0_START=0x0000f814 +--config_def ICALL_STACK0_ADDR=0x0000f815 diff --git a/examples/cc2650lp/throughput_example_central/ccs/stack/throughput_example_central_cc2650lp_stack.projectspec b/examples/cc2650lp/throughput_example_central/ccs/stack/throughput_example_central_cc2650lp_stack.projectspec index c9c4201..400554a 100644 --- a/examples/cc2650lp/throughput_example_central/ccs/stack/throughput_example_central_cc2650lp_stack.projectspec +++ b/examples/cc2650lp/throughput_example_central/ccs/stack/throughput_example_central_cc2650lp_stack.projectspec @@ -236,6 +236,8 @@ + + diff --git a/examples/cc2650lp/throughput_example_peripheral/ccs/stack/throughput_example_peripheral_cc2650lp_stack.projectspec b/examples/cc2650lp/throughput_example_peripheral/ccs/stack/throughput_example_peripheral_cc2650lp_stack.projectspec index 1737d34..31bb42a 100644 --- a/examples/cc2650lp/throughput_example_peripheral/ccs/stack/throughput_example_peripheral_cc2650lp_stack.projectspec +++ b/examples/cc2650lp/throughput_example_peripheral/ccs/stack/throughput_example_peripheral_cc2650lp_stack.projectspec @@ -243,6 +243,8 @@ + + diff --git a/examples/cc2650rc/hid_adv_remote_privacy/ccs/app/hid_adv_remote_privacy_cc2650rc_app.projectspec b/examples/cc2650rc/hid_adv_remote_privacy/ccs/app/hid_adv_remote_privacy_cc2650rc_app.projectspec index 05500b2..475d94b 100644 --- a/examples/cc2650rc/hid_adv_remote_privacy/ccs/app/hid_adv_remote_privacy_cc2650rc_app.projectspec +++ b/examples/cc2650rc/hid_adv_remote_privacy/ccs/app/hid_adv_remote_privacy_cc2650rc_app.projectspec @@ -7,7 +7,7 @@ cgtVersion="5.2.6" connection="common/targetdb/connections/TIXDS110_Connection.xml" toolChain="TI" - linkerCommandFile="cc26xx_app.cmd" + linkerCommandFile="" compilerBuildOptions=" --cmd_file=${TI_BLE_SDK_BASE}/src/config/build_components.opt --cmd_file=${PROJECT_IMPORT_LOC}/../../iar/stack/build_config.opt @@ -18,6 +18,7 @@ -me -g -O4 + --opt_for_speed=0 --c99 --gcc --gen_func_subsections=on @@ -75,6 +76,7 @@ -l${PROJECT_IMPORT_LOC}/../config/ccs_linker_defines.cmd -l${TI_BLE_SDK_BASE}/src/common/cc26xx/ccs/cc26xx_app.cmd -l${CC26XXWARE}/driverlib/bin/ccs/driverlib.lib + -l${TI_BLE_SDK_BASE}/src/rom/common_rom_releases/03282014/common_rom.symbols --diag_suppress=16002-D --diag_suppress=10247-D --diag_suppress=10325-D @@ -97,7 +99,8 @@ - + diff --git a/examples/cc2650rc/hid_adv_remote_privacy/ccs/stack/hid_adv_remote_privacy_cc2650rc_stack.projectspec b/examples/cc2650rc/hid_adv_remote_privacy/ccs/stack/hid_adv_remote_privacy_cc2650rc_stack.projectspec index 4761d06..d60aaae 100644 --- a/examples/cc2650rc/hid_adv_remote_privacy/ccs/stack/hid_adv_remote_privacy_cc2650rc_stack.projectspec +++ b/examples/cc2650rc/hid_adv_remote_privacy/ccs/stack/hid_adv_remote_privacy_cc2650rc_stack.projectspec @@ -8,37 +8,8 @@ connection="common/targetdb/connections/TIXDS110_Connection.xml" toolChain="TI" linkerCommandFile="cc26xx_stack.cmd" - - preBuildStep=" - "${TI_BLE_SDK_BASE}/tools/lib_search/lib_search.exe" - ${PROJECT_IMPORT_LOC}/../../iar/stack/build_config.opt - "${TI_BLE_SDK_BASE}/tools/lib_search/params_split_cc2640.xml" - ${TI_BLE_SDK_BASE}/blelib - "${PROJECT_IMPORT_LOC}/../../iar/config/lib_linker.cmd" - " - - postBuildStep=" - ${CG_TOOL_HEX} -order MS --memwidth=8 --romwidth=8 --intel -o ${ProjName}.hex ${ProjName}.out; - ${TI_BLE_SDK_BASE}/tools/frontier/frontier.exe ccs ${PROJECT_LOC}/${ConfigName}/${ProjName}_linkInfo.xml ${PROJECT_IMPORT_LOC}/../config/ccs_compiler_defines.bcfg ${PROJECT_IMPORT_LOC}/../config/ccs_linker_defines.cmd - " - - compilerBuildOptions=" - --cmd_file="${PROJECT_IMPORT_LOC}/../../iar/stack/build_config.opt" - --cmd_file="${TI_BLE_SDK_BASE}/src/config/build_components.opt" - -O4 - --opt_for_speed=0 - -mv7M3 - --code_state=16 - --abi=eabi - -me - --c99 - --display_error_number - --diag_wrap=off - --diag_suppress=48 - --diag_suppress=16004 - --diag_warning=225 - --diag_warning=2 - --c99 + compilerBuildOptions="--cmd_file="${TI_BLE_SDK_BASE}/src/config/build_components.opt" --cmd_file="${PROJECT_ROOT}/TOOLS/build_config.opt" + -mv7M3 -O4 --opt_for_speed=0 --code_state=16 --abi=eabi -me --c99 --display_error_number --diag_wrap=off --diag_suppress=48 --diag_suppress=16004 --diag_warning=225 --diag_warning=2 --c99 -DUSE_ICALL -DFLASH_ROM_BUILD @@ -87,11 +58,11 @@ " linkerBuildOptions=" - -l${PROJECT_IMPORT_LOC}/../../iar/config/lib_linker.cmd + -l${PROJECT_LOC}/TOOLS/lib_linker.cmd -l${TI_BLE_SDK_BASE}/src/rom/enc_lib/cc26xx_ecc_rom_api.a -l${TI_BLE_SDK_BASE}/src/rom/ble_rom_releases/04242014/ble_rom_patch.symbols -l${CC26XXWARE}/driverlib/bin/ccs/driverlib.lib - -llibc.a -x + -x --entry_point=startup_entry --diag_suppress=16002-D --diag_suppress=10247-D @@ -100,6 +71,21 @@ " description="" launchWizard="false" + + preBuildStep=" + "${TI_BLE_SDK_BASE}/tools/lib_search/lib_search.exe" + ${PROJECT_ROOT}/TOOLS/build_config.opt + "${TI_BLE_SDK_BASE}/tools/lib_search/params_split_cc2640.xml" + ${TI_BLE_SDK_BASE}/blelib + "${PROJECT_ROOT}/TOOLS/lib_linker.cmd" + " + + postBuildStep=" + ${CG_TOOL_HEX} -order MS --memwidth=8 --romwidth=8 --intel -o ${ProjName}.hex ${ProjName}.out; + ${TI_BLE_SDK_BASE}/tools/frontier/frontier.exe ccs ${PROJECT_LOC}/${ConfigName}/${ProjName}_linkInfo.xml ${PROJECT_ROOT}/TOOLS/ccs_compiler_defines.bcfg ${PROJECT_ROOT}/TOOLS/ccs_linker_defines.cmd + " + + > @@ -186,6 +172,8 @@ + + @@ -238,11 +226,11 @@ - + - + - + diff --git a/examples/util/mSBClibrary/bin/cc2650_mSBCdecode_library.a b/examples/util/mSBClibrary/bin/cc2650_mSBCdecode_library.a new file mode 100644 index 0000000..d9d37c0 Binary files /dev/null and b/examples/util/mSBClibrary/bin/cc2650_mSBCdecode_library.a differ diff --git a/examples/util/mSBClibrary/bin/cc2650_mSBCdecode_library.lib b/examples/util/mSBClibrary/bin/cc2650_mSBCdecode_library.lib new file mode 100644 index 0000000..cb4507c Binary files /dev/null and b/examples/util/mSBClibrary/bin/cc2650_mSBCdecode_library.lib differ diff --git a/examples/util/mSBClibrary/bin/cc2650_mSBCencode_library.a b/examples/util/mSBClibrary/bin/cc2650_mSBCencode_library.a new file mode 100644 index 0000000..9f9d7d2 Binary files /dev/null and b/examples/util/mSBClibrary/bin/cc2650_mSBCencode_library.a differ diff --git a/examples/util/mSBClibrary/bin/cc2650_mSBCencode_library.lib b/examples/util/mSBClibrary/bin/cc2650_mSBCencode_library.lib new file mode 100644 index 0000000..f85c672 Binary files /dev/null and b/examples/util/mSBClibrary/bin/cc2650_mSBCencode_library.lib differ diff --git a/examples/util/mSBClibrary/ccs/cc2650_mSBC_library.projectspec b/examples/util/mSBClibrary/ccs/cc2650_mSBC_library.projectspec new file mode 100644 index 0000000..fc2c2f2 --- /dev/null +++ b/examples/util/mSBClibrary/ccs/cc2650_mSBC_library.projectspec @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/util/mSBClibrary/iar/app/cc2650_mSBC_library.ewd b/examples/util/mSBClibrary/iar/app/cc2650_mSBC_library.ewd new file mode 100644 index 0000000..ddd121c --- /dev/null +++ b/examples/util/mSBClibrary/iar/app/cc2650_mSBC_library.ewd @@ -0,0 +1,3285 @@ + + + + 2 + + mSBCencode + + ARM + + 1 + + C-SPY + 2 + + 28 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ARMSIM_ID + 2 + + 1 + 1 + 1 + + + + + + + + ANGEL_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + + CADI_ID + 2 + + 0 + 1 + 1 + + + + + + + + + CMSISDAP_ID + 2 + + 4 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GDBSERVER_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + IARROM_ID + 2 + + 1 + 1 + 1 + + + + + + + + + IJET_ID + 2 + + 8 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JLINK_ID + 2 + + 16 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LMIFTDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + MACRAIGOR_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + PEMICRO_ID + 2 + + 3 + 1 + 1 + + + + + + + + RDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + + + + + + + STLINK_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + THIRDPARTY_ID + 2 + + 0 + 1 + 1 + + + + + + + + TIFET_ID + 2 + + 1 + 1 + 1 + + + + + + + + + + + + + + + + + + + XDS100_ID + 2 + + 6 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $TOOLKIT_DIR$\plugins\middleware\HCCWare\HCCWare.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\middleware\PercepioTraceExporter\PercepioTraceExportPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\AVIX\AVIX.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxTinyArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\embOS\embOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\MQX\MQXRtosPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\OpenRTOS\OpenRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\Quadros\Quadros_EWB7_Plugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SafeRTOS\SafeRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\ThreadX\ThreadXArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\TI-RTOS\tirtosplugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-286-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-III\uCOS-III-KA-CSpy.ewplugin + 0 + + + $EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin + 1 + + + $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin + 0 + + + $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin + 0 + + + + + mSBCdecode + + ARM + + 1 + + C-SPY + 2 + + 28 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ARMSIM_ID + 2 + + 1 + 1 + 1 + + + + + + + + ANGEL_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + + CADI_ID + 2 + + 0 + 1 + 1 + + + + + + + + + CMSISDAP_ID + 2 + + 4 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GDBSERVER_ID + 2 + + 0 + 1 + 1 + + + + + + + + + + + IARROM_ID + 2 + + 1 + 1 + 1 + + + + + + + + + IJET_ID + 2 + + 8 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JLINK_ID + 2 + + 16 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LMIFTDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + MACRAIGOR_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + PEMICRO_ID + 2 + + 3 + 1 + 1 + + + + + + + + RDI_ID + 2 + + 2 + 1 + 1 + + + + + + + + + + + + + + + + STLINK_ID + 2 + + 3 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + THIRDPARTY_ID + 2 + + 0 + 1 + 1 + + + + + + + + TIFET_ID + 2 + + 1 + 1 + 1 + + + + + + + + + + + + + + + + + + + XDS100_ID + 2 + + 6 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $TOOLKIT_DIR$\plugins\middleware\HCCWare\HCCWare.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\middleware\PercepioTraceExporter\PercepioTraceExportPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\AVIX\AVIX.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\CMX\CmxTinyArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\embOS\embOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\MQX\MQXRtosPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\OpenRTOS\OpenRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\Quadros\Quadros_EWB7_Plugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\SafeRTOS\SafeRTOSPlugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\ThreadX\ThreadXArmPlugin.ENU.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\TI-RTOS\tirtosplugin.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-286-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-II\uCOS-II-KA-CSpy.ewplugin + 0 + + + $TOOLKIT_DIR$\plugins\rtos\uCOS-III\uCOS-III-KA-CSpy.ewplugin + 0 + + + $EW_DIR$\common\plugins\CodeCoverage\CodeCoverage.ENU.ewplugin + 1 + + + $EW_DIR$\common\plugins\Orti\Orti.ENU.ewplugin + 0 + + + $EW_DIR$\common\plugins\uCProbe\uCProbePlugin.ENU.ewplugin + 0 + + + + + + diff --git a/examples/util/mSBClibrary/iar/app/cc2650_mSBC_library.ewp b/examples/util/mSBClibrary/iar/app/cc2650_mSBC_library.ewp new file mode 100644 index 0000000..272183a --- /dev/null +++ b/examples/util/mSBClibrary/iar/app/cc2650_mSBC_library.ewp @@ -0,0 +1,2002 @@ + + + + 2 + + mSBCencode + + ARM + + 1 + + General + 3 + + 24 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 31 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 9 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 18 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + + mSBCdecode + + ARM + + 1 + + General + 3 + + 24 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 31 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 9 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + 0 + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 18 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + + SBC + + $PROJ_DIR$\..\..\..\..\..\src\util\sbc\sbc.c + + + $PROJ_DIR$\..\..\..\..\..\src\util\sbc\sbc_primitives.c + + + + + diff --git a/examples/util/mSBClibrary/iar/cc2650_mSBC_library.custom_argvars b/examples/util/mSBClibrary/iar/cc2650_mSBC_library.custom_argvars new file mode 100644 index 0000000..2f84b13 --- /dev/null +++ b/examples/util/mSBClibrary/iar/cc2650_mSBC_library.custom_argvars @@ -0,0 +1,50 @@ + + + + + + TI_BLE_SDK_BASE + C:\ti\simplelink\ble_sdk_2_02_01_18 + + + TI_RTOS_DRIVERS_BASE + C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\tidrivers_cc13xx_cc26xx_2_20_01_10\packages + + + BIOS_BASE + C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\bios_6_46_01_38\packages + + + XDCPATH + C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\tidrivers_cc13xx_cc26xx_2_20_01_10\packages;C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\bios_6_46_01_38\packages;$TI_BLE_SDK_BASE$ + + + CC26XXWARE + C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\cc26xxware_2_24_02_17393 + + + XDCROOT + C:\ti\xdctools_3_32_00_06_core + + + SRC_EX + $TI_BLE_SDK_BASE$\src + + + SRC_BLE_CORE + $TI_BLE_SDK_BASE$\src + + + SRC_COMMON + $TI_BLE_SDK_BASE$\src\components + + + TOOLS_BLE + $TI_BLE_SDK_BASE$\tools + + + ROM + $TI_BLE_SDK_BASE$\src\rom + + + diff --git a/examples/util/mSBClibrary/iar/cc2650_mSBC_library.eww b/examples/util/mSBClibrary/iar/cc2650_mSBC_library.eww new file mode 100644 index 0000000..4d91505 --- /dev/null +++ b/examples/util/mSBClibrary/iar/cc2650_mSBC_library.eww @@ -0,0 +1,10 @@ + + + + + $WS_DIR$\app\cc2650_mSBC_library.ewp + + + + + diff --git a/examples/util/mSBClibrary/include/msbc_library.h b/examples/util/mSBClibrary/include/msbc_library.h new file mode 100644 index 0000000..d5b5c87 --- /dev/null +++ b/examples/util/mSBClibrary/include/msbc_library.h @@ -0,0 +1,64 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2012-2014 Intel Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __MSBC_LIBRARY_H +#define __MSBC_LIBRARY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef int32_t ssize_t; + +struct sbc_struct { + unsigned long flags; + + void *priv; + void *priv_alloc_base; +}; + +typedef struct sbc_struct sbc_t; + +int sbc_init_msbc(sbc_t *sbc, unsigned long flags); + +/* Decodes ONE input block into ONE output block */ +ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len, + void *output, size_t output_len, size_t *written); + +/* Encodes ONE input block into ONE output block */ +ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len, + void *output, size_t output_len, ssize_t *written); + +void sbc_finish(sbc_t *sbc); + +#ifdef __cplusplus +} +#endif + +#endif /* __MSBC_LIBRARY_H */ diff --git a/mSBC_audio_codec_cc26xx_cc13xx_1.0_manifest.html b/mSBC_audio_codec_cc26xx_cc13xx_1.0_manifest.html new file mode 100644 index 0000000..f82fd7c --- /dev/null +++ b/mSBC_audio_codec_cc26xx_cc13xx_1.0_manifest.html @@ -0,0 +1,357 @@ + + + + + + + + + + + + + +Texas Instruments Manifest + + + +
+ + + + + + + +
+ + + + + + + +
+
+

+ +mSBC_audio_codec_cc26xx_cc13xx Manifest + +

+ +

+ +01-17-2017 + +

+ + +

+ +Manifest ID - SRAS00003543 + +

+
+

Legend

+

(explanation of the fields in the Manifest Table below)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+Software Name + +The name of the application or file +
+Version + +Version of the application or file +
+License Type + +Type of license(s) under which TI will be providing +software to the licensee (e.g. BSD-3-Clause, GPL-2.0, TI TSPA License, TI +Commercial License). The license could be under Commercial terms or Open Source. See Open Source Reference License Disclaimer in +the Disclaimers Section. Whenever possible, TI will use an SPDX Short Identifier for an Open Source +License. TI Commercial license terms are not usually included in the manifest and are conveyed through a variety +of means such as a clickwrap license upon install, +a signed license agreement and so forth. +
+Location + +The directory name and path on the media or a specific file where the Software is located. Typically fully qualified path names +are not used and instead the relevant top level directory of the application is given. +A notation often used in the manifests is [as installed]/directory/*. Note that the asterisk implies that all +files under that directory are licensed as the License Type field denotes. Any exceptions to this will +generally be denoted as [as installed]/directory/* except as noted below which means as shown in subsequent rows of +the manifest. +
+Delivered As + +This field will either be “Source”, “Binary” or “Source +and Binary” and is the primary form the content of the Software is delivered +in. If the Software is delivered in an archive format, this field +applies to the contents of the archive. If the word Limited is used +with Source, as in “Limited Source” or “Limited Source and Binary” then +only portions of the Source for the application are provided. +
+Modified by TI + +This field will either be “Yes” or “No”. A “Yes” means +TI has made changes to the Software. A “No” means TI has not made any +changes. Note: This field is not applicable for Software “Obtained +from” TI. +
+Obtained from + +This field specifies from where or from whom TI obtained +the Software. It may be a URL to an Open Source site, a 3rd +party licensor, or TI. See Links Disclaimer in the Disclaimers +Section. +
+
+

Disclaimers

+

Export Control Classification Number (ECCN)

+

Any use of ECCNs listed in the Manifest is at the user’s risk +and without recourse to TI. Your +company, as the exporter of record, is responsible for determining the +correct classification of any item at +the time of export. Any export classification by TI of Software is for +TI’s internal use only and shall not be construed as a representation +or warranty +regarding the proper export classification for such Software or whether +an export +license or other documentation is required for exporting such Software

+

Links in the Manifest

+

Any +links appearing on this Manifest +(for example in the “Obtained from” field) were verified at the time +the Manifest was created. TI makes no guarantee that any listed links +will +remain active in the future.

+

Open Source License References

+

Your company is responsible for confirming the +applicable license terms for any open source Software +listed in this Manifest that was not “Obtained from” TI. Any open +source license +specified in this Manifest for Software that was +not “Obtained from” TI is for TI’s internal use only and shall not be +construed as a representation or warranty regarding the proper open +source license terms +for such Software.

+
+

Export Information

+

ECCN for Software included in this release:

+Publicly Available - Open Source or TI TSPA License +
+ + + + + +

+ mSBC_audio_codec_cc26xx_cc13xx Manifest Table +

+ + +

+ + See the Legend above for a description of these columns. + +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Software NameVersionLicense TypeDelivered AsModified by TI
+ mSBC_audio_codec_cc26xx_cc13xx + + 1.0 + + LGPLv2.1 + + Binary + + Yes + Location + https://github.com/ti-simplelink/ble_examples/examples/util/mSBClibrary/bin +
Obtained from + +
+ mSBC_audio_codec_cc26xx_cc13xx + + 1.0 + + LGPLv2.1 + + Source + + Yes + Location + https://github.com/ti-simplelink/ble_examples/src/util/sbc +
Obtained from + http://www.bluez.org/sbc-12/ +
+ +

+

+

+ +

+

Credits

+




+
+

Licenses

+

mSBC_audio_codec_cc26xx_cc13xx Licenses




GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999

Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]

Preamble

The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.

This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.

When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.

To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.

For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.

We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.

To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.

Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.

Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.

When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.

We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.

For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.

In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.

Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.

The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.

GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".

A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.

The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)

"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.

1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.

You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.

2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

a) The modified work must itself be a software library.

b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.

c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.

d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.

(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)

These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.

In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.

Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.

This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.

4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.

If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.

5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.

However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.

When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.

If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)

Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.

6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.

You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:

a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)

b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.

c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.

d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.

e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.

For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.

It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.

7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:

a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.

b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.

8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.

9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.

10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.

11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.

13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.

14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.

NO WARRANTY

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.

END OF TERMS AND CONDITIONS

How to Apply These Terms to Your New Libraries

If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).

To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.

<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Also add information on how to contact you by electronic and paper mail.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.

<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice

That's all there is to it!




+
+ + \ No newline at end of file diff --git a/src/boards/CC2650_LAUNCHXL/Board.h b/src/boards/CC2650_LAUNCHXL/Board.h new file mode 100644 index 0000000..fe9f4ff --- /dev/null +++ b/src/boards/CC2650_LAUNCHXL/Board.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __BOARD_H +#define __BOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "CC2650_LAUNCHXL.h" + +/* These #defines allow us to reuse TI-RTOS across other device families */ +#define Board_LED0 Board_RLED +#define Board_LED1 Board_GLED +#define Board_LED2 Board_LED0 + +#define Board_BUTTON0 Board_BTN1 +#define Board_BUTTON1 Board_BTN2 + +#define Board_UART0 Board_UART +#define Board_AES0 Board_AES +#define Board_WATCHDOG0 Board_WATCHDOG + +#define Board_ADC0 CC2650_LAUNCHXL_ADCVSS +#define Board_ADC1 CC2650_LAUNCHXL_ADCVDDS + +#define Board_ADCBuf0 CC2650_LAUNCHXL_ADCBuf0 +#define Board_ADCBufChannel0 (0) +#define Board_ADCBufChannel1 (1) + +#define Board_initGeneral() { \ + Power_init(); \ + if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) \ + {System_abort("Error with PIN_init\n"); \ + } \ +} + +#define Board_initGPIO() +#define Board_initPWM() PWM_init() +#define Board_initSPI() SPI_init() +#define Board_initUART() UART_init() +#define Board_initWatchdog() Watchdog_init() +#define Board_initADCBuf() ADCBuf_init() +#define Board_initADC() ADC_init() +#define GPIO_toggle(n) +#define GPIO_write(n,m) + +#ifdef __cplusplus +} +#endif + +#endif /* __BOARD_H */ diff --git a/src/boards/CC2650_LAUNCHXL/CC2650_LAUNCHXL.c b/src/boards/CC2650_LAUNCHXL/CC2650_LAUNCHXL.c new file mode 100644 index 0000000..b8f4b91 --- /dev/null +++ b/src/boards/CC2650_LAUNCHXL/CC2650_LAUNCHXL.c @@ -0,0 +1,791 @@ +/* + * Filename: CC2650_LAUNCHXL.c + * + * Description: Implementation of CC2650LP + CC3200AUDBOOST combo board + * file + * + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * ====================== CC2650_LAUNCHXL.c =================================== + * This file is responsible for setting up the board specific items for the + * CC2650 LaunchPad. + */ + + +/* + * ====================== Includes ============================================ + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Board.h" + +/* + * ========================= IO driver initialization ========================= + * From main, PIN_init(BoardGpioInitTable) should be called to setup safe + * settings for this board. + * When a pin is allocated and then de-allocated, it will revert to the state + * configured in this table. + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(BoardGpioInitTable, ".const:BoardGpioInitTable") +#pragma DATA_SECTION(PINCC26XX_hwAttrs, ".const:PINCC26XX_hwAttrs") +#endif + +const PIN_Config BoardGpioInitTable[] = { + + Board_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_BTN1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + Board_BTN2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES | PIN_HYSTERESIS, /* Button is active low */ + Board_SPI_FLASH_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* External flash chip select */ + Board_UART_RX | PIN_INPUT_EN | PIN_PULLDOWN, /* UART RX via debugger back channel */ + Board_UART_TX | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL, /* UART TX via debugger back channel */ + Board_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master out - slave in */ + Board_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI master in - slave out */ + Board_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN, /* SPI clock */ + Board_DIO25_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Debug IO initially high */ + Board_DIO26_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Debug IO initially high */ + Board_DIO27_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Debug IO initially high */ + Board_DIO28_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Debug IO initially high */ + + PIN_TERMINATE +}; + +const PINCC26XX_HWAttrs PINCC26XX_hwAttrs = { + .intPriority = ~0, + .swiPriority = 0 +}; +/*============================================================================*/ + +/* + * ============================= Power begin ================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PowerCC26XX_config, ".const:PowerCC26XX_config") +#endif +const PowerCC26XX_Config PowerCC26XX_config = { + .policyInitFxn = NULL, + .policyFxn = &PowerCC26XX_standbyPolicy, + .calibrateFxn = &PowerCC26XX_calibrate, + .enablePolicy = TRUE, + .calibrateRCOSC_LF = TRUE, + .calibrateRCOSC_HF = TRUE, +}; +/* + * ============================= Power end ==================================== + */ + +/* + * ============================= UART begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UART_config, ".const:UART_config") +#pragma DATA_SECTION(uartCC26XXHWAttrs, ".const:uartCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include +#include + +/* UART objects */ +UARTCC26XX_Object uartCC26XXObjects[CC2650_LAUNCHXL_UARTCOUNT]; + +/* UART hardware parameter structure, also used to assign UART pins */ +const UARTCC26XX_HWAttrsV1 uartCC26XXHWAttrs[CC2650_LAUNCHXL_UARTCOUNT] = { + { + .baseAddr = UART0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UART0, + .intNum = INT_UART0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .txPin = Board_UART_TX, + .rxPin = Board_UART_RX, + .ctsPin = PIN_UNASSIGNED, + .rtsPin = PIN_UNASSIGNED + } +}; + +/* UART configuration structure */ +const UART_Config UART_config[] = { + { + .fxnTablePtr = &UARTCC26XX_fxnTable, + .object = &uartCC26XXObjects[0], + .hwAttrs = &uartCC26XXHWAttrs[0] + }, + {NULL, NULL, NULL} +}; +/* + * ============================= UART end ===================================== + */ + +/* + * ============================= UDMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(UDMACC26XX_config, ".const:UDMACC26XX_config") +#pragma DATA_SECTION(udmaHWAttrs, ".const:udmaHWAttrs") +#endif + +/* Include drivers */ +#include + +/* UDMA objects */ +UDMACC26XX_Object udmaObjects[CC2650_LAUNCHXL_UDMACOUNT]; + +/* UDMA configuration structure */ +const UDMACC26XX_HWAttrs udmaHWAttrs[CC2650_LAUNCHXL_UDMACOUNT] = { + { + .baseAddr = UDMA0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_UDMA, + .intNum = INT_DMA_ERR, + .intPriority = ~0 + } +}; + +/* UDMA configuration structure */ +const UDMACC26XX_Config UDMACC26XX_config[] = { + { + .object = &udmaObjects[0], + .hwAttrs = &udmaHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ============================= UDMA end ===================================== + */ + +/* + * ========================== SPI DMA begin =================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(SPI_config, ".const:SPI_config") +#pragma DATA_SECTION(spiCC26XXDMAHWAttrs, ".const:spiCC26XXDMAHWAttrs") +#endif + +/* Include drivers */ +#include + +/* SPI objects */ +SPICC26XXDMA_Object spiCC26XXDMAObjects[CC2650_LAUNCHXL_SPICOUNT]; + +/* SPI configuration structure, describing which pins are to be used */ +const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[CC2650_LAUNCHXL_SPICOUNT] = { + { + .baseAddr = SSI0_BASE, + .intNum = INT_SSI0_COMB, + .intPriority = ~0, + .swiPriority = 0, + .powerMngrId = PowerCC26XX_PERIPH_SSI0, + .defaultTxBufValue = 0, + .rxChannelBitMask = 1< + +/* I2C objects */ +I2CCC26XX_Object i2cCC26xxObjects[CC2650_LAUNCHXL_I2CCOUNT]; + +/* I2C configuration structure, describing which pins are to be used */ +const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650_LAUNCHXL_I2CCOUNT] = { + { + .baseAddr = I2C0_BASE, + .powerMngrId = PowerCC26XX_PERIPH_I2C0, + .intNum = INT_I2C_IRQ, + .intPriority = ~0, + .swiPriority = 0, + .sdaPin = Board_I2C0_SDA0, + .sclPin = Board_I2C0_SCL0, + } +}; + +/* I2C configuration structure */ +const I2C_Config I2C_config[] = { + { + .fxnTablePtr = &I2CCC26XX_fxnTable, + .object = &i2cCC26xxObjects[0], + .hwAttrs = &i2cCC26xxHWAttrs[0] + }, + {NULL, NULL, NULL} +}; +/* + * ========================== I2C end ========================================= + */ + +/* + * ========================== Crypto begin ==================================== + * NOTE: The Crypto implementation should be considered experimental + * and not validated! + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(CryptoCC26XX_config, ".const:CryptoCC26XX_config") +#pragma DATA_SECTION(cryptoCC26XXHWAttrs, ".const:cryptoCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include + +/* Crypto objects */ +CryptoCC26XX_Object cryptoCC26XXObjects[CC2650_LAUNCHXL_CRYPTOCOUNT]; + +/* Crypto configuration structure, describing which pins are to be used */ +const CryptoCC26XX_HWAttrs cryptoCC26XXHWAttrs[CC2650_LAUNCHXL_CRYPTOCOUNT] = { + { + .baseAddr = CRYPTO_BASE, + .powerMngrId = PowerCC26XX_PERIPH_CRYPTO, + .intNum = INT_CRYPTO_RESULT_AVAIL_IRQ, + .intPriority = ~0, + } +}; + +/* Crypto configuration structure */ +const CryptoCC26XX_Config CryptoCC26XX_config[] = { + { + .object = &cryptoCC26XXObjects[0], + .hwAttrs = &cryptoCC26XXHWAttrs[0] + }, + {NULL, NULL} +}; +/* + * ========================== Crypto end ====================================== + */ + +/* + * ========================= RF driver begin ================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(RFCC26XX_hwAttrs, ".const:RFCC26XX_hwAttrs") +#endif + +/* Include drivers */ +#include + +/* RF hwi and swi priority */ +const RFCC26XX_HWAttrs RFCC26XX_hwAttrs = { + .hwiCpe0Priority = ~0, + .hwiHwPriority = ~0, + .swiCpe0Priority = 5, + .swiHwPriority = 5, +}; + +/* + * ========================== RF driver end =================================== + */ + +/* + * ============================= I2S begin ===================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(I2SCC26XX_config, ".const:I2SCC26XX_config") +#pragma DATA_SECTION(i2sCC26XXHWAttrs, ".const:i2sCC26XXHWAttrs") +#endif + +#include "I2SCC26XX.h" + +I2SCC26XX_Object i2sCC26XXObject; + +const I2SCC26XX_HWAttrs i2sCC26XXHWAttrs = { + .baseAddr = I2S0_BASE, + .intNum = INT_I2S_IRQ, + .intPriority = ~0, + .powerMngrId = PowerCC26XX_PERIPH_I2S, + .mclkPin = Board_I2S_MCLK, + .bclkPin = Board_I2S_BCLK, + .wclkPin = Board_I2S_WCLK, +#ifdef AUDIO_RECEIVER + .ad0Pin = Board_I2S_ADO, +#else //AUDIO_TRANSMITTER + .ad0Pin = Board_I2S_ADI, +#endif +}; + +/* I2S configuration structure */ +const I2SCC26XX_Config I2SCC26XX_config[] = { + { + .object = &i2sCC26XXObject, + .hwAttrs = &i2sCC26XXHWAttrs + }, + {NULL, NULL} +}; + +/* + * ========================= Display begin ==================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(Display_config, ".const:Display_config") +#pragma DATA_SECTION(displaySharpHWattrs, ".const:displaySharpHWattrs") +#pragma DATA_SECTION(displayUartHWAttrs, ".const:displayUartHWAttrs") +#endif + +#include +#include +#include + +/* Structures for UartPlain Blocking */ +DisplayUart_Object displayUartObject; + +#ifndef BOARD_DISPLAY_UART_STRBUF_SIZE +#define BOARD_DISPLAY_UART_STRBUF_SIZE 128 +#endif +static char uartStringBuf[BOARD_DISPLAY_UART_STRBUF_SIZE]; + +const DisplayUart_HWAttrs displayUartHWAttrs = { + .uartIdx = Board_UART, + .baudRate = 115200, + .mutexTimeout = BIOS_WAIT_FOREVER, + .strBuf = uartStringBuf, + .strBufLen = BOARD_DISPLAY_UART_STRBUF_SIZE, +}; + +/* Structures for SHARP */ +DisplaySharp_Object displaySharpObject; +#ifndef BOARD_DISPLAY_SHARP_SIZE +#define BOARD_DISPLAY_SHARP_SIZE 96 // 96->96x96 is the most common board, alternative is 128->128x128. +#endif +static uint8_t sharpDisplayBuf[BOARD_DISPLAY_SHARP_SIZE * BOARD_DISPLAY_SHARP_SIZE / 8]; + +const DisplaySharp_HWAttrs displaySharpHWattrs = { + .spiIndex = Board_SPI0, + .csPin = Board_LCD_CS, + .extcominPin = Board_LCD_EXTCOMIN, + .powerPin = Board_LCD_POWER, + .enablePin = Board_LCD_ENABLE, + .pixelWidth = BOARD_DISPLAY_SHARP_SIZE, + .pixelHeight = BOARD_DISPLAY_SHARP_SIZE, + .displayBuf = sharpDisplayBuf, +}; + +/* Array of displays */ +const Display_Config Display_config[] = { +#if !defined(BOARD_DISPLAY_EXCLUDE_UART) + { + .fxnTablePtr = &DisplayUart_fxnTable, + .object = &displayUartObject, + .hwAttrs = &displayUartHWAttrs, + }, +#endif +#if !defined(BOARD_DISPLAY_EXCLUDE_LCD) + { + .fxnTablePtr = &DisplaySharp_fxnTable, + .object = &displaySharpObject, + .hwAttrs = &displaySharpHWattrs + }, +#endif + { NULL, NULL, NULL } // Terminator +}; + +/* + * ========================= Display end ====================================== + */ + +/* + * ============================ GPTimer begin ================================= + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(GPTimerCC26XX_config, ".const:GPTimerCC26XX_config") +#pragma DATA_SECTION(gptimerCC26xxHWAttrs, ".const:gptimerCC26xxHWAttrs") +#endif + +/* GPTimer hardware attributes, one per timer part (Timer 0A, 0B, 1A, 1B..) */ +const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, }, + { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, }, + { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, }, + { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, }, + { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, }, +}; + +/* GPTimer objects, one per full-width timer (A+B) (Timer 0, Timer 1..) */ +GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650_LAUNCHXL_GPTIMERCOUNT]; + +/* GPTimer configuration (used as GPTimer_Handle by driver and application) */ +const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650_LAUNCHXL_GPTIMERPARTSCOUNT] = { + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A }, + { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A }, + { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A }, + { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A }, + { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B }, +}; + +/* + * ============================ GPTimer end =================================== + */ + + + +/* + * ============================= PWM begin ==================================== + * Remove unused entries to reduce flash usage both in Board.c and Board.h + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(PWM_config, ".const:PWM_config") +#pragma DATA_SECTION(pwmtimerCC26xxHWAttrs, ".const:pwmtimerCC26xxHWAttrs") +#endif + +/* PWM configuration, one per PWM output. */ +PWMTimerCC26XX_HwAttrs pwmtimerCC26xxHWAttrs[CC2650_LAUNCHXL_PWMCOUNT] = { + { .pwmPin = Board_PWMPIN0, .gpTimerUnit = Board_GPTIMER0A }, + { .pwmPin = Board_PWMPIN1, .gpTimerUnit = Board_GPTIMER0B }, + { .pwmPin = Board_PWMPIN2, .gpTimerUnit = Board_GPTIMER1A }, + { .pwmPin = Board_PWMPIN3, .gpTimerUnit = Board_GPTIMER1B }, + { .pwmPin = Board_PWMPIN4, .gpTimerUnit = Board_GPTIMER2A }, + { .pwmPin = Board_PWMPIN5, .gpTimerUnit = Board_GPTIMER2B }, + { .pwmPin = Board_PWMPIN6, .gpTimerUnit = Board_GPTIMER3A }, + { .pwmPin = Board_PWMPIN7, .gpTimerUnit = Board_GPTIMER3B }, +}; + +/* PWM object, one per PWM output */ +PWMTimerCC26XX_Object pwmtimerCC26xxObjects[CC2650_LAUNCHXL_PWMCOUNT]; + +extern const PWM_FxnTable PWMTimerCC26XX_fxnTable; + +/* PWM configuration (used as PWM_Handle by driver and application) */ +const PWM_Config PWM_config[CC2650_LAUNCHXL_PWMCOUNT + 1] = { + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[0], &pwmtimerCC26xxHWAttrs[0] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[1], &pwmtimerCC26xxHWAttrs[1] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[2], &pwmtimerCC26xxHWAttrs[2] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[3], &pwmtimerCC26xxHWAttrs[3] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[4], &pwmtimerCC26xxHWAttrs[4] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[5], &pwmtimerCC26xxHWAttrs[5] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[6], &pwmtimerCC26xxHWAttrs[6] }, + { &PWMTimerCC26XX_fxnTable, &pwmtimerCC26xxObjects[7], &pwmtimerCC26xxHWAttrs[7] }, + { NULL, NULL, NULL } +}; + + +/* + * ============================= PWM end ====================================== + */ + +/* + * ========================== ADCBuf begin ========================================= + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(ADCBuf_config, ".const:ADCBuf_config") +#pragma DATA_SECTION(adcBufCC26xxHWAttrs, ".const:adcBufCC26xxHWAttrs") +#pragma DATA_SECTION(ADCBufCC26XX_adcChannelLut, ".const:ADCBufCC26XX_adcChannelLut") +#endif + +/* Include drivers */ +#include +#include + +/* ADCBuf objects */ +ADCBufCC26XX_Object adcBufCC26xxObjects[CC2650_LAUNCHXL_ADCBufCOUNT]; + +/* + * This table converts a virtual adc channel into a dio and internal analogue input signal. + * This table is necessary for the functioning of the adcBuf driver. + * Comment out unused entries to save flash. + * Dio and internal signal pairs are hardwired. Do not remap them in the table. You may reorder entire entries though. + * The mapping of dio and internal signals is package dependent. + */ +const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[] = { + {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS}, + {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL}, + {PIN_UNASSIGNED, ADC_COMPB_IN_VSS}, + {Board_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7}, + {Board_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6}, + {Board_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5}, + {Board_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4}, + {Board_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3}, + {Board_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2}, + {Board_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1}, + {Board_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0}, +}; + +const ADCBufCC26XX_HWAttrs adcBufCC26xxHWAttrs[CC2650_LAUNCHXL_ADCBufCOUNT] = { + { + .intPriority = ~0, + .swiPriority = 0, + .adcChannelLut = ADCBufCC26XX_adcChannelLut, + .gpTimerUnit = Board_GPTIMER0A, + .gptDMAChannelMask = 1 << UDMA_CHAN_TIMER0_A, + } +}; + +const ADCBuf_Config ADCBuf_config[] = { + {&ADCBufCC26XX_fxnTable, &adcBufCC26xxObjects[0], &adcBufCC26xxHWAttrs[0]}, + {NULL, NULL, NULL}, +}; +/* + * ========================== ADCBuf end ========================================= + */ + + + +/* + * ========================== ADC begin ========================================= + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(ADC_config, ".const:ADC_config") +#pragma DATA_SECTION(adcCC26xxHWAttrs, ".const:adcCC26xxHWAttrs") +#endif + +/* Include drivers */ +#include +#include + +/* ADC objects */ +ADCCC26XX_Object adcCC26xxObjects[CC2650_LAUNCHXL_ADCCOUNT]; + + +const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[CC2650_LAUNCHXL_ADCCOUNT] = { + { + .adcDIO = Board_DIO23_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO7, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO24_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO6, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO25_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO5, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO26_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO4, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO27_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO3, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO28_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO2, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO29_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO1, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = Board_DIO30_ANALOG, + .adcCompBInput = ADC_COMPB_IN_AUXIO0, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_DCOUPL, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VSS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + }, + { + .adcDIO = PIN_UNASSIGNED, + .adcCompBInput = ADC_COMPB_IN_VDDS, + .refSource = ADCCC26XX_FIXED_REFERENCE, + .samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US, + .inputScalingEnabled = true, + .triggerSource = ADCCC26XX_TRIGGER_MANUAL + } +}; + +const ADC_Config ADC_config[] = { + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[1], &adcCC26xxHWAttrs[1]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[2], &adcCC26xxHWAttrs[2]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[3], &adcCC26xxHWAttrs[3]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[4], &adcCC26xxHWAttrs[4]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[5], &adcCC26xxHWAttrs[5]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[6], &adcCC26xxHWAttrs[6]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[7], &adcCC26xxHWAttrs[7]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[8], &adcCC26xxHWAttrs[8]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[9], &adcCC26xxHWAttrs[9]}, + {&ADCCC26XX_fxnTable, &adcCC26xxObjects[10], &adcCC26xxHWAttrs[10]}, + {NULL, NULL, NULL}, +}; + +/* + * ========================== ADC end ========================================= + */ + +/* + * ========================= TRNG begin ==================================== + */ +/* Place into subsections to allow the TI linker to remove items properly */ +#if defined(__TI_COMPILER_VERSION__) +#pragma DATA_SECTION(TRNGCC26XX_config, ".const:TRNGCC26XX_config") +#pragma DATA_SECTION(TRNGCC26XXHWAttrs, ".const:TRNGCC26XXHWAttrs") +#endif + +/* Include drivers */ +#include + +/* TRNG objects */ +TRNGCC26XX_Object trngCC26XXObjects[CC2650_LAUNCHXL_TRNGCOUNT]; + +/* TRNG configuration structure, describing which pins are to be used */ +const TRNGCC26XX_HWAttrs TRNGCC26XXHWAttrs[CC2650_LAUNCHXL_TRNGCOUNT] = { + { + .powerMngrId = PowerCC26XX_PERIPH_TRNG, + } +}; + +/* TRNG configuration structure */ +const TRNGCC26XX_Config TRNGCC26XX_config[] = { + { + .object = &trngCC26XXObjects[0], + .hwAttrs = &TRNGCC26XXHWAttrs[0] + }, + {NULL, NULL} +}; + +/* + * ========================= TRNG end ==================================== + */ diff --git a/src/boards/CC2650_LAUNCHXL/CC2650_LAUNCHXL.h b/src/boards/CC2650_LAUNCHXL/CC2650_LAUNCHXL.h new file mode 100644 index 0000000..226d428 --- /dev/null +++ b/src/boards/CC2650_LAUNCHXL/CC2650_LAUNCHXL.h @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2015-2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** ============================================================================ + * @file CC2650_LAUNCHXL.h + * + * @brief CC2650 LaunchPad Board Specific header file. + * + * NB! This is the board file for CC2650 LaunchPad PCB version 1.1 + * + * ============================================================================ + */ +#ifndef __CC2650_LAUNCHXL_BOARD_H__ +#define __CC2650_LAUNCHXL_BOARD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** ============================================================================ + * Includes + * ==========================================================================*/ +#include +#include + +/** ============================================================================ + * Externs + * ==========================================================================*/ +extern const PIN_Config BoardGpioInitTable[]; + +/** ============================================================================ + * Defines + * ==========================================================================*/ + +/* Same RF Configuration as 7x7 EM */ +#define CC2650EM_7ID + +/* Mapping of pins to board signals using general board aliases + * + */ + +/* Discrete outputs */ +#define Board_RLED IOID_6 +#define Board_GLED IOID_7 +#define Board_LED_ON 1 +#define Board_LED_OFF 0 + +/* Discrete inputs */ +#define Board_BTN1 IOID_13 +#define Board_BTN2 IOID_14 + +/* Audio */ +#define Board_I2S_ADO IOID_0 +#define Board_I2S_ADI IOID_1 + +/* I2S */ +#define Board_I2S_BCLK IOID_30 +#define Board_I2S_MCLK (PIN_Id)IOID_UNUSED +#define Board_I2S_WCLK IOID_29 + +/* UART Board */ +#define Board_UART_RX IOID_2 /* RXD */ +#define Board_UART_TX IOID_3 /* TXD */ +#define Board_UART_CTS IOID_19 /* CTS */ +#define Board_UART_RTS IOID_18 /* RTS */ + +/* SPI Board */ +#define Board_SPI0_MISO IOID_8 /* RF1.20 */ +#define Board_SPI0_MOSI IOID_9 /* RF1.18 */ +#define Board_SPI0_CLK IOID_10 /* RF1.16 */ +#define Board_SPI0_CSN PIN_UNASSIGNED +#define Board_SPI1_MISO PIN_UNASSIGNED +#define Board_SPI1_MOSI PIN_UNASSIGNED +#define Board_SPI1_CLK PIN_UNASSIGNED +#define Board_SPI1_CSN PIN_UNASSIGNED + +/* I2C */ +#define Board_I2C0_SCL0 IOID_4 +#define Board_I2C0_SDA0 IOID_5 + +/* SPI */ +#define Board_SPI_FLASH_CS IOID_20 +#define Board_FLASH_CS_ON 0 +#define Board_FLASH_CS_OFF 1 + +/* Booster pack generic */ +#define Board_DIO0 IOID_0 +#define Board_DIO1_RFSW IOID_1 +#define Board_DIO12 IOID_12 +#define Board_DIO15 IOID_15 +#define Board_DIO16_TDO IOID_16 +#define Board_DIO17_TDI IOID_17 +#define Board_DIO21 IOID_21 +#define Board_DIO22 IOID_22 + +#define Board_DIO23_ANALOG IOID_23 +#define Board_DIO24_ANALOG IOID_24 +#define Board_DIO25_ANALOG IOID_25 +#define Board_DIO26_ANALOG IOID_26 +#define Board_DIO27_ANALOG IOID_27 +#define Board_DIO28_ANALOG IOID_28 +#define Board_DIO29_ANALOG IOID_29 +#define Board_DIO30_ANALOG IOID_30 + +/* Booster pack LCD (430BOOST - Sharp96 Rev 1.1) */ +#define Board_LCD_CS IOID_24 // SPI chip select +#define Board_LCD_EXTCOMIN IOID_12 // External COM inversion +#define Board_LCD_ENABLE IOID_22 // LCD enable +#define Board_LCD_POWER IOID_23 // LCD power control +#define Board_LCD_CS_ON 1 +#define Board_LCD_CS_OFF 0 + +/* PWM outputs */ +#define Board_PWMPIN0 Board_RLED +#define Board_PWMPIN1 Board_GLED +#define Board_PWMPIN2 PIN_UNASSIGNED +#define Board_PWMPIN3 PIN_UNASSIGNED +#define Board_PWMPIN4 PIN_UNASSIGNED +#define Board_PWMPIN5 PIN_UNASSIGNED +#define Board_PWMPIN6 PIN_UNASSIGNED +#define Board_PWMPIN7 PIN_UNASSIGNED + +/** ============================================================================ + * Instance identifiers + * ==========================================================================*/ +/* Generic I2C instance identifiers */ +#define Board_I2C CC2650_LAUNCHXL_I2C0 +/* Generic SPI instance identifiers */ +#define Board_SPI0 CC2650_LAUNCHXL_SPI0 +#define Board_SPI1 CC2650_LAUNCHXL_SPI1 +/* Generic UART instance identifiers */ +#define Board_UART CC2650_LAUNCHXL_UART0 +/* Generic Crypto instance identifiers */ +#define Board_CRYPTO CC2650_LAUNCHXL_CRYPTO0 +/* Generic GPTimer instance identifiers */ +#define Board_GPTIMER0A CC2650_LAUNCHXL_GPTIMER0A +#define Board_GPTIMER0B CC2650_LAUNCHXL_GPTIMER0B +#define Board_GPTIMER1A CC2650_LAUNCHXL_GPTIMER1A +#define Board_GPTIMER1B CC2650_LAUNCHXL_GPTIMER1B +#define Board_GPTIMER2A CC2650_LAUNCHXL_GPTIMER2A +#define Board_GPTIMER2B CC2650_LAUNCHXL_GPTIMER2B +#define Board_GPTIMER3A CC2650_LAUNCHXL_GPTIMER3A +#define Board_GPTIMER3B CC2650_LAUNCHXL_GPTIMER3B +/* Generic PWM instance identifiers */ +#define Board_PWM0 CC2650_LAUNCHXL_PWM0 +#define Board_PWM1 CC2650_LAUNCHXL_PWM1 +#define Board_PWM2 CC2650_LAUNCHXL_PWM2 +#define Board_PWM3 CC2650_LAUNCHXL_PWM3 +#define Board_PWM4 CC2650_LAUNCHXL_PWM4 +#define Board_PWM5 CC2650_LAUNCHXL_PWM5 +#define Board_PWM6 CC2650_LAUNCHXL_PWM6 +#define Board_PWM7 CC2650_LAUNCHXL_PWM7 + +/** ============================================================================ + * Number of peripherals and their names + * ==========================================================================*/ + +/*! + * @def CC2650_LAUNCHXL_I2CName + * @brief Enum of I2C names on the CC2650 dev board + */ +typedef enum CC2650_LAUNCHXL_I2CName { + CC2650_LAUNCHXL_I2C0 = 0, + + CC2650_LAUNCHXL_I2CCOUNT +} CC2650_LAUNCHXL_I2CName; + +/*! + * @def CC2650_LAUNCHXL_CryptoName + * @brief Enum of Crypto names on the CC2650 dev board + */ +typedef enum CC2650_LAUNCHXL_CryptoName { + CC2650_LAUNCHXL_CRYPTO0 = 0, + + CC2650_LAUNCHXL_CRYPTOCOUNT +} CC2650_LAUNCHXL_CryptoName; + + +/*! + * @def CC2650_LAUNCHXL_SPIName + * @brief Enum of SPI names on the CC2650 dev board + */ +typedef enum CC2650_LAUNCHXL_SPIName { + CC2650_LAUNCHXL_SPI0 = 0, + CC2650_LAUNCHXL_SPI1, + + CC2650_LAUNCHXL_SPICOUNT +} CC2650_LAUNCHXL_SPIName; + +/*! + * @def CC2650_LAUNCHXL_TRNGName + * @brief Enum of TRNG names on the board + */ +typedef enum CC2650_LAUNCHXL_TRNGName { + CC2650_LAUNCHXL_TRNG0 = 0, + CC2650_LAUNCHXL_TRNGCOUNT +} CC2650_LAUNCHXL_TRNGName; + +/*! + * @def CC2650_LAUNCHXL_UARTName + * @brief Enum of UARTs on the CC2650 dev board + */ +typedef enum CC2650_LAUNCHXL_UARTName { + CC2650_LAUNCHXL_UART0 = 0, + + CC2650_LAUNCHXL_UARTCOUNT +} CC2650_LAUNCHXL_UARTName; + +/*! + * @def CC2650_LAUNCHXL_UdmaName + * @brief Enum of DMA buffers + */ +typedef enum CC2650_LAUNCHXL_UdmaName { + CC2650_LAUNCHXL_UDMA0 = 0, + + CC2650_LAUNCHXL_UDMACOUNT +} CC2650_LAUNCHXL_UdmaName; + +/*! + * @def CC2650_LAUNCHXL_GPTimerName + * @brief Enum of GPTimer parts + */ +typedef enum CC2650_LAUNCHXL_GPTimerName +{ + CC2650_LAUNCHXL_GPTIMER0A = 0, + CC2650_LAUNCHXL_GPTIMER0B, + CC2650_LAUNCHXL_GPTIMER1A, + CC2650_LAUNCHXL_GPTIMER1B, + CC2650_LAUNCHXL_GPTIMER2A, + CC2650_LAUNCHXL_GPTIMER2B, + CC2650_LAUNCHXL_GPTIMER3A, + CC2650_LAUNCHXL_GPTIMER3B, + CC2650_LAUNCHXL_GPTIMERPARTSCOUNT +} CC2650_LAUNCHXL_GPTimerName; + +/*! + * @def CC2650_LAUNCHXL_GPTimers + * @brief Enum of GPTimers + */ +typedef enum CC2650_LAUNCHXL_GPTimers +{ + CC2650_LAUNCHXL_GPTIMER0 = 0, + CC2650_LAUNCHXL_GPTIMER1, + CC2650_LAUNCHXL_GPTIMER2, + CC2650_LAUNCHXL_GPTIMER3, + CC2650_LAUNCHXL_GPTIMERCOUNT +} CC2650_LAUNCHXL_GPTimers; + +/*! + * @def CC2650_LAUNCHXL_PWM + * @brief Enum of PWM outputs on the board + */ +typedef enum CC2650_LAUNCHXL_PWM +{ + CC2650_LAUNCHXL_PWM0 = 0, + CC2650_LAUNCHXL_PWM1, + CC2650_LAUNCHXL_PWM2, + CC2650_LAUNCHXL_PWM3, + CC2650_LAUNCHXL_PWM4, + CC2650_LAUNCHXL_PWM5, + CC2650_LAUNCHXL_PWM6, + CC2650_LAUNCHXL_PWM7, + CC2650_LAUNCHXL_PWMCOUNT +} CC2650_LAUNCHXL_PWM; + +/*! + * @def CC2650_LAUNCHXL_ADCBufName + * @brief Enum of ADCs + */ +typedef enum CC2650_LAUNCHXL_ADCBufName { + CC2650_LAUNCHXL_ADCBuf0 = 0, + CC2650_LAUNCHXL_ADCBufCOUNT +} CC2650_LAUNCHXL_ADCBufName; + + +/*! + * @def CC2650_LAUNCHXL_ADCName + * @brief Enum of ADCs + */ +typedef enum CC2650_LAUNCHXL_ADCName { + CC2650_LAUNCHXL_ADC0 = 0, + CC2650_LAUNCHXL_ADC1, + CC2650_LAUNCHXL_ADC2, + CC2650_LAUNCHXL_ADC3, + CC2650_LAUNCHXL_ADC4, + CC2650_LAUNCHXL_ADC5, + CC2650_LAUNCHXL_ADC6, + CC2650_LAUNCHXL_ADC7, + CC2650_LAUNCHXL_ADCDCOUPL, + CC2650_LAUNCHXL_ADCVSS, + CC2650_LAUNCHXL_ADCVDDS, + CC2650_LAUNCHXL_ADCCOUNT +} CC2650_LAUNCHXL_ADCName; + + +#ifdef __cplusplus +} +#endif + +#endif /* __CC2650_LAUNCHXL_BOARD_H__ */ diff --git a/src/common/cc26xx/ccs/cc26xx_app_auxram.cmd b/src/common/cc26xx/ccs/cc26xx_app_auxram.cmd new file mode 100644 index 0000000..b192905 --- /dev/null +++ b/src/common/cc26xx/ccs/cc26xx_app_auxram.cmd @@ -0,0 +1,157 @@ +/****************************************************************************** + + @file cc26xx_app.cmd + + @brief CC2650F128 linker configuration file for TI-RTOS with Code Composer + Studio. + + Group: WCS, BTS + Target Device: CC2650, CC2640, CC1350 + + ****************************************************************************** + + Copyright (c) 2013-2016, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + Release Name: ble_sdk_2_02_01_18 + Release Date: 2016-10-26 15:20:04 + *****************************************************************************/ + + +/* Retain interrupt vector table variable */ +--retain=g_pfnVectors +/* Override default entry point. */ +--entry_point ResetISR +/* Suppress warnings and errors: */ +/* - 10063: Warning about entry point not being _c_int00 */ +/* - 16011, 16012: 8-byte alignment errors. Observed when linking in object */ +/* files compiled using Keil (ARM compiler) */ +--diag_suppress=10063,16011,16012 + +/* The following command line options are set as part of the CCS project. */ + /* If you are building using the command line, or for some reason want to */ +/* define them here, you can uncomment and modify these lines as needed. */ +/* If you are using CCS for building, it is probably better to make any such */ +/* modifications in your CCS project and leave this file alone. */ +/* */ +/* --heap_size=0 */ +/* --stack_size=256 */ +/* --library=rtsv7M3_T_le_eabi.lib */ + +/* The starting address of the application. Normally the interrupt vectors */ +/* must be located at the beginning of the application. Flash is 128KB, with */ +/* sector length of 4KB */ +#define FLASH_APP_BASE 0x00000000 +#define FLASH_LEN 0x20000 +#define FLASH_PAGE_LEN 0x1000 + +/* Last page of Flash is allocated to App: 0x1F000 - 0x1FFFF */ +#define FLASH_LAST_PAGE_START FLASH_LEN - FLASH_PAGE_LEN + +/* RAM starts at 0x20000000 and is 20KB */ +#define RAM_APP_BASE 0x20000000 +#define RAM_LEN 0x5000 +/* RAM reserved by ROM code starts. */ +#define RAM_RESERVED_OFFSET 0x4F00 + +/* RAM starts at 0x20000000 and is 2KB */ +#define AUX_RAM_BASE 0x400E0000 +#define AUX_RAM_LEN 0x800 + +/* System memory map */ + +MEMORY +{ + /* EDITOR'S NOTE: + * the FLASH and SRAM lengths can be changed by defining + * ICALL_STACK0_START or ICALL_RAM0_START in + * Properties->ARM Linker->Advanced Options->Command File Preprocessing. + */ + + /* Application stored in and executes from internal flash */ + /* Flash Size 128 KB */ + #ifdef ICALL_STACK0_START + FLASH (RX) : origin = FLASH_APP_BASE, length = ICALL_STACK0_START - FLASH_APP_BASE + #else // default + FLASH (RX) : origin = FLASH_APP_BASE, length = FLASH_LEN - FLASH_PAGE_LEN + #endif + + // CCFG Page, contains .ccfg code section and some application code. + FLASH_LAST_PAGE (RX) : origin = FLASH_LAST_PAGE_START, length = FLASH_PAGE_LEN + + /* Application uses internal RAM for data */ + /* RAM Size 16 KB */ + #ifdef ICALL_RAM0_START + SRAM (RWX) : origin = RAM_APP_BASE, length = ICALL_RAM0_START - RAM_APP_BASE + #else //default + SRAM (RWX) : origin = RAM_APP_BASE, length = RAM_RESERVED_OFFSET + #endif + + AUXRAM (RWX) : origin = AUX_RAM_BASE, length = AUX_RAM_LEN +} + +/* Section allocation in memory */ + +SECTIONS +{ + .intvecs : > FLASH_APP_BASE + .text : >> FLASH | FLASH_LAST_PAGE + .const : >> FLASH | FLASH_LAST_PAGE + .constdata : >> FLASH | FLASH_LAST_PAGE + .rodata : >> FLASH | FLASH_LAST_PAGE + .cinit : > FLASH | FLASH_LAST_PAGE + .pinit : >> FLASH | FLASH_LAST_PAGE + .init_array : >> FLASH | FLASH_LAST_PAGE + .emb_text : >> FLASH | FLASH_LAST_PAGE + .ccfg : > FLASH_LAST_PAGE (HIGH) + + GROUP > SRAM + { + .data + .bss + .vtable + .vtable_ram + vtable_ram + .sysmem + .nonretenvar + } LOAD_END(heapStart) + + .stack : > SRAM (HIGH) LOAD_START(heapEnd) + + .aux_ram : > AUXRAM +} + +/* Create global constant that points to top of stack */ +/* CCS: Change stack size under Project Properties */ +__STACK_TOP = __stack + __STACK_SIZE; + +/* Allow main() to take args */ +--args 0x8 diff --git a/src/components/display_eng/ti/mw/display/DisplaySharp.c b/src/components/display_eng/ti/mw/display/DisplaySharp.c new file mode 100644 index 0000000..af917ac --- /dev/null +++ b/src/components/display_eng/ti/mw/display/DisplaySharp.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* ----------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------------ + */ +// TI RTOS drivers +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +/* ----------------------------------------------------------------------------- + * Constants and macros + * ------------------------------------------------------------------------------ + */ +// Timeout of semaphore that controls exclusive to the LCD (infinite) +#define ACCESS_TIMEOUT BIOS_WAIT_FOREVER + +/* ----------------------------------------------------------------------------- + * Type definitions + * ------------------------------------------------------------------------------ + */ + + +/* ----------------------------------------------------------------------------- + * Local variables + * ------------------------------------------------------------------------------ + */ +/* Display function table for sharp implementation */ +const Display_FxnTable DisplaySharp_fxnTable = { + DisplaySharp_open, + DisplaySharp_clear, + DisplaySharp_clearLines, + DisplaySharp_put5, + DisplaySharp_close, + DisplaySharp_control, + DisplaySharp_getType, +}; + +/* ----------------------------------------------------------------------------- + * Functions + * ------------------------------------------------------------------------------ + */ +/*! + * @fn DisplaySharp_open + * + * @brief Initialize the LCD + * + * @descr Initializes the pins used by the LCD, creates resource access + * protection semaphore, turns on the LCD device, initializes the + * frame buffer, initializes to white background/dark foreground, + * and finally clears the object->displayColor. + * + * @param hDisplay - pointer to Display_Config struct + * @param params - display parameters + * + * @return Pointer to Display_Config struct + */ +Display_Handle DisplaySharp_open(Display_Handle hDisplay, + Display_Params *params) +{ + DisplaySharp_HWAttrs *hwAttrs = (DisplaySharp_HWAttrs *)hDisplay->hwAttrs; + DisplaySharp_Object *object = (DisplaySharp_Object *)hDisplay->object; + + PIN_Config pinTable[4 + 1]; + + object->lineClearMode = params->lineClearMode; + + uint32_t i = 0; + if (hwAttrs->csPin != PIN_TERMINATE) + { + pinTable[i++] = hwAttrs->csPin | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX; + } + if (hwAttrs->extcominPin != PIN_TERMINATE) + { + pinTable[i++] = hwAttrs->extcominPin | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX; + } + if (hwAttrs->powerPin != PIN_TERMINATE) + { + pinTable[i++] = hwAttrs->powerPin | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX; + } + if (hwAttrs->enablePin != PIN_TERMINATE) + { + pinTable[i++] = hwAttrs->enablePin | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX; + } + pinTable[i++] = PIN_TERMINATE; + + object->hPins = PIN_open(&object->pinState, pinTable); + if (object->hPins == NULL) + { + Log_error0("Couldn't open pins for Sharp96x96"); + return NULL; + } + + SPI_Params spiParams; + SPI_Params_init(&spiParams); + spiParams.bitRate = 4000000; + + object->hSpi = SPI_open(hwAttrs->spiIndex, &spiParams); + + if (object->hSpi == NULL) + { + Log_error0("Couldn't open SPI driver for Sharp96x96"); + PIN_close(object->hPins); + object->hPins = NULL; + return NULL; + } + + // Init colors + object->displayColor.bg = ClrBlack; + object->displayColor.fg = ClrWhite; + + // Exclusive access + Semaphore_Params semParams; + + Semaphore_Params_init(&semParams); + semParams.mode = Semaphore_Mode_BINARY; + Semaphore_construct(&object->semLCD, 1, &semParams); + + // Grab LCD + Semaphore_pend((Semaphore_Handle) & object->semLCD, ACCESS_TIMEOUT); + + // Initialize the GrLib back-end transport + SharpGrLib_init(object->hSpi, object->hPins, hwAttrs->csPin); + + object->g_sDisplay.lSize = sizeof(tDisplay); + object->g_sDisplay.pFxns = &g_sharpFxns; + object->g_sDisplay.pvDisplayData = object->displayBuffer; + object->g_sDisplay.usHeight = hwAttrs->pixelHeight; + object->g_sDisplay.usWidth = hwAttrs->pixelWidth; + object->g_sDisplay.pvDisplayData = hwAttrs->displayBuf; + + // Graphics library init + GrContextInit(&object->g_sContext, &object->g_sDisplay, &g_sharpFxns); + + // Graphics properties + GrContextForegroundSet(&object->g_sContext, object->displayColor.fg); + GrContextBackgroundSet(&object->g_sContext, object->displayColor.bg); + GrContextFontSet(&object->g_sContext, &g_sFontFixed6x8); + + // Clear display + GrClearDisplay(&object->g_sContext); + GrFlush(&object->g_sContext); + + // Release LCD + Semaphore_post((Semaphore_Handle) & object->semLCD); + + return hDisplay; +} + + +/*! + * @fn DisplaySharp_clear + * + * @brief Clears the display + * + * @param hDisplay - pointer to Display_Config struct + * + * @return void + */ +void DisplaySharp_clear(Display_Handle hDisplay) +{ + DisplaySharp_Object *object = (DisplaySharp_Object *)hDisplay->object; + + if (object->hPins == NULL) + { + return; + } + + // Grab LCD + if (Semaphore_pend((Semaphore_Handle) & object->semLCD, ACCESS_TIMEOUT)) + { + GrClearDisplay(&object->g_sContext); + GrFlush(&object->g_sContext); + + // Release LCD + Semaphore_post((Semaphore_Handle) & object->semLCD); + } +} + + +/*! + * @fn DisplaySharp_clearLines + * + * @brief Clears lines lineFrom-lineTo of the display, inclusive + * + * @param hDisplay - pointer to Display_Config struct + * @param lineFrom - line index (0 .. ) + * @param lineTo - line index (0 .. ) + * + * @return void + */ +void DisplaySharp_clearLines(Display_Handle hDisplay, + uint8_t lineFrom, uint8_t lineTo) +{ + DisplaySharp_Object *object = (DisplaySharp_Object *)hDisplay->object; + + if (lineTo <= lineFrom) + { + lineTo = lineFrom; + } + + tRectangle rect = { + .sXMin = 0, + .sXMax = object->g_sContext.sClipRegion.sXMax, + .sYMin = lineFrom * object->g_sContext.pFont->ucHeight, + .sYMax = (lineTo + 1) * object->g_sContext.pFont->ucHeight - 1, + }; + + GrContextForegroundSet(&object->g_sContext, object->displayColor.bg); + GrRectFill(&object->g_sContext, &rect); + GrContextForegroundSet(&object->g_sContext, object->displayColor.fg); + GrFlush(&object->g_sContext); +} + + +/*! + * @fn DisplaySharp_put5 + * + * @brief Write a text string to a specific line/column of the display + * + * @param hDisplay - pointer to Display_Config struct + * @param line - line index (0..) + * @param column - column index (0..) + * @param fmt - format string + * @param aN - optional format arguments + * + * @return void + */ +void DisplaySharp_put5(Display_Handle hDisplay, uint8_t line, + uint8_t column, uintptr_t fmt, uintptr_t a0, + uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4) +{ + DisplaySharp_Object *object = (DisplaySharp_Object *)hDisplay->object; + + uint8_t xp, yp, clearStartX, clearEndX; + + char dispStr[23]; + + if (object->hPins == NULL) + { + return; + } + + // Grab LCD + if (Semaphore_pend((Semaphore_Handle) & object->semLCD, ACCESS_TIMEOUT)) + { + xp = column * object->g_sContext.pFont->ucMaxWidth + 1; + yp = line * object->g_sContext.pFont->ucHeight + 0; + clearStartX = clearEndX = xp; + + switch (object->lineClearMode) + { + case DISPLAY_CLEAR_LEFT: + clearStartX = 0; + break; + case DISPLAY_CLEAR_RIGHT: + clearEndX = object->g_sContext.sClipRegion.sXMax; + break; + case DISPLAY_CLEAR_BOTH: + clearStartX = 0; + clearEndX = object->g_sContext.sClipRegion.sXMax; + break; + case DISPLAY_CLEAR_NONE: + default: + break; + } + + if (clearStartX != clearEndX) + { + tRectangle rect = { + .sXMin = clearStartX, + .sXMax = clearEndX, + .sYMin = yp, + .sYMax = yp + object->g_sContext.pFont->ucHeight - 1, + }; + + GrContextForegroundSet(&object->g_sContext, object->displayColor.bg); + GrRectFill(&object->g_sContext, &rect); + GrContextForegroundSet(&object->g_sContext, object->displayColor.fg); + } + + System_snprintf(dispStr, sizeof(dispStr), (xdc_CString)fmt, a0, a1, a2, a3, a4); + + // Draw a text on the display + GrStringDraw(&object->g_sContext, + dispStr, + AUTO_STRING_LENGTH, + xp, + yp, + OPAQUE_TEXT); + + GrFlush(&object->g_sContext); + + // Release LCD + Semaphore_post((Semaphore_Handle) & object->semLCD); + } +} + + +/*! + * @fn DisplaySharp_close + * + * @brief Turns of the display and releases the LCD control pins + * + * @param hDisplay - pointer to Display_Config struct + * + * @return void + */ +void DisplaySharp_close(Display_Handle hDisplay) +{ + DisplaySharp_HWAttrs *hwAttrs = (DisplaySharp_HWAttrs *)hDisplay->hwAttrs; + DisplaySharp_Object *object = (DisplaySharp_Object *)hDisplay->object; + + if (object->hPins == NULL) + { + return; + } + + // Grab LCD + if (Semaphore_pend((Semaphore_Handle) & object->semLCD, ACCESS_TIMEOUT)) + { + // Turn off the display + PIN_setOutputValue(object->hPins, hwAttrs->enablePin, 0); + + // Release resources + PIN_close(object->hPins); + object->hPins = NULL; + + SPI_close(object->hSpi); + object->hSpi = NULL; + + // Deconfigure GrLib back-end + SharpGrLib_init(NULL, NULL, PIN_UNASSIGNED); + + // Release LCD + Semaphore_post((Semaphore_Handle) & object->semLCD); + } +} + +/*! + * @fn DisplaySharp_control + * + * @brief Function for setting control parameters of the Display driver + * after it has been opened. + * + * @param hDisplay - pointer to Display_Config struct + * @param cmd - command to execute, supported commands are: + * | Command | Description | + * |------------------------------- |-------------------------| + * | ::DISPLAY_CMD_TRANSPORT_CLOSE | Close SPI but leave control pins | + * | ::DISPLAY_CMD_TRANSPORT_OPEN | Re-open SPI driver | + * @param arg - argument to the command + * + * @return ::DISPLAY_STATUS_SUCCESS if success, or error code if error. + */ +int DisplaySharp_control(Display_Handle hDisplay, unsigned int cmd, void *arg) +{ + DisplaySharp_HWAttrs *hwAttrs = (DisplaySharp_HWAttrs *)hDisplay->hwAttrs; + DisplaySharp_Object *object = (DisplaySharp_Object *)hDisplay->object; + + /* Initialize return value */ + int ret = DISPLAY_STATUS_ERROR; + + /* Perform command */ + switch(cmd) + { + case DISPLAY_CMD_TRANSPORT_CLOSE: + // Grab LCD + if (Semaphore_pend((Semaphore_Handle) & object->semLCD, ACCESS_TIMEOUT)) + { + if (object->hSpi) + { + // Close SPI and tell back-end there is no SPI + SPI_close(object->hSpi); + SharpGrLib_init(NULL, object->hPins, hwAttrs->csPin); + object->hSpi = NULL; + ret = DISPLAY_STATUS_SUCCESS; + } + // Release LCD + Semaphore_post((Semaphore_Handle) & object->semLCD); + } + break; + + case DISPLAY_CMD_TRANSPORT_OPEN: + // Grab LCD + if (Semaphore_pend((Semaphore_Handle) & object->semLCD, ACCESS_TIMEOUT)) + { + if (NULL == object->hSpi) + { + // Re-open SPI and re-init back-end + SPI_Params spiParams; + SPI_Params_init(&spiParams); + spiParams.bitRate = 4000000; + object->hSpi = SPI_open(hwAttrs->spiIndex, &spiParams); + SharpGrLib_init(object->hSpi, object->hPins, hwAttrs->csPin); + ret = DISPLAY_STATUS_SUCCESS; + } + // Release LCD + Semaphore_post((Semaphore_Handle) & object->semLCD); + } + break; + + case DISPLAYSHARP_CMD_SET_COLORS: + // Grab LCD + if (Semaphore_pend((Semaphore_Handle) & object->semLCD, ACCESS_TIMEOUT)) + { + object->displayColor = *(DisplaySharpColor_t *)arg; + + GrContextForegroundSet(&object->g_sContext, object->displayColor.fg); + GrContextBackgroundSet(&object->g_sContext, object->displayColor.bg); + + // Release LCD + Semaphore_post((Semaphore_Handle) & object->semLCD); + + // Return success + ret = DISPLAY_STATUS_SUCCESS; + } + break; + + default: + /* The command is not defined */ + ret = SPI_STATUS_UNDEFINEDCMD; + break; + } + + return ret; +} + +/*! + * @fn DisplaySharp_getType + * + * @brief Returns type of transport + * + * @return Display type define LCD + */ +unsigned int DisplaySharp_getType(void) +{ + return Display_Type_LCD | Display_Type_GRLIB; +} diff --git a/src/components/display_eng/ti/mw/display/DisplayUart.c b/src/components/display_eng/ti/mw/display/DisplayUart.c new file mode 100644 index 0000000..77de1de --- /dev/null +++ b/src/components/display_eng/ti/mw/display/DisplayUart.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* ----------------------------------------------------------------------------- + * Includes + * ----------------------------------------------------------------------------- + */ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +/* ----------------------------------------------------------------------------- + * Constants and macros + * ----------------------------------------------------------------------------- + */ +#ifndef MIN +# define MIN(n, m) (((n) > (m)) ? (m) : (n)) +#endif + +#define DISPLAY_UART_ESC_INITIAL "\x1b\x63" /* Reset terminal */ \ + "\x1b[2J" /* Clear screen */ \ + "\x1b[10r" /* Scrolling region from line 10 */ \ + "\x1b[11;1H" /* Set initial cursor to line 11 */ + +#define DISPLAY_UART_ESC_MOVEPOS_FMT "\x1b\x37" /* Save cursor position */ \ + "\x1b[10r" /* Retransmit scroll */ \ + "\x1b[%d;%dH" /* Move cursor fmt str */ + +#define DISPLAY_UART_ESC_RESTOREPOS "\x1b\x38" /* Restore saved cursor pos */ + +#define DISPLAY_UART_ESC_CLEAR_SCREEN "\x1b[2J" /* Clear screen */ +#define DISPLAY_UART_ESC_CLEAR_CUR_LEFT "\x1b[1K" /* Clear cursor left */ +#define DISPLAY_UART_ESC_CLEAR_CUR_RIGHT "\x1b[0K" /* Clear cursor right */ +#define DISPLAY_UART_ESC_CLEAR_BOTH "\x1b[2K" /* Clear line */ +#define DISPLAY_UART_ESC_CLEARSEQ_LEN 4 + +/* ----------------------------------------------------------------------------- + * Type definitions + * ----------------------------------------------------------------------------- + */ + + +/* ----------------------------------------------------------------------------- + * Local variables + * ----------------------------------------------------------------------------- + */ +/* Display function table for UART implementation */ +const Display_FxnTable DisplayUart_fxnTable = { + DisplayUart_open, + DisplayUart_clear, + DisplayUart_clearLines, + DisplayUart_put5, + DisplayUart_close, + DisplayUart_control, + DisplayUart_getType, +}; + +/* ----------------------------------------------------------------------------- + * Functions + * ----------------------------------------------------------------------------- + */ +/*! + * @fn DisplayUart_open + * + * @brief Initialize the UART transport + * + * @descr Opens the UART index specified in the HWAttrs, and creates a + * mutex semaphore + * + * @param hDisplay - pointer to Display_Config struct + * @param params - display parameters + * + * @return Pointer to Display_Config struct + */ +Display_Handle DisplayUart_open(Display_Handle hDisplay, + Display_Params *params) +{ + DisplayUart_HWAttrs *hwAttrs = (DisplayUart_HWAttrs *)hDisplay->hwAttrs; + DisplayUart_Object *object = (DisplayUart_Object *)hDisplay->object; + + UART_Params uartParams; + UART_Params_init(&uartParams); + uartParams.baudRate = hwAttrs->baudRate; + uartParams.writeMode = UART_MODE_BLOCKING; + + Semaphore_Params semParams; + Semaphore_Params_init(&semParams); + semParams.mode = Semaphore_Mode_BINARY; + Semaphore_construct(&object->mutex, 1, &semParams); + + switch (params->lineClearMode) + { + case DISPLAY_CLEAR_BOTH: object->lineClearSeq = DISPLAY_UART_ESC_CLEAR_BOTH; break; + case DISPLAY_CLEAR_LEFT: object->lineClearSeq = DISPLAY_UART_ESC_CLEAR_CUR_LEFT; break; + case DISPLAY_CLEAR_RIGHT: object->lineClearSeq = DISPLAY_UART_ESC_CLEAR_CUR_RIGHT; break; + default: /* fall-through */ + case DISPLAY_CLEAR_NONE: object->lineClearSeq = NULL; break; + } + + object->hUart = UART_open(hwAttrs->uartIdx, &uartParams); + if (NULL == object->hUart) + { + Log_print0(Diags_USER1, "DisplayUart.c: Couldn't open UART"); + return NULL; + } + + /* Send VT100 initial config to terminal */ + UART_write(object->hUart, DISPLAY_UART_ESC_INITIAL, sizeof DISPLAY_UART_ESC_INITIAL - 1); + + return hDisplay; +} + +/*! + * @fn DisplayUart_clear + * + * @brief Does nothing, as output is stateless. + * + * @param hDisplay - pointer to Display_Config struct + * + * @return void + */ +void DisplayUart_clear(Display_Handle hDisplay) +{ + DisplayUart_Object *object = (DisplayUart_Object *)hDisplay->object; + DisplayUart_HWAttrs *hwAttrs = (DisplayUart_HWAttrs *)hDisplay->hwAttrs; + + if (Semaphore_pend((Semaphore_Handle) & object->mutex, hwAttrs->mutexTimeout)) + { + UART_write(object->hUart, DISPLAY_UART_ESC_CLEAR_SCREEN, 4); + Semaphore_post((Semaphore_Handle) & object->mutex); + } +} + + +/*! + * @fn DisplayUart_clearLines + * + * @brief Does nothing, as output is stateless. + * + * @param hDisplay - pointer to Display_Config struct + * @param lineFrom - line index (0 .. ) + * @param lineTo - line index (0 .. ) + * + * @return void + */ +void DisplayUart_clearLines(Display_Handle hDisplay, + uint8_t lineFrom, uint8_t lineTo) +{ + DisplayUart_Object *object = (DisplayUart_Object *)hDisplay->object; + DisplayUart_HWAttrs *hwAttrs = (DisplayUart_HWAttrs *)hDisplay->hwAttrs; + + uint32_t strSize = 0; + uint32_t curLine = 0; + const uint8_t uartClearLineMoveDown[] = "\x1b[2K\x1b\x45"; + + if (lineTo <= lineFrom) + { + lineTo = lineFrom; + } + + if (Semaphore_pend((Semaphore_Handle) & object->mutex, hwAttrs->mutexTimeout)) + { + strSize += System_snprintf(hwAttrs->strBuf, hwAttrs->strBufLen, + DISPLAY_UART_ESC_MOVEPOS_FMT, lineFrom + 1, 0); + + for (curLine = lineFrom + 1; + curLine < lineTo + 2 && + hwAttrs->strBufLen - strSize > sizeof DISPLAY_UART_ESC_RESTOREPOS - 1; + curLine++) + { + memcpy(hwAttrs->strBuf + strSize, uartClearLineMoveDown, sizeof uartClearLineMoveDown - 1); + strSize += sizeof uartClearLineMoveDown - 1; + } + + memcpy(hwAttrs->strBuf + strSize, DISPLAY_UART_ESC_RESTOREPOS, sizeof DISPLAY_UART_ESC_RESTOREPOS - 1); + strSize += sizeof DISPLAY_UART_ESC_RESTOREPOS - 1; + + UART_write(object->hUart, hwAttrs->strBuf, strSize); + Semaphore_post((Semaphore_Handle) & object->mutex); + } +} + + +/*! + * @fn DisplayUart_put5 + * + * @brief Write a text string to UART with return and newline. + * + * @param hDisplay - pointer to Display_Config struct + * @param line - line index (0..) + * @param column - column index (0..) + * @param fmt - format string + * @param aN - optional format arguments + * + * @return void + */ +void DisplayUart_put5(Display_Handle hDisplay, uint8_t line, + uint8_t column, uintptr_t fmt, uintptr_t a0, + uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4) +{ + DisplayUart_Object *object = (DisplayUart_Object *)hDisplay->object; + DisplayUart_HWAttrs *hwAttrs = (DisplayUart_HWAttrs *)hDisplay->hwAttrs; + + uint32_t strSize = 0; + + char *strBuf = hwAttrs->strBuf; + const uint16_t bufLen = hwAttrs->strBufLen; + + if (Semaphore_pend((Semaphore_Handle) & object->mutex, hwAttrs->mutexTimeout)) + { + if (line != DisplayUart_SCROLLING) + { + /* Add cursor movement escape sequence */ + strSize += System_snprintf(strBuf + strSize, bufLen - strSize - 2, + DISPLAY_UART_ESC_MOVEPOS_FMT, line + 1, column + 1); + + /* Add line clearing escape sequence */ + if (object->lineClearSeq) + { + memcpy(strBuf + strSize, object->lineClearSeq, DISPLAY_UART_ESC_CLEARSEQ_LEN); + strSize += DISPLAY_UART_ESC_CLEARSEQ_LEN; + } + } + + strSize += System_snprintf(strBuf + strSize, bufLen - strSize - 2, (xdc_CString)fmt, a0, a1, a2, a3, a4); + + if (line != DisplayUart_SCROLLING) + { + memcpy(strBuf + strSize, DISPLAY_UART_ESC_RESTOREPOS, sizeof DISPLAY_UART_ESC_RESTOREPOS - 1); + strSize += 2; + } + else + { + strBuf[strSize++] = '\r'; + strBuf[strSize++] = '\n'; + } + + UART_write(object->hUart, strBuf, strSize); + Semaphore_post((Semaphore_Handle) & object->mutex); + } +} + + +/*! + * @fn DisplayUart_close + * + * @brief Closes the UART handle + * + * @param hDisplay - pointer to Display_Config struct + * + * @return void + */ +void DisplayUart_close(Display_Handle hDisplay) +{ + DisplayUart_Object *object = (DisplayUart_Object *)hDisplay->object; + + // Not sure what happens if someone is writing + UART_close(object->hUart); + object->hUart = NULL; + + // Not sure what happens if someone is pending + Semaphore_destruct(&object->mutex); +} + +/*! + * @fn DisplayUart_control + * + * @brief Function for setting control parameters of the Display driver + * after it has been opened. + * + * @param hDisplay - pointer to Display_Config struct + * @param cmd - command to execute + * @param arg - argument to the command + * + * @return ::DISPLAY_STATUS_UNDEFINEDCMD because no commands are supported + */ +int DisplayUart_control(Display_Handle hDisplay, unsigned int cmd, void *arg) +{ + return DISPLAY_STATUS_UNDEFINEDCMD; +} + +/*! + * @fn DisplayUart_getType + * + * @brief Returns type of transport + * + * @return Display type UART + */ +unsigned int DisplayUart_getType(void) +{ + return Display_Type_UART; +} diff --git a/src/components/display_eng/ti/mw/display/DisplayUart.h b/src/components/display_eng/ti/mw/display/DisplayUart.h new file mode 100644 index 0000000..f3c2dc4 --- /dev/null +++ b/src/components/display_eng/ti/mw/display/DisplayUart.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DISPLAY_UART_H_ +#define _DISPLAY_UART_H_ + +#include +#include +#include +#include + +extern const Display_FxnTable DisplayUart_fxnTable; + +/* + * @brief Line number for text to appear in scrolling region + */ +#define DisplayUart_SCROLLING 0xFF + + +typedef struct DisplayUart_HWAttrs +{ + unsigned int uartIdx; + unsigned int baudRate; + unsigned int mutexTimeout; + char *strBuf; + uint16_t strBufLen; +} DisplayUart_HWAttrs; + + +typedef struct DisplayUart_Object +{ + UART_Handle hUart; + Semaphore_Struct mutex; + uint8_t *lineClearSeq; +} DisplayUart_Object, *DisplayUart_Handle; + + +Display_Handle DisplayUart_open(Display_Handle, + Display_Params * params); +void DisplayUart_clear(Display_Handle handle); +void DisplayUart_clearLines(Display_Handle handle, + uint8_t fromLine, + uint8_t toLine); +void DisplayUart_put5(Display_Handle handle, uint8_t line, + uint8_t column, uintptr_t fmt, uintptr_t a0, + uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4); +void DisplayUart_close(Display_Handle); +int DisplayUart_control(Display_Handle handle, unsigned int cmd, void *arg); +unsigned int DisplayUart_getType(void); + +#endif // _DISPLAY_UART_H_ diff --git a/src/components/sdi/inc/sdi_config.h b/src/components/sdi/inc/sdi_config.h index 59923ee..0d7f895 100644 --- a/src/components/sdi/inc/sdi_config.h +++ b/src/components/sdi/inc/sdi_config.h @@ -77,8 +77,8 @@ extern "C" # error "ERROR: You must choose Board_SPI1 SPI module for NPI." # endif # elif defined(SDI_USE_UART) -# define MRDY_PIN Board_KEY_UP -# define SRDY_PIN Board_KEY_DOWN +# define MRDY_PIN Board_BUTTON0 +# define SRDY_PIN Board_BUTTON1 # endif # define SRDY_ENABLE() PIN_setOutputValue(hSdiHandshakePins, SRDY_PIN, 0) /* RTS low */ # define SRDY_DISABLE() PIN_setOutputValue(hSdiHandshakePins, SRDY_PIN, 1) /* RTS high */ @@ -90,7 +90,7 @@ extern "C" #define SDI_TL_BUF_SIZE 270 #define SDI_SPI_PAYLOAD_SIZE 255 #define SDI_SPI_HDR_LEN 4 - + #ifdef NPI_USE_SPI # if (NPI_TL_BUF_SIZE - NPI_SPI_HDR_LEN) < NPI_SPI_PAYLOAD_SIZE # define NPI_MAX_FRAG_SIZE (NPI_TL_BUF_SIZE - NPI_SPI_HDR_LEN) diff --git a/src/components/sdi/inc/sdi_rxbuf.h b/src/components/sdi/inc/sdi_rxbuf.h index ad882ab..0cd9c85 100644 --- a/src/components/sdi/inc/sdi_rxbuf.h +++ b/src/components/sdi/inc/sdi_rxbuf.h @@ -41,7 +41,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ - + //****************************************************************************** #ifndef SDIRXBUF_H #define SDIRXBUF_H @@ -88,7 +88,14 @@ uint16 SDIRxBuf_Read(uint16); //! //! \return uint16 - // ----------------------------------------------------------------------------- -uint16 SDIRxBuf_GetRxBufLen(); +uint16 SDIRxBuf_GetRxBufCount(); + +// ----------------------------------------------------------------------------- +//! \brief Returns number of bytes that are available in RxBuf +//! +//! \return uint16 - +// ----------------------------------------------------------------------------- +uint16 SDIRxBuf_GetRxBufAvail(); // ----------------------------------------------------------------------------- //! \brief SDIRxBuf_ReadFromRxBuf diff --git a/src/components/sdi/inc/sdi_task.h b/src/components/sdi/inc/sdi_task.h index 55ddedc..a129388 100644 --- a/src/components/sdi/inc/sdi_task.h +++ b/src/components/sdi/inc/sdi_task.h @@ -115,6 +115,15 @@ extern void SDITask_registerIncomingRXEventAppCB(sdiIncomingEventCBack_t appRxCB // ----------------------------------------------------------------------------- extern void SDITask_sendToUART(uint8_t *pMsg, uint16_t length); +// ----------------------------------------------------------------------------- +//! \brief API for application task to set packet data size to send over the air. +//! +//! \param[in] mtuSize GATT MTU size. +//! +//! \return void +// ----------------------------------------------------------------------------- +extern void SDITask_setAppDataSize(uint16_t mtuSize); + #ifdef __cplusplus { #endif // extern "C" diff --git a/src/components/sdi/inc/sdi_tl_uart.h b/src/components/sdi/inc/sdi_tl_uart.h index a1f440a..8e59125 100644 --- a/src/components/sdi/inc/sdi_tl_uart.h +++ b/src/components/sdi/inc/sdi_tl_uart.h @@ -62,7 +62,7 @@ extern "C" #define SDI_UART_INT_ENABLE TRUE #if !defined(SDI_UART_BR) -#define SDI_UART_BR 921600 //115200 +#define SDI_UART_BR 115200 #endif // !SDI_UART_BR // UART ISR Buffer define diff --git a/src/components/sdi/sdi_rxbuf.c b/src/components/sdi/sdi_rxbuf.c index a30da59..810eec1 100644 --- a/src/components/sdi/sdi_rxbuf.c +++ b/src/components/sdi/sdi_rxbuf.c @@ -115,11 +115,21 @@ uint16 SDIRxBuf_Read(uint16 len) //! //! \return uint16 - // ----------------------------------------------------------------------------- -uint16 SDIRxBuf_GetRxBufLen(void) +uint16 SDIRxBuf_GetRxBufCount(void) { return ((RxBufTail - RxBufHead) + SDI_TL_BUF_SIZE) % SDI_TL_BUF_SIZE; } +// ----------------------------------------------------------------------------- +//! \brief Returns number of bytes that are available in RxBuf +//! +//! \return uint16 - +// ----------------------------------------------------------------------------- +uint16 SDIRxBuf_GetRxBufAvail(void) +{ + return (SDI_TL_BUF_SIZE - SDIRxBuf_GetRxBufCount()); +} + // ----------------------------------------------------------------------------- //! \brief SDIRxBuf_ReadFromRxBuf //! @@ -127,7 +137,7 @@ uint16 SDIRxBuf_GetRxBufLen(void) // ----------------------------------------------------------------------------- uint16 SDIRxBuf_ReadFromRxBuf(uint8_t *buf, uint16 len) { - uint16_t idx; + uint16_t idx; for (idx = 0; idx < len; idx++) { *buf++ = RxBuf[RxBufHead]; diff --git a/src/components/sdi/sdi_task.c b/src/components/sdi/sdi_task.c index 5d2da84..91d9cc5 100644 --- a/src/components/sdi/sdi_task.c +++ b/src/components/sdi/sdi_task.c @@ -50,7 +50,6 @@ #include #include -#include #include #include #include @@ -69,25 +68,37 @@ // **************************************************************************** //! \brief Transport layer RX Event (ie. bytes received, RX ISR etc.) -#define SDITASK_TRANSPORT_RX_EVENT Event_Id_00 +#define SDITASK_TRANSPORT_RX_EVENT Event_Id_00 //! \brief Transmit Complete Event (likely associated with TX ISR etc.) -#define SDITASK_TRANSPORT_TX_DONE_EVENT Event_Id_01 +#define SDITASK_TRANSPORT_TX_DONE_EVENT Event_Id_01 //! \brief A framed message buffer is ready to be sent to the transport layer. -#define SDITASK_TX_READY_EVENT Event_Id_02 +#define SDITASK_TX_READY_EVENT Event_Id_02 //! \brief MRDY Received Event #define SDITASK_MRDY_EVENT Event_Id_03 //! \brief Size of stack created for SDI RTOS task -#define SDITASK_STACK_SIZE 512 +#ifndef Display_DISABLE_ALL +#ifdef __TI_COMPILER_VERSION__ +#define SDITASK_STACK_SIZE 752 /* in order to optimize memory, this value should be a multiple of 8 bytes */ +#else // !__TI_COMPILER_VERSION__ +#define SDITASK_STACK_SIZE 656 /* in order to optimize memory, this value should be a multiple of 8 bytes */ +#endif // __TI_COMPILER_VERSION__ +#else // Display_DISABLE_ALL +#ifdef __TI_COMPILER_VERSION__ +#define SDITASK_STACK_SIZE 752 /* in order to optimize memory, this value should be a multiple of 8 bytes */ +#else // !__TI_COMPILER_VERSION__ +#define SDITASK_STACK_SIZE 608 /* in order to optimize memory, this value should be a multiple of 8 bytes */ +#endif // __TI_COMPILER_VERSION__ +#endif // Display_DISABLE_ALL //! \brief Task priority for SDI RTOS task #define SDITASK_PRIORITY 2 //! \brief Max bytes received from UART send to App -#define MAX_UART_LENGTH 128 +#define DEFAULT_APP_DATA_LENGTH 20 // **************************************************************************** // typedefs @@ -95,7 +106,7 @@ //! \brief Queue record structure //! -typedef struct SDI_QueueRec_t +typedef struct SDI_QueueRec_t { Queue_Elem _elem; SDIMSG_msg_t *sdiMsg; @@ -105,23 +116,18 @@ typedef struct SDI_QueueRec_t //***************************************************************************** // globals //***************************************************************************** - -uint8 buf[SDI_TL_BUF_SIZE] ={0x00,}; -uint16 length; -uint8 lengthRead; -uint8 bufTest[SDI_TL_BUF_SIZE] ={0x00,}; -uint16 lenTest = 0; -//! \brief ICall ID for stack which will be sending SDI messages -//! -//static uint32_t stackServiceID = 0x0000; - //! \brief RTOS task structure for SDI task //! static Task_Struct sdiTaskStruct; //! \brief Allocated memory block for SDI task's stack //! -Char sdiTaskStack[SDITASK_STACK_SIZE]; +#if defined __TI_COMPILER_VERSION__ +#pragma DATA_ALIGN(sdiTaskStack, 8) +#else +#pragma data_alignment=8 +#endif +uint8_t sdiTaskStack[SDITASK_STACK_SIZE]; //! \brief Handle for the ASYNC TX Queue //! @@ -136,15 +142,21 @@ static uint8_t *lastQueuedTxMsg; Event_Struct uartEvent; Event_Handle hUartEvent; //!< Event used to control the UART thread -//! \brief SDI ICall Application Entity ID. -//! -ICall_EntityID sdiAppEntityID = 0; - //! \brief Pointer to Application RX event callback function for optional //! rerouting of messages to application. //! static sdiIncomingEventCBack_t incomingRXEventAppCBFunc = NULL; +//! \brief Data buffer to send to application +//! +static uint8 buf[SDI_TL_BUF_SIZE] ={0x00,}; +static uint16 length; +static uint8 lengthRead; + +//! \brief Size of data to send to application +//! +static uint16 maxAppDataSize = DEFAULT_APP_DATA_LENGTH; + //***************************************************************************** // function prototypes //***************************************************************************** @@ -169,6 +181,15 @@ static void SDITask_MRDYEventCB(int size); //! static void SDITask_ProcessTXQ(void); +// ----------------------------------------------------------------------------- +//! \brief Initialization for the SDI Thread +//! +//! \return void +// ----------------------------------------------------------------------------- +void SDITask_setAppDataSize(uint16 mtuSize) +{ + maxAppDataSize = mtuSize - 3; //subtract GATT Notification overhead: 1 byte opcode, 2 bytes conn. handle +} // ----------------------------------------------------------------------------- //! \brief Initialization for the SDI Thread @@ -187,7 +208,7 @@ static void SDITask_inititializeTask(void) Event_construct(&uartEvent, &evParams); hUartEvent = Event_handle(&uartEvent); - + // Initialize Network Processor Interface (SDI) and Transport Layer SDITL_initTL( &SDITask_transportTxDoneCallBack, &SDITask_transportRXCallBack, @@ -201,17 +222,17 @@ static void SDITask_inititializeTask(void) //! \return void // ----------------------------------------------------------------------------- static void SDITask_process(void) -{ +{ UInt postedEvents; - + /* Forever loop */ - while (1) + for (;; ) { /* Wait for response message */ postedEvents = Event_pend(hUartEvent, Event_Id_NONE, SDITASK_MRDY_EVENT | SDITASK_TX_READY_EVENT | SDITASK_TRANSPORT_RX_EVENT | SDITASK_TRANSPORT_TX_DONE_EVENT, BIOS_WAIT_FOREVER); - + { - // Capture the ISR events flags now within this task loop. + // Capture the ISR events flags now within this task loop. // MRDY event if (postedEvents & SDITASK_MRDY_EVENT) @@ -230,11 +251,11 @@ static void SDITask_process(void) { SDITask_ProcessTXQ(); } - + if (Queue_empty(sdiTxQueue)) { // Q is empty, no action. - + } else { @@ -247,21 +268,19 @@ static void SDITask_process(void) // The Transport Layer has received some bytes if(postedEvents & SDITASK_TRANSPORT_RX_EVENT) { - length = SDIRxBuf_GetRxBufLen(); + length = SDIRxBuf_GetRxBufCount(); - if(length > MAX_UART_LENGTH) + if(length > maxAppDataSize) { - lengthRead = MAX_UART_LENGTH; + lengthRead = (maxAppDataSize & 0xFF); }else { lengthRead = (length & 0xFF); } - - //bufTest[lenTest++] = length; - + //Do custom app processing SDIRxBuf_ReadFromRxBuf(buf, lengthRead); - + //Echo back via UART //SDITask_sendToUART(buf, length); @@ -269,11 +288,11 @@ static void SDITask_process(void) { incomingRXEventAppCBFunc( UART_DATA_EVT , buf, lengthRead); } - - if(length > MAX_UART_LENGTH) + + if(length > maxAppDataSize) { // Additional bytes to collect, preserve the flag and repost - // to the semaphore + // to the event Event_post(hUartEvent, SDITASK_TRANSPORT_RX_EVENT); } } @@ -282,12 +301,12 @@ static void SDITask_process(void) if(postedEvents & SDITASK_TRANSPORT_TX_DONE_EVENT) { // Current TX is done. - + if (!Queue_empty(sdiTxQueue)) { // There are pending ASYNC messages waiting to be sent // to the host. Post to event. - + Event_post(hUartEvent, SDITASK_TX_READY_EVENT); } } @@ -371,26 +390,26 @@ void SDITask_sendToUART(uint8_t *pMsg, uint16 length) SDI_QueueRec *recPtr; SDIMSG_msg_t *pSDIMsg =(SDIMSG_msg_t *)ICall_malloc( sizeof(SDIMSG_msg_t)); - - key = ICall_enterCriticalSection(); - + + key = ICall_enterCriticalSection(); + if(pSDIMsg) { pSDIMsg->msgType = SDIMSG_Type_ASYNC; pSDIMsg->pBuf = (uint8 *)ICall_allocMsg(length); pSDIMsg->pBufSize = length; - + if(pSDIMsg->pBuf) { // Payload memcpy(pSDIMsg->pBuf, pMsg, length); } - + recPtr = ICall_malloc(sizeof(SDI_QueueRec)); recPtr->sdiMsg = pSDIMsg; } - + switch (pSDIMsg->msgType) { case SDIMSG_Type_ASYNC: @@ -417,9 +436,16 @@ void SDITask_sendToUART(uint8_t *pMsg, uint16 length) // ----------------------------------------------------------------------------- static void SDITask_ProcessTXQ(void) { - + ICall_CSState key; SDI_QueueRec *recPtr = NULL; + // Processing of any TX Queue should only be done + // in a critical section since any application + // task can enqueue items freely + key = ICall_enterCriticalSection(); + + if (!Queue_empty(sdiTxQueue)) + { recPtr = Queue_dequeue(sdiTxQueue); if (recPtr != NULL) @@ -431,8 +457,10 @@ static void SDITask_ProcessTXQ(void) //free the Queue record ICall_free(recPtr->sdiMsg); ICall_free(recPtr); - } + } + } + ICall_leaveCriticalSection(key); } // ----------------------------------------------------------------------------- @@ -447,7 +475,7 @@ static void SDITask_ProcessTXQ(void) // ----------------------------------------------------------------------------- static void SDITask_transportTxDoneCallBack(int size) { - + if(lastQueuedTxMsg) { //Deallocate most recent message being transmitted. @@ -470,7 +498,16 @@ static void SDITask_transportTxDoneCallBack(int size) // ----------------------------------------------------------------------------- static void SDITask_transportRXCallBack(int size) { - SDIRxBuf_Read(size); + if ( size < SDIRxBuf_GetRxBufAvail() ) + { + SDIRxBuf_Read(size); + } + else + { + // Trap here for pending buffer overflow. If SDI_FLOW_CTRL is + // enabled, increase size of RxBuf to handle larger frames from host. + for(;;); + } Event_post(hUartEvent, SDITASK_TRANSPORT_RX_EVENT); } diff --git a/src/components/sdi/sdi_tl.c b/src/components/sdi/sdi_tl.c index df66cd1..09ede94 100644 --- a/src/components/sdi/sdi_tl.c +++ b/src/components/sdi/sdi_tl.c @@ -236,8 +236,8 @@ static void SDITL_setPM(void) return; } // set constraints for Standby and idle mode - Power_setConstraint(Power_SB_DISALLOW); - Power_setConstraint(Power_IDLE_PD_DISALLOW); + Power_setConstraint(PowerCC26XX_SB_DISALLOW); + Power_setConstraint(PowerCC26XX_IDLE_PD_DISALLOW); sdiPMSetConstraint = TRUE; } #endif @@ -256,8 +256,8 @@ static void SDITL_relPM(void) return; } // release constraints for Standby and idle mode - Power_releaseConstraint(Power_SB_DISALLOW); - Power_releaseConstraint(Power_IDLE_PD_DISALLOW); + Power_releaseConstraint(PowerCC26XX_SB_DISALLOW); + Power_releaseConstraint(PowerCC26XX_IDLE_PD_DISALLOW); sdiPMSetConstraint = FALSE; } #endif diff --git a/src/components/sdi/sdi_tl_uart.c b/src/components/sdi/sdi_tl_uart.c index 48db101..c742768 100644 --- a/src/components/sdi/sdi_tl_uart.c +++ b/src/components/sdi/sdi_tl_uart.c @@ -140,28 +140,28 @@ void SDITLUART_registerIncomingRXErrorStatusAppCB(sdiTLIncomingEventCBack_t appR void SDITLUART_closeUART(void) { ICall_CSState key; - + key = ICall_enterCriticalSection(); - + // Cancel any pending reads UART_readCancel(uartHandle); - + // Close / power off the UART. UART_close(uartHandle); - + ICall_leaveCriticalSection(key); } uint8 SDITLUART_configureUARTParams(UART_Params *initParams) -{ +{ uint8 status = SUCCESS; ICall_CSState key; - + SDITLUART_closeUART(); - + key = ICall_enterCriticalSection(); - + // Open / power on the UART. uartHandle = UART_open(Board_UART, ¶msUART); if(uartHandle != NULL) @@ -171,17 +171,17 @@ uint8 SDITLUART_configureUARTParams(UART_Params *initParams) //DEBUG("ERROR in UART_open"); status = FAILURE; } - + //Enable Partial Reads on all subsequent UART_read() status = UART_control(uartHandle, UARTCC26XX_RETURN_PARTIAL_ENABLE, NULL); - + ICall_leaveCriticalSection(key); - + #ifndef POWER_SAVING //Initiate first read to start polling UART SDITLUART_readTransport(); #endif //POWER_SAVING - + return status; } @@ -191,8 +191,8 @@ uint8 SDITLUART_configureUARTParams(UART_Params *initParams) //! //! \param[in] tRxBuf - pointer to SDI TL Tx Buffer //! \param[in] tTxBuf - pointer to SDI TL Rx Buffer -//! \param[in] sdiCBack - SDI TL call back function to be invoked at the end of -//! a UART transaction +//! \param[in] sdiCBack - SDI TL call back function to be invoked at the end of +//! a UART transaction //! //! \return void // ----------------------------------------------------------------------------- @@ -218,7 +218,7 @@ void SDITLUART_initializeTransport(Char *tRxBuf, Char *tTxBuf, sdiCB_t sdiCBack) paramsUART.writeCallback = SDITLUART_writeCallBack; //paramsUART.readReturnMode = UART_RETURN_FULL; - + // Open / power on the UART. uartHandle = UART_open(Board_UART, ¶msUART); if(uartHandle != NULL) @@ -248,7 +248,7 @@ void SDITLUART_stopTransfer(void) // or that the FIFO has already been read for this UART_read() // In either case UART_readCancel will call the read CB function and it will // invoke sdiTransmitCB with the appropriate number of bytes read - if (!UARTCharsAvail(((UARTCC26XX_HWAttrs const *)(uartHandle->hwAttrs))->baseAddr)) + if (!UARTCharsAvail(((UARTCC26XX_HWAttrsV1 const *)(uartHandle->hwAttrs))->baseAddr)) { RxActive = FALSE; UART_readCancel(uartHandle); @@ -270,7 +270,7 @@ void SDITLUART_handleMrdyEvent(void) { ICall_CSState key; key = ICall_enterCriticalSection(); - + mrdy_flag = 0; // If we haven't already begun reading, now is the time before Master @@ -299,7 +299,7 @@ void SDITLUART_handleMrdyEvent(void) } ICall_leaveCriticalSection(key); - + return; } #endif //POWER_SAVING @@ -321,7 +321,7 @@ static void SDITLUART_writeCallBack(UART_Handle handle, void *ptr, size_t size) if (errStatus = ((UARTCC26XX_Handle)handle->object)->status) { - //report UART error status to application + //report UART error status to application if(incomingRXErrorStatusAppCBFunc != NULL) incomingRXErrorStatusAppCBFunc(UART_ERROR_EVT, &errStatus, sizeof(errStatus)); } @@ -337,7 +337,7 @@ static void SDITLUART_writeCallBack(UART_Handle handle, void *ptr, size_t size) } TxActive = FALSE; - + #else if ( sdiTransmitCB ) { @@ -366,7 +366,7 @@ static void SDITLUART_readCallBack(UART_Handle handle, void *ptr, size_t size) if (errStatus = ((UARTCC26XX_Handle)handle->object)->status) { - //report UART error status to application + //report UART error status to application if(incomingRXErrorStatusAppCBFunc != NULL) incomingRXErrorStatusAppCBFunc(UART_ERROR_EVT, &errStatus, sizeof(errStatus)); } @@ -390,11 +390,11 @@ static void SDITLUART_readCallBack(UART_Handle handle, void *ptr, size_t size) #ifdef POWER_SAVING // Read has been cancelled by transport layer, or bus timeout and no bytes in FIFO // - do not invoke another read - if ( !UARTCharsAvail(((UARTCC26XX_HWAttrs const *)(uartHandle->hwAttrs))->baseAddr) && + if ( !UARTCharsAvail(((UARTCC26XX_HWAttrsV1 const *)(uartHandle->hwAttrs))->baseAddr) && mrdy_flag ) { RxActive = FALSE; - + // If TX has also completed then we are safe to issue call back if ( !TxActive && sdiTransmitCB ) { @@ -450,14 +450,14 @@ void SDITLUART_readTransport(void) { ICall_CSState key; key = ICall_enterCriticalSection(); - + #ifdef POWER_SAVING RxActive = TRUE; #endif //POWER_SAVING TransportRxLen = 0; UART_read(uartHandle, &isrRxBuf[0], UART_ISR_BUF_SIZE); - + ICall_leaveCriticalSection(key); } @@ -473,7 +473,7 @@ uint16 SDITLUART_writeTransport(uint16 len) { ICall_CSState key; key = ICall_enterCriticalSection(); - + TransportTxLen = len; #ifdef POWER_SAVING @@ -492,6 +492,6 @@ uint16 SDITLUART_writeTransport(uint16 len) } #endif //POWER_SAVING ICall_leaveCriticalSection(key); - + return TransportTxLen; } diff --git a/src/examples/simple_beacon/cc26xx/app/simple_beacon.c b/src/examples/simple_beacon/cc26xx/app/simple_beacon.c index f880606..6999812 100644 --- a/src/examples/simple_beacon/cc26xx/app/simple_beacon.c +++ b/src/examples/simple_beacon/cc26xx/app/simple_beacon.c @@ -413,7 +413,7 @@ static void SimpleBeacon_init(void) // Setup the GAP Peripheral Role Profile { - uint8_t initialAdvertEnable = TRUE; + uint8_t initialAdvertEnable = FALSE; uint8_t initialNonConnAdvEnable = TRUE; // By setting this to zero, the device will go into the waiting state after diff --git a/src/examples/simple_central/cc26xx/app/simple_central.c b/src/examples/simple_central/cc26xx/app/simple_central.c new file mode 100644 index 0000000..014baef --- /dev/null +++ b/src/examples/simple_central/cc26xx/app/simple_central.c @@ -0,0 +1,1979 @@ +/****************************************************************************** + + @file simple_central.c + + @brief This file contains the Simple BLE Central sample application for use + with the CC2650 Bluetooth Low Energy Protocol Stack. + + Group: WCS, BTS + Target Device: CC2650, CC2640, CC1350 + + ****************************************************************************** + + Copyright (c) 2013-2016, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + Release Name: ble_sdk_2_02_00_31 + Release Date: 2016-06-16 18:57:29 + *****************************************************************************/ + +/********************************************************************* + * INCLUDES + */ +#include + +#include +#include +#include +#include + +#include "bcomdef.h" + +#include "hci_tl.h" +#include "linkdb.h" +#include "gatt.h" +#include "gapgattserver.h" +#include "gattservapp.h" +#include "central.h" +#include "gapbondmgr.h" +#include "simple_gatt_profile.h" + +#include "osal_snv.h" +#include "icall_apimsg.h" + +#include "util.h" +#include "board_key.h" +#include +#include "board.h" + +#include "simple_central.h" + +#include "ble_user_config.h" + + + + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * CONSTANTS + */ + +// Simple BLE Central Task Events +#define SBC_START_DISCOVERY_EVT 0x0001 +#define SBC_PAIRING_STATE_EVT 0x0002 +#define SBC_PASSCODE_NEEDED_EVT 0x0004 +#define SBC_RSSI_READ_EVT 0x0008 +#define SBC_KEY_CHANGE_EVT 0x0010 +#define SBC_STATE_CHANGE_EVT 0x0020 +#define SBC_CONNECTING_TIMEOUT_EVT 0x0040 + +// Maximum number of scan responses +#define DEFAULT_MAX_SCAN_RES 8 + +// Scan duration in ms +#define DEFAULT_SCAN_DURATION 4000 + +// Discovery mode (limited, general, all) +#define DEFAULT_DISCOVERY_MODE DEVDISC_MODE_ALL + +// TRUE to use active scan +#define DEFAULT_DISCOVERY_ACTIVE_SCAN TRUE + +// TRUE to use white list during discovery +#define DEFAULT_DISCOVERY_WHITE_LIST FALSE + +// TRUE to use high scan duty cycle when creating link +#define DEFAULT_LINK_HIGH_DUTY_CYCLE FALSE + +// TRUE to use white list when creating link +#define DEFAULT_LINK_WHITE_LIST FALSE + +// Initial minimum connection interval (units of 1.25 ms.) +#define INITIAL_MIN_CONN_INTERVAL 160 + +// Initial minimum connection interval (units of 1.25 ms.) +#define INITIAL_MAX_CONN_INTERVAL 320 + +// Initial slave latency +#define INITIAL_SLAVE_LATENCY 0 + +// Initial supervision timeout (units of 1.25 ms) +#define INITIAL_CONN_TIMEOUT 700 + +// Default RSSI polling period in ms +#define DEFAULT_RSSI_PERIOD 1000 + +// Whether to enable automatic parameter update request when a connection is +// formed +#define DEFAULT_ENABLE_UPDATE_REQUEST FALSE + +// Minimum connection interval (units of 1.25ms) if automatic parameter update +// request is enabled +#define DEFAULT_UPDATE_MIN_CONN_INTERVAL 80 + +// Maximum connection interval (units of 1.25ms) if automatic parameter update +// request is enabled +#define DEFAULT_UPDATE_MAX_CONN_INTERVAL 160 + +// Slave latency to use if automatic parameter update request is enabled +#define DEFAULT_UPDATE_SLAVE_LATENCY 0 + +// Supervision timeout value (units of 10ms) if automatic parameter update +// request is enabled +#define DEFAULT_UPDATE_CONN_TIMEOUT 600 + +// Default passcode +#define DEFAULT_PASSCODE 19655 + +// Default GAP pairing mode +#define DEFAULT_PAIRING_MODE GAPBOND_PAIRING_MODE_WAIT_FOR_REQ + +// Default MITM mode (TRUE to require passcode or OOB when pairing) +#define DEFAULT_MITM_MODE FALSE + +// Default bonding mode, TRUE to bond +#define DEFAULT_BONDING_MODE TRUE + +// Default GAP bonding I/O capabilities +#define DEFAULT_IO_CAPABILITIES GAPBOND_IO_CAP_DISPLAY_ONLY + +// Default service discovery timer delay in ms +#define DEFAULT_SVC_DISCOVERY_DELAY 1000 + +// TRUE to filter discovery results on desired service UUID +#define DEFAULT_DEV_DISC_BY_SVC_UUID TRUE + +// Length of bd addr as a string +#define B_ADDR_STR_LEN 15 + +// Task configuration +#define SBC_TASK_PRIORITY 1 + +#ifndef SBC_TASK_STACK_SIZE +#define SBC_TASK_STACK_SIZE 864 +#endif + +// Application states +typedef enum +{ + BLE_STATE_IDLE, + BLE_STATE_BROWSING, + BLE_STATE_CONNECTING, + BLE_STATE_CONNECTED, + BLE_STATE_DISCOVERED, + BLE_STATE_DISCONNECTING +} bleState_t; + + +// Discovery states +typedef enum +{ + BLE_DISC_STATE_IDLE, // Idle + BLE_DISC_STATE_MTU, // Exchange ATT MTU size + BLE_DISC_STATE_SVC, // Service discovery + BLE_DISC_STATE_CHAR // Characteristic discovery +} bleDiscState_t; + +// Connection parameter update +enum +{ + INITIAL_PARAMETERS, + DEFAULT_UPDATE_PARAMETERS +}; + +// Screen row +enum +{ + ROW_ZERO = 0, + ROW_ONE = 1, + ROW_TWO = 2, + ROW_THREE = 3, + ROW_FOUR = 4, + ROW_FIVE = 5, + ROW_SIX = 6, + ROW_SEVEN = 7 +}; + +// Menu item state +typedef enum { + MENU_ITEM_CONN_PARAM_UPDATE, + MENU_ITEM_RSSI, + MENU_ITEM_READ_WRITE, + MENU_ITEM_DISCONNECT + } MenuItem_t; + +/********************************************************************* + * TYPEDEFS + */ + +// App event passed from profiles. +typedef struct +{ + appEvtHdr_t hdr; // event header + uint8_t *pData; // event data +} sbcEvt_t; + +// RSSI read data structure +typedef struct +{ + Clock_Struct *pClock; // pointer to clock struct + uint16_t period; // how often to read RSSI + uint16_t connHandle; // connection handle +} readRssi_t; + +/** + * Type of device discovery (Scan) to perform. + */ +typedef struct +{ + char localName[20]; //!< Device's Name + uint8_t addrType; //!< Address Type: @ref ADDRTYPE_DEFINES + uint8_t addr[B_ADDR_LEN]; //!< Device's Address + uint8_t nameLength; //!< Device name length +} devRecInfo_t; + +/********************************************************************* + * GLOBAL VARIABLES + */ + +// Display Interface +Display_Handle dispHandle = NULL; + +/********************************************************************* + * EXTERNAL VARIABLES + */ + +/********************************************************************* + * LOCAL VARIABLES + */ + +// Entity ID globally used to check for source and/or destination of messages +static ICall_EntityID selfEntity; + +// Semaphore globally used to post events to the application thread +static ICall_Semaphore sem; + +// Clock object used to signal timeout +static Clock_Struct startDiscClock; + +// Clock object used to timeout connection +static Clock_Struct connectingClock; + +// Queue object used for app messages +static Queue_Struct appMsg; +static Queue_Handle appMsgQueue; + +// Task pending events +static uint16_t events = 0; + +// Task configuration +Task_Struct sbcTask; +Char sbcTaskStack[SBC_TASK_STACK_SIZE]; + +// GAP GATT Attributes +static const uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Simple BLE Central"; + +// Number of scan results and scan result index +static uint8_t scanRes; +static uint8_t scanIdx; + +// Scan result list +static devRecInfo_t devList[DEFAULT_MAX_SCAN_RES]; + +// Scanning state +static bool scanningStarted = FALSE; + +// Connection handle of current connection +static uint16_t connHandle = GAP_CONNHANDLE_INIT; + +// Application state +static bleState_t state = BLE_STATE_IDLE; + +// Discovery state +static bleDiscState_t discState = BLE_DISC_STATE_IDLE; + +// Connection paramters +static uint8_t currentConnectionParameter = INITIAL_PARAMETERS; + +//Connection option state +static MenuItem_t selectedMenuItem = MENU_ITEM_CONN_PARAM_UPDATE; + +// Discovered service start and end handle +static uint16_t svcStartHdl = 0; +static uint16_t svcEndHdl = 0; + +// Discovered characteristic handle +static uint16_t charHdl = 0; + +// Value to write +static uint8_t charVal = 0; + +// Value read/write toggle +static bool doWrite = FALSE; + +// GATT read/write procedure state +static bool procedureInProgress = FALSE; + +// Maximum PDU size (default = 27 octets) +static uint16_t maxPduSize; + +// Array of RSSI read structures +static readRssi_t readRssi[MAX_NUM_BLE_CONNS]; + +/********************************************************************* + * LOCAL FUNCTIONS + */ +static void SimpleBLECentral_init(void); +static void SimpleBLECentral_taskFxn(UArg a0, UArg a1); + +static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg); +static void SimpleBLECentral_handleKeys(uint8_t shift, uint8_t keys); +static void SimpleBLECentral_processStackMsg(ICall_Hdr *pMsg); +static void SimpleBLECentral_processAppMsg(sbcEvt_t *pMsg); +static void SimpleBLECentral_processRoleEvent(gapCentralRoleEvent_t *pEvent); +static void SimpleBLECentral_processGATTDiscEvent(gattMsgEvent_t *pMsg); +static void SimpleBLECentral_startDiscovery(void); +static bool SimpleBLECentral_findSvcUuid(uint16_t uuid, uint8_t *pData, + uint8_t dataLen); +static void SimpleBLECentral_discoverDevices(void); +void SimpleBLECentral_timeoutConnecting(UArg arg0); +static void SimpleBLECentral_addDeviceInfo(uint8_t *pAddr, uint8_t addrType); +static bool SimpleBLECentral_findLocalName(uint8_t *pEvtData, uint8_t dataLen); +static void SimpleBLECentral_addDeviceName(uint8_t i, uint8_t *pEvtData, + uint8_t dataLen); +static void SimpleBLECentral_processPairState(uint8_t pairState, uint8_t status); +static void SimpleBLECentral_processPasscode(uint16_t connectionHandle, + uint8_t uiOutputs); + +static void SimpleBLECentral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg); +static bStatus_t SimpleBLECentral_StartRssi(uint16_t connHandle, uint16_t period); +static bStatus_t SimpleBLECentral_CancelRssi(uint16_t connHandle); +static readRssi_t *SimpleBLECentral_RssiAlloc(uint16_t connHandle); +static readRssi_t *SimpleBLECentral_RssiFind(uint16_t connHandle); +static void SimpleBLECentral_RssiFree(uint16_t connHandle); + +static uint8_t SimpleBLECentral_eventCB(gapCentralRoleEvent_t *pEvent); +static void SimpleBLECentral_passcodeCB(uint8_t *deviceAddr, uint16_t connHandle, + uint8_t uiInputs, uint8_t uiOutputs); +static void SimpleBLECentral_pairStateCB(uint16_t connHandle, uint8_t pairState, + uint8_t status); + +void SimpleBLECentral_startDiscHandler(UArg a0); +void SimpleBLECentral_keyChangeHandler(uint8_t keys); +void SimpleBLECentral_readRssiHandler(UArg a0); + +static uint8_t SimpleBLECentral_enqueueMsg(uint8_t event, uint8_t status, + uint8_t *pData); + +/********************************************************************* + * PROFILE CALLBACKS + */ + +// GAP Role Callbacks +static gapCentralRoleCB_t SimpleBLECentral_roleCB = +{ + SimpleBLECentral_eventCB // Event callback +}; + +// Bond Manager Callbacks +static gapBondCBs_t SimpleBLECentral_bondCB = +{ + (pfnPasscodeCB_t)SimpleBLECentral_passcodeCB, // Passcode callback + SimpleBLECentral_pairStateCB // Pairing state callback +}; + +/********************************************************************* + * PUBLIC FUNCTIONS + */ + +/********************************************************************* + * @fn SimpleBLEPeripheral_createTask + * + * @brief Task creation function for the Simple BLE Peripheral. + * + * @param none + * + * @return none + */ +void SimpleBLECentral_createTask(void) +{ + Task_Params taskParams; + + // Configure task + Task_Params_init(&taskParams); + taskParams.stack = sbcTaskStack; + taskParams.stackSize = SBC_TASK_STACK_SIZE; + taskParams.priority = SBC_TASK_PRIORITY; + + Task_construct(&sbcTask, SimpleBLECentral_taskFxn, &taskParams, NULL); +} + +/********************************************************************* + * @fn SimpleBLECentral_Init + * + * @brief Initialization function for the Simple BLE Central App Task. + * This is called during initialization and should contain + * any application specific initialization (ie. hardware + * initialization/setup, table initialization, power up + * notification). + * + * @param none + * + * @return none + */ +static void SimpleBLECentral_init(void) +{ + uint8_t i; + + // ****************************************************************** + // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp + // ****************************************************************** + // Register the current thread as an ICall dispatcher application + // so that the application can send and receive messages. + ICall_registerApp(&selfEntity, &sem); + + // Create an RTOS queue for message from profile to be sent to app. + appMsgQueue = Util_constructQueue(&appMsg); + + // Setup discovery delay as a one-shot timer + Util_constructClock(&startDiscClock, SimpleBLECentral_startDiscHandler, + DEFAULT_SVC_DISCOVERY_DELAY, 0, false, 0); + + // Set initial connection parameter values + GAP_SetParamValue(TGAP_CONN_EST_INT_MIN, INITIAL_MIN_CONN_INTERVAL); + GAP_SetParamValue(TGAP_CONN_EST_INT_MAX, INITIAL_MAX_CONN_INTERVAL); + GAP_SetParamValue(TGAP_CONN_EST_SUPERV_TIMEOUT, INITIAL_CONN_TIMEOUT); + GAP_SetParamValue(TGAP_CONN_EST_LATENCY, INITIAL_SLAVE_LATENCY); + + // Construct clock for connecting timeout + Util_constructClock(&connectingClock, SimpleBLECentral_timeoutConnecting, + DEFAULT_SCAN_DURATION, 0, false, 0); + + Board_initKeys(SimpleBLECentral_keyChangeHandler); + + //In the project predefines, UART is disabled by default. Thus LCD display will be used. + //Please see the project documentation for instructions on choosing LDC or UART display. + Display_Params dispParams; + dispParams.lineClearMode = DISPLAY_CLEAR_BOTH; + dispHandle = Display_open(Display_Type_LCD, &dispParams); + if (dispHandle == NULL) dispHandle = Display_open(Display_Type_UART, &dispParams); // Try UART if no LCD found + + // Initialize internal data + for (i = 0; i < MAX_NUM_BLE_CONNS; i++) + { + readRssi[i].connHandle = GAP_CONNHANDLE_ALL; + readRssi[i].pClock = NULL; + } + + // Setup Central Profile + { + uint8_t scanRes = DEFAULT_MAX_SCAN_RES; + + GAPCentralRole_SetParameter(GAPCENTRALROLE_MAX_SCAN_RES, sizeof(uint8_t), + &scanRes); + } + + // Setup GAP + GAP_SetParamValue(TGAP_GEN_DISC_SCAN, DEFAULT_SCAN_DURATION); + GAP_SetParamValue(TGAP_LIM_DISC_SCAN, DEFAULT_SCAN_DURATION); + GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, + (void *)attDeviceName); + + // Setup the GAP Bond Manager + { + uint32_t passkey = DEFAULT_PASSCODE; + uint8_t pairMode = DEFAULT_PAIRING_MODE; + uint8_t mitm = DEFAULT_MITM_MODE; + uint8_t ioCap = DEFAULT_IO_CAPABILITIES; + uint8_t bonding = DEFAULT_BONDING_MODE; + + + GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t), + &passkey); + GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode); + GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm); + GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap); + GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding); + } + + // Initialize GATT Client + VOID GATT_InitClient(); + + // Register to receive incoming ATT Indications/Notifications + GATT_RegisterForInd(selfEntity); + + // Initialize GATT attributes + GGS_AddService(GATT_ALL_SERVICES); // GAP + GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes + + // Start the Device + VOID GAPCentralRole_StartDevice(&SimpleBLECentral_roleCB); + + // Register with bond manager after starting device + GAPBondMgr_Register(&SimpleBLECentral_bondCB); + + // Register with GAP for HCI/Host messages (for RSSI) + GAP_RegisterForMsgs(selfEntity); + + // Register for GATT local events and ATT Responses pending for transmission + GATT_RegisterForMsgs(selfEntity); + + Display_print0(dispHandle, ROW_ZERO, 0, "BLE Central"); +} + +/********************************************************************* + * @fn SimpleBLECentral_taskFxn + * + * @brief Application task entry point for the Simple BLE Central. + * + * @param none + * + * @return events not processed + */ +static void SimpleBLECentral_taskFxn(UArg a0, UArg a1) +{ + // Initialize application + SimpleBLECentral_init(); + + // Application main loop + for (;;) + { + // Waits for a signal to the semaphore associated with the calling thread. + // Note that the semaphore associated with a thread is signaled when a + // message is queued to the message receive queue of the thread or when + // ICall_signal() function is called onto the semaphore. + ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER); + + if (errno == ICALL_ERRNO_SUCCESS) + { + ICall_EntityID dest; + ICall_ServiceEnum src; + ICall_HciExtEvt *pMsg = NULL; + + if (ICall_fetchServiceMsg(&src, &dest, + (void **)&pMsg) == ICALL_ERRNO_SUCCESS) + { + if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity)) + { + // Process inter-task message + SimpleBLECentral_processStackMsg((ICall_Hdr *)pMsg); + } + + if (pMsg) + { + ICall_freeMsg(pMsg); + } + } + } + + // If RTOS queue is not empty, process app message + while (!Queue_empty(appMsgQueue)) + { + sbcEvt_t *pMsg = (sbcEvt_t *)Util_dequeueMsg(appMsgQueue); + if (pMsg) + { + // Process message + SimpleBLECentral_processAppMsg(pMsg); + + // Free the space from the message + ICall_free(pMsg); + } + } + + if (events & SBC_START_DISCOVERY_EVT) + { + events &= ~SBC_START_DISCOVERY_EVT; + + SimpleBLECentral_startDiscovery(); + } + } +} + +/********************************************************************* + * @fn SimpleBLECentral_processStackMsg + * + * @brief Process an incoming task message. + * + * @param pMsg - message to process + * + * @return none + */ +static void SimpleBLECentral_processStackMsg(ICall_Hdr *pMsg) +{ + switch (pMsg->event) + { + case GAP_MSG_EVENT: + SimpleBLECentral_processRoleEvent((gapCentralRoleEvent_t *)pMsg); + break; + + case GATT_MSG_EVENT: + SimpleBLECentral_processGATTMsg((gattMsgEvent_t *)pMsg); + break; + + case HCI_GAP_EVENT_EVENT: + { + // Process HCI message + switch(pMsg->status) + { + case HCI_COMMAND_COMPLETE_EVENT_CODE: + SimpleBLECentral_processCmdCompleteEvt((hciEvt_CmdComplete_t *)pMsg); + break; + + default: + break; + } + } + break; + + default: + break; + } +} + +/********************************************************************* + * @fn SimpleBLECentral_processAppMsg + * + * @brief Central application event processing function. + * + * @param pMsg - pointer to event structure + * + * @return none + */ +static void SimpleBLECentral_processAppMsg(sbcEvt_t *pMsg) +{ + switch (pMsg->hdr.event) + { + case SBC_STATE_CHANGE_EVT: + SimpleBLECentral_processStackMsg((ICall_Hdr *)pMsg->pData); + + // Free the stack message + ICall_freeMsg(pMsg->pData); + break; + + case SBC_KEY_CHANGE_EVT: + SimpleBLECentral_handleKeys(0, pMsg->hdr.state); + break; + + case SBC_RSSI_READ_EVT: + { + readRssi_t *pRssi = (readRssi_t *)pMsg->pData; + + // If link is up and RSSI reads active + if (pRssi->connHandle != GAP_CONNHANDLE_ALL && + linkDB_Up(pRssi->connHandle)) + { + // Restart timer + Util_restartClock(pRssi->pClock, pRssi->period); + + // Read RSSI + VOID HCI_ReadRssiCmd(pRssi->connHandle); + } + } + break; + + // Pairing event + case SBC_PAIRING_STATE_EVT: + { + SimpleBLECentral_processPairState(pMsg->hdr.state, *pMsg->pData); + + ICall_free(pMsg->pData); + break; + } + + // Passcode event + case SBC_PASSCODE_NEEDED_EVT: + { + SimpleBLECentral_processPasscode(connHandle, *pMsg->pData); + + ICall_free(pMsg->pData); + break; + } + + // Connecting to device timed out + case SBC_CONNECTING_TIMEOUT_EVT: + { + GAPCentralRole_TerminateLink(connHandle); + } + + default: + // Do nothing. + break; + } +} + +/********************************************************************* + * @fn SimpleBLECentral_processRoleEvent + * + * @brief Central role event processing function. + * + * @param pEvent - pointer to event structure + * + * @return none + */ +static void SimpleBLECentral_processRoleEvent(gapCentralRoleEvent_t *pEvent) +{ + switch (pEvent->gap.opcode) + { + case GAP_DEVICE_INIT_DONE_EVENT: + { + maxPduSize = pEvent->initDone.dataPktLen; + Display_print0(dispHandle, ROW_ZERO, 0, "BLE Central"); + Display_print0(dispHandle, ROW_ONE, 0, Util_convertBdAddr2Str(pEvent->initDone.devAddr)); + Display_print0(dispHandle, ROW_TWO, 0, "Initialized"); + Display_print0(dispHandle, ROW_SEVEN, 0, ">RIGHT to scan"); + } + break; + + case GAP_DEVICE_INFO_EVENT: + { + //Find peer device address by UUID + if ( (DEFAULT_DEV_DISC_BY_SVC_UUID == FALSE) || + SimpleBLECentral_findSvcUuid(SIMPLEPROFILE_SERV_UUID, + pEvent->deviceInfo.pEvtData, + pEvent->deviceInfo.dataLen)) + { + SimpleBLECentral_addDeviceInfo(pEvent->deviceInfo.addr, + pEvent->deviceInfo.addrType); + } + + // Check if the discovered device is already in scan results + uint8_t i; + for (i = 0; i < scanRes; i++) + { + if (memcmp(pEvent->deviceInfo.addr, devList[i].addr , B_ADDR_LEN) == 0) + { + //Check if pEventData contains a device name + if (SimpleBLECentral_findLocalName(pEvent->deviceInfo.pEvtData, + pEvent->deviceInfo.dataLen)) + { + //Update deviceInfo entry with the name + SimpleBLECentral_addDeviceName(i, pEvent->deviceInfo.pEvtData, + pEvent->deviceInfo.dataLen); + } + } + } + } + break; + + case GAP_DEVICE_DISCOVERY_EVENT: + { + // discovery complete + scanningStarted = FALSE; + // initialize scan index to first + scanIdx = 0; + Display_clearLines(dispHandle, ROW_ONE, ROW_SEVEN); + Display_print1(dispHandle, ROW_ONE, 0, "Devices found %d", scanRes); + state = BLE_STATE_DISCOVERED; + + if (scanRes > 0) + { + Display_print0(dispHandle, ROW_SIX, 0, "RIGHT to scan"); + } + break; + + case GAP_LINK_ESTABLISHED_EVENT: + { + if (pEvent->gap.hdr.status == SUCCESS) + { + //Connect to selected device + state = BLE_STATE_CONNECTED; + connHandle = pEvent->linkCmpl.connectionHandle; + procedureInProgress = TRUE; + + // If service discovery not performed initiate service discovery + if (charHdl == 0) + { + Util_startClock(&startDiscClock); + } + + //Find device name in devList struct + uint8_t i; + for (i = 0; i < scanRes; i++) + { + if (memcmp(pEvent->linkCmpl.devAddr, devList[i].addr, B_ADDR_LEN) == NULL) + { + break; + } + } + Display_clearLines(dispHandle, ROW_ONE, ROW_SEVEN); + Display_print1(dispHandle, ROW_ONE, 0, "%s", devList[i].localName); + Display_print1(dispHandle, ROW_TWO, 0, "%s", Util_convertBdAddr2Str(pEvent->linkCmpl.devAddr)); + Display_print0(dispHandle, ROW_THREE, 0, "Connected"); + selectedMenuItem = MENU_ITEM_CONN_PARAM_UPDATE; + Display_print0(dispHandle, ROW_SEVEN, 0, ">Param upd req"); + } + else + { + state = BLE_STATE_IDLE; + connHandle = GAP_CONNHANDLE_INIT; + discState = BLE_DISC_STATE_IDLE; + + Display_clearLine(dispHandle, ROW_FOUR); + Display_print0(dispHandle, ROW_TWO, 0, "Connect Failed"); + Display_print1(dispHandle, ROW_THREE, 0, "Reason: %d", pEvent->gap.hdr.status); + Display_print0(dispHandle, ROW_SEVEN, 0, ">RIGHT to scan"); + } + } + break; + + case GAP_LINK_TERMINATED_EVENT: + { + state = BLE_STATE_IDLE; + connHandle = GAP_CONNHANDLE_INIT; + discState = BLE_DISC_STATE_IDLE; + charHdl = 0; + procedureInProgress = FALSE; + + // Cancel RSSI reads + SimpleBLECentral_CancelRssi(pEvent->linkTerminate.connectionHandle); + + //Clear screen and display disconnect reason + Display_clearLines(dispHandle, ROW_ONE, ROW_SEVEN); + Display_print0(dispHandle, ROW_ONE, 0, "Disconnected"); + Display_print1(dispHandle, ROW_TWO, 0, "Reason: %d", pEvent->linkTerminate.reason); + Display_print0(dispHandle, ROW_SEVEN, 0, ">RIGHT to scan"); + selectedMenuItem = MENU_ITEM_CONN_PARAM_UPDATE; + } + break; + + case GAP_LINK_PARAM_UPDATE_EVENT: + { + if (state == BLE_STATE_CONNECTED) + { + if (pEvent->linkUpdate.status == SUCCESS) + { + Display_print1(dispHandle, ROW_FOUR, 0, "ParUpd: %d ms", pEvent->linkUpdate.connInterval * 1.25); + } + else + { + Display_print1(dispHandle, ROW_FOUR, 0, "Param error: %d", pEvent->linkUpdate.status); + } + } + } + break; + + default: + break; + } +} + +/********************************************************************* + * @fn SimpleBLECentral_handleKeys + * + * @brief Handles all key events for this device. + * + * @param shift - true if in shift/alt. + * @param keys - bit field for key events. Valid entries: + * HAL_KEY_SW_2 + * HAL_KEY_SW_1 + * + * @return none + */ +static void SimpleBLECentral_handleKeys(uint8_t shift, uint8_t keys) +{ + switch (state) + { + case BLE_STATE_IDLE: + if (keys & KEY_RIGHT) + { + // Discover devices + SimpleBLECentral_discoverDevices(); + } + //If LEFT is pressed, nothing happens. + break; + + case BLE_STATE_DISCOVERED: + if (keys & KEY_LEFT) + { + //Display Discovery Results + if (!scanningStarted && scanRes > 0) + { + if (scanIdx >= scanRes) + { + Display_clearLines(dispHandle, ROW_TWO, ROW_SEVEN); + Display_print0(dispHandle, ROW_SIX, 0, "RIGHT to scan"); + + state = BLE_STATE_BROWSING; + scanIdx = 0; + } + else + { + Display_print1(dispHandle, ROW_ONE, 0, "Device %d", (scanIdx + 1)); + Display_print0(dispHandle, ROW_TWO, 0, Util_convertBdAddr2Str(devList[scanIdx].addr)); + Display_print1(dispHandle, ROW_THREE, 0, "%s", devList[scanIdx].localName); + Display_print0(dispHandle, ROW_SEVEN, 0, ">RIGHT to connect"); + + state = BLE_STATE_BROWSING; + scanIdx++; + } + } + return; + } + else if (keys & KEY_RIGHT) + { + //Start scanning + SimpleBLECentral_discoverDevices(); + } + break; + + case BLE_STATE_BROWSING: + if (keys & KEY_LEFT) + { + //Navigate through discovery results + if (!scanningStarted && scanRes > 0) + { + if (scanIdx >= scanRes) + { + //Display the scan option + Display_clearLines(dispHandle, ROW_ONE, ROW_SEVEN); + Display_print1(dispHandle, ROW_ONE, 0, "Devices found %d", scanRes); + Display_print0(dispHandle, ROW_SIX, 0, "RIGHT to scan"); + + state = BLE_STATE_BROWSING; + scanIdx = 0; + } + else + { + //Display next device + Display_print1(dispHandle, ROW_ONE, 0, "Device %d", (scanIdx + 1)); + Display_print0(dispHandle, ROW_TWO, 0, Util_convertBdAddr2Str(devList[scanIdx].addr)); + Display_print1(dispHandle, ROW_THREE, 0, "%s", devList[scanIdx].localName); + Display_print0(dispHandle, ROW_SEVEN, 0, ">RIGHT to connect"); + + state = BLE_STATE_BROWSING; + scanIdx++; + } + } + } + else if (keys & KEY_RIGHT) + { + //Scan for devices if the scan option is displayed + if (scanIdx == 0){ + SimpleBLECentral_discoverDevices(); + } + + //Connect to displayed device + else + { + uint8_t addrType; + uint8_t *peerAddr; + if (scanRes > 0 && state == BLE_STATE_BROWSING) + { + // connect to current device in scan result + peerAddr = devList[scanIdx-1].addr; + addrType = devList[scanIdx-1].addrType; + + state = BLE_STATE_CONNECTING; + + Util_startClock(&connectingClock); + + GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE, + DEFAULT_LINK_WHITE_LIST, + addrType, peerAddr); + + Display_clearLines(dispHandle, ROW_FOUR, ROW_SEVEN); + Display_print0(dispHandle, ROW_TWO, 0, Util_convertBdAddr2Str(peerAddr)); + Display_print0(dispHandle, ROW_FOUR, 0, "Connecting"); + } + } + } + break; + + case BLE_STATE_CONNECTING: + //Nothing happens if buttons are pressed while the device is connecting. + break; + + case BLE_STATE_CONNECTED: + if (keys & KEY_LEFT) //Navigate though menu. + { + //Iterate through rows + switch (selectedMenuItem) + { + case MENU_ITEM_CONN_PARAM_UPDATE: + selectedMenuItem = MENU_ITEM_RSSI; + if (SimpleBLECentral_RssiFind(connHandle) == NULL) + { + Display_print0(dispHandle, ROW_SEVEN, 0, ">Start RSSI poll"); + } + else + { + Display_print0(dispHandle, ROW_SEVEN, 0, ">Stop RSSI poll"); + } + break; + + case MENU_ITEM_RSSI: + selectedMenuItem = MENU_ITEM_READ_WRITE; + Display_print0(dispHandle, ROW_SEVEN, 0, ">Read/write req"); + break; + + case MENU_ITEM_READ_WRITE: + selectedMenuItem = MENU_ITEM_DISCONNECT; + Display_print0(dispHandle, ROW_SEVEN, 0, ">Disconnect"); + break; + + case MENU_ITEM_DISCONNECT: + selectedMenuItem = MENU_ITEM_CONN_PARAM_UPDATE; + Display_print0(dispHandle, ROW_SEVEN, 0, ">Param upd req"); + break; + } + } + if (keys & KEY_RIGHT) + { + switch (selectedMenuItem) + { + case MENU_ITEM_CONN_PARAM_UPDATE: + //Connection Parameter Update + Display_print0(dispHandle, ROW_FOUR, 0, "Param upd req"); + switch (currentConnectionParameter) + { + case INITIAL_PARAMETERS: + GAPCentralRole_UpdateLink(connHandle, + DEFAULT_UPDATE_MIN_CONN_INTERVAL, + DEFAULT_UPDATE_MAX_CONN_INTERVAL, + DEFAULT_UPDATE_SLAVE_LATENCY, + DEFAULT_UPDATE_CONN_TIMEOUT); + currentConnectionParameter = DEFAULT_UPDATE_PARAMETERS; + break; + case DEFAULT_UPDATE_PARAMETERS: + GAPCentralRole_UpdateLink(connHandle, + INITIAL_MIN_CONN_INTERVAL, + INITIAL_MAX_CONN_INTERVAL, + INITIAL_SLAVE_LATENCY, + INITIAL_CONN_TIMEOUT); + currentConnectionParameter = INITIAL_PARAMETERS; + break; + } + break; + + case MENU_ITEM_RSSI: + // Start or cancel RSSI polling + if (SimpleBLECentral_RssiFind(connHandle) == NULL) + { + Display_clearLine(dispHandle, ROW_FIVE); + SimpleBLECentral_StartRssi(connHandle, DEFAULT_RSSI_PERIOD); + Display_print0(dispHandle, ROW_SEVEN, 0, ">Stop RSSI poll"); + } + else + { + SimpleBLECentral_CancelRssi(connHandle); + Display_print0(dispHandle, ROW_FIVE, 0, "RSSI Cancelled"); + if (selectedMenuItem == MENU_ITEM_RSSI) + { + Display_print0(dispHandle, ROW_SEVEN, 0, ">Start RSSI poll"); + } + } + break; + + case MENU_ITEM_READ_WRITE: + if (state == BLE_STATE_CONNECTED && + charHdl != 0 && + procedureInProgress == FALSE) + { + uint8_t status; + // Do a read or write as long as no other read or write is in progress + if (doWrite) + { + // Do a write + attWriteReq_t req; + req.pValue = GATT_bm_alloc(connHandle, ATT_WRITE_REQ, 1, NULL); + if ( req.pValue != NULL ) + { + Display_print0(dispHandle, ROW_SIX, 0, "Write req sent"); + req.handle = charHdl; + req.len = 1; + req.pValue[0] = charVal; + req.sig = 0; + req.cmd = 0; + status = GATT_WriteCharValue(connHandle, &req, selfEntity); + if ( status != SUCCESS ) + { + GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ); + } + } + else + { + status = bleMemAllocError; + } + } + else + { + // Do a read + attReadReq_t req; + req.handle = charHdl; + status = GATT_ReadCharValue(connHandle, &req, selfEntity); + Display_print0(dispHandle, ROW_SIX, 0, "Read req sent"); + } + + if (status == SUCCESS) + { + procedureInProgress = TRUE; + doWrite = !doWrite; + } + } + break; + + case MENU_ITEM_DISCONNECT: + GAPCentralRole_TerminateLink(connHandle); + state = BLE_STATE_DISCONNECTING; + Display_clearLines(dispHandle, ROW_ONE, ROW_SEVEN); + Display_print0(dispHandle, ROW_ONE, 0, "Disconnecting"); + break; + } + } + } + return; +} + +/********************************************************************* + * @fn SimpleBLECentral_processGATTMsg + * + * @brief Process GATT messages and events. + * + * @return none + */ +static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg) +{ + if (state == BLE_STATE_CONNECTED) + { + // See if GATT server was unable to transmit an ATT response + if (pMsg->hdr.status == blePending) + { + // No HCI buffer was available. App can try to retransmit the response + // on the next connection event. Drop it for now. + Display_print1(dispHandle, ROW_SIX, 0, "ATT Rsp drped %d", pMsg->method); + } + else if ((pMsg->method == ATT_READ_RSP) || + ((pMsg->method == ATT_ERROR_RSP) && + (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ))) + { + if (pMsg->method == ATT_ERROR_RSP) + { + Display_print1(dispHandle, ROW_SIX, 0, "Read Error %d", pMsg->msg.errorRsp.errCode); + } + else + { + // After a successful read, display the read value + Display_print1(dispHandle, ROW_SIX, 0, "Read rsp: %d", pMsg->msg.readRsp.pValue[0]); + } + + procedureInProgress = FALSE; + } + else if ((pMsg->method == ATT_WRITE_RSP) || + ((pMsg->method == ATT_ERROR_RSP) && + (pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ))) + { + if (pMsg->method == ATT_ERROR_RSP) + { + Display_print1(dispHandle, ROW_SIX, 0, "Write Error %d", pMsg->msg.errorRsp.errCode); + } + else + { + // After a successful write, display the value that was written and + // increment value + Display_print1(dispHandle, ROW_SIX, 0, "Write sent: %d", charVal++); + } + + procedureInProgress = FALSE; + } + else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT) + { + // ATT request-response or indication-confirmation flow control is + // violated. All subsequent ATT requests or indications will be dropped. + // The app is informed in case it wants to drop the connection. + + // Display the opcode of the message that caused the violation. + Display_print1(dispHandle, ROW_THREE, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode); + } + else if (pMsg->method == ATT_MTU_UPDATED_EVENT) + { + // MTU size updated + Display_print1(dispHandle, ROW_THREE, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU); + } + else if (discState != BLE_DISC_STATE_IDLE) + { + SimpleBLECentral_processGATTDiscEvent(pMsg); + } + } // else - in case a GATT message came after a connection has dropped, ignore it. + + // Needed only for ATT Protocol messages + GATT_bm_free(&pMsg->msg, pMsg->method); +} + +/********************************************************************* + * @fn SimpleBLECentral_processCmdCompleteEvt + * + * @brief Process an incoming OSAL HCI Command Complete Event. + * + * @param pMsg - message to process + * + * @return none + */ +static void SimpleBLECentral_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg) +{ + switch (pMsg->cmdOpcode) + { + case HCI_READ_RSSI: + { + if (state == BLE_STATE_CONNECTED) + { + int8 rssi = (int8)pMsg->pReturnParam[3]; + Display_print1(dispHandle, ROW_FIVE, 0, "RSSI -dB: %d", (uint32_t)(-rssi)); + } + } + break; + + default: + break; + } +} + +/********************************************************************* + * @fn SimpleBLECentral_StartRssi + * + * @brief Start periodic RSSI reads on a link. + * + * @param connHandle - connection handle of link + * @param period - RSSI read period in ms + * + * @return SUCCESS: Terminate started + * bleIncorrectMode: No link + * bleNoResources: No resources + */ +static bStatus_t SimpleBLECentral_StartRssi(uint16_t connHandle, uint16_t period) +{ + readRssi_t *pRssi; + + // Verify link is up + if (!linkDB_Up(connHandle)) + { + return bleIncorrectMode; + } + + // If already allocated + if ((pRssi = SimpleBLECentral_RssiFind(connHandle)) != NULL) + { + // Stop timer + Util_stopClock(pRssi->pClock); + pRssi->period = period; + } + + // Allocate structure + else if ((pRssi = SimpleBLECentral_RssiAlloc(connHandle)) != NULL) + { + pRssi->period = period; + } + // Allocate failed + else + { + return bleNoResources; + } + // Start timer + Util_restartClock(pRssi->pClock, period); + return SUCCESS; +} + +/********************************************************************* + * @fn SimpleBLECentral_CancelRssi + * + * @brief Cancel periodic RSSI reads on a link. + * + * @param connHandle - connection handle of link + * + * @return SUCCESS: Operation successful + * bleIncorrectMode: No link + */ +static bStatus_t SimpleBLECentral_CancelRssi(uint16_t connHandle) +{ + readRssi_t *pRssi; + if ((pRssi = SimpleBLECentral_RssiFind(connHandle)) != NULL) + { + // Stop timer + Util_stopClock(pRssi->pClock); + + // Free RSSI structure + SimpleBLECentral_RssiFree(connHandle); + return SUCCESS; + } + // Not found + return bleIncorrectMode; +} + +/********************************************************************* + * @fn gapCentralRole_RssiAlloc + * + * @brief Allocate an RSSI structure. + * + * @param connHandle - Connection handle + * + * @return pointer to structure or NULL if allocation failed. + */ +static readRssi_t *SimpleBLECentral_RssiAlloc(uint16_t connHandle) +{ + uint8_t i; + + // Find free RSSI structure + for (i = 0; i < MAX_NUM_BLE_CONNS; i++) + { + if (readRssi[i].connHandle == GAP_CONNHANDLE_ALL) + { + readRssi_t *pRssi = &readRssi[i]; + pRssi->pClock = (Clock_Struct *)ICall_malloc(sizeof(Clock_Struct)); + if (pRssi->pClock) + { + Util_constructClock(pRssi->pClock, SimpleBLECentral_readRssiHandler, + 0, 0, false, i); + pRssi->connHandle = connHandle; + return pRssi; + } + } + } + // No free structure found + return NULL; +} + +/********************************************************************* + * @fn gapCentralRole_RssiFind + * + * @brief Find an RSSI structure. + * + * @param connHandle - Connection handle + * + * @return pointer to structure or NULL if not found. + */ +static readRssi_t *SimpleBLECentral_RssiFind(uint16_t connHandle) +{ + uint8_t i; + // Find free RSSI structure + for (i = 0; i < MAX_NUM_BLE_CONNS; i++) + { + if (readRssi[i].connHandle == connHandle) + { + return &readRssi[i]; + } + } + // Not found + return NULL; +} + +/********************************************************************* + * @fn gapCentralRole_RssiFree + * + * @brief Free an RSSI structure. + * + * @param connHandle - Connection handle + * + * @return none + */ +static void SimpleBLECentral_RssiFree(uint16_t connHandle) +{ + uint8_t i; + + // Find RSSI structure + for (i = 0; i < MAX_NUM_BLE_CONNS; i++) + { + if (readRssi[i].connHandle == connHandle) + { + readRssi_t *pRssi = &readRssi[i]; + if (pRssi->pClock) + { + Clock_destruct(pRssi->pClock); + + // Free clock struct + ICall_free(pRssi->pClock); + pRssi->pClock = NULL; + } + pRssi->connHandle = GAP_CONNHANDLE_ALL; + break; + } + } +} + +/********************************************************************* + * @fn SimpleBLECentral_processPairState + * + * @brief Process the new paring state. + * + * @return none + */ +static void SimpleBLECentral_processPairState(uint8_t pairState, uint8_t status) +{ + if (pairState == GAPBOND_PAIRING_STATE_STARTED) + { + Display_print0(dispHandle, ROW_SIX, 0, "Pairing started"); + } + else if (pairState == GAPBOND_PAIRING_STATE_COMPLETE) + { + if (status == SUCCESS) + { + Display_print0(dispHandle, ROW_SIX, 0, "Pairing success"); + } + else + { + Display_print1(dispHandle, ROW_SIX, 0, "Pairing fail: %d", status); + } + } + else if (pairState == GAPBOND_PAIRING_STATE_BONDED) + { + if (status == SUCCESS) + { + Display_print0(dispHandle, ROW_SIX, 0, "Bonding success"); + } + } + else if (pairState == GAPBOND_PAIRING_STATE_BOND_SAVED) + { + if (status == SUCCESS) + { + Display_print0(dispHandle, ROW_SIX, 0, "Bond save succ"); + } + else + { + Display_print1(dispHandle, ROW_SIX, 0, "Bnd save fail: %d", status); + } + } +} + +/********************************************************************* + * @fn SimpleBLECentral_processPasscode + * + * @brief Process the Passcode request. + * + * @return none + */ +static void SimpleBLECentral_processPasscode(uint16_t connectionHandle, + uint8_t uiOutputs) +{ + uint32_t passcode; + + // Create random passcode + passcode = Util_GetTRNG(); + passcode %= 1000000; + + // Display passcode to user + if (uiOutputs != 0) + { + Display_print0(dispHandle, ROW_FOUR, 0, "Passcode:"); + Display_print1(dispHandle, ROW_FIVE, 0, "%d", passcode); + } + // Send passcode response + GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode); +} + +/********************************************************************* + * @fn SimpleBLECentral_startDiscovery + * + * @brief Start service discovery. + * + * @return none + */ +static void SimpleBLECentral_startDiscovery(void) +{ + attExchangeMTUReq_t req; + + // Initialize cached handles + svcStartHdl = svcEndHdl = charHdl = 0; + + discState = BLE_DISC_STATE_MTU; + + // Discover GATT Server's Rx MTU size + req.clientRxMTU = maxPduSize - L2CAP_HDR_SIZE; + + // ATT MTU size should be set to the minimum of the Client Rx MTU + // and Server Rx MTU values + VOID GATT_ExchangeMTU(connHandle, &req, selfEntity); +} + +/********************************************************************* + * @fn SimpleBLECentral_processGATTDiscEvent + * + * @brief Process GATT discovery event + * + * @return none + */ +static void SimpleBLECentral_processGATTDiscEvent(gattMsgEvent_t *pMsg) +{ + if (discState == BLE_DISC_STATE_MTU) + { + // MTU size response received, discover simple BLE service + if (pMsg->method == ATT_EXCHANGE_MTU_RSP) + { + uint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(SIMPLEPROFILE_SERV_UUID), + HI_UINT16(SIMPLEPROFILE_SERV_UUID) }; + + // Just in case we're using the default MTU size (23 octets) + Display_print1(dispHandle, ROW_THREE, 0, "MTU Size: %d", ATT_MTU_SIZE); + discState = BLE_DISC_STATE_SVC; + + // Discovery simple BLE service + VOID GATT_DiscPrimaryServiceByUUID(connHandle, uuid, ATT_BT_UUID_SIZE, + selfEntity); + } + } + else if (discState == BLE_DISC_STATE_SVC) + { + // Service found, store handles + if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP && + pMsg->msg.findByTypeValueRsp.numInfo > 0) + { + svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); + svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); + } + + // If procedure complete + if (((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP) && + (pMsg->hdr.status == bleProcedureComplete)) || + (pMsg->method == ATT_ERROR_RSP)) + { + if (svcStartHdl != 0) + { + attReadByTypeReq_t req; + + // Discover characteristic + discState = BLE_DISC_STATE_CHAR; + + req.startHandle = svcStartHdl; + req.endHandle = svcEndHdl; + req.type.len = ATT_BT_UUID_SIZE; + req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID); + req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID); + + VOID GATT_ReadUsingCharUUID(connHandle, &req, selfEntity); + } + } + } + else if (discState == BLE_DISC_STATE_CHAR) + { + // Characteristic found, store handle + if ((pMsg->method == ATT_READ_BY_TYPE_RSP) && + (pMsg->msg.readByTypeRsp.numPairs > 0)) + { + charHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0], + pMsg->msg.readByTypeRsp.pDataList[1]); + Display_print0(dispHandle, ROW_THREE, 0, "Simple Svc Found"); + procedureInProgress = FALSE; + } + discState = BLE_DISC_STATE_IDLE; + } +} + +/********************************************************************* + * @fn SimpleBLECentral_findSvcUuid + * + * @brief Find a given UUID in an advertiser's service UUID list. + * + * @return TRUE if service UUID found + */ +static bool SimpleBLECentral_findSvcUuid(uint16_t uuid, uint8_t *pData, + uint8_t dataLen) +{ + uint8_t adLen; + uint8_t adType; + uint8_t *pEnd; + + pEnd = pData + dataLen - 1; + + // While end of data not reached + while (pData < pEnd) + { + // Get length of next AD item + adLen = *pData++; + if (adLen > 0) + { + adType = *pData; + + // If AD type is for 16-bit service UUID + if ((adType == GAP_ADTYPE_16BIT_MORE) || + (adType == GAP_ADTYPE_16BIT_COMPLETE)) + { + pData++; + adLen--; + + // For each UUID in list + while (adLen >= 2 && pData < pEnd) + { + // Check for match + if ((pData[0] == LO_UINT16(uuid)) && + (pData[1] == HI_UINT16(uuid))) + { + // Match found + return TRUE; + } + + // Go to next AD item + pData += 2; + adLen -= 2; + } + + // Handle possible erroneous extra byte in UUID list + if (adLen == 1) + { + pData++; + } + + } + else + { + // Go to next AD item + pData += adLen; + } + } + } + // Match not found + return FALSE; +} + +/********************************************************************* + * @fn SimpleBLECentral_discoverDevices + * + * @brief Scan to discover devices. + * + * @return none + */ +static void SimpleBLECentral_discoverDevices(void){ + if (!scanningStarted) + { + scanningStarted = TRUE; + + //Clear old scan results + scanRes = 0; + memset(devList, NULL, sizeof(devList[0])*DEFAULT_MAX_SCAN_RES); + + Display_clearLines(dispHandle, ROW_ONE, ROW_SEVEN); + Display_print0(dispHandle, ROW_ONE, 0, "Discovering..."); + GAPCentralRole_StartDiscovery(DEFAULT_DISCOVERY_MODE, + DEFAULT_DISCOVERY_ACTIVE_SCAN, + DEFAULT_DISCOVERY_WHITE_LIST); + } + else + { + GAPCentralRole_CancelDiscovery(); + } +} + +/********************************************************************** + * @fn SimpleBLECentral_timeoutConnecting + * + * @brief Post event if connecting is timed out. + * + * @return none + */ +Void SimpleBLECentral_timeoutConnecting(UArg arg0) +{ + if (state == BLE_STATE_CONNECTING) + { + SimpleBLECentral_enqueueMsg(SBC_CONNECTING_TIMEOUT_EVT, 0, NULL); + } +} + +/********************************************************************* + * @fn SimpleBLECentral_addDeviceInfo + * + * @brief Add a device to the device discovery result list + * + * @return none + */ +static void SimpleBLECentral_addDeviceInfo(uint8_t *pAddr, uint8_t addrType) +{ + uint8_t i; + + // If result count not at max + if (scanRes < DEFAULT_MAX_SCAN_RES) + { + // Check if device is already in scan results + for (i = 0; i < scanRes; i++) + { + if (memcmp(pAddr, devList[i].addr , B_ADDR_LEN) == 0) + { + return; + } + } + + // Add addr to scan result list + memcpy(devList[scanRes].addr, pAddr, B_ADDR_LEN); + devList[scanRes].addrType = addrType; + + // Increment scan result count + scanRes++; + } +} + +/********************************************************************* + * @fn SimpleBLECentral_findLocalName + * + * @brief Check if pEvtData contains a device local name + * + * @return TRUE if local name found + */ +static bool SimpleBLECentral_findLocalName(uint8_t *pEvtData, uint8_t dataLen) +{ + uint8_t adLen; + uint8_t adType; + uint8_t *pEnd; + + pEnd = pEvtData + dataLen - 1; + + // While end of data not reached + while (pEvtData < pEnd) + { + // Get length of next data item + adLen = *pEvtData++; + if (adLen > 0) + { + adType = *pEvtData; + + // If AD type is for local name + if ((adType == GAP_ADTYPE_LOCAL_NAME_SHORT) || + (adType == GAP_ADTYPE_LOCAL_NAME_COMPLETE)) + { + pEvtData++; + adLen--; + // For each local name in list + if (adLen >= 2 && pEvtData < pEnd) + { + return TRUE; + } + + // Handle possible erroneous extra byte in advertisement data + if (adLen == 1) + { + pEvtData++; + } + } + else + { + // Go to next item + pEvtData += adLen; + } + } + } + // No name found + return FALSE; +} + +/********************************************************************* + * @fn SimpleBLECentral_addDeviceName + * + * @brief Add a name to an existing device in the scan result list + * + * @return none + */ +static void SimpleBLECentral_addDeviceName(uint8_t i, uint8_t *pEvtData, uint8_t dataLen) +{ + uint8_t scanRspLen; + uint8_t scanRspType; + uint8_t *pEnd; + + pEnd = pEvtData + dataLen - 1; + + // While end of data not reached + while (pEvtData < pEnd) + { + // Get length of next scan response item + scanRspLen = *pEvtData++; + if (scanRspLen > 0) + { + scanRspType = *pEvtData; + + // If scan response type is for local name + if ((scanRspType == GAP_ADTYPE_LOCAL_NAME_SHORT) || + (scanRspType == GAP_ADTYPE_LOCAL_NAME_COMPLETE)) + { + //Set name length in the device struct. + devList[i].nameLength = scanRspLen - 1; + pEvtData++; + uint8_t j = 0; + + //Copy device name from the scan response data + while ((pEvtData < pEnd) && + (j < scanRspLen - 1)) + { + devList[i].localName[j] = *pEvtData; + pEvtData++; + j++; + } + } + } + else + { + // Go to next scan response item + pEvtData += scanRspLen; + } + } +} + + +/********************************************************************* + * @fn SimpleBLECentral_eventCB + * + * @brief Central event callback function. + * + * @param pEvent - pointer to event structure + * + * @return TRUE if safe to deallocate event message, FALSE otherwise. + */ +static uint8_t SimpleBLECentral_eventCB(gapCentralRoleEvent_t *pEvent) +{ + // Forward the role event to the application + if (SimpleBLECentral_enqueueMsg(SBC_STATE_CHANGE_EVT, + SUCCESS, (uint8_t *)pEvent)) + { + // App will process and free the event + return FALSE; + } + + // Caller should free the event + return TRUE; +} + +/********************************************************************* + * @fn SimpleBLECentral_pairStateCB + * + * @brief Pairing state callback. + * + * @return none + */ +static void SimpleBLECentral_pairStateCB(uint16_t connHandle, uint8_t pairState, + uint8_t status) +{ + uint8_t *pData; + + // Allocate space for the event data. + if ((pData = ICall_malloc(sizeof(uint8_t)))) + { + *pData = status; + + // Queue the event. + SimpleBLECentral_enqueueMsg(SBC_PAIRING_STATE_EVT, pairState, pData); + } +} + +/********************************************************************* + * @fn SimpleBLECentral_passcodeCB + * + * @brief Passcode callback. + * + * @return none + */ +static void SimpleBLECentral_passcodeCB(uint8_t *deviceAddr, uint16_t connHandle, + uint8_t uiInputs, uint8_t uiOutputs) +{ + uint8_t *pData; + + // Allocate space for the passcode event. + if ((pData = ICall_malloc(sizeof(uint8_t)))) + { + *pData = uiOutputs; + + // Enqueue the event. + SimpleBLECentral_enqueueMsg(SBC_PASSCODE_NEEDED_EVT, 0, pData); + } +} + +/********************************************************************* + * @fn SimpleBLECentral_startDiscHandler + * + * @brief Clock handler function + * + * @param a0 - ignored + * + * @return none + */ +void SimpleBLECentral_startDiscHandler(UArg a0) +{ + events |= SBC_START_DISCOVERY_EVT; + + // Wake up the application thread when it waits for clock event + Semaphore_post(sem); +} + +/********************************************************************* + * @fn SimpleBLECentral_keyChangeHandler + * + * @brief Key event handler function + * + * @param a0 - ignored + * + * @return none + */ +void SimpleBLECentral_keyChangeHandler(uint8_t keys) +{ + SimpleBLECentral_enqueueMsg(SBC_KEY_CHANGE_EVT, keys, NULL); +} + +/********************************************************************* + * @fn SimpleBLECentral_readRssiHandler + * + * @brief Read RSSI handler function + * + * @param a0 - read RSSI index + * + * @return none + */ +void SimpleBLECentral_readRssiHandler(UArg a0) +{ + SimpleBLECentral_enqueueMsg(SBC_RSSI_READ_EVT, SUCCESS, + (uint8_t *)&readRssi[a0]); +} + +/********************************************************************* + * @fn SimpleBLECentral_enqueueMsg + * + * @brief Creates a message and puts the message in RTOS queue. + * + * @param event - message event. + * @param state - message state. + * @param pData - message data pointer. + * + * @return TRUE or FALSE + */ +static uint8_t SimpleBLECentral_enqueueMsg(uint8_t event, uint8_t status, + uint8_t *pData) +{ + sbcEvt_t *pMsg = ICall_malloc(sizeof(sbcEvt_t)); + + // Create dynamic pointer to message. + if (pMsg) + { + pMsg->hdr.event = event; + pMsg->hdr.state = status; + pMsg->pData = pData; + + // Enqueue the message. + return Util_enqueueMsg(appMsgQueue, sem, (uint8_t *)pMsg); + } + return FALSE; +} diff --git a/src/examples/simple_central_audio_receiver/cc26xx/app/simple_central_audio_receiver.c b/src/examples/simple_central_audio_receiver/cc26xx/app/simple_central_audio_receiver.c index 8f731b7..88db65f 100644 --- a/src/examples/simple_central_audio_receiver/cc26xx/app/simple_central_audio_receiver.c +++ b/src/examples/simple_central_audio_receiver/cc26xx/app/simple_central_audio_receiver.c @@ -5,7 +5,7 @@ * data over BLE at a high throughput. * * - * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,7 @@ */ #include +#include #include #include #include @@ -75,14 +76,20 @@ #include "ble_user_config.h" -#ifdef AUDIO_SERVICE #include "audio_profile.h" -#endif + +#ifdef STREAM_TO_AUDBOOST +#include "audiocodec.h" +#include "I2SCC26XX.h" +#endif //STREAM_TO_AUDBOOST +#include "msbc_library.h" #include #include #include #include +#include + /********************************************************************* * MACROS */ @@ -92,6 +99,13 @@ uint8 audioConfigEnable = 0; * CONSTANTS */ +#if !defined(BOARD_DISPLAY_EXCLUDE_UART) + #ifdef STREAM_TO_PC + #warning Cannot stream to PC and log over UART + #undef STREAM_TO_PC + #endif +#endif + // Simple BLE Central Task Events #define SBC_START_DISCOVERY_EVT 0x0001 #define SBC_PAIRING_STATE_EVT 0x0002 @@ -100,6 +114,8 @@ uint8 audioConfigEnable = 0; #define SBC_KEY_CHANGE_EVT 0x0010 #define SBC_STATE_CHANGE_EVT 0x0020 #define SBC_SCANNING_TOGGLE_EVT 0x0040 +#define SBC_AUDIO_FORCESTOP_EVT 0x0080 +#define SBC_AUDIO_VOLUMEDOWN_EVT 0x0100 // Maximum number of scan responses @@ -182,7 +198,7 @@ uint8 audioConfigEnable = 0; #define APP_MAX_CONN_INTERVAL 8 #define APP_SLAVE_LATENCY 0 // Initially 0 for fast connection. 49 slave latency (500ms effective interval) -#define APP_CONN_TIMEOUT 500 // 1.6s supervision timeout +#define APP_CONN_TIMEOUT 200 // 2s supervision timeout // Gap Bond Manager States #define UNPAIRED_STATE 0x00 @@ -190,10 +206,30 @@ uint8 audioConfigEnable = 0; #define TI_COMPANY_ID 0x000D // To maintain connectivity with SensorTag audio project +// Simple Profile Service UUID +#define SIMPLEPROFILE_SERV_UUID 0xFFF0 + // Service Change flags #define NO_CHANGE 0x00 #define CHANGE_OCCURED 0x01 +// Copied from hid_adv_remote.c +#define BLE_AUDIO_CMD_STOP 0x00 +#define BLE_AUDIO_CMD_START 0x04 +#define BLE_AUDIO_CMD_START_MSBC 0x05 + +#define BLE_AUDIO_STREAM_NONE 0x00 +#define BLE_AUDIO_STREAM_ADPCM 0x01 +#define BLE_AUDIO_STREAM_MSBC 0x02 + +// 4:1 ADPCM compression is used, wrt to int16_t buffer, this is 2x +#define BLE_AUDIO_U16_COMPRESSION_RATE 2 + +#define BLE_AUDIO_RX_BUF_SIZE BLE_AUDIO_U16_COMPRESSION_RATE*BLEAUDIO_NOTSIZE + +#define DLE_MAX_PDU_SIZE 251 +#define DLE_MAX_TX_TIME 2120 + // Application states enum { @@ -231,16 +267,22 @@ typedef struct Clock_Struct *pClock; // pointer to clock struct } readRssi_t; +typedef struct +{ + uint8_t charProps; + uint8_t charValueHandleLow; + uint8_t charValueHandleHigh; + uint8_t charValueUUIDLow; + uint8_t charValueUUIDHigh; +}attPrimaryServiceValue_t; + typedef struct { // Service and Characteristic discovery variables. uint16 keyCharHandle; uint16 keyCCCHandle; - -#ifdef AUDIO_SERVICE uint16 audioStartCharValueHandle; uint16 audioDataCharValueHandle; -#endif uint8 lastRemoteAddr[B_ADDR_LEN]; } SimpleBLECentral_HandleInfo_t; @@ -252,6 +294,9 @@ typedef struct // Display Interface Display_Handle dispHandle = NULL; +#ifdef STREAM_TO_AUDBOOST + static uint8_t volume = 0; +#endif /********************************************************************* * EXTERNAL VARIABLES */ @@ -307,9 +352,6 @@ static uint8_t state = BLE_STATE_IDLE; static uint16_t svcStartHdl = 0; static uint16_t svcEndHdl = 0; -// Discovered characteristic handle -static uint16_t charHdl = 0; - // Maximum PDU size (default = 27 octets) static uint16 maxPduSize; @@ -342,17 +384,10 @@ static uint16 audioStartCCCHandle = GATT_INVALID_HANDLE; static uint16 audioDataCharValueHandle = GATT_INVALID_HANDLE; static uint16 audioDataCCCHandle = GATT_INVALID_HANDLE; -// CCC's of the notifications -static uint16 keyCCCHandle = GATT_INVALID_HANDLE; static uint8 serviceDiscComplete = FALSE; -//static uint8 keyReportFound = FALSE; - -/* UART driver */ -static UART_Handle uartHandle; -static UART_Params uartParams; /********************************************************************* - * LOCAL FUNCTIONS + * LOCAL VARIABLES */ static void SimpleBLECentral_init(void); static void SimpleBLECentral_taskFxn(UArg a0, UArg a1); @@ -365,8 +400,8 @@ static void SimpleBLECentral_processRoleEvent(gapCentralRoleEvent_t *pEvent); static void SimpleBLECentral_startDiscovery(void); static bool SimpleBLECentral_findSvcUuid(uint16_t uuid, uint8_t *pData, uint8_t dataLen); -static void SimpleBLECentral_addDeviceInfo(uint8_t *pAddr, uint8_t addrType) -;static void SimpleBLECentral_processPairState(uint8_t state, uint8_t status); +static void SimpleBLECentral_addDeviceInfo(uint8_t *pAddr, uint8_t addrType); +static void SimpleBLECentral_processPairState(uint8_t state, uint8_t status); static void SimpleBLECentral_processPasscode(uint16_t connectionHandle, uint8_t uiOutputs); @@ -393,14 +428,86 @@ static void SimpleBLECentral_EnableNotification( uint16 connHandle, uint16 attrH static void SimpleBLECentral_DiscoverService( uint16 connHandle, uint16 svcUuid ); static void SimpleBLECentral_SaveHandles( void ); +//static void SimpleBLECentral_processAudioPkt(uint8_t pkt_counter, uint8_t * pInBuf); + static void SimpleBLECentral_scanningToggleHandler(UArg a0); PIN_Config ledPinTable[] = { Board_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ Board_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_DIO25_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Debug IO initially high */ + Board_DIO26_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Debug IO initially high */ + Board_DIO27_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Debug IO initially high */ + Board_DIO28_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Debug IO initially high */ PIN_TERMINATE }; +#define BLEAUDIO_BUFSIZE_ADPCM 96 +#define BLEAUDIO_HDRSIZE_ADPCM 4 + +#ifdef DLE_ENABLED // Data Length Extension Enable +#define BLEAUDIO_NUM_NOT_PER_FRAME_ADPCM 1 +#define BLEAUDIO_NUM_NOT_PER_FRAME_MSBC 1 + +#else +#define BLEAUDIO_NUM_NOT_PER_FRAME_ADPCM 5 +#define BLEAUDIO_NUM_NOT_PER_FRAME_MSBC 3 +#endif + +#define ADPCM_SAMPLES_PER_FRAME (BLEAUDIO_BUFSIZE_ADPCM * 2) +#define MSBC_SAMPLES_PER_FRAME 120 +#define MSBC_ENCODED_SIZE 57 +int16_t *audio_decoded; +const unsigned char msbc_data[] = +{ + 0xad, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x01, 0x12, + 0xe1, 0xeb, 0x31, 0x60, 0x76, 0xcd, 0x61, 0xf3, + 0x40, 0xe5, 0x09, 0x38, 0xc4, 0xba, 0xa3, 0xa2, + 0x38, 0x7b, 0x09, 0xb8, 0x1d, 0xdf, 0x30, 0x7c, + 0xd1, 0xa2, 0x42, 0x4b, 0xe5, 0xae, 0xa9, 0x15, + 0x9e, 0x1e, 0xc1, 0x62, 0x07, 0x6e, 0xb5, 0x1f, + 0x33, 0x56, 0x90, 0x92, 0xf9, 0x7b, 0xaa, 0x35, + 0xe0 +}; + +#ifdef STREAM_TO_AUDBOOST +uint8_t i2sContMgtBuffer[I2S_BLOCK_OVERHEAD_IN_BYTES * I2SCC26XX_QUEUE_SIZE] = {0}; +#endif //STREAM_TO_AUDBOOST +uint8_t audio_encoded[100] = {0}; +sbc_t sbc = {0}; +size_t written = 0; +struct { + uint8_t sourceIsPDM; + uint8_t streamType; + uint8_t samplesPerFrame; + uint8_t notificationsPerFrame; + int8_t si; + int16_t pv; + int8_t maxVolume; +#ifdef STREAM_TO_AUDBOOST + uint8_t i2sOpened; +#endif //STREAM_TO_AUDBOOST +} streamVariables = {0}; + +#ifdef STREAM_TO_AUDBOOST +static void I2SCC26XX_i2sCallbackFxn(I2SCC26XX_Handle handle, I2SCC26XX_StreamNotification *notification); +static I2SCC26XX_Handle i2sHandle = NULL; +static I2SCC26XX_StreamNotification i2sStream; +static I2SCC26XX_Params i2sParams = { + .requestMode = I2SCC26XX_CALLBACK_MODE, + .ui32requestTimeout = BIOS_WAIT_FOREVER, + .callbackFxn = I2SCC26XX_i2sCallbackFxn, + .blockSize = MSBC_SAMPLES_PER_FRAME, + .pvContBuffer = NULL, + .ui32conBufTotalSize = 0, + .pvContMgtBuffer = (void *) i2sContMgtBuffer, + .ui32conMgtBufTotalSize = sizeof(i2sContMgtBuffer), + .currentStream = &i2sStream +}; +static bool i2sStreamInProgress = false; +#else //STREAM_TO_PC +UART_Handle uartHandle; +#endif //STREAM_TO_AUDBOOST /********************************************************************* * PROFILE CALLBACKS @@ -469,6 +576,11 @@ static void SimpleBLECentral_init(void) // so that the application can send and receive messages. ICall_registerApp(&selfEntity, &sem); +#if defined (DLE_ENABLED) + HCI_LE_WriteSuggestedDefaultDataLenCmd(DLE_MAX_PDU_SIZE , DLE_MAX_TX_TIME); +#endif + + HCI_EXT_SetSCACmd(120); // Open all pins ledPinHandle = PIN_open(&allPinState, ledPinTable); @@ -486,17 +598,17 @@ static void SimpleBLECentral_init(void) Util_constructClock(&scanningToggleClock, SimpleBLECentral_scanningToggleHandler, DEFAULT_SCANNING_TOGGLECLOCK, 0, false, SBC_SCANNING_TOGGLE_EVT); - // Init UART and specify non-default parameters - UART_Params_init(&uartParams); - uartParams.baudRate = 400000; - uartParams.writeDataMode = UART_DATA_BINARY; - // Open the UART and do the write - uartHandle = UART_open(Board_UART, &uartParams); - - Board_initKeys(SimpleBLECentral_keyChangeHandler); - dispHandle = Display_open(Display_Type_GRLIB, NULL); + dispHandle = Display_open(Display_Type_LCD, NULL); + if(dispHandle == NULL) + { + dispHandle = Display_open(Display_Type_UART, NULL); + + //Send the form feed char to the LCD, this is helpful if using a terminal + //as it will clear the terminal history + Display_print0(dispHandle, 0, 0, "\f"); + } // Initialize internal data for (i = 0; i < MAX_NUM_BLE_CONNS; i++) @@ -572,8 +684,32 @@ static void SimpleBLECentral_init(void) // Register for GATT local events and ATT Responses pending for transmission GATT_RegisterForMsgs(selfEntity); - +#if defined (DLE_ENABLED) + Display_print0(dispHandle, 0, 0, "Audio Central with DLE"); +#else Display_print0(dispHandle, 0, 0, "Audio Central"); +#endif + +#ifdef STREAM_TO_AUDBOOST + /* Then initialize I2S driver */ + i2sHandle = (I2SCC26XX_Handle)&(I2SCC26XX_config); + I2SCC26XX_init(i2sHandle); + + // Initialize TLV320AIC3254 Codec on Audio BP + AudioCodecOpen(); + // Configure Codec + AudioCodecConfig(AUDIO_CODEC_TI_3254, AUDIO_CODEC_16_BIT, 16000, 2, AUDIO_CODEC_SPEAKER_HP, 0); +#else //STREAM_TO_PC + UART_Params uartParams; + UART_Params_init(&uartParams); +#ifdef UART_DUMP_UNCOMPRESSED + uartParams.baudRate = 460800 * 4; +#else //!UART_DUMP_UNCOMPRESSED + uartParams.baudRate = 460800; +#endif //UART_DUMP_UNCOMPRESSED + uartParams.writeMode = UART_MODE_BLOCKING; + uartHandle = UART_open(Board_UART, &uartParams); +#endif //STREAM_TO_AUDBOOST } /********************************************************************* @@ -650,6 +786,65 @@ static void SimpleBLECentral_taskFxn(UArg a0, UArg a1) PIN_setOutputValue(ledPinHandle, Board_GLED, !PIN_getOutputValue(Board_GLED)); } + if (events & SBC_AUDIO_FORCESTOP_EVT) + { + events &= ~SBC_AUDIO_FORCESTOP_EVT; + PIN_setOutputValue(ledPinHandle, Board_RLED, Board_LED_OFF); +#ifdef STREAM_TO_AUDBOOST + if (i2sStreamInProgress) { + I2SCC26XX_stopStream(i2sHandle); + i2sStreamInProgress = false; + Display_print0(dispHandle, 5, 0, "Force Shutdown I2S stream"); + + /* Turn output volume back down */ //TODO: Turn off codec + volume = 0; + AudioCodecSpeakerVolCtrl(AUDIO_CODEC_TI_3254, AUDIO_CODEC_SPEAKER_HP, volume); + + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) + { + sbc_finish(&sbc); + } + } + if (streamVariables.i2sOpened == TRUE) + { + I2SCC26XX_close(i2sHandle); + streamVariables.i2sOpened = FALSE; + Display_print0(dispHandle, 5, 0, "Closed I2S driver"); + if (audio_decoded) { + ICall_free(audio_decoded); + audio_decoded = NULL; + Display_print0(dispHandle, 5, 0, "Free'd memory for I2S driver"); + } + else { + asm(" NOP"); + Display_print0(dispHandle, 5, 0, "Failed to free memory for I2S driver"); + } + } +#else //STREAM_TO_PC +#ifdef UART_DUMP_UNCOMPRESSED + if (audio_decoded) { + ICall_free(audio_decoded); + } +#endif //UART_DUMP_UNCOMPRESSED + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) + { + sbc_finish(&sbc); + } +#endif //STREAM_TO_AUDBOOST + streamVariables.streamType = BLE_AUDIO_CMD_STOP; + Display_print0(dispHandle, 5, 0, "Force Shutdown"); + } + + if (events & SBC_AUDIO_VOLUMEDOWN_EVT) + { + events &= ~SBC_AUDIO_VOLUMEDOWN_EVT; + /* Turn output volume back down */ //TODO: Turn off codec + volume = 0; + AudioCodecSpeakerVolCtrl(AUDIO_CODEC_TI_3254, AUDIO_CODEC_SPEAKER_HP, volume); + Display_print0(dispHandle, 5, 0, "Turn Volume down to 0"); + } + + } } @@ -783,8 +978,24 @@ static void SimpleBLECentral_processRoleEvent(gapCentralRoleEvent_t *pEvent) Display_print0(dispHandle, 2, 0, "Initialized"); if ( SimpleBLECentral_BondCount() > 0 ) { - // Initiate connection - SimpleBLECentral_EstablishLink( TRUE, addrType, remoteAddr ); + VOID GAPBondMgr_SetParameter( GAPBOND_ERASE_ALLBONDS, 0, NULL ); + Display_print0(dispHandle, 5, 0, "Erase Bond info "); + + if (!scanningStarted) + { + scanningStarted = TRUE; + scanRes = 0; + + Display_print0(dispHandle, 2, 0, "Discovering..."); + Display_clearLines(dispHandle, 3, 5); + PIN_setOutputValue( ledPinHandle, Board_RLED, 0); + + GAPCentralRole_StartDiscovery(DEFAULT_DISCOVERY_MODE, + DEFAULT_DISCOVERY_ACTIVE_SCAN, + DEFAULT_DISCOVERY_WHITE_LIST); + + Util_startClock(&scanningToggleClock); + } } else { @@ -803,6 +1014,9 @@ static void SimpleBLECentral_processRoleEvent(gapCentralRoleEvent_t *pEvent) pEvent->deviceInfo.pEvtData, pEvent->deviceInfo.dataLen)) || (SimpleBLECentral_findSvcUuid( HID_SERV_UUID, + pEvent->deviceInfo.pEvtData, + pEvent->deviceInfo.dataLen)) || + (SimpleBLECentral_findSvcUuid( AUDIO_SERV_UUID, pEvent->deviceInfo.pEvtData, pEvent->deviceInfo.dataLen)) ) { @@ -810,14 +1024,13 @@ static void SimpleBLECentral_processRoleEvent(gapCentralRoleEvent_t *pEvent) pEvent->deviceInfo.addrType); addrType = pEvent->deviceInfo.addrType; osal_memcpy( remoteAddr, pEvent->deviceInfo.addr, B_ADDR_LEN ); - peerDeviceFound = TRUE; } } - if ( ( peerDeviceFound == TRUE ) && - ( pEvent->deviceInfo.eventType == GAP_ADRPT_SCAN_RSP ) && + if (( pEvent->deviceInfo.eventType == GAP_ADRPT_SCAN_RSP ) && SimpleBLECentral_FindHIDRemote( pEvent->deviceInfo.pEvtData, pEvent->deviceInfo.dataLen ) ) { + peerDeviceFound = TRUE; // End device discovery VOID GAPCentralRole_CancelDiscovery(); } @@ -864,12 +1077,17 @@ static void SimpleBLECentral_processRoleEvent(gapCentralRoleEvent_t *pEvent) state = BLE_STATE_CONNECTED; connHandle = pEvent->linkCmpl.connectionHandle; - // If service discovery not performed initiate service discovery - if (charHdl == 0) + if (FALSE == serviceDiscComplete) { - Util_startClock(&startDiscClock); + // Begin Service Discovery of AUDIO Service to find out report handles + serviceToDiscover = AUDIO_SERV_UUID; + SimpleBLECentral_DiscoverService( connHandle, serviceToDiscover ); + serviceDiscComplete = FALSE; + audioConfigEnable =0; //This will re-trig an audio configuration if needed } + Util_startClock(&startDiscClock); + Display_print0(dispHandle, 2, 0, "Connected"); Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(pEvent->linkCmpl.devAddr)); PIN_setOutputValue(ledPinHandle, Board_GLED, 1); @@ -897,7 +1115,6 @@ static void SimpleBLECentral_processRoleEvent(gapCentralRoleEvent_t *pEvent) state = BLE_STATE_IDLE; connHandle = GAP_CONNHANDLE_INIT; - charHdl = 0; Display_print0(dispHandle, 2, 0, "Disconnected"); Display_print1(dispHandle, 3, 0, "Reason: %d", pEvent->linkTerminate.reason); @@ -915,17 +1132,14 @@ static void SimpleBLECentral_processRoleEvent(gapCentralRoleEvent_t *pEvent) // Invalidate service discovery variables. serviceDiscComplete = FALSE; - keyCharHandle = GATT_INVALID_HANDLE; - keyCCCHandle = GATT_INVALID_HANDLE; serviceToDiscover = GATT_INVALID_HANDLE; -#ifdef AUDIO_SERVICE audioStartCharValueHandle = GATT_INVALID_HANDLE; audioStartCCCHandle = GATT_INVALID_HANDLE; audioDataCharValueHandle = GATT_INVALID_HANDLE; audioDataCCCHandle = GATT_INVALID_HANDLE; -#endif + PIN_setOutputValue(ledPinHandle, Board_GLED, 0); PIN_setOutputValue(ledPinHandle, Board_RLED, 1); enableCCCDs = TRUE; @@ -1029,9 +1243,12 @@ static void SimpleBLECentral_handleKeys(uint8_t shift, uint8_t keys) * * @return none */ -static uint8_t counter; static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg) { + static uint16_t prevSeqNum = 0; + static int numberOfPackets = 0, lostPackets = 0, counterToAccountForSamplingFrequencyDifference = 0; + static uint8_t audio_pkt_counter = 0, frameReady = FALSE, missedFrames = 0; + if (state == BLE_STATE_CONNECTED) { // See if GATT server was unable to transmit an ATT response @@ -1044,17 +1261,353 @@ static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg) switch ( pMsg->method ) { - case ATT_HANDLE_VALUE_NOTI: - if (pMsg->msg.handleValueNoti.handle == audioDataCharValueHandle) { - // Output the receive packets through UART, and use audio_frame_serial_print.py to decode - UART_write(uartHandle, (pMsg->msg.handleValueNoti.pValue) , 20); - counter++; - - if (counter == 50){ - PIN_setOutputValue(ledPinHandle, Board_RLED, !PIN_getOutputValue(Board_RLED)); - counter = 0; - } + case ATT_HANDLE_VALUE_NOTI: + // Check to see if notification is from audio data or control char + if (pMsg->msg.handleValueNoti.handle == audioDataCharValueHandle) + { + PIN_setOutputValue( ledPinHandle, Board_DIO28_ANALOG, 0); + if (streamVariables.streamType == BLE_AUDIO_CMD_START) + { + // Copy to encoded buffer + memcpy(&audio_encoded[audio_pkt_counter * pMsg->msg.handleValueNoti.len], pMsg->msg.handleValueNoti.pValue, pMsg->msg.handleValueNoti.len); + + // Increment the packet counter, handle wrap around logic + audio_pkt_counter++; + if (audio_pkt_counter == streamVariables.notificationsPerFrame) + { + audio_pkt_counter = 0; + frameReady = TRUE; + // Check for missing frames + numberOfPackets++; + counterToAccountForSamplingFrequencyDifference++; + missedFrames = 0; + uint8_t curSeqNum = audio_encoded[0] >> 3; + if (((prevSeqNum + 1) & 0x001F) != curSeqNum) { + if (curSeqNum > prevSeqNum) { + missedFrames = curSeqNum - prevSeqNum; + } else { + missedFrames = (curSeqNum + 31) - prevSeqNum; + } + numberOfPackets += missedFrames; + counterToAccountForSamplingFrequencyDifference += missedFrames; + lostPackets += missedFrames; + Display_print2(dispHandle, 5, 0, "Missing frame, PER %d/%d", lostPackets, numberOfPackets); + // Don't account for too many missed frames, limit to three + missedFrames &= 0x03; + } + prevSeqNum = curSeqNum; + // Account for sampling frequency mismatch, in case source is PDM from CC26xx Remote (sampled at ~15.97kHz + if ((streamVariables.sourceIsPDM == TRUE) && (counterToAccountForSamplingFrequencyDifference >= 375)) { + counterToAccountForSamplingFrequencyDifference -= 375; + missedFrames += 1; + Display_print1(dispHandle, 5, 0, "Accounting for sampling frequency mismatch, frame %d", numberOfPackets); + } + } + } + else if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) + { + if ((pMsg->msg.handleValueNoti.pValue[0] == 0xAD) && + (pMsg->msg.handleValueNoti.pValue[2] == 0x00)) + { + audio_pkt_counter = 0; + } + // Output the receive packets through UART, and use audio_frame_serial_print.py to decode + if (audio_pkt_counter == 2) { + memcpy(&audio_encoded[audio_pkt_counter * pMsg->msg.handleValueNoti.len], pMsg->msg.handleValueNoti.pValue, pMsg->msg.handleValueNoti.len - 3); + frameReady = TRUE; + } + else + { + memcpy(&audio_encoded[audio_pkt_counter * pMsg->msg.handleValueNoti.len], pMsg->msg.handleValueNoti.pValue, pMsg->msg.handleValueNoti.len); + } + audio_pkt_counter++; + } + if (frameReady == TRUE) { +#ifdef STREAM_TO_AUDBOOST + if (i2sStreamInProgress) { + I2SCC26XX_BufferRequest bufferRequest; + void *bufferCopy; + I2SCC26XX_BufferRelease bufferRelease; + bool gotBuffer = I2SCC26XX_requestBuffer(i2sHandle, &bufferRequest); + if (gotBuffer) { + PIN_setOutputValue( ledPinHandle, Board_DIO26_ANALOG, 0); + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) { + sbc_decode(&sbc, audio_encoded, MSBC_ENCODED_SIZE, (int16_t *)bufferRequest.bufferOut, streamVariables.samplesPerFrame * sizeof(int16_t), &written); + } + else { + streamVariables.pv = BUILD_UINT16(audio_encoded[2], audio_encoded[3]); + streamVariables.si = audio_encoded[1]; + Codec1_decodeBuff((int16_t *)bufferRequest.bufferOut, (uint8_t *)&audio_encoded[4], streamVariables.samplesPerFrame * sizeof(int16_t), &streamVariables.si, &streamVariables.pv); + } + PIN_setOutputValue( ledPinHandle, Board_DIO26_ANALOG, 1); + } + // Repeat to make up for missing frames + while (missedFrames) { + // Get new buffer to copy to before releasing + bufferRelease.bufferHandleIn = NULL; + bufferRelease.bufferHandleOut = bufferRequest.bufferHandleOut; + bufferCopy = bufferRequest.bufferOut; + // Now get new buffer + gotBuffer = I2SCC26XX_requestBuffer(i2sHandle, &bufferRequest); + if (gotBuffer) { + missedFrames--; + // Copy the same samples + memcpy(bufferRequest.bufferOut, bufferCopy, streamVariables.samplesPerFrame * sizeof(int16_t)); + } + // Then release buffer, and try again if there are more missing frames + I2SCC26XX_releaseBuffer(i2sHandle, &bufferRelease); + } + bufferRelease.bufferHandleIn = NULL; + bufferRelease.bufferHandleOut = bufferRequest.bufferHandleOut; + I2SCC26XX_releaseBuffer(i2sHandle, &bufferRelease); + if (gotBuffer) { + if (volume <= streamVariables.maxVolume) { + if (volume < streamVariables.maxVolume) { + volume += 5; + } else if (volume > streamVariables.maxVolume) { + volume -= 5; + } + // Volume control + AudioCodecSpeakerVolCtrl(AUDIO_CODEC_TI_3254, AUDIO_CODEC_SPEAKER_HP, volume); + } + } + } + else if (streamVariables.i2sOpened == TRUE) { + PIN_setOutputValue( ledPinHandle, Board_DIO27_ANALOG, 0); + // Start I2S stream + i2sStreamInProgress = I2SCC26XX_startStream(i2sHandle); + if (!i2sStreamInProgress) { + Display_print0(dispHandle, 5, 0, "Failed to start I2S stream"); + I2SCC26XX_stopStream(i2sHandle); + } + else { + Display_print0(dispHandle, 5, 0, "Started I2S stream"); + } + PIN_setOutputValue( ledPinHandle, Board_DIO27_ANALOG, 1); + } + else { + // Failed to open, take the opportunity to try again + // Allocate memory for decoded PCM data + audio_decoded = ICall_malloc(sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE)); + if (audio_decoded) { + i2sParams.blockSize = streamVariables.samplesPerFrame; + i2sParams.pvContBuffer = (void *) audio_decoded; + memset(audio_decoded, 0, sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE)); + i2sParams.ui32conBufTotalSize = sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE); + I2SCC26XX_open(i2sHandle, &i2sParams); + Display_print0(dispHandle, 5, 0, "Opened I2S driver"); + volume = 40; + streamVariables.i2sOpened = TRUE; + } + else { + Display_print0(dispHandle, 5, 0, "Failed to allocate mem for I2S driver on frame"); + } + } +#else //STREAM_TO_PC +#ifdef UART_DUMP_UNCOMPRESSED + if (audio_decoded) { + PIN_setOutputValue( ledPinHandle, Board_DIO26_ANALOG, 0); + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) { + sbc_decode(&sbc, audio_encoded, MSBC_ENCODED_SIZE, audio_decoded, streamVariables.samplesPerFrame * sizeof(int16_t), &written); + } + else { + streamVariables.pv = BUILD_UINT16(audio_encoded[2], audio_encoded[3]); + streamVariables.si = audio_encoded[1]; + Codec1_decodeBuff(audio_decoded, (uint8_t *)&audio_encoded[4], streamVariables.samplesPerFrame * sizeof(int16_t), &streamVariables.si, &streamVariables.pv); + } + PIN_setOutputValue( ledPinHandle, Board_DIO26_ANALOG, 1); + static uint8_t pcmHeader[3] = {0xAD, 0x00, 0xCC}; + UART_write(uartHandle, pcmHeader, sizeof(pcmHeader)); + pcmHeader[1]++; + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) { + pcmHeader[2] = 0xCC; + } + else { + pcmHeader[2] = 0xCD; + } + PIN_setOutputValue( ledPinHandle, Board_DIO26_ANALOG, 0); + UART_write(uartHandle, audio_decoded, streamVariables.samplesPerFrame * sizeof(int16_t)); +#else //!UART_DUMP_UNCOMPRESSED + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) { + UART_write(uartHandle, audio_encoded, MSBC_ENCODED_SIZE); + } + else { + UART_write(uartHandle, audio_encoded, BLEAUDIO_BUFSIZE_ADPCM + BLEAUDIO_HDRSIZE_ADPCM); + } +#endif //UART_DUMP_UNCOMPRESSED + PIN_setOutputValue( ledPinHandle, Board_DIO26_ANALOG, 1); + } + else{ + audio_decoded = ICall_malloc(sizeof(int16_t) * streamVariables.samplesPerFrame); + } +#endif //STREAM_TO_AUDBOOST + frameReady = FALSE; + } +#ifdef STREAM_TO_AUDBOOST + else if ((streamVariables.i2sOpened == FALSE)&& (streamVariables.streamType != BLE_AUDIO_CMD_STOP)) { + // Failed to open, take the opportunity to try again + // Allocate memory for decoded PCM data + audio_decoded = ICall_malloc(sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE)); + if (audio_decoded) { + i2sParams.blockSize = streamVariables.samplesPerFrame; + i2sParams.pvContBuffer = (void *) audio_decoded; + memset(audio_decoded, 0, sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE)); + i2sParams.ui32conBufTotalSize = sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE); + I2SCC26XX_open(i2sHandle, &i2sParams); + volume = 40; + Display_print0(dispHandle, 5, 0, "Opened I2S driver"); + streamVariables.i2sOpened = TRUE; + } + else { + Display_print0(dispHandle, 5, 0, "Failed to allocate mem for I2S driver on fragment"); + } + } +#else //STREAM_TO_PC +#ifdef UART_DUMP_UNCOMPRESSED + if (!audio_decoded) { + audio_decoded = ICall_malloc(sizeof(int16_t) * streamVariables.samplesPerFrame); + Display_print0(dispHandle, 5, 0, "Failed to allocate mem for decoding"); + } +#endif //UART_DUMP_UNCOMPRESSED +#endif //STREAM_TO_AUDBOOST + PIN_setOutputValue( ledPinHandle, Board_DIO28_ANALOG, 1); + } + else if(pMsg->msg.handleValueNoti.handle == audioStartCharValueHandle) + { + PIN_setOutputValue( ledPinHandle, Board_DIO27_ANALOG, 0); + // Audio/Voice commands are 1B in length + if(AUDIOPROFILE_CMD_LEN == pMsg->msg.handleValueNoti.len) + { + // If we received a stop command reset the audio_pkt_counter, SI, PV + if(BLE_AUDIO_CMD_START == *(pMsg->msg.handleValueNoti.pValue)) + { + if (streamVariables.streamType != BLE_AUDIO_CMD_STOP) { + Display_print0(dispHandle, 5, 0, "Already started stream"); + } + else { + numberOfPackets = 0; + lostPackets = 0; + prevSeqNum = 0; + counterToAccountForSamplingFrequencyDifference = 0; + audio_pkt_counter = 0; + PIN_setOutputValue(ledPinHandle, Board_RLED, Board_LED_ON); + streamVariables.streamType = BLE_AUDIO_CMD_START; + streamVariables.notificationsPerFrame = BLEAUDIO_NUM_NOT_PER_FRAME_ADPCM; + streamVariables.samplesPerFrame = ADPCM_SAMPLES_PER_FRAME; + streamVariables.maxVolume = 85 - 10; + // Allocate memory for decoded PCM data +#ifdef STREAM_TO_AUDBOOST + audio_decoded = ICall_malloc(sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE)); + + if (audio_decoded) { + i2sParams.blockSize = streamVariables.samplesPerFrame; + i2sParams.pvContBuffer = (void *) audio_decoded; + memset(audio_decoded, 0, sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE)); + i2sParams.ui32conBufTotalSize = sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE); + I2SCC26XX_open(i2sHandle, &i2sParams); + Display_print1(dispHandle, 5, 0, "Opened I2S driver: %d", 1); + streamVariables.i2sOpened = TRUE; + } + else { + Display_print0(dispHandle, 5, 0, "Failed to allocate mem for I2S driver on start"); + } +#else //STREAM_TO_PC +#ifdef UART_DUMP_UNCOMPRESSED + audio_decoded = ICall_malloc(sizeof(int16_t) * streamVariables.samplesPerFrame); +#endif //UART_DUMP_UNCOMPRESSED +#endif //STREAM_TO_AUDBOOST + Display_print0(dispHandle, 5, 0, "ADPCM Stream"); + } + } + else if(BLE_AUDIO_CMD_START_MSBC == *(pMsg->msg.handleValueNoti.pValue)) + { + if (streamVariables.streamType != BLE_AUDIO_CMD_STOP) { + Display_print0(dispHandle, 5, 0, "Already started stream"); + } + else { + audio_pkt_counter = 0; + PIN_setOutputValue(ledPinHandle, Board_RLED, Board_LED_ON); + streamVariables.streamType = BLE_AUDIO_CMD_START_MSBC; + streamVariables.notificationsPerFrame = BLEAUDIO_NUM_NOT_PER_FRAME_MSBC; + streamVariables.samplesPerFrame = MSBC_SAMPLES_PER_FRAME; + streamVariables.maxVolume = 90 - 15; + // Allocate memory for decoded PCM data +#ifdef STREAM_TO_AUDBOOST + audio_decoded = ICall_malloc(sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE)); + + if (audio_decoded) { + i2sParams.blockSize = streamVariables.samplesPerFrame; + i2sParams.pvContBuffer = (void *) audio_decoded; + memset(audio_decoded, 0, sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE)); + i2sParams.ui32conBufTotalSize = sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE); + I2SCC26XX_open(i2sHandle, &i2sParams); + Display_print0(dispHandle, 5, 0, "Opened I2S driver"); + streamVariables.i2sOpened = TRUE; + } + else { + Display_print0(dispHandle, 5, 0, "Failed to allocate mem for I2S driver on start"); + } +#else //STREAM_TO_PC +#ifdef UART_DUMP_UNCOMPRESSED + audio_decoded = ICall_malloc(sizeof(int16_t) * streamVariables.samplesPerFrame); +#endif //UART_DUMP_UNCOMPRESSED +#endif //STREAM_TO_AUDBOOST + // Initialize encoder + sbc_init_msbc(&sbc, 0); + Display_print0(dispHandle, 5, 0, "mSBC Stream"); + } + } + else if(BLE_AUDIO_CMD_STOP == *(pMsg->msg.handleValueNoti.pValue)) + { + audio_pkt_counter = 0; + PIN_setOutputValue(ledPinHandle, Board_RLED, Board_LED_OFF); +#ifdef STREAM_TO_AUDBOOST + if (i2sStreamInProgress) { + I2SCC26XX_stopStream(i2sHandle); + i2sStreamInProgress = false; + Display_print0(dispHandle, 5, 0, "Stopped I2S stream"); + + /* Turn output volume back down */ //TODO: Turn off codec + volume = 0; + AudioCodecSpeakerVolCtrl(AUDIO_CODEC_TI_3254, AUDIO_CODEC_SPEAKER_HP, volume); + + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) + { + sbc_finish(&sbc); + } + } + if (streamVariables.i2sOpened == TRUE) + { + I2SCC26XX_close(i2sHandle); + streamVariables.i2sOpened = FALSE; + Display_print0(dispHandle, 5, 0, "Closed I2S driver"); + if (audio_decoded) { + ICall_free(audio_decoded); + audio_decoded = NULL; + Display_print0(dispHandle, 5, 0, "Free'd memory for I2S driver"); + } + else { + asm(" NOP"); + Display_print0(dispHandle, 5, 0, "Failed to free memory for I2S driver"); + } + } +#else //STREAM_TO_PC +#ifdef UART_DUMP_UNCOMPRESSED + if (audio_decoded) { + ICall_free(audio_decoded); + } +#endif //UART_DUMP_UNCOMPRESSED + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) + { + sbc_finish(&sbc); + } +#endif //STREAM_TO_AUDBOOST + streamVariables.streamType = BLE_AUDIO_CMD_STOP; + Display_print0(dispHandle, 5, 0, "No Stream"); + } + PIN_setOutputValue( ledPinHandle, Board_DIO27_ANALOG, 1); + } } break; @@ -1073,14 +1626,11 @@ static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg) { if ( svcStartHdl != 0 ) { - -#ifdef AUDIO_SERVICE if ( serviceToDiscover == AUDIO_SERV_UUID) { // Discover all characteristics GATT_DiscAllChars( connHandle, svcStartHdl, svcEndHdl, selfEntity ); } -#endif } } @@ -1093,12 +1643,10 @@ static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg) && pMsg->msg.errorRsp.handle == 0x0001) //0x0001 is the start attribute handle of 0xfff0, AUDIO_SERV_UUID { - - if ( (enableCCCDs == TRUE) && (keyCharHandle != GATT_INVALID_HANDLE)) + if ( (enableCCCDs == TRUE) && (audioStartCharValueHandle != GATT_INVALID_HANDLE)) { - keyCCCHandle = keyCharHandle + 1; - // Begin configuring the characteristics for notifications - SimpleBLECentral_EnableNotification( connHandle, keyCCCHandle ); + audioStartCCCHandle = audioStartCharValueHandle + 1 ; + SimpleBLECentral_EnableNotification( connHandle, audioStartCCCHandle ); } } break; @@ -1122,7 +1670,7 @@ static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg) } else if (charUUID == AUDIOPROFILE_AUDIO_UUID ){ pHandle = &audioDataCharValueHandle; - *pHandle = BUILD_UINT16( pRsp->pDataList[3] , pRsp->pDataList[4]); + *pHandle = BUILD_UINT16( pRsp->pDataList[3] , pRsp->pDataList[4]); } } break; @@ -1134,7 +1682,6 @@ static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg) { if ( serviceToDiscover == AUDIO_SERV_UUID ) { - counter = 0; /* This kicks off the enabling the 1st of notification enable event */ if (audioStartCharValueHandle != GATT_INVALID_HANDLE) { audioStartCCCHandle = audioStartCharValueHandle + 1 ; @@ -1158,9 +1705,6 @@ static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg) else if (audioDataCCCHandle == GATT_INVALID_HANDLE) { handle = audioDataCCCHandle = audioDataCharValueHandle + 1; } - else if (keyCCCHandle == GATT_INVALID_HANDLE ) { - handle = keyCCCHandle = keyCharHandle + 1; - } else { serviceDiscComplete = TRUE; break; @@ -1189,6 +1733,13 @@ static void SimpleBLECentral_processGATTMsg(gattMsgEvent_t *pMsg) } break; + // Service Change indication + case ATT_EXCHANGE_MTU_RSP: + { + Display_print1(dispHandle, 10, 0, "server Rx MTU size : %d", pMsg->msg.exchangeMTURsp.serverRxMTU); + } + break; + default: // Unknown event break; @@ -1246,9 +1797,12 @@ static void SimpleBLECentral_processPairState(uint8_t state, uint8_t status) // Enter a GAP Bond manager Paired state Display_print0(dispHandle, 2, 0, "Pairing success"); - // Begin Service Discovery of AUDIO Service to find out report handles - serviceToDiscover = AUDIO_SERV_UUID; - SimpleBLECentral_DiscoverService( connHandle, serviceToDiscover ); + if (FALSE == serviceDiscComplete) + { + // Begin Service Discovery of AUDIO Service to find out report handles + serviceToDiscover = AUDIO_SERV_UUID; + SimpleBLECentral_DiscoverService( connHandle, serviceToDiscover ); + } } else { @@ -1271,10 +1825,8 @@ static void SimpleBLECentral_processPairState(uint8_t state, uint8_t status) { if ( -#ifdef AUDIO_SERVICE ( remoteHandles.audioStartCharValueHandle == GATT_INVALID_HANDLE ) || ( remoteHandles.audioDataCharValueHandle == GATT_INVALID_HANDLE ) -#endif ) { serviceToDiscover = AUDIO_SERV_UUID; @@ -1292,13 +1844,11 @@ static void SimpleBLECentral_processPairState(uint8_t state, uint8_t status) // bonding indicates that we probably already enabled all these characteristics. easy fix if not. serviceDiscComplete = TRUE; -#ifdef AUDIO_SERVICE audioStartCharValueHandle = remoteHandles.audioStartCharValueHandle; audioDataCharValueHandle = remoteHandles.audioDataCharValueHandle; //Still, Force update of Audio config for now... audioConfigEnable =1; -#endif } } else if ( osal_isbufset( remoteHandles.lastRemoteAddr, 0x00, B_ADDR_LEN ) == TRUE ) @@ -1364,7 +1914,7 @@ static void SimpleBLECentral_startDiscovery(void) attExchangeMTUReq_t req; // Initialize cached handles - svcStartHdl = svcEndHdl = charHdl = 0; + svcStartHdl = svcEndHdl = 0; // Discover GATT Server's Rx MTU size req.clientRxMTU = maxPduSize - L2CAP_HDR_SIZE; @@ -1633,6 +2183,12 @@ static uint8 SimpleBLECentral_FindHIDRemote( uint8* pData, uint8 length ) { 'C', 'C', '2', '6', '5', '0', ' ', 'R', 'C' }; + static uint8 remoteNameTx[] = + { + 'S', 'i', 'm', 'p', 'l', 'e', + 'B', 'L', 'E', + 'A', 'u', 'd', 'i', 'o', 'T', 'x', + }; // move pointer to the start of the scan response data. pData += 2; @@ -1640,7 +2196,14 @@ static uint8 SimpleBLECentral_FindHIDRemote( uint8* pData, uint8 length ) // adjust length as well length -= 2; - resultFindRC = osal_memcmp( remoteNameRC, pData, length ); + streamVariables.sourceIsPDM = FALSE; + if (length == sizeof(remoteNameRC)) { + resultFindRC = osal_memcmp( remoteNameRC, pData, length ); + streamVariables.sourceIsPDM = TRUE; + } + else if (length == sizeof(remoteNameTx)) { + resultFindRC = osal_memcmp( remoteNameTx, pData, length ); + } // did not find RC, then search for ST if (!resultFindRC){ @@ -1651,28 +2214,6 @@ static uint8 SimpleBLECentral_FindHIDRemote( uint8* pData, uint8 length ) 'S', 'e', 'n', 's', 'o', 'r', 'T', 'a', 'g' }; - // // complete name - // 0x11, // length of this data - // GAP_ADTYPE_LOCAL_NAME_COMPLETE, - // 'C', 'C', '2', '6', '5', '0', ' ', - // 'S', 'e', 'n', 's', 'o', 'r', 'T', 'a', 'g', - // - // // connection interval range - // 0x05, // length of this data - // GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE, - // LO_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), - // HI_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), - // LO_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), - // HI_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), - // - // // Tx power level - // 0x02, // length of this data - // GAP_ADTYPE_POWER_LEVEL, - // 0 // 0dBm - - // adjust length as well, totla length is 0x11 + 0xA = 0x1B = 27 - // the needed array size(for the name) is only 16 bytes -// length -= 11; // already moved when search for RC length -= 9; resultFindST = osal_memcmp( remoteNameST, pData, length ); } @@ -1812,10 +2353,8 @@ static void SimpleBLECentral_SaveHandles( void ) // // CCC's of the notifications // remoteHandles.keyCCCHandle = keyCCCHandle; -#ifdef AUDIO_SERVICE remoteHandles.audioStartCharValueHandle = audioStartCharValueHandle; remoteHandles.audioDataCharValueHandle = audioDataCharValueHandle; -#endif } /********************************************************************* @@ -1836,5 +2375,42 @@ static void SimpleBLECentral_scanningToggleHandler(UArg arg) Semaphore_post(sem); } +#ifdef STREAM_TO_AUDBOOST +static void I2SCC26XX_i2sCallbackFxn(I2SCC26XX_Handle handle, I2SCC26XX_StreamNotification *notification) { + static uint8_t lostConsecutively = 0; + uint32_t hwiKey; + if (notification->status == I2SCC26XX_STREAM_BUFFER_READY) { + // Provide buffer + PIN_setOutputValue( ledPinHandle, Board_DIO25_ANALOG, !(PIN_getOutputValue(Board_DIO25_ANALOG))); + lostConsecutively = 0; + streamVariables.maxVolume = 75; + } + else if (notification->status == I2SCC26XX_STREAM_BUFFER_READY_BUT_NO_AVAILABLE_BUFFERS) { + // Provide buffer + lostConsecutively++; + PIN_setOutputValue( ledPinHandle, Board_DIO25_ANALOG, !(PIN_getOutputValue(Board_DIO25_ANALOG))); + if ((lostConsecutively > 5 ) & (lostConsecutively <= 40 )) { + if( volume > 0 ){ + // hwiKey = Hwi_disable(); + // events |= SBC_AUDIO_VOLUMEDOWN_EVT; + // Hwi_restore(hwiKey); + // Semaphore_post(sem); + streamVariables.maxVolume = 0; + } + } + else if (lostConsecutively > 40 ) { + hwiKey = Hwi_disable(); + events |= SBC_AUDIO_FORCESTOP_EVT; + lostConsecutively = 0; + Hwi_restore(hwiKey); + Semaphore_post(sem); + } + } + else { + PIN_setOutputValue( ledPinHandle, Board_RLED, !(PIN_getOutputValue(Board_RLED))); + } +} +#endif //STREAM_TO_AUDBOOST + /********************************************************************* *********************************************************************/ diff --git a/src/examples/simple_peripheral_audio_transmitter/cc26xx/app/simple_peripheral_audio_transmitter.c b/src/examples/simple_peripheral_audio_transmitter/cc26xx/app/simple_peripheral_audio_transmitter.c new file mode 100644 index 0000000..f67f1cd --- /dev/null +++ b/src/examples/simple_peripheral_audio_transmitter/cc26xx/app/simple_peripheral_audio_transmitter.c @@ -0,0 +1,1727 @@ + +/* + * Filename: simple_peripheral_audio_transmitter.c + * + * Description: This is the simple_peripheral example modified to send + * audio data over BLE. + * + * + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/********************************************************************* + * INCLUDES + */ +#include + +#include +#include +#include +#include +#include + +#include "hci_tl.h" +#include "gatt.h" +#include "linkdb.h" +#include "gapgattserver.h" +#include "gattservapp.h" +//#include "devinfoservice.h" +//#include "simple_gatt_profile.h" + +#if defined(FEATURE_OAD) || defined(IMAGE_INVALIDATE) +#include "oad_target.h" +#include "oad.h" +#endif //FEATURE_OAD || IMAGE_INVALIDATE + +#include "peripheral.h" +#include "gapbondmgr.h" + +#include "osal_snv.h" +#include "icall_apimsg.h" + +#include "util.h" + +#ifdef USE_RCOSC +#include "rcosc_calibration.h" +#endif //USE_RCOSC + +#include +#include "board_key.h" + +#include "board.h" + +#include "simple_peripheral.h" + +#include "audio_profile.h" + +#include +#include "audiocodec.h" +#include "msbc_library.h" +#include "I2SCC26XX.h" + +/********************************************************************* + * CONSTANTS + */ + +// Advertising interval when device is discoverable (units of 625us, 160=100ms) +#define DEFAULT_ADVERTISING_INTERVAL 160 + +// Limited discoverable mode advertises for 30.72s, and then stops +// General discoverable mode advertises indefinitely +#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_GENERAL + +#ifndef FEATURE_OAD +// Minimum connection interval (units of 1.25ms, 80=100ms) if automatic +// parameter update request is enabled +#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 8 + +// Maximum connection interval (units of 1.25ms, 800=1000ms) if automatic +// parameter update request is enabled +#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 16 +#else //!FEATURE_OAD +// Minimum connection interval (units of 1.25ms, 8=10ms) if automatic +// parameter update request is enabled +#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 8 + +// Maximum connection interval (units of 1.25ms, 8=10ms) if automatic +// parameter update request is enabled +#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 8 +#endif // FEATURE_OAD + +// Slave latency to use if automatic parameter update request is enabled +#define DEFAULT_DESIRED_SLAVE_LATENCY 0 + +// Supervision timeout value (units of 10ms, 1000=10s) if automatic parameter +// update request is enabled +#define DEFAULT_DESIRED_CONN_TIMEOUT 1000 + +// Whether to enable automatic parameter update request when a connection is +// formed +#define DEFAULT_ENABLE_UPDATE_REQUEST FALSE + +// Connection Pause Peripheral time value (in seconds) +#define DEFAULT_CONN_PAUSE_PERIPHERAL 2 + +// How often to perform periodic event (in msec) +//#define SBP_PERIODIC_EVT_PERIOD DEFAULT_DESIRED_MIN_CONN_INTERVAL+2 +#define SBP_PERIODIC_EVT_PERIOD 8 + +#ifdef FEATURE_OAD +// The size of an OAD packet. +#define OAD_PACKET_SIZE ((OAD_BLOCK_SIZE) + 2) +#endif // FEATURE_OAD + +// Task configuration +#define SBP_TASK_PRIORITY 1 + + +#ifndef SBP_TASK_STACK_SIZE +#define SBP_TASK_STACK_SIZE 644 +#endif + +// Internal Events for RTOS application +#define SBP_STATE_CHANGE_EVT 0x0001 +#define SBP_CHAR_CHANGE_EVT 0x0002 +#define SBP_PERIODIC_EVT 0x0004 +#define SBP_CONN_EVT_END_EVT 0x0008 +#define SBP_KEY_CHANGE_EVT 0x0010 +#define SBP_I2S_FRAME_EVENT 0x0020 +#define SBP_I2S_ERROR_EVENT 0x0040 +#define SBP_SEND_STOP_CMD_EVENT 0x0080 +#define SBP_SEND_START_CMD_EVENT 0x0100 +#define SBP_STOP_I2S_EVENT 0x0200 +#define SBP_START_I2S_EVENT 0x0400 + +#define DLE_MAX_PDU_SIZE 251 +#define DLE_MAX_TX_TIME 2120 + +#define DEFAULT_PDU_SIZE 27 +#define DEFAULT_TX_TIME 328 + +// The combined overhead for L2CAP and ATT notification headers +#define TOTAL_PACKET_OVERHEAD 7 + +// GATT notifications for throughput example don't require an authenticated link +#define GATT_NO_AUTHENTICATION 0 + +#define BLE_AUDIO_CMD_STOP 0x00 +#define BLE_AUDIO_CMD_START 0x04 +#define BLE_AUDIO_CMD_START_MSBC 0x05 +#define BLE_AUDIO_CMD_NONE 0xFF + +#define RAS_DATA_TIC1_CMD 0x01 + +/********************************************************************* + * TYPEDEFS + */ + +// App event passed from profiles. +typedef struct +{ + appEvtHdr_t hdr; // event header. +} sbpEvt_t; + +/********************************************************************* + * GLOBAL VARIABLES + */ + +// Display Interface +Display_Handle dispHandle = NULL; + +/********************************************************************* + * LOCAL VARIABLES + */ +static PIN_Config SBP_configTable[] = +{ + Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, + Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, + Board_DIO25_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Debug IO initially high */ + Board_DIO26_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Debug IO initially high */ + Board_DIO27_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Debug IO initially high */ + Board_DIO28_ANALOG | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Debug IO initially high */ + PIN_TERMINATE +}; + +static PIN_State sbpPins; +static PIN_Handle hSbpPins; + +// Entity ID globally used to check for source and/or destination of messages +static ICall_EntityID selfEntity; + +// Semaphore globally used to post events to the application thread +static ICall_Semaphore sem; + +// Clock instances for internal periodic events. +static Clock_Struct periodicClock; + +// Queue object used for app messages +static Queue_Struct appMsg; +static Queue_Handle appMsgQueue; + +#if defined(FEATURE_OAD) +// Event data from OAD profile. +static Queue_Struct oadQ; +static Queue_Handle hOadQ; +#endif //FEATURE_OAD + +// events flag for internal application events. +static uint16_t events; + +// Task configuration +Task_Struct sbpTask; +Char sbpTaskStack[SBP_TASK_STACK_SIZE]; + +// Profile state and parameters +//static gaprole_States_t gapProfileState = GAPROLE_INIT; + +// GAP - SCAN RSP data (max size = 31 bytes) +static uint8_t scanRspData[] = +{ + // complete name + 0x14, // length of this data + GAP_ADTYPE_LOCAL_NAME_COMPLETE, + 'S', + 'i', + 'm', + 'p', + 'l', + 'e', + 'B', + 'L', + 'E', + 'A', + 'u', + 'd', + 'i', + 'o', + 'T', + 'x', +}; + +// GAP - Advertisement data (max size = 31 bytes, though this is +// best kept short to conserve power while advertisting) +static uint8_t advertData[] = +{ + // Flags; this sets the device to use limited discoverable + // mode (advertises for 30 seconds at a time) instead of general + // discoverable mode (advertises indefinitely) + 0x02, // length of this data + GAP_ADTYPE_FLAGS, + DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED, + + // service UUID, to notify central devices what services are included + // in this peripheral +#if !defined(FEATURE_OAD) || defined(FEATURE_OAD_ONCHIP) + 0x03, // length of this data +#else //OAD for external flash + 0x05, // lenght of this data +#endif //FEATURE_OAD + GAP_ADTYPE_16BIT_MORE, // some of the UUID's, but not all +#ifdef FEATURE_OAD + LO_UINT16(OAD_SERVICE_UUID), + HI_UINT16(OAD_SERVICE_UUID), +#endif //FEATURE_OAD +#ifndef FEATURE_OAD_ONCHIP + LO_UINT16(AUDIO_SERV_UUID), + HI_UINT16(AUDIO_SERV_UUID) +#endif //FEATURE_OAD_ONCHIP +}; + +// GAP GATT Attributes +static uint8_t attDeviceName[GAP_DEVICE_NAME_LEN] = "Simple BLE AudioTx"; + +// Globals used for ATT Response retransmission +static gattMsgEvent_t *pAttRsp = NULL; +static uint8_t rspTxRetry = 0; + +#define INPUT_OPTION AUDIO_CODEC_MIC_ONBOARD +#define BLEAUDIO_BUFSIZE_ADPCM 96 +#define BLEAUDIO_HDRSIZE_ADPCM 4 + +#ifdef DLE_ENABLED // Data Length Extension Enable +#define BLEAUDIO_NUM_NOT_PER_FRAME_ADPCM 1 +#define BLEAUDIO_NUM_NOT_PER_FRAME_MSBC 1 + +#else +#define BLEAUDIO_NUM_NOT_PER_FRAME_ADPCM 5 +#define BLEAUDIO_NUM_NOT_PER_FRAME_MSBC 3 +#endif + +#define ADPCM_SAMPLES_PER_FRAME (BLEAUDIO_BUFSIZE_ADPCM * 2) +#define MSBC_SAMPLES_PER_FRAME 120 +#define MSBC_ENCODED_SIZE 57 +typedef enum { + STREAM_STATE_IDLE, + STREAM_STATE_SEND_START_CMD, + STREAM_STATE_START_I2S, + STREAM_STATE_ACTIVE, + STREAM_STATE_SEND_STOP_CMD, + STREAM_STATE_STOP_I2S, +} STREAM_STATE_E; +const unsigned char msbc_data[] = +{ + 0xad, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x01, 0x12, + 0xe1, 0xeb, 0x31, 0x60, 0x76, 0xcd, 0x61, 0xf3, + 0x40, 0xe5, 0x09, 0x38, 0xc4, 0xba, 0xa3, 0xa2, + 0x38, 0x7b, 0x09, 0xb8, 0x1d, 0xdf, 0x30, 0x7c, + 0xd1, 0xa2, 0x42, 0x4b, 0xe5, 0xae, 0xa9, 0x15, + 0x9e, 0x1e, 0xc1, 0x62, 0x07, 0x6e, 0xb5, 0x1f, + 0x33, 0x56, 0x90, 0x92, 0xf9, 0x7b, 0xaa, 0x35, + 0xe0 +}; +//int16_t pcmSamples[MSBC_SAMPLES_PER_FRAME * I2SCC26XX_QUEUE_SIZE] = {0}; +int16_t *pcmSamples; + +uint8_t i2sContMgtBuffer[I2S_BLOCK_OVERHEAD_IN_BYTES * I2SCC26XX_QUEUE_SIZE] = {0}; +uint8_t audio_encoded[100] = {0}; +sbc_t sbc = {0}; +ssize_t written = 0; +struct { + STREAM_STATE_E streamState; + STREAM_STATE_E requestedStreamState; + uint8_t streamType; + uint8_t requestedStreamType; + uint8_t samplesPerFrame; + uint8_t notificationsPerFrame; + int8_t si; + int16_t pv; + uint8_t activeLED; +} streamVariables = {STREAM_STATE_IDLE, STREAM_STATE_IDLE, 0, 0, 0, 0, 0, 0, 0}; + +static void I2SCC26XX_i2sCallbackFxn(I2SCC26XX_Handle handle, I2SCC26XX_StreamNotification *notification); +static I2SCC26XX_Handle i2sHandle = NULL; +static I2SCC26XX_StreamNotification i2sStream; +static I2SCC26XX_Params i2sParams = { + .requestMode = I2SCC26XX_CALLBACK_MODE, + .ui32requestTimeout = BIOS_WAIT_FOREVER, + .callbackFxn = I2SCC26XX_i2sCallbackFxn, + .blockSize = MSBC_SAMPLES_PER_FRAME, + .pvContBuffer = NULL, + .ui32conBufTotalSize = 0, + .pvContMgtBuffer = (void *) i2sContMgtBuffer, + .ui32conMgtBufTotalSize = sizeof(i2sContMgtBuffer), + .currentStream = &i2sStream +}; +static bool i2sStreamInProgress = false; +static uint8_t volume = 0, seqNum = 0; + +#include +UART_Handle uartHandle; + +/********************************************************************* + * LOCAL FUNCTIONS + */ + +static void SimpleBLEPeripheral_init( void ); +static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1); + +static uint8_t SimpleBLEPeripheral_processStackMsg(ICall_Hdr *pMsg); +static uint8_t SimpleBLEPeripheral_processGATTMsg(gattMsgEvent_t *pMsg); +static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *pMsg); +static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState); +static void SimpleBLEPeripheral_clockHandler(UArg arg); + +static void SimpleBLEPeripheral_sendAttRsp(void); +static void SimpleBLEPeripheral_freeAttRsp(uint8_t status); + +static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState); + +static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state); + +#ifdef FEATURE_OAD +void SimpleBLEPeripheral_processOadWriteCB(uint8_t event, uint16_t connHandle, + uint8_t *pData); +#endif //FEATURE_OAD + +void SimpleBLEPeripheral_keyChangeHandler(uint8 keys); +static void SimpleBLEPeripheral_handleKeys(uint8_t shift, uint8_t keys); + +static uint8_t SimpleBLEPeripheral_transmitAudioStreamCmd(uint8_t cmd); +static void SimpleBLEPeripheral_startStreaming(void); +//static void SimpleBLEPeripheral_processPdmData(void); +static void SimpleBLEPeripheral_transmitAudioFrame(uint8_t *buf); +static void SimpleBLEPeripheral_stopStreaming(void); +static void SimpleBLEPeripheral_sendStopCmd(void); +static void SimpleBLEPeripheral_sendStartCmd(void); +static void SimpleBLEPeripheral_startI2Sstream(void); +static void SimpleBLEPeripheral_stopI2Sstream(void); +static void SimpleBLEPeripheral_finishStream(void); + +/********************************************************************* + * PROFILE CALLBACKS + */ + +// GAP Role Callbacks +static gapRolesCBs_t SimpleBLEPeripheral_gapRoleCBs = +{ + SimpleBLEPeripheral_stateChangeCB // Profile State Change Callbacks +}; + +// GAP Bond Manager Callbacks +static gapBondCBs_t simpleBLEPeripheral_BondMgrCBs = +{ + NULL, // Passcode callback (not used by application) + NULL // Pairing / Bonding state Callback (not used by application) +}; + +#ifdef FEATURE_OAD +static oadTargetCBs_t simpleBLEPeripheral_oadCBs = +{ + SimpleBLEPeripheral_processOadWriteCB // Write Callback. +}; +#endif //FEATURE_OAD + +/********************************************************************* + * PUBLIC FUNCTIONS + */ + +/********************************************************************* + * @fn SimpleBLEPeripheral_createTask + * + * @brief Task creation function for the Simple BLE Peripheral. + * + * @param None. + * + * @return None. + */ +void SimpleBLEPeripheral_createTask(void) +{ + Task_Params taskParams; + + // Configure task + Task_Params_init(&taskParams); + taskParams.stack = sbpTaskStack; + taskParams.stackSize = SBP_TASK_STACK_SIZE; + taskParams.priority = SBP_TASK_PRIORITY; + + Task_construct(&sbpTask, SimpleBLEPeripheral_taskFxn, &taskParams, NULL); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_init + * + * @brief Called during initialization and contains application + * specific initialization (ie. hardware initialization/setup, + * table initialization, power up notification, etc), and + * profile initialization/setup. + * + * @param None. + * + * @return None. + */ +static void SimpleBLEPeripheral_init(void) +{ + // ****************************************************************** + // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp + // ****************************************************************** + // Register the current thread as an ICall dispatcher application + // so that the application can send and receive messages. + ICall_registerApp(&selfEntity, &sem); + + // Hard code the DB Address till CC2650 board gets its own IEEE address + uint8 bdAddress[B_ADDR_LEN] = { 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA }; + HCI_EXT_SetBDADDRCmd(bdAddress); + +#ifdef USE_RCOSC + RCOSC_enableCalibration(); +#endif // USE_RCOSC + +#if defined (DLE_ENABLED) + HCI_LE_WriteSuggestedDefaultDataLenCmd(DLE_MAX_PDU_SIZE , DLE_MAX_TX_TIME); +#endif + + // Create an RTOS queue for message from profile to be sent to app. + appMsgQueue = Util_constructQueue(&appMsg); + + // Create one-shot clocks for internal periodic events. + Util_constructClock(&periodicClock, SimpleBLEPeripheral_clockHandler, + SBP_PERIODIC_EVT_PERIOD, 0, false, SBP_PERIODIC_EVT); + + dispHandle = Display_open(Display_Type_LCD, NULL); + if(dispHandle == NULL) + { + dispHandle = Display_open(Display_Type_UART, NULL); + + //Send the form feed char to the LCD, this is helpful if using a terminal + //as it will clear the terminal history + Display_print0(dispHandle, 0, 0, "\f"); + } + + // Highjack UART handle + DisplayUart_Object *object = (DisplayUart_Object *)dispHandle->object; + uartHandle = object->hUart; + + // Setup the GAP + GAP_SetParamValue(TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL); + + // Setup the GAP Peripheral Role Profile + { + // For all hardware platforms, device starts advertising upon initialization + uint8_t initialAdvertEnable = TRUE; + + // By setting this to zero, the device will go into the waiting state after + // being discoverable for 30.72 second, and will not being advertising again + // until the enabler is set back to TRUE + uint16_t advertOffTime = 0; + + uint8_t enableUpdateRequest = DEFAULT_ENABLE_UPDATE_REQUEST; + uint16_t desiredMinInterval = DEFAULT_DESIRED_MIN_CONN_INTERVAL; + uint16_t desiredMaxInterval = DEFAULT_DESIRED_MAX_CONN_INTERVAL; + uint16_t desiredSlaveLatency = DEFAULT_DESIRED_SLAVE_LATENCY; + uint16_t desiredConnTimeout = DEFAULT_DESIRED_CONN_TIMEOUT; + + // Set the GAP Role Parameters + GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), + &initialAdvertEnable); + GAPRole_SetParameter(GAPROLE_ADVERT_OFF_TIME, sizeof(uint16_t), + &advertOffTime); + + GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), + scanRspData); + GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData); + + GAPRole_SetParameter(GAPROLE_PARAM_UPDATE_ENABLE, sizeof(uint8_t), + &enableUpdateRequest); + GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t), + &desiredMinInterval); + GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t), + &desiredMaxInterval); + GAPRole_SetParameter(GAPROLE_SLAVE_LATENCY, sizeof(uint16_t), + &desiredSlaveLatency); + GAPRole_SetParameter(GAPROLE_TIMEOUT_MULTIPLIER, sizeof(uint16_t), + &desiredConnTimeout); + } + + // Set the GAP Characteristics + GGS_SetParameter(GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName); + + // Set advertising interval + { + uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL; + + GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MIN, advInt); + GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MAX, advInt); + GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MIN, advInt); + GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MAX, advInt); + } + + // Setup the GAP Bond Manager + { + uint32_t passkey = 0; // passkey "000000" + uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ; + uint8_t mitm = TRUE; + uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY; + uint8_t bonding = TRUE; + + GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t), + &passkey); + GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode); + GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm); + GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap); + GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding); + } + + // Initialize GATT attributes + GGS_AddService(GATT_ALL_SERVICES); // GAP + GATTServApp_AddService(GATT_ALL_SERVICES); // GATT attributes + +#ifdef FEATURE_OAD + VOID OAD_addService(); // OAD Profile + OAD_register((oadTargetCBs_t *)&simpleBLEPeripheral_oadCBs); + hOadQ = Util_constructQueue(&oadQ); +#endif //FEATURE_OAD + +#ifdef IMAGE_INVALIDATE + Reset_addService(); +#endif //IMAGE_INVALIDATE + + // Add Audio Service + Audio_AddService(); + + // Start the Device + VOID GAPRole_StartDevice(&SimpleBLEPeripheral_gapRoleCBs); + + // Start Bond Manager + VOID GAPBondMgr_Register(&simpleBLEPeripheral_BondMgrCBs); + + // Register with GAP for HCI/Host messages + GAP_RegisterForMsgs(selfEntity); + + // Register for GATT local events and ATT Responses pending for transmission + GATT_RegisterForMsgs(selfEntity); + + HCI_LE_ReadMaxDataLenCmd(); + +#if defined FEATURE_OAD + #if defined (HAL_IMAGE_A) + Display_print0(dispHandle, 0, 0, "Audio Tx Peripheral A"); + #else + Display_print0(dispHandle, 0, 0, "Audio Tx Peripheral B"); + #endif // HAL_IMAGE_A +#else + #if defined (DLE_ENABLED) + Display_print0(dispHandle, 0, 0, "Audio Tx Peripheral with DLE"); + #else + Display_print0(dispHandle, 0, 0, "Audio Tx Peripheral"); + #endif +#endif // FEATURE_OAD + + // Open pin structure for use + hSbpPins = PIN_open(&sbpPins, SBP_configTable); + + Board_initKeys(SimpleBLEPeripheral_keyChangeHandler); + + /* Then initialize I2S driver */ + i2sHandle = (I2SCC26XX_Handle)&(I2SCC26XX_config); + I2SCC26XX_init(i2sHandle); + + // Initialize TLV320AIC3254 Codec on Audio BP + AudioCodecOpen(); + // Configure Codec + AudioCodecConfig(AUDIO_CODEC_TI_3254, AUDIO_CODEC_16_BIT, 16000, 2, 0, INPUT_OPTION); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_taskFxn + * + * @brief Application task entry point for the Simple BLE Peripheral. + * + * @param a0, a1 - not used. + * + * @return None. + */ +static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1) +{ + uint32_t hwiKey; + // Initialize application + SimpleBLEPeripheral_init(); + + // Application main loop + for (;;) + { + // Waits for a signal to the semaphore associated with the calling thread. + // Note that the semaphore associated with a thread is signaled when a + // message is queued to the message receive queue of the thread or when + // ICall_signal() function is called onto the semaphore. + ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER); + + if (errno == ICALL_ERRNO_SUCCESS) + { + ICall_EntityID dest; + ICall_ServiceEnum src; + ICall_HciExtEvt *pMsg = NULL; + + if (ICall_fetchServiceMsg(&src, &dest, + (void **)&pMsg) == ICALL_ERRNO_SUCCESS) + { + uint8 safeToDealloc = TRUE; + + if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity)) + { + ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg; + + // Check for BLE stack events first + if (pEvt->signature == 0xffff) + { + if (pEvt->event_flag & SBP_CONN_EVT_END_EVT) + { + // Try to retransmit pending ATT Response (if any) + SimpleBLEPeripheral_sendAttRsp(); + } + } + else + { + // Process inter-task message + safeToDealloc = SimpleBLEPeripheral_processStackMsg((ICall_Hdr *)pMsg); + } + } + + if (pMsg && safeToDealloc) + { + ICall_freeMsg(pMsg); + } + } + } + + // If RTOS queue is not empty, process app message. + while (!Queue_empty(appMsgQueue)) + { + sbpEvt_t *pMsg = (sbpEvt_t *)Util_dequeueMsg(appMsgQueue); + if (pMsg) + { + // Process message. + SimpleBLEPeripheral_processAppMsg(pMsg); + + // Free the space from the message. + ICall_free(pMsg); + } + } + + if (events & SBP_PERIODIC_EVT) + { + events &= ~SBP_PERIODIC_EVT; + + PIN_setOutputValue( hSbpPins, Board_DIO27_ANALOG, !(PIN_getOutputValue(Board_DIO27_ANALOG))); + + // Kick off next round, if we're still streaming + if (streamVariables.streamState == STREAM_STATE_ACTIVE) { +// static uint8_t period = SBP_PERIODIC_EVT_PERIOD; +// if (period == SBP_PERIODIC_EVT_PERIOD) { +// period = SBP_PERIODIC_EVT_PERIOD - 1; +// } else { +// period = SBP_PERIODIC_EVT_PERIOD; +// } +// Util_rescheduleClock(&periodicClock, period); //7-8ms delay (try to get 7.5ms on average) + Util_rescheduleClock(&periodicClock, SBP_PERIODIC_EVT_PERIOD); //8ms delay + Util_startClock(&periodicClock); + } + } + + if (events & SBP_I2S_FRAME_EVENT) + { + events &= ~SBP_I2S_FRAME_EVENT; + if (i2sStreamInProgress) { + I2SCC26XX_BufferRequest bufferRequest; + I2SCC26XX_BufferRelease bufferRelease; + bool gotBuffer = I2SCC26XX_requestBuffer(i2sHandle, &bufferRequest); + while (gotBuffer) { + PIN_setOutputValue( hSbpPins, Board_DIO26_ANALOG, 0); + // Flush on UART +// UART_write(uartHandle, bufferRequest.bufferIn, streamVariables.samplesPerFrame * sizeof(int16_t)); + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) { + sbc_encode(&sbc, (int16_t *)bufferRequest.bufferIn, streamVariables.samplesPerFrame * sizeof(int16_t), audio_encoded, MSBC_ENCODED_SIZE, &written); + audio_encoded[1] = seqNum++; + } + else { + audio_encoded[0] = (((seqNum++ % 32) << 3) | RAS_DATA_TIC1_CMD); + // Send previous PV and SI + audio_encoded[1] = streamVariables.si; + audio_encoded[2] = LO_UINT16(streamVariables.pv); + audio_encoded[3] = HI_UINT16(streamVariables.pv); + Codec1_encodeBuff((uint8_t *)&audio_encoded[4], (int16_t *)bufferRequest.bufferIn, streamVariables.samplesPerFrame, &streamVariables.si, &streamVariables.pv); + } + SimpleBLEPeripheral_transmitAudioFrame(audio_encoded); + PIN_setOutputValue( hSbpPins, Board_DIO26_ANALOG, 1); + bufferRelease.bufferHandleIn = bufferRequest.bufferHandleIn; + bufferRelease.bufferHandleOut = NULL; + I2SCC26XX_releaseBuffer(i2sHandle, &bufferRelease); + if (volume <= 70) { + if ((volume & 0x0F) == 0x04) { + // Volume control + AudioCodecMicVolCtrl(AUDIO_CODEC_TI_3254, INPUT_OPTION, volume); + } + volume++; + } + gotBuffer = I2SCC26XX_requestBuffer(i2sHandle, &bufferRequest); + } + } + } + + if (events & SBP_I2S_ERROR_EVENT) + { + events &= ~SBP_I2S_ERROR_EVENT; + PIN_setOutputValue( hSbpPins, Board_DIO27_ANALOG, 0); + + // Move to stop state + hwiKey = Hwi_disable(); + streamVariables.streamState = STREAM_STATE_SEND_STOP_CMD; + events |= SBP_SEND_STOP_CMD_EVENT; + Hwi_restore(hwiKey); + PIN_setOutputValue( hSbpPins, Board_DIO27_ANALOG, 1); + } + + if (events & SBP_SEND_STOP_CMD_EVENT) + { + events &= ~SBP_SEND_STOP_CMD_EVENT; + SimpleBLEPeripheral_sendStopCmd(); + } + + if (events & SBP_STOP_I2S_EVENT) + { + events &= ~SBP_STOP_I2S_EVENT; + SimpleBLEPeripheral_stopI2Sstream(); + } + + if (events & SBP_SEND_START_CMD_EVENT) + { + events &= ~SBP_SEND_START_CMD_EVENT; + SimpleBLEPeripheral_sendStartCmd(); + } + + if (events & SBP_START_I2S_EVENT) + { + events &= ~SBP_START_I2S_EVENT; + SimpleBLEPeripheral_startI2Sstream(); + } + +#ifdef FEATURE_OAD + while (!Queue_empty(hOadQ)) + { + oadTargetWrite_t *oadWriteEvt = Queue_dequeue(hOadQ); + + // Identify new image. + if (oadWriteEvt->event == OAD_WRITE_IDENTIFY_REQ) + { + OAD_imgIdentifyWrite(oadWriteEvt->connHandle, oadWriteEvt->pData); + } + // Write a next block request. + else if (oadWriteEvt->event == OAD_WRITE_BLOCK_REQ) + { + OAD_imgBlockWrite(oadWriteEvt->connHandle, oadWriteEvt->pData); + } + + // Free buffer. + ICall_free(oadWriteEvt); + } +#endif //FEATURE_OAD + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_processStackMsg + * + * @brief Process an incoming stack message. + * + * @param pMsg - message to process + * + * @return TRUE if safe to deallocate incoming message, FALSE otherwise. + */ +static uint8_t SimpleBLEPeripheral_processStackMsg(ICall_Hdr *pMsg) +{ + uint8_t safeToDealloc = TRUE; + + switch (pMsg->event) + { + case GATT_MSG_EVENT: + // Process GATT message + safeToDealloc = SimpleBLEPeripheral_processGATTMsg((gattMsgEvent_t *)pMsg); + break; + + case HCI_GAP_EVENT_EVENT: + { + // Process HCI message + switch(pMsg->status) + { + case HCI_COMMAND_COMPLETE_EVENT_CODE: + // Process HCI Command Complete Event + break; + + default: + break; + } + } + break; + + default: + // do nothing + break; + } + + return (safeToDealloc); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_processGATTMsg + * + * @brief Process GATT messages and events. + * + * @return TRUE if safe to deallocate incoming message, FALSE otherwise. + */ +static uint8_t SimpleBLEPeripheral_processGATTMsg(gattMsgEvent_t *pMsg) +{ + // See if GATT server was unable to transmit an ATT response + if (pMsg->hdr.status == blePending) + { + // No HCI buffer was available. Let's try to retransmit the response + // on the next connection event. + if (HCI_EXT_ConnEventNoticeCmd(pMsg->connHandle, selfEntity, + SBP_CONN_EVT_END_EVT) == SUCCESS) + { + // First free any pending response + SimpleBLEPeripheral_freeAttRsp(FAILURE); + + // Hold on to the response message for retransmission + pAttRsp = pMsg; + + // Don't free the response message yet + return (FALSE); + } + } + else if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT) + { + // ATT request-response or indication-confirmation flow control is + // violated. All subsequent ATT requests or indications will be dropped. + // The app is informed in case it wants to drop the connection. + + // Display the opcode of the message that caused the violation. + Display_print1(dispHandle, 5, 0, "FC Violated: %d", pMsg->msg.flowCtrlEvt.opcode); + } + else if (pMsg->method == ATT_MTU_UPDATED_EVENT) + { + // MTU size updated + Display_print1(dispHandle, 5, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU); + } + + // Free message payload. Needed only for ATT Protocol messages + GATT_bm_free(&pMsg->msg, pMsg->method); + + // It's safe to free the incoming message + return (TRUE); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_sendAttRsp + * + * @brief Send a pending ATT response message. + * + * @param none + * + * @return none + */ +static void SimpleBLEPeripheral_sendAttRsp(void) +{ + // See if there's a pending ATT Response to be transmitted + if (pAttRsp != NULL) + { + uint8_t status; + + // Increment retransmission count + rspTxRetry++; + + // Try to retransmit ATT response till either we're successful or + // the ATT Client times out (after 30s) and drops the connection. + status = GATT_SendRsp(pAttRsp->connHandle, pAttRsp->method, &(pAttRsp->msg)); + if ((status != blePending) && (status != MSG_BUFFER_NOT_AVAIL)) + { + // Disable connection event end notice + HCI_EXT_ConnEventNoticeCmd(pAttRsp->connHandle, selfEntity, 0); + + // We're done with the response message + SimpleBLEPeripheral_freeAttRsp(status); + } + else + { + // Continue retrying + Display_print1(dispHandle, 5, 0, "Rsp send retry: %d", rspTxRetry); + } + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_freeAttRsp + * + * @brief Free ATT response message. + * + * @param status - response transmit status + * + * @return none + */ +static void SimpleBLEPeripheral_freeAttRsp(uint8_t status) +{ + // See if there's a pending ATT response message + if (pAttRsp != NULL) + { + // See if the response was sent out successfully + if (status == SUCCESS) + { + Display_print1(dispHandle, 5, 0, "Rsp sent retry: %d", rspTxRetry); + } + else + { + // Free response payload + GATT_bm_free(&pAttRsp->msg, pAttRsp->method); + + Display_print1(dispHandle, 5, 0, "Rsp retry failed: %d", rspTxRetry); + } + + // Free response message + ICall_freeMsg(pAttRsp); + + // Reset our globals + pAttRsp = NULL; + rspTxRetry = 0; + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_processAppMsg + * + * @brief Process an incoming callback from a profile. + * + * @param pMsg - message to process + * + * @return None. + */ +static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *pMsg) +{ + switch (pMsg->hdr.event) + { + case SBP_STATE_CHANGE_EVT: + SimpleBLEPeripheral_processStateChangeEvt((gaprole_States_t)pMsg-> + hdr.state); + break; + + case SBP_KEY_CHANGE_EVT: + SimpleBLEPeripheral_handleKeys(0, pMsg->hdr.state); + break; + + default: + // Do nothing. + break; + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_stateChangeCB + * + * @brief Callback from GAP Role indicating a role state change. + * + * @param newState - new state + * + * @return None. + */ +static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState) +{ + SimpleBLEPeripheral_enqueueMsg(SBP_STATE_CHANGE_EVT, newState); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_processStateChangeEvt + * + * @brief Process a pending GAP Role state change event. + * + * @param newState - new state + * + * @return None. + */ +static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState) +{ +#ifdef PLUS_BROADCASTER + static bool firstConnFlag = false; +#endif // PLUS_BROADCASTER + + switch ( newState ) + { + case GAPROLE_STARTED: + { + uint8_t ownAddress[B_ADDR_LEN]; + + GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress); + + // Display device address + Display_print0(dispHandle, 1, 0, Util_convertBdAddr2Str(ownAddress)); + Display_print0(dispHandle, 2, 0, "Initialized"); + } + break; + + case GAPROLE_ADVERTISING: + Display_print0(dispHandle, 2, 0, "Advertising"); + break; + +#ifdef PLUS_BROADCASTER + /* After a connection is dropped a device in PLUS_BROADCASTER will continue + * sending non-connectable advertisements and shall sending this change of + * state to the application. These are then disabled here so that sending + * connectable advertisements can resume. + */ + case GAPROLE_ADVERTISING_NONCONN: + { + uint8_t advertEnabled = FALSE; + + // Disable non-connectable advertising. + GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t), + &advertEnabled); + + advertEnabled = TRUE; + + // Enabled connectable advertising. + GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), + &advertEnabled); + + // Reset flag for next connection. + firstConnFlag = false; + + SimpleBLEPeripheral_freeAttRsp(bleNotConnected); + } + break; +#endif //PLUS_BROADCASTER + + case GAPROLE_CONNECTED: + { + uint8_t peerAddress[B_ADDR_LEN]; + + GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress); + + Display_print0(dispHandle, 2, 0, "Connected"); + Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(peerAddress)); + + #ifdef PLUS_BROADCASTER + // Only turn advertising on for this state when we first connect + // otherwise, when we go from connected_advertising back to this state + // we will be turning advertising back on. + if (firstConnFlag == false) + { + uint8_t advertEnabled = FALSE; // Turn on Advertising + + // Disable connectable advertising. + GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), + &advertEnabled); + + // Set to true for non-connectabel advertising. + advertEnabled = TRUE; + + // Enable non-connectable advertising. + GAPRole_SetParameter(GAPROLE_ADV_NONCONN_ENABLED, sizeof(uint8_t), + &advertEnabled); + firstConnFlag = true; + } + #endif // PLUS_BROADCASTER + } + break; + + case GAPROLE_CONNECTED_ADV: + Display_print0(dispHandle, 2, 0, "Connected Advertising"); + break; + + case GAPROLE_WAITING: + Util_stopClock(&periodicClock); + SimpleBLEPeripheral_freeAttRsp(bleNotConnected); + + Display_print0(dispHandle, 2, 0, "Disconnected"); + + // Clear remaining lines + Display_clearLines(dispHandle, 3, 5); + break; + + case GAPROLE_WAITING_AFTER_TIMEOUT: + SimpleBLEPeripheral_freeAttRsp(bleNotConnected); + + Display_print0(dispHandle, 2, 0, "Timed Out"); + + // Clear remaining lines + Display_clearLines(dispHandle, 3, 5); + + #ifdef PLUS_BROADCASTER + // Reset flag for next connection. + firstConnFlag = false; + #endif //#ifdef (PLUS_BROADCASTER) + break; + + case GAPROLE_ERROR: + Display_print0(dispHandle, 2, 0, "Error"); + break; + + default: + Display_clearLine(dispHandle, 2); + break; + } + + // Update the state + //gapProfileState = newState; +} + + +#ifdef FEATURE_OAD +/********************************************************************* + * @fn SimpleBLEPeripheral_processOadWriteCB + * + * @brief Process a write request to the OAD profile. + * + * @param event - event type: + * OAD_WRITE_IDENTIFY_REQ + * OAD_WRITE_BLOCK_REQ + * @param connHandle - the connection Handle this request is from. + * @param pData - pointer to data for processing and/or storing. + * + * @return None. + */ +void SimpleBLEPeripheral_processOadWriteCB(uint8_t event, uint16_t connHandle, + uint8_t *pData) +{ + oadTargetWrite_t *oadWriteEvt = ICall_malloc( sizeof(oadTargetWrite_t) + \ + sizeof(uint8_t) * OAD_PACKET_SIZE); + + if ( oadWriteEvt != NULL ) + { + oadWriteEvt->event = event; + oadWriteEvt->connHandle = connHandle; + + oadWriteEvt->pData = (uint8_t *)(&oadWriteEvt->pData + 1); + memcpy(oadWriteEvt->pData, pData, OAD_PACKET_SIZE); + + Queue_enqueue(hOadQ, (Queue_Elem *)oadWriteEvt); + + // Post the application's semaphore. + Semaphore_post(sem); + } + else + { + // Fail silently. + } +} +#endif //FEATURE_OAD + +/********************************************************************* + * @fn SimpleBLEPeripheral_clockHandler + * + * @brief Handler function for clock timeouts. + * + * @param arg - event type + * + * @return None. + */ +static void SimpleBLEPeripheral_clockHandler(UArg arg) +{ + // Store the event. + events |= arg; + + // Wake up the application. + Semaphore_post(sem); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_keyChangeHandler + * + * @brief Key event handler function + * + * @param a0 - ignored + * + * @return none + */ +void SimpleBLEPeripheral_keyChangeHandler(uint8 keys) +{ + SimpleBLEPeripheral_enqueueMsg(SBP_KEY_CHANGE_EVT, keys); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_enqueueMsg + * + * @brief Creates a message and puts the message in RTOS queue. + * + * @param event - message event. + * @param state - message state. + * + * @return None. + */ +static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state) +{ + sbpEvt_t *pMsg; + + // Create dynamic pointer to message. + if ((pMsg = ICall_malloc(sizeof(sbpEvt_t)))) + { + pMsg->hdr.event = event; + pMsg->hdr.state = state; + + // Enqueue the message. + Util_enqueueMsg(appMsgQueue, sem, (uint8*)pMsg); + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_handleKeys + * + * @brief Handles all key events for this device. + * + * @param shift - true if in shift/alt. + * @param keys - bit field for key events. Valid entries: + * KEY_LEFT + * KEY_RIGHT + * + * @return none + */ +static void SimpleBLEPeripheral_handleKeys(uint8_t shift, uint8_t keys) +{ + (void)shift; // Intentionally unreferenced parameter + + // Check for both keys first + if (keys == (KEY_LEFT | KEY_RIGHT)) + { + if (streamVariables.streamState != STREAM_STATE_IDLE) + { + streamVariables.requestedStreamState = STREAM_STATE_IDLE; + streamVariables.requestedStreamType = BLE_AUDIO_CMD_STOP; + // Start chain of events to stop stream + SimpleBLEPeripheral_stopStreaming(); + } + } + else if (keys & KEY_LEFT) + { + if (streamVariables.streamState == STREAM_STATE_IDLE) { + // Start MSBC stream, from IDLE + streamVariables.streamType = BLE_AUDIO_CMD_START_MSBC; + streamVariables.samplesPerFrame = MSBC_SAMPLES_PER_FRAME; + streamVariables.notificationsPerFrame = BLEAUDIO_NUM_NOT_PER_FRAME_MSBC; + streamVariables.activeLED = Board_LED2; + streamVariables.requestedStreamType = BLE_AUDIO_CMD_NONE; + streamVariables.requestedStreamState = STREAM_STATE_ACTIVE; + SimpleBLEPeripheral_startStreaming(); + } + else if (streamVariables.streamType == BLE_AUDIO_CMD_START) { + // Change stream to mSBC, from ADPCM + streamVariables.requestedStreamType = BLE_AUDIO_CMD_START_MSBC; + streamVariables.requestedStreamState = STREAM_STATE_ACTIVE; + // Start chain of events to stop stream + SimpleBLEPeripheral_stopStreaming(); + } + } + else if (keys & KEY_RIGHT) + { + if (streamVariables.streamState == STREAM_STATE_IDLE) { + // Start ADPCM stream, from IDLE + streamVariables.streamType = BLE_AUDIO_CMD_START; + streamVariables.samplesPerFrame = ADPCM_SAMPLES_PER_FRAME; + streamVariables.notificationsPerFrame = BLEAUDIO_NUM_NOT_PER_FRAME_ADPCM; + streamVariables.activeLED = Board_LED1; + streamVariables.requestedStreamType = BLE_AUDIO_CMD_NONE; + streamVariables.requestedStreamState = STREAM_STATE_ACTIVE; + SimpleBLEPeripheral_startStreaming(); + } + else if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) { + // Change stream to ADPCM, from mSBC + streamVariables.requestedStreamType = BLE_AUDIO_CMD_START; + streamVariables.requestedStreamState = STREAM_STATE_ACTIVE; + // Start chain of events to stop stream + SimpleBLEPeripheral_stopStreaming(); + } + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_transmitAudioStreamCmd + * + * @brief Transmits GATT Notification in order to start or stop stream + * + * @param cmd - command to transmit + * + * @return SUCCESS if successful, FAILURE if not + */ +static uint8_t SimpleBLEPeripheral_transmitAudioStreamCmd(uint8_t cmd) +{ + return Audio_SetParameter(AUDIOPROFILE_START, AUDIOPROFILE_CMD_LEN, &cmd); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_transmitAudioFrame + * + * @brief Transmits processed audio frame to connected device + * + * @param buf - pointer to PDM buffer + * + * @return None. + */ +static void SimpleBLEPeripheral_transmitAudioFrame(uint8_t *buf) +{ + PIN_setOutputValue( hSbpPins, Board_DIO28_ANALOG, 0); + // Send 3 GATT notifications for every audio frame + for (int i = 0; i < streamVariables.notificationsPerFrame; ) + { + if (Audio_SetParameter(AUDIOPROFILE_AUDIO, BLEAUDIO_NOTSIZE, buf) == SUCCESS) + { + PIN_setOutputValue( hSbpPins, Board_DIO28_ANALOG, !(PIN_getOutputValue(Board_DIO28_ANALOG))); + // Move on to next section of audio frame + buf += BLEAUDIO_NOTSIZE; + i++; + PIN_setOutputValue(hSbpPins, streamVariables.activeLED, 1); + } + else + { + PIN_setOutputValue(hSbpPins, streamVariables.activeLED, 0); + } + } + PIN_setOutputValue( hSbpPins, Board_DIO28_ANALOG, 1); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_startStreaming + * + * @brief Starts streaming audio to connected device + * + * @param None. + * + * @return None. + */ +static void SimpleBLEPeripheral_startStreaming(void) +{ + uint32_t hwiKey; + // LED on while streaming + PIN_setOutputValue(hSbpPins, streamVariables.activeLED, 1); + + // Increase TX power during stream + HCI_EXT_SetTxPowerCmd(HCI_EXT_TX_POWER_5_DBM); + + // Allocate memory for decoded PCM data + pcmSamples = ICall_malloc(sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE)); + i2sParams.blockSize = streamVariables.samplesPerFrame; + i2sParams.pvContBuffer = (void *) pcmSamples; + i2sParams.ui32conBufTotalSize = sizeof(int16_t) * (streamVariables.samplesPerFrame * I2SCC26XX_QUEUE_SIZE); + I2SCC26XX_Handle i2sHandleTmp = I2SCC26XX_open(i2sHandle, &i2sParams); + + Display_print1(dispHandle, 5, 0, "Opened I2S: %d samples/frame", streamVariables.samplesPerFrame); + + if (i2sHandleTmp == i2sHandle) { + // Move to send start command + hwiKey = Hwi_disable(); + streamVariables.streamState = STREAM_STATE_SEND_START_CMD; + events |= SBP_SEND_START_CMD_EVENT; + Hwi_restore(hwiKey); + } + else { + // Return, or move to IDLE state + streamVariables.streamState = STREAM_STATE_IDLE; + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_stopStreaming + * + * @brief Stops streaming audio to connected device + * + * @param None. + * + * @return None. + */ +static void SimpleBLEPeripheral_stopStreaming(void) +{ + uint32_t hwiKey; + PIN_setOutputValue( hSbpPins, Board_DIO27_ANALOG, 0); + // Check if we're at the right state in the stopping process + if (streamVariables.streamState == STREAM_STATE_ACTIVE) { + // Start by sending STOP command + streamVariables.streamState = STREAM_STATE_SEND_STOP_CMD; + hwiKey = Hwi_disable(); + events |= SBP_SEND_STOP_CMD_EVENT; + Hwi_restore(hwiKey); + Semaphore_post(sem); + } + PIN_setOutputValue( hSbpPins, Board_DIO27_ANALOG, 1); +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_startI2Sstream + * + * @brief Start I2S stream + * + * @param None. + * + * @return None. + */ +static void SimpleBLEPeripheral_startI2Sstream(void) +{ + // Check that we're in the correct state + if (streamVariables.streamState == STREAM_STATE_START_I2S) { + if (streamVariables.requestedStreamState == STREAM_STATE_ACTIVE) { + // Try to start I2S stream + i2sStreamInProgress = I2SCC26XX_startStream(i2sHandle); + if (i2sStreamInProgress) { + // Move to ACTIVE as we have completed start sequence + streamVariables.streamState = STREAM_STATE_ACTIVE; + +// Util_rescheduleClock(&periodicClock, SBP_PERIODIC_EVT_PERIOD); //8ms delay +// Util_startClock(&periodicClock); + + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) { + Display_print0(dispHandle, 5, 0, "mSBC Stream"); + } + else if (streamVariables.streamType == BLE_AUDIO_CMD_START) { + Display_print0(dispHandle, 5, 0, "ADPCM Stream"); + } + } + else { + Display_print0(dispHandle, 5, 0, "Failed to start I2S stream"); + } + } + else { + Display_print0(dispHandle, 5, 0, "Started stream when Active was not requested"); + } + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_stopI2Sstream + * + * @brief Stop I2S stream + * + * @param None. + * + * @return None. + */ +static void SimpleBLEPeripheral_stopI2Sstream(void) +{ + // Check that we're in the correct state + if (streamVariables.streamState == STREAM_STATE_STOP_I2S) { + // Try to stop I2S stream + if (I2SCC26XX_stopStream(i2sHandle)) { + SimpleBLEPeripheral_finishStream(); + if (streamVariables.requestedStreamState == STREAM_STATE_IDLE) { + // Simply move to IDLE as we have completed stop sequence + streamVariables.streamState = STREAM_STATE_IDLE; + Display_print0(dispHandle, 5, 0, "No Stream"); + } + else if (streamVariables.requestedStreamType == BLE_AUDIO_CMD_START_MSBC) { + // Start chain of events to start stream again + streamVariables.streamType = BLE_AUDIO_CMD_START_MSBC; + streamVariables.samplesPerFrame = MSBC_SAMPLES_PER_FRAME; + streamVariables.notificationsPerFrame = BLEAUDIO_NUM_NOT_PER_FRAME_MSBC; + streamVariables.activeLED = Board_LED2; + streamVariables.requestedStreamType = BLE_AUDIO_CMD_NONE; + streamVariables.requestedStreamState = STREAM_STATE_ACTIVE; + SimpleBLEPeripheral_startStreaming(); + } + else if (streamVariables.requestedStreamType == BLE_AUDIO_CMD_START) { + streamVariables.streamType = BLE_AUDIO_CMD_START; + streamVariables.samplesPerFrame = ADPCM_SAMPLES_PER_FRAME; + streamVariables.notificationsPerFrame = BLEAUDIO_NUM_NOT_PER_FRAME_ADPCM; + streamVariables.activeLED = Board_LED1; + streamVariables.requestedStreamType = BLE_AUDIO_CMD_NONE; + streamVariables.requestedStreamState = STREAM_STATE_ACTIVE; + SimpleBLEPeripheral_startStreaming(); + } + else { + Display_print2(dispHandle, 5, 0, "Incorrect state %d.%d", + streamVariables.requestedStreamState, streamVariables.requestedStreamType); + } + } + else { + Display_print0(dispHandle, 5, 0, "Failed to stop I2S stream"); + } + } + else { + Display_print1(dispHandle, 5, 0, "Tried to stop I2S stream in state %d", streamVariables.streamState); + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_sendStartCmd + * + * @brief Sends a start command to connected device + * + * @param None. + * + * @return None. + */ +static void SimpleBLEPeripheral_sendStartCmd(void) +{ + uint32_t hwiKey; + // Check that we're in the correct state + if (streamVariables.streamState == STREAM_STATE_SEND_START_CMD) { + if (SimpleBLEPeripheral_transmitAudioStreamCmd(streamVariables.streamType) == SUCCESS) + { + PIN_setOutputValue( hSbpPins, Board_DIO27_ANALOG, 0); + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) { + // Initialize encoder + sbc_init_msbc(&sbc, 0); + } + else { + // Initialize encoder + streamVariables.pv = 0; + streamVariables.si = 0; + } + // Try next state + streamVariables.streamState = STREAM_STATE_START_I2S; + hwiKey = Hwi_disable(); + events |= SBP_START_I2S_EVENT; + Hwi_restore(hwiKey); + Semaphore_post(sem); + PIN_setOutputValue( hSbpPins, Board_DIO27_ANALOG, 1); + } + else { + // Try again + hwiKey = Hwi_disable(); + events |= SBP_SEND_START_CMD_EVENT; + Hwi_restore(hwiKey); + Semaphore_post(sem); + } + } + else { + // Try next state + hwiKey = Hwi_disable(); + events |= SBP_START_I2S_EVENT; + Hwi_restore(hwiKey); + Semaphore_post(sem); + } + +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_sendStopCmd + * + * @brief Sends a stop command to connected device + * + * @param None. + * + * @return None. + */ +static void SimpleBLEPeripheral_sendStopCmd(void) +{ + uint32_t hwiKey; + + // Check that we're in the correct state + if (streamVariables.streamState == STREAM_STATE_SEND_STOP_CMD) { + uint8_t gapRoleState; + uint8_t retVal = SUCCESS; + GAPRole_GetParameter(GAPROLE_STATE, &gapRoleState); + + if (gapRoleState == GAPROLE_CONNECTED) + { + retVal = SimpleBLEPeripheral_transmitAudioStreamCmd(BLE_AUDIO_CMD_STOP); + if (retVal == SUCCESS) + { + // Move to stop I2S stream + hwiKey = Hwi_disable(); + // Reset TX power + HCI_EXT_SetTxPowerCmd(HCI_EXT_TX_POWER_0_DBM); + streamVariables.streamState = STREAM_STATE_STOP_I2S; + events |= SBP_STOP_I2S_EVENT; + Hwi_restore(hwiKey); + } + else + { + Display_print1(dispHandle, 5, 0, "Failed to send STOP: %d", retVal); + // Try again + hwiKey = Hwi_disable(); + events |= SBP_SEND_STOP_CMD_EVENT; + Hwi_restore(hwiKey); + Semaphore_post(sem); + } + } + else + { + // Move to stop I2S stream + hwiKey = Hwi_disable(); + // Reset TX power + HCI_EXT_SetTxPowerCmd(HCI_EXT_TX_POWER_0_DBM); + streamVariables.streamState = STREAM_STATE_STOP_I2S; + events |= SBP_STOP_I2S_EVENT; + Hwi_restore(hwiKey); + } + } + else { + // Try next state + hwiKey = Hwi_disable(); + events |= SBP_STOP_I2S_EVENT; + Hwi_restore(hwiKey); + Semaphore_post(sem); + } +} + +/********************************************************************* + * @fn SimpleBLEPeripheral_finishStream + * + * @brief Finish stream + * + * @param None. + * + * @return None. + */ +void SimpleBLEPeripheral_finishStream(void) { + // LED off + PIN_setOutputValue(hSbpPins, streamVariables.activeLED, 0); + /* Turn output volume back down */ + volume = 0; + AudioCodecMicVolCtrl(AUDIO_CODEC_TI_3254, INPUT_OPTION, volume); + + // Stop potentially pending events + events &= ~(SBP_I2S_FRAME_EVENT | SBP_I2S_ERROR_EVENT); + + if (streamVariables.streamType == BLE_AUDIO_CMD_START_MSBC) + { + sbc_finish(&sbc); + } + /* Close I2S driver */ + I2SCC26XX_close(i2sHandle); + /* Free memory */ + ICall_free(pcmSamples); + pcmSamples = NULL; +} + +static void I2SCC26XX_i2sCallbackFxn(I2SCC26XX_Handle handle, I2SCC26XX_StreamNotification *notification) { + if (notification->status == I2SCC26XX_STREAM_ERROR) { + /* Let thread process PDM error */ + events |= SBP_I2S_ERROR_EVENT; + Semaphore_post(sem); + } + else if (notification->status == I2SCC26XX_STREAM_BUFFER_READY) { + // Provide buffer + events |= SBP_I2S_FRAME_EVENT; + Semaphore_post(sem); + PIN_setOutputValue( hSbpPins, Board_DIO25_ANALOG, !(PIN_getOutputValue(Board_DIO25_ANALOG))); + PIN_setOutputValue( hSbpPins, (streamVariables.activeLED == Board_LED0) ? Board_LED1 : Board_LED0, 0); + } + else { + PIN_setOutputValue( hSbpPins, (streamVariables.activeLED == Board_LED0) ? Board_LED1 : Board_LED0, 1); + } +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/examples/simple_peripheral_observer/cc26xx/app/simple_peripheral_observer.c b/src/examples/simple_peripheral_observer/cc26xx/app/simple_peripheral_observer.c index c89b1eb..a802282 100644 --- a/src/examples/simple_peripheral_observer/cc26xx/app/simple_peripheral_observer.c +++ b/src/examples/simple_peripheral_observer/cc26xx/app/simple_peripheral_observer.c @@ -1144,7 +1144,7 @@ static void SimpleBLEPeripheral_ObserverStateChangeCB(gapPeripheralObserverRoleE memcpy(pDevDiscMsg, pEvent, sizeof(gapDevDiscEvent_t)); pDevDiscMsg->pDevList = ICall_malloc((pEvent->discCmpl.numDevs)*sizeof(gapDevRec_t)); - memcpy(pDevDiscMsg->pDevList, pEvent->discCmpl.pDevList, sizeof((pEvent->discCmpl.numDevs)*sizeof(gapDevRec_t))); + memcpy(pDevDiscMsg->pDevList, pEvent->discCmpl.pDevList, (pEvent->discCmpl.numDevs)*sizeof(gapDevRec_t)); pMsg->pData = (uint8 *)pDevDiscMsg; } diff --git a/src/examples/simple_proprietary_beacon/cc26xx/app/simple_proprietary_beacon.c b/src/examples/simple_proprietary_beacon/cc26xx/app/simple_proprietary_beacon.c index b7464fc..3ccfa3f 100644 --- a/src/examples/simple_proprietary_beacon/cc26xx/app/simple_proprietary_beacon.c +++ b/src/examples/simple_proprietary_beacon/cc26xx/app/simple_proprietary_beacon.c @@ -418,7 +418,7 @@ static void SimplePropBeacon_init(void) // Setup the GAP Peripheral Role Profile { - uint8_t initialAdvertEnable = TRUE; + uint8_t initialAdvertEnable = FALSE; uint8_t initialNonConnAdvEnable = TRUE; // By setting this to zero, the device will go into the waiting state after diff --git a/src/examples/spp_ble_client/cc26xx/app/main.c b/src/examples/spp_ble_client/cc26xx/app/main.c index f65f79f..84945db 100644 --- a/src/examples/spp_ble_client/cc26xx/app/main.c +++ b/src/examples/spp_ble_client/cc26xx/app/main.c @@ -10,7 +10,7 @@ ****************************************************************************** $License: BSD3 2013 $ *****************************************************************************/ - + /******************************************************************************* * INCLUDES */ @@ -26,7 +26,7 @@ #include "bcomdef.h" #include "central.h" #include "spp_ble_client.h" -#include "inc/sdi_task.h" +#include "inc/sdi_task.h" /* Header files required to enable instruction fetch cache */ #include @@ -41,8 +41,6 @@ bleUserCfg_t user0Cfg = BLE_USER_CFG; #endif // USE_DEFAULT_USER_CFG -//#include - /******************************************************************************* * MACROS */ @@ -63,24 +61,6 @@ bleUserCfg_t user0Cfg = BLE_USER_CFG; * GLOBAL VARIABLES */ -#ifdef CC1350_LAUNCHXL -#ifdef POWER_SAVING -// Power Notify Object for wake-up callbacks -Power_NotifyObj rFSwitchPowerNotifyObj; -static uint8_t rFSwitchNotifyCb(uint8_t eventType, uint32_t *eventArg, - uint32_t *clientArg); -#endif //POWER_SAVING - -PIN_State radCtrlState; -PIN_Config radCtrlCfg[] = -{ - Board_DIO1_RFSW | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* RF SW Switch defaults to 2.4GHz path*/ - Board_DIO30_SWPWR | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* Power to the RF Switch */ - PIN_TERMINATE -}; -PIN_Handle radCtrlHandle; -#endif //CC1350_LAUNCHXL - /******************************************************************************* * EXTERNS */ @@ -103,7 +83,7 @@ extern uint16 dispHandle; * * @param None. * - * @return None. + * @return None. */ int main() { @@ -112,17 +92,6 @@ int main() PIN_init(BoardGpioInitTable); -#ifdef CC1350_LAUNCHXL - // Enable 2.4GHz Radio - radCtrlHandle = PIN_open(&radCtrlState, radCtrlCfg); - -#ifdef POWER_SAVING - Power_registerNotify(&rFSwitchPowerNotifyObj, - PowerCC26XX_ENTERING_STANDBY | PowerCC26XX_AWAKE_STANDBY, - (Power_NotifyFxn) rFSwitchNotifyCb, NULL); -#endif //POWER_SAVING -#endif //CC1350_LAUNCHXL - #ifndef POWER_SAVING /* Set constraints for Standby, powerdown and idle mode */ Power_setConstraint(PowerCC26XX_SB_DISALLOW); @@ -139,8 +108,8 @@ int main() GAPCentralRole_createTask(); /* SDI UART Example Task - Priority 2 */ - SDITask_createTask(); - + SDITask_createTask(); + /* Kick off application - Priority 1 */ SPPBLEClient_createTask(); @@ -264,7 +233,7 @@ static uint8_t rFSwitchNotifyCb(uint8_t eventType, uint32_t *eventArg, // Power up RF Switch PIN_setOutputValue(radCtrlHandle, Board_DIO30_SWPWR, 1); } - + // Notification handled successfully return Power_NOTIFYDONE; } diff --git a/src/examples/spp_ble_client/cc26xx/app/spp_ble_client.c b/src/examples/spp_ble_client/cc26xx/app/spp_ble_client.c index 9b55ba5..cab6faa 100644 --- a/src/examples/spp_ble_client/cc26xx/app/spp_ble_client.c +++ b/src/examples/spp_ble_client/cc26xx/app/spp_ble_client.c @@ -69,7 +69,6 @@ #include "util.h" #include "board_key.h" -//#include #include "board.h" #include "ble_user_config.h" @@ -176,7 +175,7 @@ #define SBC_TASK_STACK_SIZE 864 #endif - + // Application states enum { @@ -203,14 +202,14 @@ enum */ // RTOS queue for profile/app messages. -typedef struct _queueRec_ +typedef struct _queueRec_ { Queue_Elem _elem; // queue element uint8_t *pData; // pointer to app data } queueRec_t; // App event passed from profiles. -typedef struct +typedef struct { appEvtHdr_t hdr; // event header uint8_t *pData; // event data pointer @@ -219,7 +218,7 @@ typedef struct // App event passed from profiles. typedef struct { - uint8_t data[SERIALPORTSERVICE_DATA_LEN]; // New data + uint8_t *pData; // New data uint8_t length; // New status } sbcUARTEvt_t; @@ -270,7 +269,7 @@ static Queue_Handle appMsgQueue; // Queue object used for UART messages static Queue_Struct appUARTMsg; -static Queue_Handle appUARTMsgQueue; +static Queue_Handle appUARTMsgQueue; // Task pending events static uint16_t events = 0; @@ -323,6 +322,9 @@ static bool procedureInProgress = FALSE; // Maximum PDU size (default = 27 octets) static uint16 maxPduSize; +// Maximum MTU size (default = 23 octets) +static uint16 currentMTUSize; + // Pins that are actively used by the application static PIN_Config SPPBLEAppPinTable[] = { @@ -437,9 +439,9 @@ void SPPBLEClient_blinkLed(uint8_t led, uint8_t nBlinks) for (i=0; ipData; - + if (pMsg && (state == BLE_STATE_CONNECTED)) { // Process message. bStatus_t retVal = FAILURE; - // Do a write - attWriteReq_t req; - - //Allocate data bytes to send over the air - req.pValue = GATT_bm_alloc(connHandle, ATT_WRITE_REQ, pMsg->length, NULL); - - if ( (req.pValue != NULL) && charDataHdl) - { - req.handle = charDataHdl; //handle for Value of Data characteristic found during service discovery - req.len = pMsg->length; - memcpy(req.pValue, pMsg->data, pMsg->length); - req.sig = FALSE; - req.cmd = TRUE; + // Do a write + attWriteReq_t req; + + //Allocate data bytes to send over the air + req.pValue = GATT_bm_alloc(connHandle, ATT_WRITE_REQ, pMsg->length, NULL); + + if ( (req.pValue != NULL) && charDataHdl) + { + req.handle = charDataHdl; //handle for Value of Data characteristic found during service discovery + req.len = pMsg->length; + memcpy(req.pValue, pMsg->pData, pMsg->length); + req.sig = FALSE; + req.cmd = TRUE; retVal = GATT_WriteNoRsp(connHandle, &req); - + if ( retVal != SUCCESS ) { GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ); - DEBUG("FAIL FROM CLIENT"); + DEBUG("FAIL FROM CLIENT: "); DEBUG((uint8_t*)convInt32ToText((int)retVal)); DEBUG_NEWLINE(); }else { //Remove from the queue @@ -671,10 +673,11 @@ static void SPPBLEClient_taskFxn(UArg a0, UArg a1) //Toggle LED to indicate data received from UART terminal and sent over the air //SPPBLEClient_toggleLed(Board_GLED, Board_LED_TOGGLE); - + + ICall_freeMsg(pMsg->pData); // Free the space from the message. ICall_free(pMsg); - + if(!Queue_empty(appUARTMsgQueue)) { // Wake up the application to flush out any remaining UART data in the queue. @@ -682,11 +685,11 @@ static void SPPBLEClient_taskFxn(UArg a0, UArg a1) } } } - + } } - + // If RTOS queue is not empty, process app message while (!Queue_empty(appMsgQueue)) { @@ -700,23 +703,23 @@ static void SPPBLEClient_taskFxn(UArg a0, UArg a1) ICall_free(pMsg); } } - - + + if (events & SBC_UART_CHANGE_EVT) - { + { // Process message. uint8 retVal; attWriteReq_t req; uint8 configData[2] = {0x01,0x00}; - + events &= ~SBC_UART_CHANGE_EVT; - + req.pValue = GATT_bm_alloc(connHandle, ATT_WRITE_REQ, 2, NULL); - - if ((charCCCDHdl == NULL) && (charDataHdl != NULL)) {charCCCDHdl = charDataHdl + 1;} //Hardcoded + + if ((charCCCDHdl == NULL) && (charDataHdl != NULL)) {charCCCDHdl = charDataHdl + 1;} //Hardcoded if ( (req.pValue != NULL) && charCCCDHdl) { - req.handle = charCCCDHdl; //Handle for CCCD of Data characteristic + req.handle = charCCCDHdl; //Handle for CCCD of Data characteristic req.len = 2; memcpy(req.pValue, configData, 2); req.cmd = TRUE; //Has to be true for NoRsp from server(command, not request) @@ -730,30 +733,30 @@ static void SPPBLEClient_taskFxn(UArg a0, UArg a1) { DEBUG("Notification enabled...\n\r"); } - } + } } - + if (events & SBC_START_DISCOVERY_EVT) { events &= ~SBC_START_DISCOVERY_EVT; - + if(!scanningStarted) - SPPBLEClient_startDiscovery(); - + SPPBLEClient_startDiscovery(); + } if (events & SBC_AUTO_CONNECT_EVT) { events &= ~SBC_AUTO_CONNECT_EVT; -#if defined (CLIENT_AUTO_CONNECT) && (CLIENT_AUTO_CONNECT == TRUE) +#if defined (CLIENT_AUTO_CONNECT) && (CLIENT_AUTO_CONNECT == TRUE) SPPBLEClient_autoConnect(); #endif } - - - + + + } } @@ -882,10 +885,10 @@ static void SPPBLEClient_processRoleEvent(gapCentralRoleEvent_t *pEvent) Display_print0(dispHandle, 1, 0, Util_convertBdAddr2Str(pEvent->initDone.devAddr)); Display_print0(dispHandle, 2, 0, "Initialized"); - -#if defined (CLIENT_AUTO_CONNECT) && (CLIENT_AUTO_CONNECT == TRUE) + +#if defined (CLIENT_AUTO_CONNECT) && (CLIENT_AUTO_CONNECT == TRUE) SPPBLEClient_genericHandler(SBC_AUTO_CONNECT_EVT); -#endif +#endif } break; @@ -898,7 +901,7 @@ static void SPPBLEClient_processRoleEvent(gapCentralRoleEvent_t *pEvent) pEvent->deviceInfo.pEvtData, pEvent->deviceInfo.dataLen)) { - SPPBLEClient_addDeviceInfo(pEvent->deviceInfo.addr, + SPPBLEClient_addDeviceInfo(pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType); } } @@ -940,7 +943,7 @@ static void SPPBLEClient_processRoleEvent(gapCentralRoleEvent_t *pEvent) procedureInProgress = TRUE; SPPBLEClient_toggleLed(Board_GLED, Board_LED_TOGGLE); - + // If service discovery not performed initiate service discovery if (charDataHdl == 0) { @@ -1005,19 +1008,19 @@ static void SPPBLEClient_processRoleEvent(gapCentralRoleEvent_t *pEvent) static void SPPBLEClient_handleKeys(uint8_t shift, uint8_t keys) { (void)shift; // Intentionally unreferenced parameter - - - // Set Packet Length in a Connection + + + // Set Packet Length in a Connection if (keys & KEY_RIGHT) { //SPPBLEClient_toggleLed(Board_GLED, Board_LED_TOGGLE); - + if (state == BLE_STATE_CONNECTED ) - { + { //Request max supported size uint16_t requestedPDUSize = APP_SUGGESTED_PDU_SIZE; uint16_t requestedTxTime = APP_SUGGESTED_TX_TIME; - + //This API is documented in hci.h if(SUCCESS != HCI_LE_SetDataLenCmd(connHandle, requestedPDUSize, requestedTxTime)) { @@ -1028,7 +1031,7 @@ static void SPPBLEClient_handleKeys(uint8_t shift, uint8_t keys) { uint8_t addrType; uint8_t *peerAddr; - + // Connect or disconnect if (state == BLE_STATE_IDLE) { @@ -1038,9 +1041,9 @@ static void SPPBLEClient_handleKeys(uint8_t shift, uint8_t keys) // connect to current device in scan result peerAddr = devList[scanIdx].addr; addrType = devList[scanIdx].addrType; - + state = BLE_STATE_CONNECTING; - + GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE, DEFAULT_LINK_WHITE_LIST, addrType, peerAddr); @@ -1053,7 +1056,7 @@ static void SPPBLEClient_handleKeys(uint8_t shift, uint8_t keys) if (keys & KEY_LEFT) { //SPPBLEClient_toggleLed(Board_RLED, Board_LED_TOGGLE); - + // Start or stop discovery if (state == BLE_STATE_CONNECTED && charDataHdl != 0 && @@ -1092,7 +1095,7 @@ static void SPPBLEClient_handleKeys(uint8_t shift, uint8_t keys) } else { -#if defined (CLIENT_AUTO_CONNECT) && (CLIENT_AUTO_CONNECT == TRUE) +#if defined (CLIENT_AUTO_CONNECT) && (CLIENT_AUTO_CONNECT == TRUE) SPPBLEClient_genericHandler(SBC_AUTO_CONNECT_EVT); #endif } @@ -1113,7 +1116,7 @@ void SPPBLEClient_autoConnect(void) { uint8_t addrType; uint8_t peerAddr[6]; - + // connect to hardcoded device address i.e. 0x050403020100 int x = 0; for(x = 0; x<6; x++) @@ -1124,7 +1127,7 @@ void SPPBLEClient_autoConnect(void) addrType = ADDRTYPE_PUBLIC; DEBUG("Auto connecting..."); DEBUG_NEWLINE(); - + GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE, DEFAULT_LINK_WHITE_LIST, addrType, peerAddr); @@ -1142,12 +1145,12 @@ static void SPPBLEClient_processGATTMsg(gattMsgEvent_t *pMsg) { if (state == BLE_STATE_CONNECTED) { - + if(pMsg->method == ATT_HANDLE_VALUE_NOTI) - { + { //Send received bytes to serial port - SDITask_sendToUART(pMsg->msg.handleValueNoti.pValue, pMsg->msg.handleValueNoti.len); - + SDITask_sendToUART(pMsg->msg.handleValueNoti.pValue, pMsg->msg.handleValueNoti.len); + //Toggle LED to indicate data received from client SPPBLEClient_toggleLed(Board_RLED, Board_LED_TOGGLE); } @@ -1203,6 +1206,11 @@ static void SPPBLEClient_processGATTMsg(gattMsgEvent_t *pMsg) } else if (pMsg->method == ATT_MTU_UPDATED_EVENT) { + currentMTUSize = pMsg->msg.mtuEvt.MTU; + SDITask_setAppDataSize(currentMTUSize); + + DEBUG("MTU Size: "); DEBUG((uint8_t*)convInt32ToText((int)currentMTUSize)); DEBUG_NEWLINE(); + // MTU size updated Display_print1(dispHandle, 4, 0, "MTU Size: %d", pMsg->msg.mtuEvt.MTU); } @@ -1237,13 +1245,13 @@ static void SPPBLEClient_processCmdCompleteEvt(hciEvt_CmdComplete_t *pMsg) DEBUG("Max TX bytes: "); DEBUG((uint8_t*)convInt32ToText((int)pMsg->pReturnParam[1] + (pMsg->pReturnParam[2]<<8))); DEBUG_NEWLINE(); DEBUG("Max TX time: "); - DEBUG((uint8_t*)convInt32ToText((int)pMsg->pReturnParam[3] + (pMsg->pReturnParam[4]<<8))); DEBUG_NEWLINE(); + DEBUG((uint8_t*)convInt32ToText((int)pMsg->pReturnParam[3] + (pMsg->pReturnParam[4]<<8))); DEBUG_NEWLINE(); DEBUG("Max RX bytes: "); - DEBUG((uint8_t*)convInt32ToText((int)pMsg->pReturnParam[5] + (pMsg->pReturnParam[6]<<8))); DEBUG_NEWLINE(); + DEBUG((uint8_t*)convInt32ToText((int)pMsg->pReturnParam[5] + (pMsg->pReturnParam[6]<<8))); DEBUG_NEWLINE(); DEBUG("Max RX time: "); DEBUG((uint8_t*)convInt32ToText((int)pMsg->pReturnParam[7] + (pMsg->pReturnParam[8]<<8))); DEBUG_NEWLINE(); break; - + // case HCI_READ_RSSI: // { // int8 rssi = (int8)pMsg->pReturnParam[3]; @@ -1531,21 +1539,18 @@ static void SPPBLEClient_startDiscovery(void) * @return none */ static void SPPBLEClient_processGATTDiscEvent(gattMsgEvent_t *pMsg) -{ +{ if (discState == BLE_DISC_STATE_MTU) { // MTU size response received, discover simple BLE service if (pMsg->method == ATT_EXCHANGE_MTU_RSP) { uint8_t uuid[ATT_UUID_SIZE] = { TI_BASE_UUID_128(SERIALPORTSERVICE_SERV_UUID) }; - - DEBUG("Server receive MTU: "); - DEBUG((uint8_t*)convInt32ToText((int)pMsg->msg.exchangeMTURsp.serverRxMTU)); DEBUG_NEWLINE(); - + discState = BLE_DISC_STATE_SVC; - - DEBUG("Discovering services..."); - + + DEBUG("Discovering services..."); DEBUG_NEWLINE(); + // Discovery simple BLE service VOID GATT_DiscPrimaryServiceByUUID(connHandle, uuid, ATT_UUID_SIZE, selfEntity); @@ -1561,9 +1566,9 @@ static void SPPBLEClient_processGATTDiscEvent(gattMsgEvent_t *pMsg) svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0); DEBUG("Found Serial Port Service..."); } - + // If procedure complete - if (((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP) && + if (((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP) && (pMsg->hdr.status == bleProcedureComplete)) || (pMsg->method == ATT_ERROR_RSP)) { @@ -1571,34 +1576,34 @@ static void SPPBLEClient_processGATTDiscEvent(gattMsgEvent_t *pMsg) { attReadByTypeReq_t req; uint8_t uuid[ATT_UUID_SIZE] = { TI_BASE_UUID_128(SERIALPORTSERVICE_DATA_UUID) }; - + // Discover characteristic discState = BLE_DISC_STATE_CHAR; - + req.startHandle = svcStartHdl; req.endHandle = svcEndHdl; req.type.len = ATT_UUID_SIZE; memcpy(req.type.uuid, uuid, ATT_UUID_SIZE); - + //DEBUG("Reading UUIDs..."); - + // Discover characteristic descriptors GATT_DiscAllCharDescs(connHandle, svcStartHdl + 1, svcEndHdl, - selfEntity); + selfEntity); } } } else if (discState == BLE_DISC_STATE_CHAR) - { + { // Characteristic descriptors found if (pMsg->method == ATT_FIND_INFO_RSP && - pMsg->msg.findInfoRsp.numInfo > 0) + pMsg->msg.findInfoRsp.numInfo > 0) { uint8_t i; - + // For each handle/uuid pair for (i = 0; i < pMsg->msg.findInfoRsp.numInfo; i++) { @@ -1627,27 +1632,27 @@ static void SPPBLEClient_processGATTDiscEvent(gattMsgEvent_t *pMsg) } } } - - + + // If procedure complete - if ((pMsg->method == ATT_FIND_INFO_RSP && + if ((pMsg->method == ATT_FIND_INFO_RSP && pMsg->hdr.status == bleProcedureComplete) || (pMsg->method == ATT_ERROR_RSP)) { - + //Enable notification on peripheral(after a few seconds delay, let it finish connection/discovery process) { Util_startClock(&startNotiEnableClock); } - - procedureInProgress = FALSE; + + procedureInProgress = FALSE; discState = BLE_DISC_STATE_IDLE; } - - - - + + + + } } @@ -1893,16 +1898,22 @@ static void SPPBLEClient_genericHandler(UArg arg) void SPPBLEClient_enqueueUARTMsg(uint8_t event, uint8_t *data, uint8_t len) { sbcUARTEvt_t *pMsg; - + //Enqueue message only in a connected state if(state == BLE_STATE_CONNECTED) { // Create dynamic pointer to message. if (pMsg = ICall_malloc(sizeof(sbcUARTEvt_t))) { - memcpy(pMsg->data , data, len); + + pMsg->pData = (uint8 *)ICall_allocMsg(len); + if(pMsg->pData) + { + //payload + memcpy(pMsg->pData , data, len); + } pMsg->length = len; - + // Enqueue the message. Util_enqueueMsg(appUARTMsgQueue, sem, (uint8_t *)pMsg); } diff --git a/src/examples/spp_ble_server/cc26xx/app/spp_ble_server.c b/src/examples/spp_ble_server/cc26xx/app/spp_ble_server.c index 27fbf06..0a90972 100644 --- a/src/examples/spp_ble_server/cc26xx/app/spp_ble_server.c +++ b/src/examples/spp_ble_server/cc26xx/app/spp_ble_server.c @@ -71,7 +71,7 @@ #ifdef USE_RCOSC #include "rcosc_calibration.h" #endif //USE_RCOSC - + //#include #include "board_key.h" @@ -79,7 +79,7 @@ #include "serial_port_service.h" #include "spp_ble_server.h" -#include "inc/sdi_task.h" +#include "inc/sdi_task.h" #include "inc/sdi_tl_uart.h" @@ -157,7 +157,7 @@ * TYPEDEFS */ // RTOS queue for profile/app messages. -typedef struct _queueRec_ +typedef struct _queueRec_ { Queue_Elem _elem; // queue element uint8_t *pData; // pointer to app data @@ -173,9 +173,9 @@ typedef struct typedef struct { uint8_t event; // Type of event - uint8_t data[SERIALPORTSERVICE_DATA_LEN]; // New data + uint8_t *pData; // New data uint8_t length; // New status -} sbpUARTEvt_t; //size = 22 bytes +} sbpUARTEvt_t; /********************************************************************* * GLOBAL VARIABLES */ @@ -186,6 +186,9 @@ typedef struct // Global pin resources PIN_State pinGpioState; PIN_Handle hGpioPin; + +uint16 currentMTUSize; + /********************************************************************* * LOCAL VARIABLES */ @@ -205,7 +208,7 @@ static Queue_Handle appMsgQueue; // Queue object used for UART messages static Queue_Struct appUARTMsg; -static Queue_Handle appUARTMsgQueue; +static Queue_Handle appUARTMsgQueue; #if defined(FEATURE_OAD) // Event data from OAD profile. @@ -249,7 +252,7 @@ static uint8_t scanRspData[] = 'V', 'E', 'R', - + // connection interval range 0x05, // length of this data GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE, @@ -304,7 +307,7 @@ static uint8_t rspTxRetry = 0; static PIN_Config SPPBLEAppPinTable[] = { Board_RLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ - Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ + Board_GLED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX, /* LED initially off */ PIN_TERMINATE }; @@ -413,9 +416,9 @@ void SPPBLEServer_blinkLed(uint8_t led, uint8_t nBlinks) for (i=0; ipData; - + if (pMsg && ((gapProfileState == GAPROLE_CONNECTED) || (gapProfileState == GAPROLE_CONNECTED_ADV))) { bStatus_t retVal = FAILURE; switch(pMsg->event) { -// case SBP_UART_ERROR_EVT: -// { -// SerialPortService_AddStatusErrorCount((UART_Status)pMsg->data); -// //Remove from queue -// Util_dequeueMsg(appUARTMsgQueue); -// // Free the space from the message. -// ICall_free(pMsg); -// -// break; -// } - case SBP_UART_DATA_EVT: { //Send the notification - retVal = SerialPortService_SetParameter(SERIALPORTSERVICE_CHAR_DATA, pMsg->length, pMsg->data); + retVal = SerialPortService_SetParameter(SERIALPORTSERVICE_CHAR_DATA, pMsg->length, pMsg->pData); if(retVal != SUCCESS) { @@ -718,18 +710,20 @@ static void SPPBLEServer_taskFxn(UArg a0, UArg a1) else { //Increment TX status counter - SerialPortService_AddStatusTXBytes(pMsg->length); - + SerialPortService_AddStatusTXBytes(pMsg->length); + //Remove from queue Util_dequeueMsg(appUARTMsgQueue); - + //Toggle LED to indicate data received from UART terminal and sent over the air - //SPPBLEServer_toggleLed(Board_LED2, Board_LED_TOGGLE); - + //SPPBLEServer_toggleLed(Board_GLED, Board_LED_TOGGLE); + + //Deallocate data payload being transmitted. + ICall_freeMsg(pMsg->pData); // Free the space from the message. ICall_free(pMsg); } - + if(!Queue_empty(appUARTMsgQueue)) { // Wake up the application to flush out any remaining UART data in the queue. @@ -742,8 +736,8 @@ static void SPPBLEServer_taskFxn(UArg a0, UArg a1) } } } - - + + // If RTOS queue is not empty, process app message. while (!Queue_empty(appMsgQueue)) { @@ -758,7 +752,7 @@ static void SPPBLEServer_taskFxn(UArg a0, UArg a1) } } } - + if (events & SBP_PERIODIC_EVT) { events &= ~SBP_PERIODIC_EVT; @@ -875,9 +869,10 @@ static uint8_t SPPBLEServer_processGATTMsg(gattMsgEvent_t *pMsg) else if (pMsg->method == ATT_MTU_UPDATED_EVENT) { // MTU size updated - Display_print1(dispHandle, 5, 0, "MTU Size: $d", pMsg->msg.mtuEvt.MTU); - DEBUG("MTU Updated: "); - DEBUG((uint8_t*)convInt32ToText((int)pMsg->msg.mtuEvt.MTU)); DEBUG_NEWLINE(); + currentMTUSize = pMsg->msg.mtuEvt.MTU; + SDITask_setAppDataSize(currentMTUSize); + Display_print1(dispHandle, 5, 0, "MTU Size: %d", currentMTUSize); + DEBUG("MTU Size: "); DEBUG((uint8_t*)convInt32ToText((int)currentMTUSize)); DEBUG_NEWLINE(); } // Free message payload. Needed only for ATT Protocol messages @@ -978,11 +973,11 @@ static void SPPBLEServer_processAppMsg(sbpEvt_t *pMsg) SPPBLEServer_processStateChangeEvt((gaprole_States_t)pMsg-> hdr.state); break; - + case SBP_KEY_CHANGE_EVT: SPPBLEServer_handleKeys(0, pMsg->hdr.state); break; - + case SBP_CHAR_CHANGE_EVT: SPPBLEServer_processCharValueChangeEvt(pMsg->hdr.state); break; @@ -1092,17 +1087,18 @@ static void SPPBLEServer_processStateChangeEvt(gaprole_States_t newState) uint8_t numActive = 0; Util_startClock(&periodicClock); - + numActive = linkDB_NumActive(); - + connHandle = numActive - 1; - + // Use numActive to determine the connection handle of the last // connection if ( linkDB_GetInfo( numActive - 1, &linkInfo ) == SUCCESS ) { Display_print1(dispHandle, 2, 0, "Num Conns: %d", (uint16_t)numActive); Display_print0(dispHandle, 3, 0, Util_convertBdAddr2Str(linkInfo.addr)); + DEBUG("CONNECTED..."); DEBUG_NEWLINE(); } else { @@ -1116,7 +1112,7 @@ static void SPPBLEServer_processStateChangeEvt(gaprole_States_t newState) } SPPBLEServer_toggleLed(Board_GLED, Board_LED_TOGGLE); - + #ifdef PLUS_BROADCASTER // Only turn advertising on for this state when we first connect // otherwise, when we go from connected_advertising back to this state @@ -1151,6 +1147,7 @@ static void SPPBLEServer_processStateChangeEvt(gaprole_States_t newState) Display_print0(dispHandle, 2, 0, "Disconnected"); + DEBUG("DISCONNECTED..."); DEBUG_NEWLINE(); // Clear remaining lines //Display_clearLines(dispHandle, 3, 5); break; @@ -1159,7 +1156,7 @@ static void SPPBLEServer_processStateChangeEvt(gaprole_States_t newState) SPPBLEServer_freeAttRsp(bleNotConnected); Display_print0(dispHandle, 2, 0, "Timed Out"); - + DEBUG("DISCONNECTED AFTER TIMEOUT..."); DEBUG_NEWLINE(); // Clear remaining lines //Display_clearLines(dispHandle, 3, 5); @@ -1212,7 +1209,7 @@ static void SPPBLEServer_charValueChangeCB(uint8_t paramID) static void SPPBLEServer_processCharValueChangeEvt(uint8_t paramID) { - + } /********************************************************************* @@ -1311,10 +1308,15 @@ void SPPBLEServer_enqueueUARTMsg(uint8_t event, uint8_t *data, uint8_t len) { // Create dynamic pointer to message. if (pMsg = ICall_malloc(sizeof(sbpUARTEvt_t))) - { - + { + pMsg->event = event; - memcpy(pMsg->data , data, len); + pMsg->pData = (uint8 *)ICall_allocMsg(len); + if(pMsg->pData) + { + //payload + memcpy(pMsg->pData , data, len); + } pMsg->length = len; // Enqueue the message. @@ -1363,20 +1365,20 @@ static void SPPBLEServer_enqueueMsg(uint8_t event, uint8_t state) static void SPPBLEServer_handleKeys(uint8_t shift, uint8_t keys) { (void)shift; // Intentionally unreferenced parameter - - - // Set Packet Length in a Connection + + + // Set Packet Length in a Connection if (keys & KEY_RIGHT) { //SPPBLEServer_toggleLed(Board_GLED, Board_LED_TOGGLE); - + if (gapProfileState == GAPROLE_CONNECTED ) - { + { //Request max supported size uint16_t requestedPDUSize = APP_SUGGESTED_PDU_SIZE; uint16_t requestedTxTime = APP_SUGGESTED_TX_TIME; - + //This API is documented in hci.h if(SUCCESS != HCI_LE_SetDataLenCmd(connHandle, requestedPDUSize, requestedTxTime)) { @@ -1390,15 +1392,15 @@ static void SPPBLEServer_handleKeys(uint8_t shift, uint8_t keys) if (keys & KEY_LEFT) { //SPPBLEServer_toggleLed(Board_RLED, Board_LED_TOGGLE); - + // Start or stop discovery if (gapProfileState == GAPROLE_CONNECTED) { uint8_t status; - + //Send the notification - status = SerialPortService_SetParameter(SERIALPORTSERVICE_CHAR_DATA, 1, &charVal); - + status = SerialPortService_SetParameter(SERIALPORTSERVICE_CHAR_DATA, 1, &charVal); + if(status == SUCCESS){ charVal++; } diff --git a/src/profiles/audio/audio_profile.c b/src/profiles/audio/audio_profile.c new file mode 100644 index 0000000..5a7d972 --- /dev/null +++ b/src/profiles/audio/audio_profile.c @@ -0,0 +1,517 @@ +/****************************************************************************** + + @file audio_profile.c + + @brief This file contains the audio profile sample service profile for use + with the BLE sample application. + + Group: WCS, BTS + Target Device: CC2650, CC2640, CC1350 + + ****************************************************************************** + + Copyright (c) 2015-2016, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + Release Name: ble_sdk_2_02_01_18 + Release Date: 2016-10-26 15:20:04 + *****************************************************************************/ + +/********************************************************************* + * INCLUDES + */ +#include +#include "bcomdef.h" +#include "OSAL.h" +#include "linkdb.h" +#include "att.h" +#include "gatt.h" +#include "gatt_uuid.h" +#include "gattservapp.h" +#include "gapbondmgr.h" +#include "peripheral.h" + +#include "audio_profile.h" +#include "ll.h" + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * CONSTANTS + */ + +/********************************************************************* + * TYPEDEFS + */ + +/********************************************************************* + * GLOBAL VARIABLES + */ +// audio GATT Profile Service UUID: 0xB000 +static CONST uint8 audioProfileServUUID[ATT_UUID_SIZE] = +{ + TI_BASE_UUID_128(AUDIO_SERV_UUID) +}; + +// Start/Stop Characteristic UUID: 0xB001 +static CONST uint8 audioProfileStartUUID[ATT_UUID_SIZE] = +{ + TI_BASE_UUID_128(AUDIOPROFILE_START_UUID) +}; + +// Audio Stream Characteristic UUID: 0xB002 +static CONST uint8 audioProfileAudioUUID[ATT_UUID_SIZE] = +{ + TI_BASE_UUID_128(AUDIOPROFILE_AUDIO_UUID) +}; + + +/********************************************************************* + * EXTERNAL VARIABLES + */ + +/********************************************************************* + * EXTERNAL FUNCTIONS + */ + +/********************************************************************* + * LOCAL VARIABLES + */ + +/********************************************************************* + * Profile Attributes - variables + */ +// Audio Profile Service attribute +static CONST gattAttrType_t audioProfileService = {ATT_UUID_SIZE, + audioProfileServUUID}; + +// Audio Profile Start/Stop Characteristic Properties +static uint8 audioProfileStartProps = GATT_PROP_READ | GATT_PROP_NOTIFY; + +// Start/Stop Characteristic Value +static uint8 audioProfileStart = 0; + +// Start/Stop Characteristic Configuration Descriptor Value +static gattCharCfg_t *audioProfileStartConfig; + +// Simple Profile Audio Stream Characteristic Properties +static uint8 audioProfileAudioProps = GATT_PROP_READ | GATT_PROP_NOTIFY; + +// Audio Stream Characteristic Value +static uint8_t audioProfileAudio[BLEAUDIO_NOTSIZE]; + +// Audio Stream Characteristic Configuration Descriptor Value +static gattCharCfg_t *audioProfileAudioConfig; + + +/********************************************************************* + * Profile Attributes - Table + */ + +static gattAttribute_t audioProfileAttrTbl[] = +{ + // Audio Profile Service + { + {ATT_BT_UUID_SIZE, primaryServiceUUID}, /* type */ + GATT_PERMIT_READ, /* permissions */ + 0, /* handle */ + (uint8 *)&audioProfileService /* pValue */ + }, + + // Start/Stop Characteristic Declaration + { + {ATT_BT_UUID_SIZE, characterUUID}, + GATT_PERMIT_READ, + 0, + &audioProfileStartProps + }, + + // Start/Stop Characteristic Value + { + {ATT_UUID_SIZE, audioProfileStartUUID}, + GATT_PERMIT_READ, + 0, + &audioProfileStart + }, + + // Start/Stop Characteristic configuration + { + {ATT_BT_UUID_SIZE, clientCharCfgUUID}, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8 *)&audioProfileStartConfig + }, + + // Audio Stream Characteristic Declaration + { + {ATT_BT_UUID_SIZE, characterUUID}, + GATT_PERMIT_READ, + 0, + &audioProfileAudioProps + }, + + // Audio Stream Characteristic Value + { + {ATT_UUID_SIZE, audioProfileAudioUUID}, + GATT_PERMIT_READ, + 0, + (uint8 *)audioProfileAudio + }, + + // Audio Stream Characteristic configuration + { + {ATT_BT_UUID_SIZE, clientCharCfgUUID}, + GATT_PERMIT_READ | GATT_PERMIT_WRITE, + 0, + (uint8 *)&audioProfileAudioConfig + }, +}; + +/********************************************************************* + * LOCAL FUNCTIONS + */ +static uint8 audioProfile_ReadAttrCB(uint16 connHandle, gattAttribute_t *pAttr, + uint8 *pValue, uint16 *pLen, uint16 offset, + uint16 maxLen, uint8 method); +static bStatus_t audioProfile_WriteAttrCB(uint16 connHandle, + gattAttribute_t *pAttr, + uint8 *pValue, + uint16 len, + uint16 offset, + uint8 method); + +/********************************************************************* + * PROFILE CALLBACKS + */ +// Audio Profile Service Callbacks +// Note: When an operation on a characteristic requires authorization and +// pfnAuthorizeAttrCB is not defined for that characteristic's service, the +// Stack will report a status of ATT_ERR_UNLIKELY to the client. When an +// operation on a characteristic requires authorization the Stack will call +// pfnAuthorizeAttrCB to check a client's authorization prior to calling +// pfnReadAttrCB or pfnWriteAttrCB, so no checks for authorization need to be +// made within these functions. +static CONST gattServiceCBs_t audioProfileCBs = +{ + audioProfile_ReadAttrCB, // Read callback function pointer + audioProfile_WriteAttrCB, // Write callback function pointer + NULL // Authorization callback function pointer +}; + +/********************************************************************* + * PUBLIC FUNCTIONS + */ + +/********************************************************************* + * @fn Audio_AddService + * + * @brief Initializes the Audio Profile service by registering + * GATT attributes with the GATT server. + * + * @return SUCCESS, bleMemAllocError, or return value of + * GATTServApp_RegisterService + */ +bStatus_t Audio_AddService(void) +{ + uint8 status = SUCCESS; + + // Allocate Audio Cmd Client Characteristic Configuration table + audioProfileStartConfig = (gattCharCfg_t *)ICall_malloc(sizeof(gattCharCfg_t)* + linkDBNumConns ); + if (audioProfileStartConfig == NULL) + { + return bleMemAllocError; + } + + // Initialize Audio Cmd Client Characteristic Configuration attributes + GATTServApp_InitCharCfg(INVALID_CONNHANDLE, audioProfileStartConfig); + + // Allocate Audio Stream Client Characteristic Configuration table + audioProfileAudioConfig = (gattCharCfg_t *)ICall_malloc(sizeof(gattCharCfg_t)* + linkDBNumConns); + if (audioProfileAudioConfig == NULL) + { + return bleMemAllocError; + } + + // Initialize Audio Stream Client Characteristic Configuration attributes + GATTServApp_InitCharCfg(INVALID_CONNHANDLE, audioProfileAudioConfig); + + // Register GATT attribute list and CBs with GATT Server App + status = GATTServApp_RegisterService(audioProfileAttrTbl, + GATT_NUM_ATTRS(audioProfileAttrTbl), + GATT_MAX_ENCRYPT_KEY_SIZE, + &audioProfileCBs); + + return status; +} + +/********************************************************************* + * @fn Audio_SetParameter + * + * @brief Set an Audio Profile parameter. + * + * @param param - Profile parameter ID + * @param len - length of data to write + * @param value - pointer to data to write. This is dependent on + * the parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be cast to + * uint16 pointer). + * + * @return SUCCESS, bleInvalidRange, INVALIDPARAMETER, or return + * value of GATTServApp_ProcessCharCfg + */ +bStatus_t Audio_SetParameter(uint8 param, uint8 len, void *value) +{ + bStatus_t ret = SUCCESS; + + switch (param) + { + case AUDIOPROFILE_START: + if (len == sizeof (audioProfileStart)) + { + audioProfileStart = *((uint8*)value); + + // See if Notifications have been enabled and send + ret = GATTServApp_ProcessCharCfg(audioProfileStartConfig, + &audioProfileStart, + FALSE, + audioProfileAttrTbl, + GATT_NUM_ATTRS(audioProfileAttrTbl), + INVALID_TASK_ID, + audioProfile_ReadAttrCB); + } + else + { + ret = bleInvalidRange; + } + break; + + case AUDIOPROFILE_AUDIO: + { + VOID memcpy(audioProfileAudio, value, BLEAUDIO_NOTSIZE); + + // See if Notifications have been enabled and send + ret = GATTServApp_ProcessCharCfg(audioProfileAudioConfig, + (uint8_t *)audioProfileAudio, + FALSE, + audioProfileAttrTbl, + GATT_NUM_ATTRS(audioProfileAttrTbl), + INVALID_TASK_ID, + audioProfile_ReadAttrCB); + } + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ret; +} + +/********************************************************************* + * @fn Audio_GetParameter + * + * @brief Get a Audio Profile parameter. + * + * @param param - Profile parameter ID + * @param value - pointer to data to put. This is dependent on + * the parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be cast to + * uint16 pointer). + * + * @return SUCCESS or INVALIDPARAMETER + */ +bStatus_t Audio_GetParameter(uint8 param, void *value) +{ + bStatus_t ret = SUCCESS; + + switch (param) + { + case AUDIOPROFILE_START: + *((uint8*)value) = audioProfileStart; + break; + + case AUDIOPROFILE_AUDIO: + VOID memcpy(value, audioProfileAudio, BLEAUDIO_NOTSIZE); + break; + + default: + ret = INVALIDPARAMETER; + break; + } + + return ret; +} + +/********************************************************************* + * @fn audioProfile_ReadAttrCB + * + * @brief Read an attribute. + * + * @param connHandle - connection message was received on + * @param pAttr - pointer to attribute + * @param pValue - pointer to data to be read + * @param pLen - length of data to be read + * @param offset - offset of the first octet to be read + * @param maxLen - maximum length of data to be read + * @param method - type of read message + * + * @return SUCCESS, ATT_ERR_INSUFFICIENT_AUTHOR, + * ATT_ERR_ATTR_NOT_LONG, or ATT_ERR_INVALID_HANDLE + */ +static uint8 audioProfile_ReadAttrCB(uint16 connHandle, + gattAttribute_t *pAttr, + uint8 *pValue, + uint16 *pLen, + uint16 offset, + uint16 maxLen, + uint8 method) +{ + bStatus_t status = SUCCESS; + + // Make sure it's not a blob operation (no attributes in the profile are long) + if (offset > 0) + { + return ATT_ERR_ATTR_NOT_LONG; + } + + if (pAttr->type.len == ATT_UUID_SIZE) + { + // 128-bit UUID + uint16 uuid = BUILD_UINT16(pAttr->type.uuid[12], pAttr->type.uuid[13]); + switch (uuid) + { + case AUDIOPROFILE_START_UUID: + // Let remote side know the current state of play + *pLen = sizeof(audioProfileStart); + pValue[0] = *pAttr->pValue; + break; + + case AUDIOPROFILE_AUDIO_UUID: + *pLen = BLEAUDIO_NOTSIZE; + VOID memcpy(pValue, pAttr->pValue, BLEAUDIO_NOTSIZE); + break; + + default: + // Should never get here! + *pLen = 0; + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + // 16-bit UUID + *pLen = 0; + status = ATT_ERR_INVALID_HANDLE; + } + + return status; +} + +/********************************************************************* + * @fn audioProfile_WriteAttrCB + * + * @brief Validate attribute data prior to a write operation + * + * @param connHandle - connection message was received on + * @param pAttr - pointer to attribute + * @param pValue - pointer to data to be written + * @param len - length of data + * @param offset - offset of the first octet to be written + * @param method - type of read message + * + * @return SUCCESS, ATT_ERR_INSUFFICIENT_AUTHOR, + * ATT_ERR_ATTR_NOT_LONG, or ATT_ERR_INVALID_HANDLE + */ +static bStatus_t audioProfile_WriteAttrCB(uint16 connHandle, + gattAttribute_t *pAttr, + uint8 *pValue, + uint16 len, + uint16 offset, + uint8 method) +{ + bStatus_t status = SUCCESS; + + if (offset != 0) + { + return ATT_ERR_ATTR_NOT_LONG; + } + + if (pAttr->type.len == ATT_BT_UUID_SIZE) + { + // 16-bit UUID + uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]); + switch (uuid) + { + case GATT_CLIENT_CHAR_CFG_UUID: + status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len, + offset, GATT_CLIENT_CFG_NOTIFY); + break; + + default: + // Should never get here! + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else if (pAttr->type.len == ATT_UUID_SIZE) + { + // 128-bit UUID + uint16 uuid = BUILD_UINT16(pAttr->type.uuid[12], pAttr->type.uuid[13]); + switch (uuid) + { + case AUDIOPROFILE_START_UUID: + case AUDIOPROFILE_AUDIO_UUID: + // Write not permitted + status = ATT_ERR_WRITE_NOT_PERMITTED; + break; + + default: + // Should never get here! + status = ATT_ERR_ATTR_NOT_FOUND; + break; + } + } + else + { + status = ATT_ERR_INVALID_HANDLE; + } + + return status; +} + +/********************************************************************* +*********************************************************************/ diff --git a/src/profiles/audio/audio_profile.h b/src/profiles/audio/audio_profile.h new file mode 100644 index 0000000..9bb5877 --- /dev/null +++ b/src/profiles/audio/audio_profile.h @@ -0,0 +1,204 @@ +/****************************************************************************** + + @file audio_profile.h + + @brief This file contains the audio profile sample service profile for use + with the BLE sample application. + + Group: WCS, BTS + Target Device: CC2650, CC2640, CC1350 + + ****************************************************************************** + + Copyright (c) 2015-2016, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + Release Name: ble_sdk_2_02_01_18 + Release Date: 2016-10-26 15:20:04 + *****************************************************************************/ + +#ifndef AUDIOPROFILE_H +#define AUDIOPROFILE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************* + * INCLUDES + */ + +/********************************************************************* + * CONSTANTS + */ +// Profile Parameters +#define AUDIOPROFILE_START 0 +#define AUDIOPROFILE_AUDIO 1 + +// Audio Profile Service UUID +#define AUDIO_SERV_UUID 0xB000 + +// Key Pressed UUID +#define AUDIOPROFILE_START_UUID 0xB001 +#define AUDIOPROFILE_AUDIO_UUID 0xB002 + +#define AUDIOPROFILE_CMD_LEN 1 + +#define BLEAUDIO_BUFSIZE 96 +#define BLEAUDIO_HDRSIZE 4 + +#ifdef DLE_ENABLED // Data Length Extension Enable +#define BLEAUDIO_NOTSIZE 100 +#define BLEAUDIO_NUM_NOT_PER_FRAME 1 +#else +#define BLEAUDIO_NOTSIZE 20 +#define BLEAUDIO_NUM_NOT_PER_FRAME 5 +#endif +/********************************************************************* + * TYPEDEFS + */ +typedef struct audioServiceConfig +{ + uint8 mode; + uint16 l2capCh; +} audioServiceConfig_t; + +/********************************************************************* + * MACROS + */ + +/********************************************************************* + * Profile Callbacks + */ + +// Callback when a characteristic value has changed +typedef void (*audioProfileChange_t)(uint8 paramID); + +typedef struct +{ + // Called when characteristic value changes + audioProfileChange_t pfnAudioProfileChange; +} audioProfileCBs_t; + + + +/********************************************************************* + * API FUNCTIONS + */ + +/********************************************************************* + * @fn Audio_AddService + * + * @brief Initializes the Audio Profile service by registering + * GATT attributes with the GATT server. + * + * @param None. + * + * @return Generic BLE status return + */ +extern bStatus_t Audio_AddService(void); + +/********************************************************************* + * @fn Audio_SetParameter + * + * @brief Set an Audio Profile parameter. + * + * @param param - Profile parameter ID + * @param len - length of data to right + * @param value - pointer to data to write. This is dependent on + * the parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be cast to + * uint16 pointer). + * + * @return Generic BLE status return + */ +extern bStatus_t Audio_SetParameter(uint8 param, uint8 len, void *value); + +/********************************************************************* + * @fn Audio_GetParameter + * + * @brief Get an Audio Profile parameter. + * + * @param param - Profile parameter ID + * @param value - pointer to data to read. This is dependent on + * the parameter ID and WILL be cast to the appropriate + * data type (example: data type of uint16 will be cast to + * uint16 pointer). + * + * @return Generic BLE status return + */ +extern bStatus_t Audio_GetParameter(uint8 param, void *value); + +/********************************************************************* + * @fn Audio_ProcessEvent + * + * @brief Audio Profile event handler routine. + * + * @param taskID - The HCI Test Application OSAL task identifer. + * @param events - HCI Test Application OSAL task events. + * + * @return Unprocessed events. + */ +extern uint16 Audio_ProcessEvent(uint8 task_id, uint16 events); + +/********************************************************************* + * @fn Audio_StartTxStreaming + * + * @brief This is the Audio Pofile start function that + * will start audio streaming. + * + * @param None. + * + * @return None. + */ +extern void Audio_StartTxStreaming(void); + +/********************************************************************* + * @fn Audio_StopTxStreaming + * + * @brief This is the Audio Pofile stop function that + * will stop audio streaming. + * + * @param None. + * + * @return None. + */ +extern void Audio_StopTxStreaming(void); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif // AUDIOPROFILE_H diff --git a/src/util/audio_codec/I2SCC26XX.c b/src/util/audio_codec/I2SCC26XX.c new file mode 100644 index 0000000..97a3361 --- /dev/null +++ b/src/util/audio_codec/I2SCC26XX.c @@ -0,0 +1,1203 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// TODO: Create correct path +//#include +#include "I2SCC26XX.h" + +#include + +/* driverlib header files */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* I2SCC26XX functions */ +void I2SCC26XX_init(I2SCC26XX_Handle handle); +I2SCC26XX_Handle I2SCC26XX_open(I2SCC26XX_Handle handle, I2SCC26XX_Params *params); +void I2SCC26XX_close(I2SCC26XX_Handle handle); +bool I2SCC26XX_startStream(I2SCC26XX_Handle handle); +bool I2SCC26XX_stopStream(I2SCC26XX_Handle handle); +bool I2SCC26XX_requestBuffer(I2SCC26XX_Handle handle, I2SCC26XX_BufferRequest *bufferRequest); +void I2SCC26XX_releaseBuffer(I2SCC26XX_Handle handle, I2SCC26XX_BufferRelease *bufferRelease); +/* Internal functions */ +static void I2SCC26XX_initHw(I2SCC26XX_Handle handle); +static bool I2SCC26XX_initIO(I2SCC26XX_Handle handle); +static void I2SCC26XX_hwiFxn (UArg arg); +static void I2SCC26XX_callback(I2SCC26XX_Handle handle, I2SCC26XX_StreamNotification *msg); +static void I2SCC26XX_cleanUpQueues(); + +#ifdef I2S_DEBUG + static int32_t dbgCntDmaIn = 0, dbgCntDmaOut = 0, dbgCntPtrErr = 0; + static int32_t dbgCntI2SReqBuf = 0; + static int32_t dbgCntI2SRelBuf = 0; +#endif //I2S_DEBUG + +#ifdef I2S_DEBUG +typedef enum { + NODE_INDICATOR_NO_QUEUE, // 0: not part of queue + NODE_INDICATOR_AVAIL_QUEUE, // 1: part of available + NODE_INDICATOR_READY_QUEUE, // 2: part of ready, + NODE_INDICATOR_NEXT, // 3: next + NODE_INDICATOR_ACTIVE, // 4: active + NODE_INDICATOR_USER, // 5: handled by user + NODE_INDICATOR_REUSED, // 6: reusable +} queueIndicator_t; +#endif +typedef struct +{ + Queue_Elem _elem; // queue element +#ifdef I2S_DEBUG + queueIndicator_t queueIndicator; +#endif //I2S_DEBUG + void *buf; // Buffer pointer, allocated by caller + // TODO: Add output buffer +} queueNodeI2S_t; + +//queueNodeI2S_t nodeTable[NUM_OF_NODES]; + +#ifdef I2S_DEBUG +static queueNodeI2S_t * shadowQueueNodeTable[I2SCC26XX_QUEUE_SIZE]; +#endif //I2S_DEBUG + +static queueNodeI2S_t *i2sBlockActiveIn = NULL; // Reference to the element which is currently being filled by I2S DMA In +static queueNodeI2S_t *i2sBlockNextIn = NULL; // Reference to the next element which will be filled by I2S DMA In +static queueNodeI2S_t *i2sBlockRepeatIn = NULL; // Reference to an reusable element which will be filled by I2S DMA In + +static queueNodeI2S_t *i2sBlockActiveOut = NULL; // Reference to the element which is currently being used by I2S DMA Out +static queueNodeI2S_t *i2sBlockNextOut = NULL; // Reference to the next element which will be used by I2S DMA Out +static queueNodeI2S_t *i2sBlockRepeatOut = NULL; // Reference to an reusable element which will be used by I2S DMA Out + +static Queue_Struct i2sBlockAvailIn; +static Queue_Handle i2sBlockAvailInQueue; + +static Queue_Struct i2sBlockReadyIn; +static Queue_Handle i2sBlockReadyInQueue; + +static Queue_Struct i2sBlockAvailOut; +static Queue_Handle i2sBlockAvailOutQueue; + +static Queue_Struct i2sBlockReadyOut; +static Queue_Handle i2sBlockReadyOutQueue; + +I2SControlTable g_ControlTable; + +/* + * ======== I2SCC26XX_init ======== + * @pre Function assumes that the handle is not NULL + */ +void I2SCC26XX_init(I2SCC26XX_Handle handle) { + I2SCC26XX_Object *object; + + /* Get the pointer to the object */ + object = handle->object; + + /* Mark the object as available */ + object->isOpen = false; + + /* Make sure struct in driverlib I2S driver is initialized */ + g_pControlTable = &g_ControlTable; +} + +/* + * ======== I2SCC26XX_open ======== + * @pre Function assumes that the handle is not NULL + */ +I2SCC26XX_Handle I2SCC26XX_open(I2SCC26XX_Handle handle, I2SCC26XX_Params *params) { + /* Use union to save on stack allocation */ + union { + Semaphore_Params semParams; + Hwi_Params hwiParams; + } paramsUnion; + I2SCC26XX_Object *object; + I2SCC26XX_HWAttrs const *hwAttrs; + unsigned int key; + + /* Get the pointer to the object and hwAttrs */ + object = handle->object; + hwAttrs = handle->hwAttrs; + + /* Disable preemption while checking if the I2S is open. */ + key = Hwi_disable(); + + /* Check if the I2S is open already with the base addr. */ + if (object->isOpen == true) { + Hwi_restore(key); + + Log_warning1("I2S:(%p) already in use.", hwAttrs->baseAddr); + + return (NULL); + } + + /* Mark the handle as being used */ + object->isOpen = true; + Hwi_restore(key); + + /* Initialize the I2S object */ + object->currentStream = NULL; + object->requestMode = params->requestMode; + object->ui32requestTimeout = params->ui32requestTimeout; + object->i32SampleRate = params->i32SampleRate; + object->audioClkCfg = params->audioClkCfg; + object->audioPinCfg = params->audioPinCfg; + object->audioFmtCfg = params->audioFmtCfg; + object->blockSize = params->blockSize; + object->pvContBuffer = params->pvContBuffer; + object->ui32conBufTotalSize = params->ui32conBufTotalSize; + object->pvContMgtBuffer = params->pvContMgtBuffer; + object->ui32conMgtBufTotalSize = params->ui32conMgtBufTotalSize; + object->currentStream = params->currentStream; + object->currentStream->status = I2SCC26XX_STREAM_IDLE; + + /* The following are constants that apply to PDM */ + object->i32SampleRate = 0;//I2S_SAMPLE_RATE_16K; /* If negative then use user configured clock division */ + object->audioClkCfg.wclkDiv = 250; //16 /* I2S Word Clock divider override*/ + object->audioClkCfg.sampleOnPositiveEdge = I2SCC26XX_SampleEdge_Postive; /* I2S Sample Edge */ + object->audioClkCfg.wclkPhase = I2SCC26XX_WordClockPhase_Dual; /* I2S Word Clock Phase */ + object->audioClkCfg.wclkInverted = I2SCC26XX_ClockSource_Normal; /* I2S Invert Word Clock */ + object->audioClkCfg.wclkSource = I2SCC26XX_WordClockSource_Int; /* I2S Word Clock source */ + object->audioClkCfg.bclkDiv = 6;//94; /* I2S Bit Clock divider override */ + object->audioClkCfg.reserved = 0; + object->audioClkCfg.bclkSource = I2SCC26XX_BitClockSource_Int; /* I2S Bit Clock source */ + object->audioClkCfg.mclkDiv = 4; /* I2S Master Clock divider override */ + + object->audioPinCfg.bitFields.ad1Usage = I2SCC26XX_ADUsageDisabled; /* I2S AD1 usage (0: Disabled, 1: Input, 2: Output) */ + object->audioPinCfg.bitFields.enableMclkPin = I2SCC26XX_GENERIC_DISABLED;/* I2S Enable Master clock output on pin */ + object->audioPinCfg.bitFields.reserved = 0; + object->audioPinCfg.bitFields.ad1NumOfChannels = 0; /* I2S AD1 number of channels (1 - 8). !Must match channel mask */ + object->audioPinCfg.bitFields.ad1ChannelMask = I2SCC26XX_DISABLED_MODE; /* I2S AD1 Channel Mask */ +#ifdef AUDIO_RECEIVER + object->audioPinCfg.bitFields.ad0Usage = I2SCC26XX_ADUsageOutput; /* I2S AD0 usage (0: Disabled, 1: Input, 2: Output) */ +#else //AUDIO_TRANSMITTER + object->audioPinCfg.bitFields.ad0Usage = I2SCC26XX_ADUsageInput; /* I2S AD0 usage (0: Disabled, 1: Input, 2: Output) */ +#endif + object->audioPinCfg.bitFields.enableWclkPin = I2SCC26XX_GENERIC_ENABLED; /* I2S Enable Word clock output on pin */ + object->audioPinCfg.bitFields.enableBclkPin = I2SCC26XX_GENERIC_ENABLED; /* I2S Enable Bit clock output on pin */ + object->audioPinCfg.bitFields.ad0NumOfChannels = 1; /* I2S AD0 number of channels (1 - 8). !Must match channel mask. \sa PDM_NUM_OF_CHANNELS */ + object->audioPinCfg.bitFields.ad0ChannelMask = I2SCC26XX_MONO_MODE; /* I2S AD0 Channel Mask */ + + object->audioFmtCfg.wordLength = I2SCC26XX_WordLength16; /* Number of bits per word (8-24). Exact for single phase, max for dual phase */ + object->audioFmtCfg.sampleEdge = I2SCC26XX_PositiveEdge; /* Data and Word clock is samples, and clocked out, on opposite edges of BCLK */ + object->audioFmtCfg.dualPhase = I2SCC26XX_DualPhase; /* Selects dual- or single phase format (0: Single, 1: Dual) */ + object->audioFmtCfg.memLen = I2SCC26XX_MemLen16bit; /* Size of each word stored to or loaded from memory (0: 16, 1: 24) */ + object->audioFmtCfg.dataDelay = I2SCC26XX_FormatI2SandDSP; /* Number of BCLK perids between a WCLK edge and MSB of the first word in a phase */ + // Find out how many channels are In and Out respectively + uint8_t ui8TotalNumberOfChannelsIn = 0; + uint8_t ui8TotalNumberOfChannelsOut = 0; + switch (object->audioPinCfg.bitFields.ad0Usage) + { + case I2SCC26XX_ADUsageInput: + ui8TotalNumberOfChannelsIn += object->audioPinCfg.bitFields.ad0NumOfChannels; + break; + case I2SCC26XX_ADUsageOutput: + ui8TotalNumberOfChannelsOut += object->audioPinCfg.bitFields.ad0NumOfChannels; + break; + } + switch (object->audioPinCfg.bitFields.ad1Usage) + { + case I2SCC26XX_ADUsageInput: + ui8TotalNumberOfChannelsIn += object->audioPinCfg.bitFields.ad1NumOfChannels; + break; + case I2SCC26XX_ADUsageOutput: + ui8TotalNumberOfChannelsOut += object->audioPinCfg.bitFields.ad1NumOfChannels; + break; + } + + uint32_t ui32BlockSizeInBytesIn = (object->blockSize * ( (object->audioFmtCfg.memLen) ? 3 : 2 ) * ui8TotalNumberOfChannelsIn); + uint32_t ui32BlockSizeInBytesOut = (object->blockSize * ( (object->audioFmtCfg.memLen) ? 3 : 2 ) * ui8TotalNumberOfChannelsOut); + uint32_t ui32NumberOfBlocks = (object->ui32conBufTotalSize/(ui32BlockSizeInBytesIn + ui32BlockSizeInBytesOut)); + if (ui32NumberOfBlocks < I2SCC26XX_MIN_ALLOWED_QUEUE_SIZE) { + Log_warning2("I2S:(%p) Buffer size %d too small.", + hwAttrs->baseAddr, + ui32BlockSizeInBytesIn * ui32NumberOfBlocks); + + /* Release power dependency - i.e. potentially power down serial domain. */ + //Power_releaseDependency(hwAttrs->powerMngrId); + + /* Mark the module as available */ + key = Hwi_disable(); + object->isOpen = false; + Hwi_restore(key); + + /* Signal back to application that I2S driver was not succesfully opened */ + return (NULL); + } + /* Check if we have enough buffer for management */ + uint32_t ui32TotalNumberOfBlocks = 0; + if (ui32BlockSizeInBytesIn) { + ui32TotalNumberOfBlocks += ui32NumberOfBlocks; + } + if (ui32BlockSizeInBytesOut) { + ui32TotalNumberOfBlocks += ui32NumberOfBlocks; + } + if ( (ui32TotalNumberOfBlocks * sizeof(queueNodeI2S_t)) < object->ui32conMgtBufTotalSize ) { + /* Not enough memory has been allocated */ + Log_warning0("Not enough memory provided"); + + /* Release power dependency - i.e. potentially power down serial domain. */ + //Power_releaseDependency(hwAttrs->powerMngrId); + + /* Mark the module as available */ + key = Hwi_disable(); + object->isOpen = false; + Hwi_restore(key); + + /* Signal back to application that I2S driver was not succesfully opened */ + return (NULL); + } + + Log_print2(Diags_USER2,"I2S:(%p) Found memory for %d blocks", + hwAttrs->baseAddr, ui32NumberOfBlocks); + + /* Register power dependency - i.e. power up and enable clock for I2S. */ + Power_setDependency(hwAttrs->powerMngrId); + /* Add dependency on uDMA to keep bus alive in IDLE */ + Power_setDependency(PowerCC26XX_PERIPH_UDMA); + + /* Configure IOs after hardware has been initialized so that IOs aren't */ + /* toggled unnecessary and make sure it was successful */ + if (!I2SCC26XX_initIO(handle)) { + /* Trying to use I2S driver when some other driver or application + * has already allocated these pins, error! */ + Log_warning0("Could not allocate I2S pins, already in use."); + + /* Release power dependency - i.e. potentially power down serial domain. */ + Power_releaseDependency(hwAttrs->powerMngrId); + + /* Mark the module as available */ + key = Hwi_disable(); + object->isOpen = false; + Hwi_restore(key); + + /* Signal back to application that I2S driver was not succesfully opened */ + return (NULL); + } + + /* First part of the buffer is used for input */ + if (ui32BlockSizeInBytesIn) { + int i = 0; + /* Setup queues now that we now whether they are needed */ + Queue_construct(&i2sBlockReadyIn, NULL); + i2sBlockReadyInQueue = Queue_handle(&i2sBlockReadyIn); + + Queue_construct(&i2sBlockAvailIn, NULL); + i2sBlockAvailInQueue = Queue_handle(&i2sBlockAvailIn); + + for (i = 0; i < ui32NumberOfBlocks ; i++) { + queueNodeI2S_t * tmpNode = (queueNodeI2S_t *)&((uint8_t *)object->pvContMgtBuffer)[i * sizeof(queueNodeI2S_t)]; + // Split continuous buffer + tmpNode->buf = &((uint8_t *)object->pvContBuffer)[i * ui32BlockSizeInBytesIn]; + if (i == (ui32NumberOfBlocks - 1)) { + i2sBlockRepeatIn = tmpNode; +#ifdef I2S_DEBUG + tmpNode->queueIndicator = NODE_INDICATOR_REUSED; +#endif //I2S_DEBUG + } + else { + Queue_enqueue(i2sBlockAvailInQueue, &tmpNode->_elem); +#ifdef I2S_DEBUG + tmpNode->queueIndicator = NODE_INDICATOR_AVAIL_QUEUE; +#endif //I2S_DEBUG + } +#ifdef I2S_DEBUG + shadowQueueNodeTable[i] = tmpNode; +#endif //I2S_DEBUG + } + } + else { + i2sBlockReadyInQueue = NULL; + } + /* Second part of the buffer is used for output */ + if (ui32BlockSizeInBytesOut) { + int i = 0; + /* Setup queues now that we now whether they are needed */ + Queue_construct(&i2sBlockReadyOut, NULL); + i2sBlockReadyOutQueue = Queue_handle(&i2sBlockReadyOut); + + Queue_construct(&i2sBlockAvailOut, NULL); + i2sBlockAvailOutQueue = Queue_handle(&i2sBlockAvailOut); + + uint32_t ui32NumberOfBlocksIn = object->ui32conBufTotalSize/ui32BlockSizeInBytesIn; + for (i = 0; i < ui32NumberOfBlocks ; i++) { + queueNodeI2S_t * tmpNode = (queueNodeI2S_t *)&((uint8_t *)object->pvContMgtBuffer)[(i * sizeof(queueNodeI2S_t)) + (ui32NumberOfBlocksIn * sizeof(queueNodeI2S_t))]; + // Split continuous buffer + tmpNode->buf = &((uint8_t *)object->pvContBuffer)[(i * ui32BlockSizeInBytesOut) + (ui32NumberOfBlocks * ui32BlockSizeInBytesIn)]; + if (i == (ui32NumberOfBlocks - 1)) { + i2sBlockRepeatOut = tmpNode; +#ifdef I2S_DEBUG + tmpNode->queueIndicator = NODE_INDICATOR_REUSED; +#endif //I2S_DEBUG + } + else { + Queue_enqueue(i2sBlockAvailOutQueue, &tmpNode->_elem); +#ifdef I2S_DEBUG + tmpNode->queueIndicator = NODE_INDICATOR_AVAIL_QUEUE; +#endif //I2S_DEBUG + } +#ifdef I2S_DEBUG + shadowQueueNodeTable[i] = tmpNode; +#endif //I2S_DEBUG + } + } + else { + i2sBlockReadyOutQueue = NULL; + } + + /* Create the Hwi for this I2S peripheral. */ + Hwi_Params_init(¶msUnion.hwiParams); + paramsUnion.hwiParams.arg = (UArg) handle; + paramsUnion.hwiParams.priority = hwAttrs->intPriority; + Hwi_construct(&(object->hwi), (int) hwAttrs->intNum, I2SCC26XX_hwiFxn, ¶msUnion.hwiParams, NULL); + + /* Create a semaphore to block task execution while stopping the stream */ + Semaphore_Params_init(¶msUnion.semParams); + paramsUnion.semParams.mode = Semaphore_Mode_BINARY; + Semaphore_construct(&(object->semStopping), 0, ¶msUnion.semParams); + + /* Check the transfer mode */ + if (object->requestMode == I2SCC26XX_MODE_BLOCKING) { + Log_print1(Diags_USER2, "I2S:(%p) in I2SCC26XX_MODE_BLOCKING mode", + hwAttrs->baseAddr); + + /* Create a semaphore to block task execution for the duration of the + * I2S transfer */ + Semaphore_Params_init(¶msUnion.semParams); + paramsUnion.semParams.mode = Semaphore_Mode_COUNTING; + Semaphore_construct(&(object->blockComplete), 0, ¶msUnion.semParams); + + /* Store internal callback function */ + object->callbackFxn = I2SCC26XX_callback; + } + else { + Log_print1(Diags_USER2, "I2S:(%p) in I2SCC26XX_MODE_NONBLOCKING mode", hwAttrs->baseAddr); + + /* Check to see if a callback function was defined for async mode */ + Assert_isTrue(params->callbackFxn != NULL, NULL); + + /* Save the callback function pointer */ + object->callbackFxn = params->callbackFxn; + } + + Log_print1(Diags_USER2, "I2S:(%p) opened", hwAttrs->baseAddr); + + /* Register notification functions */ +// Power_registerNotify(&object->i2sPostObj, Power_AWAKE_STANDBY, (Fxn)i2sPostNotify, (UInt32)handle, NULL ); + + return (handle); +} + +/* + * ======== I2SCC26XX_close ======== + * @pre Function assumes that the handle is not NULL + */ +void I2SCC26XX_close(I2SCC26XX_Handle handle) { + unsigned int key; + I2SCC26XX_Object *object; + I2SCC26XX_HWAttrs const *hwAttrs; + + /* Get the pointer to the object and hwAttrs */ + hwAttrs = handle->hwAttrs; + object = handle->object; + + /* Deallocate pins */ + PIN_close(object->pinHandle); + + /* Disable the I2S */ + I2SDisable(hwAttrs->baseAddr); + + /* Destroy the Hwi */ + Hwi_destruct(&(object->hwi)); + + /* Release power dependency on I2S. */ + Power_releaseDependency(hwAttrs->powerMngrId); + /* Release power dependency on UDMA. */ + Power_releaseDependency(PowerCC26XX_PERIPH_UDMA); + + /* Destroy the stopping semaphore */ + Semaphore_destruct(&(object->semStopping)); + + if (object->requestMode == I2SCC26XX_MODE_BLOCKING) { + /* Destroy the block complete semaphore */ + Semaphore_destruct(&(object->blockComplete)); + } + + /* Clean up queues before destroying queues*/ + I2SCC26XX_cleanUpQueues(); + + if (i2sBlockReadyInQueue) { + Queue_destruct(&i2sBlockReadyIn); + Queue_destruct(&i2sBlockAvailIn); + } + + i2sBlockActiveIn = NULL; + i2sBlockNextIn = NULL; + + if (i2sBlockReadyOutQueue) { + Queue_destruct(&i2sBlockReadyOut); + Queue_destruct(&i2sBlockAvailOut); + } + + i2sBlockActiveOut = NULL; + i2sBlockNextOut = NULL; + + /* Mark the module as available */ + key = Hwi_disable(); + object->isOpen = false; + Hwi_restore(key); + + Log_print1(Diags_USER2, "I2S:(%p) closed", hwAttrs->baseAddr); +} + +/* + * ======== I2SCC26XX_hwiFxn ======== + * ISR for the I2S + */ +static void I2SCC26XX_hwiFxn (UArg arg) { + I2SCC26XX_StreamNotification *notification; + I2SCC26XX_Object *object; + I2SCC26XX_HWAttrs const *hwAttrs; + uint32_t intStatus; + + /* Get the pointer to the object and hwAttrs */ + object = ((I2SCC26XX_Handle)arg)->object; + hwAttrs = ((I2SCC26XX_Handle)arg)->hwAttrs; + + Log_print1(Diags_USER2, "I2S:(%p) interrupt context start", hwAttrs->baseAddr); + + /* Get the interrupt status of the I2S controller */ + intStatus = I2SIntStatus(hwAttrs->baseAddr, true); + I2SIntClear(hwAttrs->baseAddr, intStatus); + + if (intStatus & I2S_IRQMASK_AIF_DMA_IN) { +#ifdef I2S_DEBUG + dbgCntDmaIn++; + if (dbgCntDmaIn == 2) { + asm(" NOP"); + } + if (dbgCntDmaIn == 300) { + asm(" NOP"); + } +#endif //I2S_DEBUG + /* Move completed buffer to ready queue, if not reusable buffer */ + if (i2sBlockActiveIn != i2sBlockRepeatIn) { + /* Move completed buffer to ready queue */ + Queue_put(i2sBlockReadyInQueue, &i2sBlockActiveIn->_elem); +#ifdef I2S_DEBUG + i2sBlockActiveIn->queueIndicator = NODE_INDICATOR_READY_QUEUE; +#endif //I2S_DEBUG + } + /* Setup next active buffer */ + i2sBlockActiveIn = i2sBlockNextIn; + /* Mark next buffer as empty*/ + i2sBlockNextIn = NULL; +#ifdef I2S_DEBUG + // Avoid null-pointer exception + if (i2sBlockActiveIn) { + i2sBlockActiveIn->queueIndicator = NODE_INDICATOR_ACTIVE; + } + else { + // This can happen if stream is stopping + asm(" NOP"); + } +#endif //I2S_DEBUG + + if (object->currentStream->status == I2SCC26XX_STREAM_STOPPING) { + /* Part of shut down sequence*/ + object->currentStream->status = I2SCC26XX_STREAM_STOPPED; + } + else if (object->currentStream->status != I2SCC26XX_STREAM_STOPPED) { + if (!Queue_empty(i2sBlockAvailInQueue)) { + i2sBlockNextIn = Queue_get(i2sBlockAvailInQueue); +#ifdef I2S_DEBUG + i2sBlockNextIn->queueIndicator = NODE_INDICATOR_NEXT; +#endif //I2S_DEBUG + I2SPointerSet(hwAttrs->baseAddr, true, (uint32_t *)i2sBlockNextIn->buf); + /* Buffer is ready */ + object->currentStream->status = I2SCC26XX_STREAM_BUFFER_READY; + } + else + { + //ITM_Port32(2) = 0xDEADABBA; + object->currentStream->status = I2SCC26XX_STREAM_BUFFER_READY_BUT_NO_AVAILABLE_BUFFERS; + // Send reusable frames + i2sBlockNextIn = i2sBlockRepeatIn; +#ifdef I2S_DEBUG + i2sBlockNextIn->queueIndicator = NODE_INDICATOR_REUSED; +#endif //I2S_DEBUG + I2SPointerSet(hwAttrs->baseAddr, true, (uint32_t *)i2sBlockNextIn->buf); + } + + /* Use a temporary stream pointer in case the callback function + * attempts to perform another I2SCC26XX_bufferRequest call + */ + notification = object->currentStream; + + /* Notify caller about availability of buffer */ + object->callbackFxn((I2SCC26XX_Handle)arg, notification); + } + } + + if (intStatus & I2S_IRQMASK_AIF_DMA_OUT) { +#ifdef I2S_DEBUG + dbgCntDmaOut++; + if (dbgCntDmaOut == 2) { + asm(" NOP"); + } + if (dbgCntDmaOut == 300) { + asm(" NOP"); + } +#endif //I2S_DEBUG + /* Move completed buffer to ready queue, if not reusable buffer */ + if (i2sBlockActiveOut != i2sBlockRepeatOut) { + Queue_put(i2sBlockReadyOutQueue, &i2sBlockActiveOut->_elem); +#ifdef I2S_DEBUG + i2sBlockActiveOut->queueIndicator = NODE_INDICATOR_READY_QUEUE; +#endif //I2S_DEBUG + } + /* Setup next active buffer */ + i2sBlockActiveOut = i2sBlockNextOut; + /* Mark next buffer as empty*/ + i2sBlockNextOut = NULL; +#ifdef I2S_DEBUG + // Avoid null-pointer exception + if (i2sBlockActiveOut) { + i2sBlockActiveOut->queueIndicator = NODE_INDICATOR_ACTIVE; + } + else { + // This can happen if stream is stopping + asm(" NOP"); + } +#endif //I2S_DEBUG + + if (object->currentStream->status == I2SCC26XX_STREAM_STOPPING) { + /* Part of shut down sequence*/ + object->currentStream->status = I2SCC26XX_STREAM_STOPPED; + } + else if (object->currentStream->status != I2SCC26XX_STREAM_STOPPED) { + if ((dbgCntI2SRelBuf > 3) && !Queue_empty(i2sBlockAvailOutQueue)) + { + i2sBlockNextOut = Queue_get(i2sBlockAvailOutQueue); +#ifdef I2S_DEBUG + i2sBlockNextOut->queueIndicator = NODE_INDICATOR_NEXT; +#endif //I2S_DEBUG + I2SPointerSet(hwAttrs->baseAddr, false, (uint32_t *)i2sBlockNextOut->buf); + /* Buffer is ready */ + object->currentStream->status = I2SCC26XX_STREAM_BUFFER_READY; + } + else + { + //ITM_Port32(2) = 0xDEADABBA; + object->currentStream->status = I2SCC26XX_STREAM_BUFFER_READY_BUT_NO_AVAILABLE_BUFFERS; + if (i2sBlockReadyOutQueue) { + // Send reusable frames + i2sBlockNextOut = i2sBlockRepeatOut; + // Copy data from previous frame, best to repeat this + memcpy(i2sBlockRepeatOut->buf, i2sBlockActiveOut->buf, object->blockSize * ((object->audioFmtCfg.memLen) ? 3 : 2 )); +#ifdef I2S_DEBUG + i2sBlockNextOut->queueIndicator = NODE_INDICATOR_REUSED; +#endif //I2S_DEBUG + I2SPointerSet(hwAttrs->baseAddr, false, (uint32_t *)i2sBlockNextOut->buf); + } + } + + /* Use a temporary stream pointer in case the callback function + * attempts to perform another I2SCC26XX_bufferRequest call + */ + notification = object->currentStream; + object->currentStream->arg = shadowQueueNodeTable; + + /* Notify caller about availability of buffer */ + object->callbackFxn((I2SCC26XX_Handle)arg, notification); + } + } + + /* Error handling: + * Overrun in the RX Fifo -> at least one sample in the shift + * register has been discarded */ + if (intStatus & I2S_IRQMASK_PTR_ERR) { +#ifdef I2S_DEBUG + dbgCntPtrErr++; +#endif //I2S_DEBUG + /* disable the interrupt */ + I2SIntDisable(hwAttrs->baseAddr, I2S_INT_PTR_ERR); + /* Check if we are expecting this interrupt as part of stopping */ + if ( object->currentStream->status == I2SCC26XX_STREAM_STOPPED ) { + /* This happened because I2SCC26XX_stopStream was called for some reason + * Post the semaphore + */ + Semaphore_post(Semaphore_handle(&(object->semStopping))); + } + else { + asm(" NOP"); + object->currentStream->status = I2SCC26XX_STREAM_ERROR; + /* Use a temporary stream pointer in case the callback function + * attempts to perform another I2SCC26XX_bufferRequest call + */ + notification = object->currentStream; + /* Notify caller about availability of buffer */ + object->callbackFxn((I2SCC26XX_Handle)arg, notification); + Log_print1(Diags_USER2, "I2S missing next pointer: (%p) !\n", hwAttrs->baseAddr); + } + } + else if (intStatus & (I2S_INT_TIMEOUT | I2S_INT_BUS_ERR | I2S_INT_WCLK_ERR)) { + asm(" NOP"); // Any other error + } + + Log_print1(Diags_USER2, "I2S:(%p) interrupt context end", + hwAttrs->baseAddr); +} + +/* + * ======== I2SCC26XX_startStream ======== + * @pre Function assumes that handle is not NULL + */ +bool I2SCC26XX_startStream(I2SCC26XX_Handle handle) { + unsigned int key; + I2SCC26XX_Object *object; + I2SCC26XX_HWAttrs const *hwAttrs; + + /* Get the pointer to the object and hwAttr*/ + object = handle->object; + hwAttrs = handle->hwAttrs; + + /* Disable preemption while checking if a transfer is in progress */ + key = Hwi_disable(); + if (object->currentStream->status != I2SCC26XX_STREAM_IDLE) { + Hwi_restore(key); + + Log_error1("I2S:(%p) stream still in progress", + ((I2SCC26XX_HWAttrs const *)(handle->hwAttrs))->baseAddr); + + /* Flag that the transfer failed to start */ + object->currentStream->status = I2SCC26XX_STREAM_FAILED; + + /* Transfer is in progress */ + return (false); + } + + /* Make sure to flag that a stream is now active */ + object->currentStream->status = I2SCC26XX_STREAM_STARTED; + + if (i2sBlockReadyOutQueue) { + /* Clear repeat buffer */ + memset(i2sBlockRepeatOut->buf, 0, object->blockSize * ((object->audioFmtCfg.memLen) ? 3 : 2 )); + } + + Hwi_restore(key); + + I2SCC26XX_cleanUpQueues(); + + /* Set constraint during streaming */ + Power_setConstraint(PowerCC26XX_SB_DISALLOW); + + /* Configure the hardware module */ + I2SCC26XX_initHw(handle); + + /* Kick off clocks */ + PRCMAudioClockEnable(); + PRCMLoadSet(); + + //TODO: Rename from I2S to AIF + // Enable samplestamp + //I2SSampleStampEnable(hwAttrs->baseAddr); + + if ((i2sBlockActiveIn == NULL) && i2sBlockReadyInQueue) { + i2sBlockActiveIn = Queue_dequeue(i2sBlockAvailInQueue); +#ifdef I2S_DEBUG + i2sBlockActiveIn->queueIndicator = NODE_INDICATOR_ACTIVE; +#endif //I2S_DEBUG + } + if ((i2sBlockNextIn == NULL) && i2sBlockReadyInQueue) { + i2sBlockNextIn = Queue_dequeue(i2sBlockAvailInQueue); +#ifdef I2S_DEBUG + i2sBlockNextIn->queueIndicator = NODE_INDICATOR_NEXT; +#endif //I2S_DEBUG + } + + if ((i2sBlockActiveOut == NULL) && i2sBlockReadyOutQueue) { + i2sBlockActiveOut = Queue_dequeue(i2sBlockAvailOutQueue); +#ifdef I2S_DEBUG + i2sBlockActiveOut->queueIndicator = NODE_INDICATOR_ACTIVE; +#endif //I2S_DEBUG + } + if ((i2sBlockNextOut == NULL) && i2sBlockReadyOutQueue) { + i2sBlockNextOut = Queue_dequeue(i2sBlockAvailOutQueue); +#ifdef I2S_DEBUG + i2sBlockNextOut->queueIndicator = NODE_INDICATOR_NEXT; +#endif //I2S_DEBUG + // Move at least one buffer to ready queue + if (!Queue_empty(i2sBlockAvailOutQueue)) { + queueNodeI2S_t *availNode = Queue_dequeue(i2sBlockAvailOutQueue); + /* Move buffer to ready queue */ + Queue_enqueue(i2sBlockReadyOutQueue, &availNode->_elem); +#ifdef I2S_DEBUG + availNode->queueIndicator = NODE_INDICATOR_READY_QUEUE; +#endif //I2S_DEBUG + } + } + + /* Configure buffers */ + I2SBufferConfig(hwAttrs->baseAddr, + (i2sBlockActiveIn) ? (uint32_t)i2sBlockActiveIn->buf : NULL, + (i2sBlockActiveOut) ? (uint32_t)i2sBlockActiveOut->buf : NULL, object->blockSize, + I2SCC26XX_DEFAULT_SAMPLE_STAMP_MOD); + /* Enable the I2S module. This will set first buffer and DMA length */ + I2SEnable(hwAttrs->baseAddr); + /* Second buffer is then set in hardware after DMA length is set */ + if (i2sBlockReadyInQueue) { + I2SPointerSet(hwAttrs->baseAddr, true, (uint32_t *)i2sBlockNextIn->buf); + } + if (i2sBlockReadyOutQueue) { + I2SPointerSet(hwAttrs->baseAddr, false, (uint32_t *)i2sBlockNextOut->buf); + } + + /* Enable the RX overrun interrupt in the I2S module */ + if (i2sBlockReadyInQueue) { + I2SIntEnable(hwAttrs->baseAddr, I2S_INT_DMA_IN | I2S_INT_PTR_ERR); + } + if (i2sBlockReadyOutQueue) { + I2SIntEnable(hwAttrs->baseAddr, I2S_INT_DMA_OUT | I2S_INT_PTR_ERR | I2S_INT_ALL); + } + + /* Clear internal pending interrupt flags */ + I2SIntClear(I2S0_BASE, I2S_INT_ALL); + +#ifdef I2S_DEBUG + dbgCntDmaIn = 0; + dbgCntDmaOut = 0; + dbgCntI2SReqBuf = 0; + dbgCntI2SRelBuf = 0; +#endif //I2S_DEBUG + + /* Configuring sample stamp generator will trigger the audio stream to start */ + I2SSampleStampConfigure(hwAttrs->baseAddr, (i2sBlockReadyInQueue) ? true : false, (i2sBlockReadyOutQueue) ? true : false); + + /* Enable samplestamp */ + I2SSampleStampEnable(hwAttrs->baseAddr); + + /* Clear potential pending I2S interrupt to CM3 */ + Hwi_clearInterrupt(INT_I2S_IRQ); + + /* Enable I2S interrupt to CM3 */ + Hwi_enableInterrupt(INT_I2S_IRQ); + + return (true); +} + +/* + * ======== I2SCC26XX_stopStream ======== + * @pre Function assumes that handle is not NULL + */ +bool I2SCC26XX_stopStream(I2SCC26XX_Handle handle) { + I2SCC26XX_Object *object; + I2SCC26XX_HWAttrs const *hwAttrs; + unsigned int key; + + /* Get the pointer to the object and hwAttrs */ + object = handle->object; + hwAttrs = handle->hwAttrs; + + /* Check if a transfer is in progress */ + key = Hwi_disable(); + + /* Check if there is an active stream */ + if ( (object->currentStream->status == I2SCC26XX_STREAM_STOPPING) || + (object->currentStream->status == I2SCC26XX_STREAM_STOPPED) || + (object->currentStream->status == I2SCC26XX_STREAM_IDLE) ) { + Hwi_restore(key); + return false; + } + + /* Begin stopping sequence, if not stopped because of error */ + if (object->currentStream->status != I2SCC26XX_STREAM_ERROR) { + object->currentStream->status = I2SCC26XX_STREAM_STOPPING; + + /* Reenable the interrupt as it may have been disabled during an error*/ + I2SIntEnable(hwAttrs->baseAddr, I2S_INT_PTR_ERR); + + Hwi_restore(key); + + /* Wait for I2S module to complete all buffers*/ + // if (!Semaphore_pend(Semaphore_handle(&(object->semStopping)), BIOS_WAIT_FOREVER)) { + if (!Semaphore_pend(Semaphore_handle(&(object->semStopping)), 40000)) { + object->currentStream->status = I2SCC26XX_STREAM_FAILED_TO_STOP; + return false; + } + } + + /* restore HWI */ + Hwi_restore(key); + + /* Disable the I2S module */ + I2SDisable(hwAttrs->baseAddr); + + /* Disable and clear any pending interrupts */ + I2SIntDisable(hwAttrs->baseAddr, I2S_INT_ALL); + I2SIntClear(hwAttrs->baseAddr, I2S_INT_ALL); + Hwi_clearInterrupt(INT_I2S_IRQ); + Hwi_disableInterrupt(INT_I2S_IRQ); + + /* Flush any unprocessed I2S data */ + I2SCC26XX_cleanUpQueues(); + + /* Indicate we are done with this stream */ + object->currentStream->status = I2SCC26XX_STREAM_IDLE; + + Log_print2(Diags_USER2,"I2S:(%p) stream: %p stopped", + hwAttrs->baseAddr, (UArg)object->currentStream); + + /* Release constraint after streaming */ + Power_releaseConstraint(PowerCC26XX_SB_DISALLOW); + + /* Stream was successfully stopped */ + return true; +} + +/* + * ======== I2SCC26XX_requestBuffer ======== + * @pre Function assumes that stream has started and that bufferRequest is not NULL + */ +bool I2SCC26XX_requestBuffer(I2SCC26XX_Handle handle, I2SCC26XX_BufferRequest *bufferRequest) { + I2SCC26XX_Object *object; + bool retVal = false; + /* Get the pointer to the object */ + object = handle->object; + +#ifdef I2S_DEBUG + dbgCntI2SReqBuf++; +#endif //I2S_DEBUG + + if (object->requestMode == I2SCC26XX_MODE_BLOCKING) { + Log_print1(Diags_USER2, "I2S:(%p) request pending on blockComplete " + "semaphore", + ((I2SCC26XX_HWAttrs const *)(handle->hwAttrs))->baseAddr); + + if (!Semaphore_pend(Semaphore_handle(&(object->blockComplete)), object->ui32requestTimeout)) { + /* Stop stream, if we experience a timeout */ + I2SCC26XX_stopStream(handle); + + bufferRequest->status = object->currentStream->status; + + return false; + } + }; + bufferRequest->bufferHandleIn = NULL; + bufferRequest->bufferHandleOut = NULL; + /* When in callback mode we typically expect the user to call this + * after being notified of available buffers. Hence we may directly + * check queue and dequeue buffer + */ + if (i2sBlockReadyInQueue) { + if (!Queue_empty(i2sBlockReadyInQueue)) { + queueNodeI2S_t *readyNode = Queue_get(i2sBlockReadyInQueue); + bufferRequest->bufferIn = readyNode->buf; + bufferRequest->status = object->currentStream->status; + bufferRequest->bufferHandleIn = readyNode; +#ifdef I2S_DEBUG + readyNode->queueIndicator = NODE_INDICATOR_USER; +#endif //I2S_DEBUG + retVal = true; + } + } + + if (i2sBlockReadyOutQueue) { + if (!Queue_empty(i2sBlockReadyOutQueue)) { + queueNodeI2S_t *readyNode = Queue_get(i2sBlockReadyOutQueue); + bufferRequest->bufferOut = readyNode->buf; + bufferRequest->status = object->currentStream->status; + bufferRequest->bufferHandleOut = readyNode; +#ifdef I2S_DEBUG + readyNode->queueIndicator = NODE_INDICATOR_USER; +#endif //I2S_DEBUG + retVal = true; + } + } + + return retVal; +} + +/* + * ======== I2SCC26XX_releaseBuffer ======== + * @pre Function assumes bufferRelease contains a valid bufferHandle (identical to + * the one provided in the bufferRequest in I2SCC26XX_requestBuffer + */ +void I2SCC26XX_releaseBuffer(I2SCC26XX_Handle handle, I2SCC26XX_BufferRelease *bufferRelease) +{ + unsigned int key; +#ifdef I2S_DEBUG + dbgCntI2SRelBuf++; +#endif //I2S_DEBUG + if (bufferRelease->bufferHandleIn) { + /* Place released buffer back in available queue */ + Queue_put(i2sBlockAvailInQueue, &((queueNodeI2S_t *)bufferRelease->bufferHandleIn)->_elem); +#ifdef I2S_DEBUG + ((queueNodeI2S_t *)bufferRelease->bufferHandleIn)->queueIndicator = NODE_INDICATOR_AVAIL_QUEUE; +#endif //I2S_DEBUG + } + if (bufferRelease->bufferHandleOut) { + key = Hwi_disable(); + /* Check if we current have the reusable buffer as next, replace it */ + if (i2sBlockNextOut == i2sBlockRepeatOut) + { + i2sBlockNextOut = ((queueNodeI2S_t *)bufferRelease->bufferHandleOut); +#ifdef I2S_DEBUG + ((queueNodeI2S_t *)bufferRelease->bufferHandleOut)->queueIndicator = NODE_INDICATOR_NEXT; +#endif //I2S_DEBUG + } + else { + /* Place released buffer back in available queue */ + Queue_put(i2sBlockAvailOutQueue, &((queueNodeI2S_t *)bufferRelease->bufferHandleOut)->_elem); +#ifdef I2S_DEBUG + ((queueNodeI2S_t *)bufferRelease->bufferHandleOut)->queueIndicator = NODE_INDICATOR_AVAIL_QUEUE; +#endif //I2S_DEBUG + } + Hwi_restore(key); + } +} + +/* + * ======== I2SCC26XX_callback ======== + * Callback function for when the I2S is in I2SCC26XX_MODE_BLOCKING + * + * @pre Function assumes that the handle is not NULL + */ +static void I2SCC26XX_callback(I2SCC26XX_Handle handle, I2SCC26XX_StreamNotification *msg) { + I2SCC26XX_Object *object; + + Log_print1(Diags_USER2, "I2S DMA:(%p) posting block complete semaphore", + ((I2SCC26XX_HWAttrs const *)(handle->hwAttrs))->baseAddr); + + /* Get the pointer to the object */ + object = handle->object; + + /* Post the semaphore */ + Semaphore_post(Semaphore_handle(&(object->blockComplete))); +} + +/* +* ======== I2SCC26XX_hwInit ======== +* This functions initializes the I2S hardware module. +* +* @pre Function assumes that the I2S handle is pointing to a hardware +* module which has already been opened. +*/ +static void I2SCC26XX_initHw(I2SCC26XX_Handle handle) { + I2SCC26XX_Object *object; + I2SCC26XX_HWAttrs const *hwAttrs; + + /* Get the pointer to the object and hwAttrs */ + object = handle->object; + hwAttrs = handle->hwAttrs; + + /* Disable I2S operation */ + I2SDisable(hwAttrs->baseAddr); + + /* Configure Audio format */ + I2SAudioFormatConfigure(hwAttrs->baseAddr, + *(uint32_t *)&object->audioFmtCfg, + object->audioFmtCfg.dataDelay); + + /* Configure Channels */ + I2SChannelConfigure(hwAttrs->baseAddr, + object->audioPinCfg.driverLibParams.ad0, + object->audioPinCfg.driverLibParams.ad1, + ~I2SCC26XX_DIR_CHA_M); + + /* Turn on I2S clocks */ +// PRCMPeripheralRunEnable(PRCM_PERIPH_I2S); + + /* Configure Clocks*/ + uint32_t clkCfg = object->audioClkCfg.wclkSource; + clkCfg |= (object->audioClkCfg.wclkInverted) ? I2S_INVERT_WCLK : 0; + I2SClockConfigure(hwAttrs->baseAddr, clkCfg); + uint32_t ui32MstDiv = object->audioClkCfg.mclkDiv; + uint32_t ui32BitDiv = object->audioClkCfg.bclkDiv; + uint32_t ui32WordDiv = object->audioClkCfg.wclkDiv; + clkCfg = (object->audioClkCfg.wclkPhase << PRCM_I2SCLKCTL_WCLK_PHASE_S); + clkCfg |= (object->audioClkCfg.sampleOnPositiveEdge << PRCM_I2SCLKCTL_SMPL_ON_POSEDGE_S); + if ( (object->i32SampleRate >= I2S_SAMPLE_RATE_16K) && + (object->i32SampleRate <= I2S_SAMPLE_RATE_48K)) { + PRCMAudioClockConfigSet(clkCfg, object->i32SampleRate); + } + else { + PRCMAudioClockConfigSetOverride(clkCfg, ui32MstDiv, ui32BitDiv, ui32WordDiv); + } + // TODO: Replace this with Driverlib code + HWREG(PRCM_BASE + PRCM_O_I2SBCLKSEL) = (object->audioClkCfg.bclkSource & PRCM_I2SBCLKSEL_SRC_M); + /* Apply configuration */ + PRCMLoadSet(); + + /* Disable I2S module interrupts */ +// uint32_t ui32IntFlags + I2SIntDisable(hwAttrs->baseAddr, I2S_INT_ALL); + + /* Print the configuration */ + Log_print1(Diags_USER2, "I2S:(%p) Configured", hwAttrs->baseAddr); +} + +/* +* ======== I2SCC26XX_initIO ======== +* This functions initializes the I2S IOs. +* +* @pre Function assumes that the I2S handle is pointing to a hardware +* module which has already been opened. +*/ +static bool I2SCC26XX_initIO(I2SCC26XX_Handle handle) { + I2SCC26XX_Object *object; + I2SCC26XX_HWAttrs const *hwAttrs; + PIN_Config i2sPinTable[6]; + uint32_t i=0; + + /* Get the pointer to the object and hwAttrs */ + object = handle->object; + hwAttrs = handle->hwAttrs; + + /* Configure IOs */ + /* Build local list of pins, allocate through PIN driver and map HW ports */ + if (object->audioPinCfg.bitFields.enableMclkPin) { + i2sPinTable[i++] = hwAttrs->mclkPin | IOC_STD_OUTPUT; + } + if (object->audioPinCfg.bitFields.enableWclkPin) { + i2sPinTable[i++] = hwAttrs->wclkPin | IOC_STD_OUTPUT; + } + if (object->audioPinCfg.bitFields.enableBclkPin) { + i2sPinTable[i++] = hwAttrs->bclkPin | IOC_STD_OUTPUT; + } + if (object->audioPinCfg.bitFields.ad0Usage == I2SCC26XX_ADUsageInput) { + i2sPinTable[i++] = hwAttrs->ad0Pin | PIN_INPUT_EN | PIN_NOPULL; + } + else if (object->audioPinCfg.bitFields.ad0Usage == I2SCC26XX_ADUsageOutput) { + i2sPinTable[i++] = hwAttrs->ad0Pin | IOC_STD_OUTPUT; + } + if (object->audioPinCfg.bitFields.ad1Usage == I2SCC26XX_ADUsageInput) { + i2sPinTable[i++] = hwAttrs->ad1Pin | IOC_STD_INPUT; + } + else if (object->audioPinCfg.bitFields.ad1Usage == I2SCC26XX_ADUsageOutput) { + i2sPinTable[i++] = hwAttrs->ad1Pin | IOC_STD_OUTPUT; + } + i2sPinTable[i++] = PIN_TERMINATE; + + /* Open and assign pins through pin driver */ + if (!(object->pinHandle = PIN_open(&(object->pinState), i2sPinTable))) { + return false; + } + + /* Set IO muxing for the I2S pins */ + + if (object->audioPinCfg.bitFields.enableMclkPin) { + PINCC26XX_setMux(object->pinHandle, hwAttrs->mclkPin, IOC_PORT_MCU_I2S_MCLK); + } + if (object->audioPinCfg.bitFields.enableWclkPin) { + PINCC26XX_setMux(object->pinHandle, hwAttrs->wclkPin, IOC_PORT_MCU_I2S_WCLK); + } + if (object->audioPinCfg.bitFields.enableBclkPin) { + PINCC26XX_setMux(object->pinHandle, hwAttrs->bclkPin, IOC_PORT_MCU_I2S_BCLK); + } + if (object->audioPinCfg.bitFields.ad0Usage != I2SCC26XX_ADUsageDisabled) { + PINCC26XX_setMux(object->pinHandle, hwAttrs->ad0Pin, IOC_PORT_MCU_I2S_AD0); + } + if (object->audioPinCfg.bitFields.ad1Usage != I2SCC26XX_ADUsageDisabled) { + PINCC26XX_setMux(object->pinHandle, hwAttrs->ad1Pin, IOC_PORT_MCU_I2S_AD1); + } + + return true; +} +/* +* ======== I2SCC26XX_cleanUpQueues ======== +* This functions cleans up the queues. +* +* @pre Function assumes that the I2S driver has been opened. +*/ +static void I2SCC26XX_cleanUpQueues() { + if (i2sBlockReadyInQueue) + { + /* Clean up unused queue elements */ + while (!Queue_empty(i2sBlockReadyInQueue)) { + queueNodeI2S_t *readyNode = Queue_dequeue(i2sBlockReadyInQueue); + /* Move buffer to avail queue */ + Queue_enqueue(i2sBlockAvailInQueue, &readyNode->_elem); +#ifdef I2S_DEBUG + readyNode->queueIndicator = NODE_INDICATOR_AVAIL_QUEUE; +#endif //I2S_DEBUG + } + } + if (i2sBlockReadyOutQueue) { + /* Clean up unused queue elements */ + while (!Queue_empty(i2sBlockReadyOutQueue)) { + queueNodeI2S_t *readyNode = Queue_dequeue(i2sBlockReadyOutQueue); + /* Move buffer to avail queue */ + Queue_enqueue(i2sBlockAvailOutQueue, &readyNode->_elem); +#ifdef I2S_DEBUG + readyNode->queueIndicator = NODE_INDICATOR_AVAIL_QUEUE; +#endif //I2S_DEBUG + } + } +} + +/* + * ======== i2sPostNotify ======== + * This functions is called to notify the I2S driver of an ongoing transition + * out of sleep mode. + * + * @pre Function assumes that the I2S handle (clientArg) is pointing to a + * hardware module which has already been opened. + */ +int i2sPostNotify(char eventType, uint32_t clientArg) { + I2SCC26XX_Handle i2sHandle; + + /* Get the pointers to I2S objects */ + i2sHandle = (I2SCC26XX_Handle) clientArg; + + /* Reconfigure the hardware when returning from standby */ + I2SCC26XX_initHw(i2sHandle); + + return Power_NOTIFYDONE; +} diff --git a/src/util/audio_codec/I2SCC26XX.h b/src/util/audio_codec/I2SCC26XX.h new file mode 100644 index 0000000..fced3bf --- /dev/null +++ b/src/util/audio_codec/I2SCC26XX.h @@ -0,0 +1,1141 @@ +/* + * Copyright (c) 2014, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** ============================================================================ + * @file I2SCC26XX.h + * + * @brief I2S driver implementation for a CC26XX I2S controller. + * + * The I2S header file should be included in an application as follows: + * @code + * #include + * @endcode + * + * # Overview # + * This driver is written specifically for the I2S module on CC26XX. The user + * should be aware that although this module is called I2S it is a highly + * configurable audio interface module. I2S is only one of many configurations. + * + * ## General Behavior # + * Before using I2S on CC26XX: + * - The I2S driver object is initialized by calling I2SCC26XX_init(). This + * should be done in main before BIOS_start() is called. + * - The I2S system dependencies flags are set by calling I2SCC26XX_open(). + * The driver is also taken. Prior to this the user should call + * I2SCC26XX_Params_init() to get the parameters to use in I2SCC26XX_open(). + * + * While using I2S on CC26XX: + * - A stream is started, hardware configured and sleep prevented, when + * I2SCC26XX_startStream() is called. From now on callbacks are generated + * every time a buffer is ready; if callbacks are asked for. + * - Data is acquired by calling I2SCC26XX_requestBuffer(). Be sure to release + * buffer back to driver by calling I2SCC26XX_releaseBuffer(). + * - The stream is stopped when I2SCC26XX_stopStream() is called. Note that + * this is a blocking call that will wait until the hardware has gracefully + * shut down. This will maximally take the same time that it takes to fill + * one buffer. The buffer size is configurable, so the time this function + * blocks is variable. System is allowed to sleep after + * I2SCC26XX_stopStream() is called. + * + * After I2S operation has ended: + * - Release system dependencies for I2S by calling I2SCC26XX_close(). + * + * ## Supported Functionality # + * All possible configurations the I2S module can take are supported. However, + * the user is encourage to use the I2SCC26XX_Params_init() function. Currently + * the driver supports two configurations: + * - PDM + * - I2S (Note! Beta stage) + * + * ## Error handling # + * Most APIs in this driver returns a boolean value indicating the success + * or failure of the API. During streaming there is only one failure worth + * discussing. + * - Failure to provide new pointer to the I2S module (audio interface module) + * When stopping the stream this error is actually forced as it is part + * of the graceful shutdown sequence. It can however happen if the interrupt + * is not serviced in time, or there is no buffer available when serviced. + * - No buffer available: + * This error can happen if the caller does not request and release + * buffers fast enough to make sure at least one buffer is + * available for the driver. If this seems to be an intermittent + * unavoidable problem then it can be solved by providing a larger + * buffer to the driver. + * - Interrupt not serviced in time: + * This error can happen if interrupts are disabled, or another + * higher priority interrupt is being processed, for a duration + * longer than the time it takes to fill one buffer. + * If the above mentioned error happens then the driver will notify the user + * via the provided callback. It disables the pointer error interrupt, so that + * it only generates this callback once. The user can now choose to process + * the available buffers, before it must stop the stream. The user may, after + * stopping the stream, restart the stream. + * + * ## Power Management # + * The I2SCC26XXDMA driver is setting a power constraint during stream to keep + * the device out of standby. When the stream has ended, the power + * constraint is released. The user is controlling the duration of the stream + * via calls to I2SCC26XX_startStream() and I2SCC26XX_stopStream(). + * The following statements are valid: + * - After I2SCC26XX_open(): the device is still allowed to enter standby. + * - During I2SCC26XX_startStream(): the device cannot enter standby. + * - After I2SCC26XX_stopStream() succeeds: the device can enter standby. + * - If I2SCC26XX_close() is called: the device can enter standby. + * + * ## Supported Functions ## + * | API function | Description | + * |--------------------------- |------------------------------------------------------| + * | I2SCC26XX_init() | Initialize I2S driver | + * | I2SCC26XX_Params_init() | Get configuration specific parameters (e.g. PDM, I2S)| + * | I2SCC26XX_open() | Set system dependencies, configure pins | + * | I2SCC26XX_startStream() | Initialize I2S HW, start stream and prevent standby | + * | I2SCC26XX_stopStream() | Stop stream and release standby hold | + * | I2SCC26XX_requestBuffer() | Request a buffer from the driver | + * | I2SCC26XX_releaseBuffer() | Release a buffer to the driver after processing it | + * | I2SCC26XX_close() | Disable I2S HW and release system dependencies | + * + * ## Use Cases \anchor USE_CASES_I2S ## + * ### PDM Mode # + * Receive data until told to stop. + * @code + * I2SCC26XX_StreamNotification pdmStream; + * I2SCC26XX_Handle i2sHandle; + * I2SCC26XX_BufferRequest bufferRequest; + * I2SCC26XX_BufferRelease bufferRelease; + * I2SCC26XX_Params i2sCC26XX_params; + * I2SCC26XX_PDM_Params i2sCC26XX_PDM_params = { + * I2SCC26XX_CALLBACK_MODE, + * BIOS_WAIT_FOREVER, + * NULL, + * PDM_BLOCK_SIZE_IN_SAMPLES, + * (void *) pdmContinuousBuffer, + * sizeof(pdmContinuousBuffer), + * (void *) pdmContMgtBuffer, + * sizeof(pdmContMgtBuffer), + * &pdmStream + * }; + * + * // Set callback function + * i2sCC26XX_PDM_params.callbackFxn = I2S_callbackFxn; + * + * // Get PDM specific configuration + * I2SCC26XX_Params_init(&i2sCC26XX_params, I2SCC26XX_PDM, &i2sCC26XX_PDM_params); + * + * // Then open the I2S + * I2SCC26XX_open(i2sHandle, &i2sCC26XX_params); + * + * // Now you can start stream + * I2SCC26XX_startStream(i2sHandle); + * + * // Wait for callback indicating buffers are ready. Typically this would + * // be in a thread waiting for a semaphore. The semaphore would be set in + * // the callback. In this case we're just assuming a volatile variable + * // bufferReady that is set in the callback + * while (!bufferReady); + * // Now request a buffer as it was indicated that one is available + * I2SCC26XX_requestBuffer(i2sHandle, &bufferRequest); + * // Process the buffer, e.g. perform PDM2PCM conversion + * ... + * // Then release the buffer after it has been processed + * // Release PDM buffer + * bufferRelease.bufferHandleIn = bufferRequest.bufferHandleIn; + * bufferRelease.bufferHandleOut = bufferRequest.bufferHandleOut; + * I2SCC26XX_releaseBuffer(i2sHandle, &bufferRelease); + * + * // Now go back to waiting for next buffer, or stop stream + * + * // After processing all buffers one can stop the stream + * I2SCC26XX_stopStream(i2sHandle); + * + * // Then process all remaining buffers + * while (I2SCC26XX_requestBuffer(i2sHandle, &bufferRequest)) + * { + * // Process the buffer, e.g. perform PDM2PCM conversion + * ... + * // Then release the buffer after it has been processed + * // Release PDM buffer + * bufferRelease.bufferHandleIn = bufferRequest.bufferHandleIn; + * bufferRelease.bufferHandleOut = bufferRequest.bufferHandleOut; + * I2SCC26XX_releaseBuffer(i2sHandle, &bufferRelease); + * } + * + * // Then if we're really done, close the driver + * I2SCC26XX_close(i2sHandle); + * + * @endcode + * + * # Instrumentation # + * The I2SCC26XX driver has a debug mode that can be enabled compilation time. + * Use the flag I2S_DEBUG to enable this mode. In debug mode all buffers are + * labeled to indicate where in the process it is. It can have 6 different + * states: + * + * Enum Queue Indicator | Details | + * --------------------------- | --------------------- | + * NODE_INDICATOR_NO_QUEUE | not part of queue | + * NODE_INDICATOR_AVAIL_QUEUE | part of available | + * NODE_INDICATOR_READY_QUEUE | part of ready | + * NODE_INDICATOR_NEXT | next | + * NODE_INDICATOR_ACTIVE | active | + * NODE_INDICATOR_USER | handled by user | + * + * # TODOs # + * * More optimized buffer management might be supported in later releases. + * * Complete ::I2SCC26XX_I2S_Params and enable I2S mode + * . + * + * ============================================================================ + */ + +#ifndef ti_drivers_i2s_I2SCC26XX__include +#define ti_drivers_i2s_I2SCC26XX__include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +/*! + * The following allows this header file to be included in an application file + * which also includes ti/sysbios/hal/Hwi.h. + */ +#define ti_sysbios_family_arm_m3_Hwi__nolocalnames +#include +#include + +/*! + * @brief Define to control debug mode + * + * Production code should set this to xI2S_DEBUG. To enable debug mode + * rename the define to \b I2S_DEBUG. + */ +#define I2S_DEBUG + +/*! + * At least three elements must exist for good flow in driver + */ +#define I2SCC26XX_MIN_ALLOWED_QUEUE_SIZE 3 +#define I2SCC26XX_QUEUE_SIZE 7 + +/*! + * PDM block overhead size in number of bytes --> sizeof(queueNodeI2S_t) + */ +#ifdef I2S_DEBUG +#define I2S_BLOCK_OVERHEAD_IN_BYTES 16 +#else //I2S_DEBUG +#define I2S_BLOCK_OVERHEAD_IN_BYTES 12 +#endif //I2S_DEBUG + +/*! Return code when I2SCC26XX_control() was successful. */ +#define I2SCC26XX_CMD_SUCCESS 0 +/*! Return code when a I2S command or function is undefined/not-implemented. */ +#define I2SCC26XX_CMD_UNDEFINED -1 +/*! Return code when I2SCC26XX_control() was unsuccessful. */ +#define I2SCC26XX_CMD_NO_SUCCESS -2 + +/*! Generic macro for disabled */ +#define I2SCC26XX_GENERIC_DISABLED 0 +/*! Generic macro for enabled */ +#define I2SCC26XX_GENERIC_ENABLED 1 + +/*! + * @brief A handle that is returned from a I2SCC26XX_open() call. + */ +typedef struct I2SCC26XX_Config *I2SCC26XX_Handle; + +/*! + * @brief Status codes that are set by the I2S driver. + */ +typedef enum I2SCC26XX_Status { + I2SCC26XX_STREAM_IDLE = 0, /*!< Idle mode. Stream not started */ + I2SCC26XX_STREAM_STARTED, /*!< Stream started, no buffer yet available */ + I2SCC26XX_STREAM_CANCELED, /*!< Unused state. */ + I2SCC26XX_STREAM_FAILED, /*!< I2SCC26XX_startStream() called while stream + * is already running */ + I2SCC26XX_STREAM_ERROR, /*!< No pointer available when one was expected, + * meaning the driver failed to provide new + * pointer and I2SCC26XX_stopStream() was not + * called */ + I2SCC26XX_STREAM_BUFFER_READY, /*!< Buffer ready, either IN or OUT or + * both, whichever are expected */ + I2SCC26XX_STREAM_BUFFER_READY_BUT_NO_AVAILABLE_BUFFERS, /*!< Buffer + * ready, either IN or OUT or both, whichever + * are expected. However, driver has no more + * buffers available to provide to the hardware + * on next interrupt. This serves as an + * indication to the caller that the driver is + * about to fail, unless caller processes ready + * buffers */ + I2SCC26XX_STREAM_STOPPING, /*!< I2SCC26XX_stopStream() is called, a + * graceful shutdown procedure is started */ + I2SCC26XX_STREAM_STOPPED, /*!< Driver transitioned from Stopping to + * Stopped state during graceful shutdown. Now + * a pointer error is expected, and upon it a + * semaphore is set allowing + * I2SCC26XX_stopStream() to return */ + I2SCC26XX_STREAM_FAILED_TO_STOP /*!< I2SCC26XX_stopStream() was called, + * but driver timed out trying to gracefully + * shutdown */ +} I2SCC26XX_Status; + +/*! + * @brief + * Definitions for various I2SCC26XX modes of operation. + */ +typedef enum I2SCC26XX_Mode { + I2SCC26XX_PDM = 0, /*!< I2SCC26XX in PDM microphone mode */ + I2SCC26XX_I2S = 1 /*!< I2SCC26XX in I2S mode */ +} I2SCC26XX_Mode; + +/*! + * We don't use sample stamp generator, but we can't start without + * enabling it and configuring the trigger. This is because the + * trigger also starts the audio stream + * Since we don't use it we keep the word period at its max 2^16 + * For the driverlib which runs a modulo on the word period we can + * set the modulo to 0xFFFF to avoid issues with division by zero. + */ +#define I2SCC26XX_DEFAULT_SAMPLE_STAMP_MOD 0x0000FFFF + +/*! + * Definitions for different I2S Word Clock phase settings. + * + * Defines how WCLK division ratio is calculated to generate different + * duty cycles. + * \sa I2SWCLKDIV.WDIV + * + * Macro | Value | + * ------------------------------------------- | ------| + * I2SCC26XX_WordClockPhase_Single | 0 | + * I2SCC26XX_WordClockPhase_Dual | 1 | + * I2SCC26XX_WordClockPhase_UserDefined | 2 | + */ +#define I2SCC26XX_WordClockPhase_Single 0 +/*! + * \sa I2SCC26XX_WordClockPhase_Single + */ +#define I2SCC26XX_WordClockPhase_Dual 1 +/*! + * \sa I2SCC26XX_WordClockPhase_Single + */ +#define I2SCC26XX_WordClockPhase_UserDefined 2 + +/*! + * Definitions to set sample edge + * + * Macro | Value | + * ----------------------------------- | ------| + * I2SCC26XX_SampleEdge_Negative | 0 | + * I2SCC26XX_SampleEdge_Postive | 1 | + */ +#define I2SCC26XX_SampleEdge_Negative 0 +/*! + * \sa I2SCC26XX_SampleEdge_Negative + */ +#define I2SCC26XX_SampleEdge_Postive 1 + +/*! + * Definitions different I2S Word Clock source settings. + * + * Macro | Value | + * ----------------------------------- | ------| + * I2SCC26XX_WordClockSource_Ext | 0 | + * I2SCC26XX_WordClockSource_Int | 1 | + */ +#define I2SCC26XX_WordClockSource_Ext 1 +/*! + * \sa I2SCC26XX_WordClockSource_Ext + */ +#define I2SCC26XX_WordClockSource_Int 2 + +/*! + * Definitions different I2S Bit Clock source settings. + * + * Macro | Value | + * ----------------------------------- | ------| + * I2SCC26XX_BitClockSource_Ext | 0 | + * I2SCC26XX_BitClockSource_Int | 1 | + */ +#define I2SCC26XX_BitClockSource_Ext 0 +/*! + * \sa I2SCC26XX_BitClockSource_Ext + */ +#define I2SCC26XX_BitClockSource_Int 1 + +/*! + * Definitions to either invert I2S word or bit clock or not + * + * Macro | Value | + * ----------------------------------- | ------| + * I2SCC26XX_ClockSource_Normal | 0 | + * I2SCC26XX_ClockSource_Inverted | 1 | + */ +#define I2SCC26XX_ClockSource_Normal 0 +/*! + * \sa I2SCC26XX_ClockSource_Normal + */ +#define I2SCC26XX_ClockSource_Inverted 1 + +/*! + * I2SCC26XX Audio Data Pin Usage. + * + * Macro | Details | + * --------------------------- | --------------| + * I2SCC26XX_ADUsageDisabled | Disabled | + * I2SCC26XX_ADUsageInput | Input | + * I2SCC26XX_ADUsageOutput | Output | + */ +#define I2SCC26XX_ADUsageDisabled 0 +/*! + * \sa I2SCC26XX_ADUsageDisabled + */ +#define I2SCC26XX_ADUsageInput 1 +/*! + * \sa I2SCC26XX_ADUsageDisabled + */ +#define I2SCC26XX_ADUsageOutput 2 + +/*! + * I2SCC26XX Audio Channel Masks. + * + * Macro | Value | Usage | + * --------------------------- | --------------|-------------------------------| + * I2SCC26XX_CHAN0_ACT | 0x00000001 | OR in to enable channel 0 | + * I2SCC26XX_CHAN1_ACT | 0x00000002 | OR in to enable channel 1 | + * I2SCC26XX_CHAN2_ACT | 0x00000004 | OR in to enable channel 2 | + * I2SCC26XX_CHAN3_ACT | 0x00000008 | OR in to enable channel 3 | + * I2SCC26XX_CHAN4_ACT | 0x00000010 | OR in to enable channel 4 | + * I2SCC26XX_CHAN5_ACT | 0x00000020 | OR in to enable channel 5 | + * I2SCC26XX_CHAN6_ACT | 0x00000040 | OR in to enable channel 6 | + * I2SCC26XX_CHAN7_ACT | 0x00000080 | OR in to enable channel 7 | + * I2SCC26XX_MONO_MODE | 0x00000001 | Use to set Mono mode | + * I2SCC26XX_STEREO_MODE | 0x00000003 | Use to set Stereo mode | + * I2SCC26XX_DISABLED_MODE | 0x00000000 | Use to disable | + * I2SCC26XX_CHAN_CFG_MASK | 0x000000FF | Use to mask out invalid | + */ +#define I2SCC26XX_CHAN0_ACT 0x00000001 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_CHAN1_ACT 0x00000002 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_CHAN2_ACT 0x00000004 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_CHAN3_ACT 0x00000008 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_CHAN4_ACT 0x00000010 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_CHAN5_ACT 0x00000020 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_CHAN6_ACT 0x00000040 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_CHAN7_ACT 0x00000080 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_MONO_MODE 0x00000001 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_STEREO_MODE 0x00000003 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_DISABLED_MODE 0x00000000 +/*! \sa I2SCC26XX_CHAN0_ACT */ +#define I2SCC26XX_CHAN_CFG_MASK 0x000000FF + +/*! + * I2SCC26XX data word length is used to determine how bits to transfer per word. + * + * Macro | Value | Usage | + * --------------------------- | ------|---------------------------------------| + * I2SCC26XX_WordLengthMin | 8 | Minimum transfer length is 8 bits | + * I2SCC26XX_WordLength16 | 16 | A typical transfer length is 16 bits | + * I2SCC26XX_WordLengthMax | 24 | Maximum transfer length is 24 bits | + */ +#define I2SCC26XX_WordLengthMin 8 +/*! \sa I2SCC26XX_WordLengthMin */ +#define I2SCC26XX_WordLength16 16 +/*! \sa I2SCC26XX_WordLengthMin */ +#define I2SCC26XX_WordLengthMax 24 + +/*! + * I2SCC26XX Phase is set to select Dual or Single phase format + * + * Macro | Value | + * --------------------------- | ------| + * I2SCC26XX_SinglePhase | 0 | + * I2SCC26XX_DualPhase | 1 | + */ +#define I2SCC26XX_SinglePhase 0 +/*! \sa I2SCC26XX_SinglePhase */ +#define I2SCC26XX_DualPhase 1 + +/*! + * I2SCC26XX Sample Edge is set to control what edge to sample and clock out + * data on. + * + * Macro | Value | + * --------------------------- | ------| + * I2SCC26XX_NegativeEdge | 0 | + * I2SCC26XX_PositiveEdge | 1 | + */ +#define I2SCC26XX_NegativeEdge 0 +/*! \sa I2SCC26XX_NegativeEdge */ +#define I2SCC26XX_PositiveEdge 1 + +/*! + * I2SCC26XX data word size is used to determine how to configure the + * I2S data transfers to/from memory. + * + * Macro | Value | Usage | + * --------------------------- | ------|-------------------------------| + * I2SCC26XX_MemLen16bit | 0 | sample 16 bits per word | + * I2SCC26XX_MemLen24bit | 1 | sample 24 bits per word | + * + * I2SCC26XX_MemLen16bit: sample 16 bits per word + * I2SCC26XX_MemLen24bit: sample 24 bits per word + */ +#define I2SCC26XX_MemLen16bit 0 +/*! \sa I2SCC26XX_MemLen16bit */ +#define I2SCC26XX_MemLen24bit 1 + +/*! + * I2SCC26XX Data Delay, which translates into format (LJF, I2S/DSP, RJF). + * + * This field can be set to any 8 bit value. The macros are just defined + * for convenience. Left justified mode means that sampling should start + * immediately. For right justified mode the data delay depends on how + * many samples should be taken per word. It is an alignment. + * + * I2S is a special mode that defines that no sample occur on first edge, + * hence there is one period data delay. + * + * Macro | Value | Usage | + * --------------------------- | ------|-------------------------------| + * I2SCC26XX_FormatLJF | 0 | no data delay | + * I2SCC26XX_FormatI2SandDSP | 1 | one period data delay | + * I2SCC26XX_FormatRJFmin | 2 | two periods data delay | + * I2SCC26XX_FormatRJFmax | 255 | 255 periods data delay | + */ +#define I2SCC26XX_FormatLJF 0 +/*! \sa I2SCC26XX_FormatLJF */ +#define I2SCC26XX_FormatI2SandDSP 1 +/*! \sa I2SCC26XX_FormatLJF */ +#define I2SCC26XX_FormatRJFmin 2 +/*! \sa I2SCC26XX_FormatLJF */ +#define I2SCC26XX_FormatRJFmax 255 + +/*! Number of samples (16 or 24 bits) per queue element buffer */ +typedef uint32_t I2SCC26XX_TransferSize; + +/*! + * @brief + * The I2SCC26XX_Config structure contains a set of pointers used to characterize + * the I2SCC26XX driver implementation. + */ +typedef struct I2SCC26XX_Config { + /*! Pointer to a driver specific data object */ + void *object; + + /*! Pointer to a driver specific hardware attributes structure */ + void const *hwAttrs; +} I2SCC26XX_Config; + +extern const I2SCC26XX_Config I2SCC26XX_config[]; + +/*! + * @brief I2SCC26XX Hardware attributes + * + * These fields are used by driverlib APIs and therefore must be populated by + * driverlib macro definitions. For CC26xxWare these definitions are found in: + * - inc/hw_memmap.h + * - inc/hw_ints.h + * + * A sample structure is shown below: + * @code + * const I2SCC26XX_HWAttrs i2sCC26XXHWAttrs = { + * { + * I2S0_BASE, + * INT_I2S, + * PERIPH_I2S, + * Board_I2S_MCLK, + * Board_I2S_BCLK, + * Board_I2S_WCLK, + * Board_I2S_ADI, + * Board_I2S_ADO + * }, + * }; + * @endcode + */ +typedef struct I2SCC26XX_HWAttrs { + /*! I2S Peripheral's base address */ + uint32_t baseAddr; + /*! I2S Peripheral's interrupt vector */ + uint8_t intNum; + /*! I2S Peripheral's interrupt priority */ + uint8_t intPriority; + /*! I2S Peripheral's power manager ID */ + PowerCC26XX_Resource powerMngrId; + /*! I2S MCLK pin */ + PIN_Id mclkPin; + /*! I2S BCLK pin */ + PIN_Id bclkPin; + /*! I2S WCLK pin */ + PIN_Id wclkPin; + /*! I2S AD0 pin */ + PIN_Id ad0Pin; + /*! I2S AD1 pin */ + PIN_Id ad1Pin; +} I2SCC26XX_HWAttrs; + +/*! + * @brief I2SCC26XX Audio Clock configuration + * + * These fields are used by the driver to set up the I2S module + * + * A sample structure is shown below (single PDM microphone): + * @code + * const I2SCC26XX_AudioClockConfig i2sCC26XXobjects[] = { + * 16, // Word clock division + * I2SCC26XX_SampleEdge_Negative, + * I2SCC26XX_WordClockPhase_Dual, + * I2SCC26XX_ClockSource_Inverted, + * I2SCC26XX_WordClockSource_Int, + * 47, // Bit clock division + * 0, // Reserved + * I2SCC26XX_BitClockSource_Int + * 6, // Master clock division + * }; + * @endcode + */ +typedef struct I2SCC26XX_AudioClockConfig { + /*! I2S Word Clock divider override */ + uint16_t wclkDiv; + /*! I2S Sample Edge. + * 0 - data and WCLK are sampled on the negative edge and clocked out on the positive edge. + * 1 - data and WCLK are sampled on the positive edge and clocked out on the negative edge */ + uint16_t sampleOnPositiveEdge:1; + /*! I2S Word Clock Phase(I2SCC26XX_WordClockPhase_Dual, I2SCC26XX_WordClockPhase_Single or I2SCC26XX_WordClockPhase_UserDefined) */ + uint16_t wclkPhase:2; + /*! I2S Invert Word Clock (I2SCC26XX_ClockSource_Inverted or I2SCC26XX_ClockSource_Normal) */ + uint16_t wclkInverted:1; + /*! I2S Word Clock source (I2SCC26XX_WordClockSource_Ext or I2SCC26XX_WordClockSource_Int) */ + uint16_t wclkSource:2; + /*! I2S Bit Clock divider override */ + uint16_t bclkDiv:10; + /*! Reserved bit field */ + uint16_t reserved:5; + /*! I2S Bit Clock source (I2SCC26XX_BitClockSource_Ext or I2SCC26XX_BitClockSource_Int) */ + uint16_t bclkSource:1; + /*! I2S Master Clock divider override */ + uint16_t mclkDiv:10; +} I2SCC26XX_AudioClockConfig; + +/*! + * @brief I2SCC26XX Audio Pin configuration + * + * These fields are used by the driver to set up the I2S module + * + * A sample structure is shown below (single PDM microphone): + * @code + * const I2SCC26XX_AudioPinConfig i2sCC26XXobjects[] = { + * I2SCC26XX_ADUsageDisabled, + * 0, + * 0, + * 0, + * 0, + * I2SCC26XX_ADUsageInput, + * 0, + * 1, + * 2, + * I2S_MONO_MODE + * }; + * @endcode + */ +typedef union I2SCC26XX_AudioPinConfig { + /*! Can be used to set pin configurations in DriverLib*/ + struct { + /*! Field that can be used to set pin configuration in DriverLib */ + uint16_t ad1; + /*! Field that can be used to set pin configuration in DriverLib */ + uint16_t ad0; + } driverLibParams; + /*! Used to configure various aspects of the I2S hardware during initialisation */ + struct { + /*! I2S AD1 usage (0: Disabled, 1: Input, 2: Output) */ + uint8_t ad1Usage:2; + /*! I2S Enable Master clock output on pin (0: Disabled, 1: Enabled) */ + uint8_t enableMclkPin:1; + /*! Reserved bit field */ + uint8_t reserved:1; + /*! I2S AD1 number of channels (1 - 8). !Must match channel mask */ + uint8_t ad1NumOfChannels:4; + /*! I2S AD1 Channel Mask bitwise 0:Disabled, 1:Enabled) E.g. Mono: 0x01, Stereo: 0x03 */ + uint8_t ad1ChannelMask; + /*! I2S AD0 usage (0: Disabled, 1: Input, 2: Output) */ + uint8_t ad0Usage:2; + /*! I2S Enable Word clock output on pin (0: Disabled, 1: Enabled) */ + uint8_t enableWclkPin:1; + /*! I2S Enable Bit clock output on pin (0: Disabled, 1: Enabled) */ + uint8_t enableBclkPin:1; + /*! I2S AD0 number of channels (1 - 8). !Must match channel mask*/ + uint8_t ad0NumOfChannels:4; + /*! I2S AD0 Channel Mask bitwise(0:Disabled, 1:Enabled) E.g. Mono: 0x01, Stereo: 0x03 */ + uint8_t ad0ChannelMask; + } bitFields; +} I2SCC26XX_AudioPinConfig; +/*! Mask to use with I2SCC26XX_AudioPinConfig.driverLibParams when calling + * DriverLib. + */ +#define I2SCC26XX_DIR_CHA_M (I2S_LINE_MASK | I2S_CHAN_CFG_MASK) + +/*! + * @brief I2SCC26XX Hardware configuration + * + * These fields are used by the driver to set up the I2S module + * + * A sample structure is shown below (single PDM microphone): + * @code + * const I2SCC26XX_AudioFormatConfig i2sCC26XXobjects[] = { + * I2SCC26XX_WordLength16, + * I2SCC26XX_PositiveEdge, + * I2SCC26XX_DualPhase, + * I2SCC26XX_MemLen16bit, + * I2SCC26XX_FormatI2SandDSP + * }; + * @endcode + */ +typedef struct I2SCC26XX_AudioFormatConfig { + /*! Number of bits per word (8-24). Exact for single phase, max for dual phase */ + uint8_t wordLength:5; + /*! Sample edge. Data and Word clock is samples, and clocked out, on opposite edges of BCLK. + * 0: NEG (Data is sample on the negative edge and clocked out on the positive edge) + * 1: POS (Data is sample on the positive edge and clocked out on the negative edge)*/ + uint8_t sampleEdge:1; + /*! Selects dual- or single phase format (0: Single, 1: Dual) */ + uint8_t dualPhase:1; + /*! Size of each word stored to or loaded from memory (0: 16, 1: 24) */ + uint8_t memLen:1; + /*! Number of BCLK perids between a WCLK edge and MSB of the first word in a phase */ + uint8_t dataDelay; +} I2SCC26XX_AudioFormatConfig; + + +/*! + * @brief I2SCC26XX Object + * + * The application must not access any member variables of this structure! + */ +typedef enum I2SCC26XX_RequestMode { + /*! + * I2SCC26XX_requestBuffer() blocks execution. This mode can only be used when called + * within a Task context. + */ + I2SCC26XX_MODE_BLOCKING, + /*! + * I2SCC26XX_requestBuffer returns immediately + * if no buffer is available. The caller is notified through events each time + * a buffer is available. This mode can be used in a Task, Swi, or Hwi context. + */ + I2SCC26XX_CALLBACK_MODE +} I2SCC26XX_RequestMode; + +/*! + * @brief + * A ::I2SCC26XX_StreamNotification data structure is used with I2SCC26XX_CallbackFxn(). + * Provides notification about available buffers and potential errors + */ +typedef struct I2SCC26XX_StreamNotification { + void *arg; /*!< Argument to be passed to the callback function */ + I2SCC26XX_Status status; /*!< Status code set by I2SCC26XX driver */ +} I2SCC26XX_StreamNotification; + +/*! + * @brief + * A ::I2SCC26XX_BufferRequest data structure is used with I2SCC26XX_requestBuffer(). + * + * bufferIn is a pointer to the requested buffer. It is NULL if no buffer is + * available\n + * bufferOut is a pointer to the buffer that the caller wants to send. It is + * NULL if no output is available.\n + * If only input is supported then set bufferOut to NULL + * + * Input Mode | Interpretation of bufferIn being NULL after returning | + * --------------------|-------------------------------------------------------| + * Blocking mode | Request timed out and still no buffer available | + * Non-Blocking mode | No buffer available | + * + * I2SCC26XX_requestBuffer will also return \b false if there are no buffers + * available. + * + * \sa I2SCC26XX_requestBuffer + */ +typedef struct I2SCC26XX_BufferRequest { + void *bufferIn; /*!< Pointer to requested In buffer */ + void *bufferOut; /*!< Pointer to requested Out buffer */ + void *bufferHandleIn; /*!< Pointer to requested In buffers handle */ + void *bufferHandleOut; /*!< Pointer to requested Out buffers handle */ + I2SCC26XX_Status status; /*!< Status code set by I2SCC26XX_requestBuffer */ +} I2SCC26XX_BufferRequest; + +/*! + * @brief + * A ::I2SCC26XX_BufferRelease data structure is used with I2SCC26XX_releaseBuffer(). + * + * bufferHandleIn and bufferHandleOut allows the driver to take back and + * reuse memory. + */ +typedef struct I2SCC26XX_BufferRelease { + void *bufferHandleIn; /*!< Pointer to requested In buffers handle that we now release */ + void *bufferHandleOut; /*!< Pointer to requested Out buffers handle that we now release */ +} I2SCC26XX_BufferRelease; + +/*! + * @brief The definition of a callback function used when wakeup on + * chip select is enabled + * + * @param I2SCC26XX_Handle I2SCC26XX_Handle + */ +typedef void (*I2SCC26XX_CallbackFxn) (I2SCC26XX_Handle handle, I2SCC26XX_StreamNotification *notification); + +/*! + * @brief + * I2SCC26XX PDM Parameters are used to with the I2SCC26XX_Params_init() call. + * + * @sa I2SCC26XX_Params_init + */ +typedef struct I2SCC26XX_PDM_Params { + /* I2S control variables */ + I2SCC26XX_RequestMode requestMode; /*!< Blocking or Callback mode */ + uint32_t ui32requestTimeout; /*!< Timeout for the request when in blocking mode */ + I2SCC26XX_CallbackFxn callbackFxn; /*!< Callback function pointer */ + I2SCC26XX_TransferSize blockSize; /*!< I2S DMA transfer size in number of samples. Each + * sample consumes either 16 or 24 bits per channel, + * set by ::I2SCC26XX_AudioFormatConfig.memLen. Number + * of channels are set in + * ::I2SCC26XX_AudioPinConfig.ad0NumOfChannels and + * ::I2SCC26XX_AudioPinConfig.ad1NumOfChannels*/ + + /* I2S stream variables */ + void *pvContBuffer; /*!< Pointer to consecutive buffer in memory. Driver + * will chunk it into the queue. Make sure to provide + * correct buffer size ::I2SCC26XX_I2S_Params.ui32conBufTotalSize*/ + uint32_t ui32conBufTotalSize; /*!< Size of consecutive buffer must match total + * available sample size: (wanted number of blocks) * + * (number of samples per block) * (samplesize(in bytes)) * + * number of channels*/ + void *pvContMgtBuffer; /*!< Pointer to consecutive buffer in memory. Driver + * will use this to manage buffer. Make sure to provide correct + * buffer size ::I2SCC26XX_I2S_Params.ui32conMgtBufTotalSize*/ + uint32_t ui32conMgtBufTotalSize; /*!< Size of consecutive buffer must match total + * available sample size: (wanted number of blocks IN and OUT, + * it must be same number IN and OUT) * overhead size + * ::I2S_BLOCK_OVERHEAD_IN_BYTES */ + I2SCC26XX_StreamNotification *currentStream; /*!< Pointer to information about the current state + * of the stream*/ +} I2SCC26XX_PDM_Params; + +/*! + * @brief + * I2SCC26XX I2S Parameters are used to with the I2SCC26XX_Params_init() call. + * + * @sa I2SCC26XX_Params_init + */ +typedef struct I2SCC26XX_I2S_Params { + /* I2S control variables */ + I2SCC26XX_RequestMode requestMode; /*!< Blocking or Callback mode */ + uint32_t ui32requestTimeout; /*!< Timeout for the request when in blocking mode */ + I2SCC26XX_CallbackFxn callbackFxn; /*!< Callback function pointer */ + int32_t i32SampleRate; /*!< I2S bit clock frequency in Hz. If negative, or one of I2S_SAMPLE_RATE_16K/_24K/_32K/_48K then use user configured clock division.*/ + I2SCC26XX_TransferSize blockSize; /*!< I2S DMA transfer size in number of samples. Each + * sample consumes either 16 or 24 bits per channel, + * set by ::I2SCC26XX_AudioFormatConfig.memLen. Number + * of channels are set in + * ::I2SCC26XX_AudioPinConfig.ad0NumOfChannels and + * ::I2SCC26XX_AudioPinConfig.ad1NumOfChannels*/ + + /* I2S stream variables */ + void *pvContBuffer; /*!< Pointer to consecutive buffer in memory. Driver + * will chunk it into the queue. Make sure to provide + * correct buffer size ::I2SCC26XX_I2S_Params.ui32conBufTotalSize*/ + uint32_t ui32conBufTotalSize; /*!< Size of consecutive buffer must match total + * available sample size: (wanted number of blocks) * + * (number of samples per block) * (samplesize(in bytes)) * + * number of channels*/ + void *pvContMgtBuffer; /*!< Pointer to consecutive buffer in memory. Driver + * will use this to manage buffer. Make sure to provide correct + * buffer size ::I2SCC26XX_I2S_Params.ui32conMgtBufTotalSize*/ + uint32_t ui32conMgtBufTotalSize; /*!< Size of consecutive buffer must match total + * available sample size: (wanted number of blocks IN and OUT, + * it must be same number IN and OUT) * overhead size + * ::I2S_BLOCK_OVERHEAD_IN_BYTES */ + I2SCC26XX_StreamNotification *currentStream; /*!< Pointer to information about the current state + * of the stream*/ +} I2SCC26XX_I2S_Params; + +/*! + * @brief + * I2SCC26XX Parameters are used to with the I2SCC26XX_open() call. Default values for + * these parameters are set using I2SCC26XX_Params_init(). + * + * @sa I2SCC26XX_Params_init + */ +typedef struct I2SCC26XX_Params { + /* I2S control variables */ + I2SCC26XX_RequestMode requestMode; /*!< Blocking or return mode */ + uint32_t ui32requestTimeout; /*!< Timeout for the request when in blocking mode */ + I2SCC26XX_CallbackFxn callbackFxn; /*!< Callback function pointer */ + int32_t i32SampleRate; /*!< I2S bit clock frequency in Hz. If negative, or one of I2S_SAMPLE_RATE_16K/_24K/_32K/_48K then use user configured clock division.*/ + I2SCC26XX_AudioClockConfig audioClkCfg; /*!< I2S clock division override and clock config*/ + I2SCC26XX_AudioPinConfig audioPinCfg; /*!< I2S pin configuration*/ + I2SCC26XX_AudioFormatConfig audioFmtCfg; /*!< I2S audio format configuration*/ + I2SCC26XX_TransferSize blockSize; /*!< I2S DMA transfer size in number of samples. Each sample consumes either 16 or 24 bits per channel, set by ::I2SCC26XX_AudioFormatConfig.memLen. Number of channels are set in ::I2SCC26XX_AudioPinConfig.adXNumOfChannels*/ + + /* I2S stream variables */ + void *pvContBuffer; /*!< Pointer to consecutive buffer in memory. Driver will chunk it into the queue*/ + uint32_t ui32conBufTotalSize; /*!< Size of consecutive buffer must match total available sample size: wanted number of blocks * number of samples per block * samplesize(in bytes) * number of channels*/ + void *pvContMgtBuffer; /*!< Pointer to consecutive buffer in memory. Driver will use this to manage buffer */ + uint32_t ui32conMgtBufTotalSize; /*!< Size of consecutive buffer must match total available sample size: wanted number of blocks in and out (must be same number in and out) * overhead size () */ + I2SCC26XX_StreamNotification *currentStream; /*!< Ptr to information about the current transaction*/ + void *custom; /*!< Custom argument used by driver implementation */ +} I2SCC26XX_Params; + +/*! + * @brief I2SCC26XX Object + * + * The application must not access any member variables of this structure! + */ +typedef struct I2SCC26XX_Object { + /* I2S control variables */ + I2SCC26XX_RequestMode requestMode; /*!< Blocking or return mode */ + uint32_t ui32requestTimeout; /*!< Timeout for the request when in blocking mode */ + I2SCC26XX_CallbackFxn callbackFxn; /*!< Callback function pointer */ + int32_t i32SampleRate; /*!< I2S bit clock frequency in Hz. If negative, or not one of I2S_SAMPLE_RATE_16K/_24K/_32K/_48K then use user configured clock division.*/ + I2SCC26XX_AudioClockConfig audioClkCfg; /*!< I2S clock division override and clock config*/ + I2SCC26XX_AudioPinConfig audioPinCfg; /*!< I2S pin configuration*/ + I2SCC26XX_AudioFormatConfig audioFmtCfg; /*!< I2S audio format configuration*/ + I2SCC26XX_TransferSize blockSize; /*!< I2S DMA transfer size, determines the block size in number of samples. Each sample consumes either 16 or 24 bits, set by ::I2SCC26XX_AudioFormatConfig.memLen*/ + + /* I2S stream variables */ + void *pvContBuffer; /*!< Pointer to consecutive buffer in memory. Driver will chunk it into the queue*/ + uint32_t ui32conBufTotalSize; /*!< Size of consecutive buffer must match total available sample size: block * number of samples * samplesize(in bytes) * number of channels*/ + void *pvContMgtBuffer; /*!< Pointer to consecutive buffer in memory. Driver will use this to manage buffer */ + uint32_t ui32conMgtBufTotalSize; /*!< Size of consecutive buffer must match total available sample size: wanted number of blocks in and out (must be same number in and out) * overhead size () */ + I2SCC26XX_StreamNotification *currentStream; /*!< Ptr to information about the current transaction*/ + + /* I2S SYS/BIOS objects */ + ti_sysbios_family_arm_m3_Hwi_Struct hwi; /*!< Hwi object handle */ + Semaphore_Struct blockComplete; /*!< Notify complete I2SCC26XX block transfer */ + Semaphore_Struct semStopping; /*!< I2SCC26XX stopping sequence semaphore */ + + /* PIN driver state object and handle */ + PIN_State pinState; /*!< PIN driver state object */ + PIN_Handle pinHandle; /*!< PIN driver handle */ + + bool isOpen; /*!< Has the object been opened */ +} I2SCC26XX_Object; + +/*! + * @brief I2S CC26XX initialization + * + * @param handle A I2SCC26XX_Handle + * + */ +extern void I2SCC26XX_init(I2SCC26XX_Handle handle); + +/*! + * @brief Function to set initialization parameters for the audio interface. + * + * The parameter \b mode specifies which mode the audio interface module will + * operate. \b modeSpecificParams must point to a struct that matches the + * selected mode. This is because this function will type-cast the void* based + * on the selected mode. + * + * \b params is filled correctly by this function. Its memory must be allocated + * by the caller. Note however that it only has to live past the call to + * I2SCC26XX_open(). + * + * @param params Pointer to allocated structure to hold parameters to be used in I2SCC26XX_open + * @param mode Selects what predefined mode to configure + * @modeSpecificParams Pointer to parameters that are specific to the requested configuration + * + */ +extern bool I2SCC26XX_Params_init(I2SCC26XX_Params *params, I2SCC26XX_Mode mode, void *modeSpecificParams); + +/*! + * @brief Function to open a given CC26XX I2S peripheral specified by the + * I2S handle. + * + * The function will set a dependency on its power domain, i.e. power up the + * module and enable the clock. The IOs are allocated. The I2S will not be + * enabled. + * + * \b params must point a correctly initialized I2SCC26XX_Params struct. + * I2SCC26XX_Params_init is a convenience function to initialize the struct + * correctly. + * + * @pre I2S controller has been initialized + * + * @param handle A I2SCC26XX_Handle + * + * @param params Pointer to a parameter block, if NULL it will use + * default values + * + * @return A I2SCC26XX_Handle on success or a NULL on an error or if it has been + * already opened + * + * @sa I2SCC26XX_close() + */ +extern I2SCC26XX_Handle I2SCC26XX_open(I2SCC26XX_Handle handle, I2SCC26XX_Params *params); + +/*! + * @brief Function to close a given CC26XX I2S peripheral specified by the + * I2S handle. + * + * Will disable the I2S, disable all I2S interrupts and release the + * dependency on the corresponding power domain. It will also destroy all + * semaphores and queues that have been used. + * + * @pre I2SCC26XX_open() has to be called first. + * + * @param handle A I2SCC26XX_Handle returned from I2SCC26XX_open() + * + * @sa I2SCC26XX_open + */ +extern void I2SCC26XX_close(I2SCC26XX_Handle handle); + +/*! + * @brief Function for starting an I2S interface. + * + * Calling this function will prevent the device from sleeping, as the + * stream is continuous and thus require power to the audio interface module + * from start to end. + * This function will configure all hardware registers that does not have + * retention. Hence, one may call I2SCC26XX_open then go to sleep before this + * function is called. + * + * If non-blocking mode is selected then the I2SCC26XX module will begin + * calling the provided callback function every time a new buffer is ready. + * + * @pre I2SCC26XX_open() has to be called first. + * + * @param handle An I2S handle returned from I2SCC26XX_open() + * + * @return True if transfer is successful and false if not + * + * @sa I2SCC26XX_open(), I2SCC26XX_stopStream() + */ +extern bool I2SCC26XX_startStream(I2SCC26XX_Handle handle); + +/*! + * @brief Function for stopping an I2S interface. + * + * This function will initiate the shut down sequence. The audio interface + * module is designed with a graceful shutdown. What this means is that the + * current buffer is filled before stopping. This function will block while + * the last buffer is completing. The maximum blocking delay is a function + * of the configured DMA transfer size, and the word clock rate. + * + * When this function returns it is recommended to complete processing of + * all pending ready buffers. If the caller is not interested in the last + * audio data it may simply call I2SCC26XX_requestBuffer() and + * I2SCC26XX_releaseBuffer() in a loop until I2SCC26XX_requestBuffer() returns + * false. + * + * Will disable the I2S, disable all I2S interrupts and release the + * dependency on the corresponding power domain. + * + * @pre I2SCC26XX_startStream() has to be called first. + * + * @param handle An I2S handle returned from I2SCC26XX_open() + * + * @return True if stream stopped successfully and false if not + * + * @sa I2SCC26XX_open(), I2SCC26XX_startStream() + */ +extern bool I2SCC26XX_stopStream(I2SCC26XX_Handle handle); + +/*! + * @brief Function for requesting buffer. + * + * In ::I2SCC26XX_MODE_BLOCKING, I2SCC26XX_requestBuffer will block task + * execution until at least one buffer is ready. + * + * In ::I2SCC26XX_CALLBACK_MODE, I2SCC26XX_requestBuffer returns immediately + * if no buffer is available. The caller is notified through events each time + * a buffer is available. + * + * This function takes as an argument a pointer to a struct which contains + * 4 pointers. There are two pairs; one for Input and one for Output. + * If input is defined then the input buffer pointer will point to the + * new input buffer. Same goes for output and the output buffer pointer. + * The caller is not expected to allocate memory for the buffer as no copy + * is performed. The other two pointers must be maintained by the caller until + * it is ready to call I2SCC26XX_releaseBuffer(). + * + * @pre I2SCC26XX_open() and I2SCC26XX_startStream() has to be called first. + * + * @param handle A I2S handle returned from I2SCC26XX_open() + * + * @param *bufferRequest Pointer to I2SCC26XX_BufferRequest struct + * + * @return True if a buffer is available, false if not. + * + * @sa I2SCC26XX_open(), I2SCC26XX_startStream(), I2SCC26XX_releaseBuffer() + */ +extern bool I2SCC26XX_requestBuffer(I2SCC26XX_Handle handle, I2SCC26XX_BufferRequest *bufferRequest); + +/*! + * @brief Function for releasing buffer. + * + * The caller of I2SCC26XX_requestBuffer() must call this function when it is + * finished working on the buffer. This function takes as an argument a pointer + * to a struct which contains two other pointers. These pointers must be set + * the pointers received in I2SCC26XX_requestBuffer(). + * + * @pre I2SCC26XX_requestBuffer() has to be called first. + * + * @param handle A I2S handle returned from I2SCC26XX_open() + * + * @param *bufferRelease Pointer to I2SCC26XX_BufferRelease struct + * + * @return True if release is successful and false if not + * + * @sa I2SCC26XX_open(), I2SCC26XX_startStream(), I2SCC26XX_requestBuffer() + */ +extern Void I2SCC26XX_releaseBuffer(I2SCC26XX_Handle handle, I2SCC26XX_BufferRelease *bufferRelease); + +/* Do not interfere with the app if they include the family Hwi module */ +#undef ti_sysbios_family_arm_m3_Hwi__nolocalnames + +#ifdef __cplusplus +} +#endif + +#endif /* ti_drivers_i2s_I2SCC26XX__include */ diff --git a/src/util/audio_codec/audiocodec.c b/src/util/audio_codec/audiocodec.c new file mode 100644 index 0000000..1332d72 --- /dev/null +++ b/src/util/audio_codec/audiocodec.c @@ -0,0 +1,638 @@ +/* + * Filename: audiocodec.c + * + * Description: This file implments the control interface to the + * TLV320AIC3254 Stereo Audio Codec + * + * + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/********************************************************************* + * INCLUDES + */ +#include +#include + +#include +#include +#include "audiocodec.h" +#include "ti3254.h" +#include "Board.h" + + +/********************************************************************* + * LOCAL VARIABLES + */ + +// I2C driver interface +static I2C_Handle i2cHandle; +static I2C_Params i2cParams; + +/********************************************************************* + * LOCAL VARIABLES + */ +static unsigned long AudioCodecPageSelect(unsigned char ulPageAddress); +static unsigned long AudioCodecRegWrite(unsigned char ulRegAddr,unsigned char ucRegValue); + + +/********************************************************************* + * @fn AudioCodecOpen + * + * @brief Initalizes and opens I2C interface to TLV320AIC3254, resets + * + * @param none + * + * @return status - AUDIO_CODEC_STATUS_SUCCESS: if succeeded + * AUDIO_CODEC_STATUS_I2C_FAIL: if I2C failed to open + */ +uint8_t AudioCodecOpen() +{ + // Initialize the I2C pins + I2C_init(); + I2C_Params_init(&i2cParams); + + // Setup I2C with fast bitrate, blocking mode + i2cParams.bitRate = I2C_400kHz; + i2cParams.transferMode = I2C_MODE_BLOCKING; + + // Open the I2C and get a handle + i2cHandle = I2C_open(Board_I2C, &i2cParams); + + // Ensure that I2C is able to open + if (NULL == i2cHandle) + { + return AUDIO_CODEC_STATUS_I2C_FAIL; + } + + // Reset the device + AudioCodecReset(AUDIO_CODEC_TI_3254, NULL); + + + return AUDIO_CODEC_STATUS_SUCCESS; +} + + +/********************************************************************* + * @fn AudioCodecClose + * + * @brief Closes I2C interface to TLV320AIC3254 + * + * @param none + * + * @return none + */ +void AudioCodecClose() +{ + if (i2cHandle != NULL) + { + I2C_close(i2cHandle); + } + return; +} + +/********************************************************************* + * @fn AudioCodecReset + * + * @brief Perform a soft reset of the device + * + * @param none + * + * @return none + */ +int AudioCodecReset(unsigned char codecId, void *arg) +{ + if(codecId == AUDIO_CODEC_TI_3254) + { + + // + // Select page 0 + // + AudioCodecPageSelect(TI3254_PAGE_0); + + // + // Soft RESET + // + AudioCodecRegWrite(TI3254_SW_RESET_REG, 0x01); + } + + return 0; +} + +/********************************************************************* + * @fn AudioCodecConfig + * + * @brief Configure audio codec for smaple rate, bits and number of channels + * + * @param[in] codecId - Device id + * @param[in] bitsPerSample - Bits per sample (8, 16, 24 etc..) + * Please ref Bits per sample Macro section + * @param[in] bitRate - Sampling rate in Hz. (8000, 16000, 44100 etc..) + * @param[in] noOfChannels - Number of channels. (Mono, stereo etc..) + * Please refer Number of Channels Macro section + * @param[in] speaker - Audio out that need to configure. (headphone, line out, all etc..) + * Please refer Audio Out Macro section + * @param[in] mic - Audio in that need to configure. (line in, mono mic, all etc..) + * Please refer Audio In Macro section + * + * @return 0 on success else -ve. + */ +int AudioCodecConfig(unsigned char codecId, unsigned char bitsPerSample, unsigned short bitRate, + unsigned char noOfChannels, unsigned char speaker, unsigned char mic) +{ + unsigned int bitClk = 0; + + if(codecId == AUDIO_CODEC_TI_3254) + { + AudioCodecPageSelect(TI3254_PAGE_0); + + if(bitsPerSample == AUDIO_CODEC_16_BIT) + { + // Set I2S Mode and Word Length + AudioCodecRegWrite(TI3254_AUDIO_IF_1_REG, 0x00); // 0x00 16bit, I2S, BCLK is input to the device + // WCLK is input to the device, + } + else + { + return -1; + } + + bitClk = bitsPerSample * bitRate * noOfChannels; + if(bitClk == 512000) + { + AudioCodecPageSelect(TI3254_PAGE_0); + + AudioCodecRegWrite(TI3254_CLK_MUX_REG, 0x03); // PLL Clock is CODEC_CLKIN +// AudioCodecRegWrite(TI3254_CLK_PLL_P_R_REG, 0x14 | 0x80); // PLL is powered up, P=1, R=4 + AudioCodecRegWrite(TI3254_CLK_PLL_P_R_REG, 0x71 | 0x80); // PLL is powered up, P=7, R=1 +// AudioCodecRegWrite(TI3254_CLK_PLL_J_REG, 0x2A); // J=42 + AudioCodecRegWrite(TI3254_CLK_PLL_J_REG, 0x2B); // J=43 + AudioCodecRegWrite(TI3254_CLK_PLL_D_MSB_REG, 0x00); // D = 0 + +// AudioCodecRegWrite(TI3254_CLK_NDAC_REG, 0x8E); // NDAC divider powered up, NDAC = 14 + AudioCodecRegWrite(TI3254_CLK_NDAC_REG, 0x88); // NDAC divider powered up, NDAC = 8 +// AudioCodecRegWrite(TI3254_CLK_MDAC_REG, 0x81); // MDAC divider powered up, MDAC = 1 + AudioCodecRegWrite(TI3254_CLK_MDAC_REG, 0x81); // MDAC divider powered up, MDAC = 1 + AudioCodecRegWrite(TI3254_DAC_OSR_MSB_REG, 0x01); // DOSR = 0x0180 = 384 + AudioCodecRegWrite(TI3254_DAC_OSR_LSB_REG, 0x80); // DOSR = 0x0180 = 384 + +// AudioCodecRegWrite(TI3254_CLK_NADC_REG, 0x95); // NADC divider powered up, NADC = 21 + AudioCodecRegWrite(TI3254_CLK_NADC_REG, 0x8C); // NADC divider powered up, NADC = 12 + AudioCodecRegWrite(TI3254_CLK_MADC_REG, 0x82); // MADC divider powered up, MADC = 2 + AudioCodecRegWrite(TI3254_ADC_OSR_REG, 0x80); // AOSR = 128 ((Use with PRB_R1 to PRB_R6, ADC Filter Type A) + } + else + { + return -1; + } + + + // Configure Power Supplies + AudioCodecPageSelect(TI3254_PAGE_1); //Select Page 1 + + AudioCodecRegWrite(TI3254_PWR_CTRL_REG, 0x08); // Disabled weak connection of AVDD with DVDD + AudioCodecRegWrite(TI3254_LDO_CTRL_REG, 0x01); // Over Current detected for AVDD LDO + AudioCodecRegWrite(TI3254_ANALOG_IP_QCHRG_CTRL_REG, 0x32); // Analog inputs power up time is 6.4 ms + AudioCodecRegWrite(TI3254_REF_PWR_UP_CTRL_REG, 0x01); // Reference will power up in 40ms when analog blocks are powered up + + + if(speaker) + { + unsigned char reg1; + + AudioCodecPageSelect(TI3254_PAGE_0); //Select Page 0 + + + // ##Configure Processing Blocks + AudioCodecRegWrite(TI3254_DAC_SIG_P_BLK_CTRL_REG, 0x2); // DAC Signal Processing Block PRB_P2 + + + AudioCodecPageSelect(TI3254_PAGE_44); // Select Page 44 + + AudioCodecRegWrite(TI3254_DAC_ADP_FILTER_CTRL_REG, 0x04); // Adaptive Filtering enabled for DAC + + + AudioCodecPageSelect(TI3254_PAGE_1); // Select Page 1 + + reg1 = 0x00; + + if(speaker & AUDIO_CODEC_SPEAKER_HP) + { + //De-pop: 5 time constants, 6k resistance + AudioCodecRegWrite(TI3254_HP_DRV_START_UP_CTRL_REG, 0x25); // Headphone ramps power up time is determined with 6k resistance, + // Headphone ramps power up slowly in 5.0 time constants + + //Route LDAC/RDAC to HPL/HPR + AudioCodecRegWrite(TI3254_HPL_ROUTING_SEL_REG, 0x08); // Left Channel DAC reconstruction filter's positive terminal is routed to HPL + AudioCodecRegWrite(TI3254_HPR_ROUTING_SEL_REG, 0x08); // Left Channel DAC reconstruction filter's negative terminal is routed to HPR + + reg1 |= 0x30; // HPL and HPR is powered up + } + + if(speaker & AUDIO_CODEC_SPEAKER_LO) + { + //Route LDAC/RDAC to LOL/LOR + AudioCodecRegWrite(TI3254_LOL_ROUTING_SEL_REG, 0x08); // Left Channel DAC reconstruction filter output is routed to LOL + AudioCodecRegWrite(TI3254_LOR_ROUTING_SEL_REG, 0x08); // Right Channel DAC reconstruction filter output is routed to LOR + + reg1 |= 0x0C; // LOL and LOR is powered up + } + + //Power up HPL/HPR and LOL/LOR drivers + AudioCodecRegWrite(TI3254_OP_DRV_PWR_CTRL_REG, reg1); + + if(speaker & AUDIO_CODEC_SPEAKER_HP) + { + //Unmute HPL/HPR driver, 0dB Gain + AudioCodecRegWrite(TI3254_HPL_DRV_GAIN_CTRL_REG, 0x00); // HPL driver is not muted, HPL driver gain is 0dB + AudioCodecRegWrite(TI3254_HPR_DRV_GAIN_CTRL_REG, 0x00); // HPR driver is not muted, HPL driver gain is 0dB + } + + if(speaker & AUDIO_CODEC_SPEAKER_LO) + { + //Unmute LOL/LOR driver, 0dB Gain + AudioCodecRegWrite(TI3254_LOL_DRV_GAIN_CTRL_REG, 0x0E); // LOL driver gain is 11dB + AudioCodecRegWrite(TI3254_LOR_DRV_GAIN_CTRL_REG, 0x0E); // LOL driver gain is 11dB + } + + + + AudioCodecPageSelect(TI3254_PAGE_0); //Select Page 0 + + //DAC => 64dB + AudioCodecRegWrite(TI3254_LEFT_DAC_VOL_CTRL_REG, 0x80); // Digital Volume Control = 64.0dB silent Note: As per data sheet its reserved but on setting this value there is silent + AudioCodecRegWrite(TI3254_RIGHT_DAC_VOL_CTRL_REG, 0x80); // Digital Volume Control = 64.0dB silent Note: As per data sheet its reserved but on setting this value there is silent + + + AudioCodecPageSelect(TI3254_PAGE_0); //Select Page 0 + + //Power up LDAC/RDAC + AudioCodecRegWrite(TI3254_DAC_CHANNEL_SETUP_1_REG, 0xD6); // Left and Right DAC Channel Powered Up + // Left DAC data Left Channel Audio Interface Data + // Right DAC data is Left Channel Audio Interface Data + // Soft-Stepping is disabled + + //Unmute LDAC/RDAC + AudioCodecRegWrite(TI3254_DAC_CHANNEL_SETUP_2_REG, 0x00); // When Right DAC Channel is powered down, the data is zero. + // Auto Mute disabled + // Left and Right DAC Channel not muted + // Left and Right Channel have independent volume control + } + + + if(mic) + { + unsigned char reg1 = 0x00; // TI3254_MICBIAS_CTRL_REG + unsigned char reg2 = 0x00; // TI3254_LEFT_MICPGA_P_CTRL_REG + unsigned char reg3 = 0x00; // TI3254_LEFT_MICPGA_N_CTRL_REG + unsigned char reg4 = 0x00; // TI3254_RIGHT_MICPGA_P_CTRL_REG + unsigned char reg5 = 0x00; // TI3254_RIGHT_MICPGA_N_CTRL_REG + unsigned char reg6 = 0x00; // TI3254_FLOAT_IP_CTRL_REG + + + AudioCodecPageSelect(TI3254_PAGE_8); // Select Page 8 + + AudioCodecRegWrite(TI3254_ADC_ADP_FILTER_CTRL_REG, 0x04); // Adaptive Filtering enabled for ADC + + + AudioCodecPageSelect(TI3254_PAGE_0); //Select Page 0 + + AudioCodecRegWrite(TI3254_ADC_SIG_P_BLK_CTRL_REG, 0x2); // ADC Signal Processing Block PRB_P2 + + if(mic & AUDIO_CODEC_MIC_LINE_IN) + { + reg1 |= 0x40; // MICBIAS powered up + reg2 |= 0x40; // IN1L is routed to Left MICPGA with 10k resistance + reg3 |= 0x40; // CM is routed to Left MICPGA via CM1L with 10k resistance + reg4 |= 0x40; // IN1R is routed to Right MICPGA with 10k resistance + reg5 |= 0x40; // CM is routed to Right MICPGA via CM1R with 10k resistance + reg6 |= 0xC0; // IN1L input is weakly driven to common mode. Use when not routing IN1L to Left and Right MICPGA and HPL, HPR + } + + if(mic & AUDIO_CODEC_MIC_MONO) + { + reg1 |= 0x40; // MICBIAS powered up + reg2 |= 0x00; + reg3 |= 0x10; + reg4 |= 0x10; // IN2R is routed to Right MICPGA with 10k resistance + reg5 |= 0x40; // CM is routed to Right MICPGA via CM1R with 10k resistance + reg6 |= 0x10; // IN2R input is weakly driven to common mode. Use when not routing IN2R to Left and Right MICPGA + } + + if(mic & AUDIO_CODEC_MIC_ONBOARD) + { + reg1 |= 0x40; // MICBIAS powered up + reg2 |= 0x00; + reg3 |= 0x04; + reg4 |= 0x04; // IN3R is routed to Right MICPGA with 10k resistance + reg5 |= 0x40; // CM is routed to Right MICPGA via CM1R with 10k resistance + reg6 |= 0x04; // IN3R input is weakly driven to common mode. Use when not routing IN3R to Left and Right MICPGA + } + + AudioCodecPageSelect(TI3254_PAGE_1); //Select Page 1 + + AudioCodecRegWrite(TI3254_MICBIAS_CTRL_REG, reg1); + + //Route IN2L not routed + AudioCodecRegWrite(TI3254_LEFT_MICPGA_P_CTRL_REG, reg2); + + //Route IN2R CM1L to LEFT_N with 10K input impedance + AudioCodecRegWrite(TI3254_LEFT_MICPGA_N_CTRL_REG, reg3); + + //Route IN2R to RIGHT_P with 10K input impedance + AudioCodecRegWrite(TI3254_RIGHT_MICPGA_P_CTRL_REG, reg4); + + //Route CM1R to RIGHT_M with 10K input impedance + AudioCodecRegWrite(TI3254_RIGHT_MICPGA_N_CTRL_REG, reg5); + + AudioCodecRegWrite(TI3254_FLOAT_IP_CTRL_REG, reg6); + + + //make channel gain 0dB, since 20K input + //impedance is used single ended + AudioCodecRegWrite(TI3254_LEFT_MICPGA_VOL_CTRL_REG, 0x00); // 0.0dB + + //Unmute Right MICPGA, Gain selection of 6dB to + //make channel gain 0dB, since 20K input + //impedance is used single ended + AudioCodecRegWrite(TI3254_RIGHT_MICPGA_VOL_CTRL_REG, 0x00); // 0.0dB + + + AudioCodecRegWrite(TI3254_LEFT_ADC_VOL_CTRL_REG, 0x68); // -12dB + AudioCodecRegWrite(TI3254_RIGHT_ADC_VOL_CTRL_REG, 0x68); // -12dB + + + + AudioCodecPageSelect(TI3254_PAGE_0); // Select Page 0 + + //Power up LADC/RADC + AudioCodecRegWrite(TI3254_ADC_CHANNEL_SETUP_REG, 0xC0); // Left and Right Channel ADC is powered up + + //Unmute LADC/RADC + AudioCodecRegWrite(TI3254_ADC_FINE_GAIN_ADJ_REG, 0x00); // Left and Right ADC Channel Un-muted. Left and Right ADC Channel Fine Gain = 0dB, + } + + } + + return 0; +} + +/********************************************************************* + * @fn AudioCodecSpeakerVolCtrl + * + * @brief Configure volume level for specific audio out on a codec device + * + * @param[in] codecId - Device id + * @param[in] speaker - Audio out id. (headphone, line out, all etc..) + * Please refer Audio out Macro section + * @param[in] volumeLevel - Volume level. 0-100 + * + * @return 0 on success else -ve. + */ +int AudioCodecSpeakerVolCtrl(unsigned char codecId, unsigned char speaker, signed char volumeLevel) +{ + short vol = 0; + + if(volumeLevel < 4) + { + vol = 128; + } + else if (volumeLevel > 97) + { + vol = 304; + } + else + { + vol = 122 + (volumeLevel << 1); + } + + + AudioCodecPageSelect(TI3254_PAGE_0); + AudioCodecRegWrite(TI3254_LEFT_DAC_VOL_CTRL_REG, (unsigned char )(vol&0x00FF)); + AudioCodecRegWrite(TI3254_RIGHT_DAC_VOL_CTRL_REG, (unsigned char )(vol&0x00FF)); + return 0; +} + +/********************************************************************* + * @fn AudioCodecSpeakerMute + * + * @brief Mute Audio line out + * + * @param[in] codecId - Device id + * @param[in] speaker - Audio out id. (headphone, line out, all etc..) + * Please refer Audio out Macro section + * + * @return 0 on success else -ve. + */ +int AudioCodecSpeakerMute(unsigned char codecId, unsigned char speaker) +{ + AudioCodecPageSelect(TI3254_PAGE_0); + + //Unmute LDAC/RDAC + AudioCodecRegWrite(TI3254_DAC_CHANNEL_SETUP_2_REG, 0x0C); // Left and Right DAC Channel muted + return 0; +} + +/********************************************************************* + * @fn AudioCodecSpeakerUnmute + * + * @brief Unmute audio line out + * + * @param[in] codecId - Device id + * @param[in] speaker - Audio out id. (headphone, line out, all etc..) + * Please refer Audio out Macro section + * + * @return 0 on success else -ve. + */ +int AudioCodecSpeakerUnmute(unsigned char codecId, unsigned char speaker) +{ + + AudioCodecPageSelect(TI3254_PAGE_0); + + //Unmute LDAC/RDAC + AudioCodecRegWrite(TI3254_DAC_CHANNEL_SETUP_2_REG, 0x00); // Left and Right DAC Channel not muted + return 0; +} + +/********************************************************************* + * @fn AudioCodecMicVolCtrl + * + * @brief Configure volume level for specific audio in on a codec device + * + * @param[in] codecId - Device id + * @param[in] mic - Audio in id. (line in, mono mic, all etc..) + * Please refer Audio In Macro section + * @param[in] volumeLevel - Volume level (0 - 100) + * + * @return 0 on success else -ve. + */ +int AudioCodecMicVolCtrl(unsigned char codecId, unsigned char mic, signed char volumeLevel) +{ + static unsigned char vol = 0x00; + + //Note: Volume level 0 will not mute the ADC + + if(volumeLevel < 2) + { + vol = 104; + } + else + { + vol = 103 + (volumeLevel >> 1); + } + + AudioCodecPageSelect(TI3254_PAGE_0); // Select Page 0 + + + //Unmute LADC/RADC + AudioCodecRegWrite(TI3254_LEFT_ADC_VOL_CTRL_REG, (unsigned char )(vol&0x7F)); + AudioCodecRegWrite(TI3254_RIGHT_ADC_VOL_CTRL_REG, (unsigned char )(vol&0x7F)); + return 0; +} + +/********************************************************************* + * @fn AudioCodecMicMute + * + * @brief Mute Audio line in + * + * @param[in] codecId - Device id + * @param[in] mic - Audio in id. (line in, mono mic, all etc..) + * Please refer Audio In Macro section + * + * @return 0 on success else -ve. + */ +int AudioCodecMicMute(unsigned char codecId, unsigned char mic) +{ + + AudioCodecPageSelect(TI3254_PAGE_0); // Select Page 0 + + //Unmute LADC/RADC + AudioCodecRegWrite(TI3254_ADC_FINE_GAIN_ADJ_REG, 0x88); // Left and Right ADC Channel Un-muted. Left and Right ADC Channel Fine Gain = 0dB, + return 0; +} + +/********************************************************************* + * @fn AudioCodecMicUnmute + * + * @brief Unmute audio line + * + * @param[in] codecId - Device id + * @param[in] mic - Audio in id. (line in, mono mic, all etc..) + * Please refer Audio In Macro section + * + * @return 0 on success else -ve. + */ +int AudioCodecMicUnmute(unsigned char codecId, unsigned char mic) +{ + AudioCodecPageSelect(TI3254_PAGE_0); // Select Page 0 + + //Unmute LADC/RADC + AudioCodecRegWrite(TI3254_ADC_FINE_GAIN_ADJ_REG, 0x00); // Left and Right ADC Channel Un-muted. Left and Right ADC Channel Fine Gain = 0dB, + return 0; +} + +/********************************************************************* + * @fn AudioCodecPageSelect + * + * @brief Select Codec page that need to configure + * + * @param[in] ulPageAddress - page id + * + * @return 0 on success else -ve. + */ +static unsigned long AudioCodecPageSelect(unsigned char ulPageAddress) +{ + return AudioCodecRegWrite(TI3254_PAGE_SEL_REG,ulPageAddress); +} + +/********************************************************************* + * @fn AudioCodecRegWrite + * + * @brief Select Codec page that need to configure + * + * @param[in] ulRegAddr - Register Address + * @param[in] ucRegValue - 8 bit Register Value + * + * @return 0 on success else -ve. + */ +static unsigned long AudioCodecRegWrite(unsigned char ulRegAddr,unsigned char ucRegValue) +{ + + // Initialize return value to success + uint8_t stat = AUDIO_CODEC_STATUS_SUCCESS; + uint8_t writeDataBuf[2]; + writeDataBuf[0] = (uint8_t)ulRegAddr; + writeDataBuf[1] = ucRegValue; + + uint8_t readDataBuf[1]; + + I2C_Transaction i2cTransaction; + i2cTransaction.writeBuf = writeDataBuf; + i2cTransaction.writeCount = 2; + i2cTransaction.readBuf = readDataBuf; + i2cTransaction.readCount = 0; + + i2cTransaction.slaveAddress = CODEC_I2C_SLAVE_ADDR; + + // Write to the register + bool ret = I2C_transfer(i2cHandle, &i2cTransaction); + if (true != ret) + { + stat = AUDIO_CODEC_STATUS_I2C_FAIL; + } + + // Setup the struct for reading back + i2cTransaction.writeBuf = writeDataBuf; + i2cTransaction.writeCount = 1; + i2cTransaction.readBuf = readDataBuf; + i2cTransaction.readCount = 1; + + // Read back to the register + ret = I2C_transfer(i2cHandle, &i2cTransaction); + if (true != ret) + { + stat = AUDIO_CODEC_STATUS_I2C_FAIL; + } + + // Ensure that the write value matches the read value + if(readDataBuf[0] != ucRegValue) + { + stat = AUDIO_CODEC_STATUS_I2C_FAIL; + } + + return stat; +} + + + + diff --git a/src/util/audio_codec/audiocodec.h b/src/util/audio_codec/audiocodec.h new file mode 100644 index 0000000..be16169 --- /dev/null +++ b/src/util/audio_codec/audiocodec.h @@ -0,0 +1,198 @@ +/* + * Filename: audiocodec.h + * + * Description: This file implments the control interface to the + * TLV320AIC3254 Stereo Audio Codec + * + * + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef AUDIOCODEC_H_ +#define AUDIOCODEC_H_ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +// Define 8-bit codec id to identify codec device +#define AUDIO_CODEC_TI_3254 0 +#define AUDIO_CODEC_TI_3110 1 + + +// Bits per sample Macro +#define AUDIO_CODEC_8_BIT 8 +#define AUDIO_CODEC_16_BIT 16 +#define AUDIO_CODEC_20_BIT 20 +#define AUDIO_CODEC_24_BIT 24 + + + +// Number of Channels Macro +#define AUDIO_CODEC_DEFAULT 0 +#define AUDIO_CODEC_MONO 1 +#define AUDIO_CODEC_STEREO 2 +#define AUDIO_CODEC_REVERSE_MONO 3 +#define AUDIO_CODEC_REVERSE_STEREO 4 + +// Audio out Macro +// Note: Max 8 line out per codec device supported +#define AUDIO_CODEC_SPEAKER_NONE (0x00) +#define AUDIO_CODEC_SPEAKER_HP (0x01) // Headphone line +#define AUDIO_CODEC_SPEAKER_LO (0x02) // Line out +#define AUDIO_CODEC_SPEAKER_RESERVED1 (0x04) // Onboard mic device +#define AUDIO_CODEC_SPEAKER_RESERVED2 (0x08) // Onboard mic device +#define AUDIO_CODEC_SPEAKER_RESERVED3 (0x10) // Onboard mic device +#define AUDIO_CODEC_SPEAKER_RESERVED4 (0x20) // Onboard mic device +#define AUDIO_CODEC_SPEAKER_RESERVED5 (0x40) // Onboard mic device +#define AUDIO_CODEC_SPEAKER_RESERVED6 (0x80) // Onboard mic device +#define AUDIO_CODEC_SPEAKER_ALL (0xFF) + +// Audio in macro. +// Max 8 line in per codec device supported +#define AUDIO_CODEC_MIC_NONE (0x00) +#define AUDIO_CODEC_MIC_MONO (0x01) // Mono mic +#define AUDIO_CODEC_MIC_LINE_IN (0x02) // Line in +#define AUDIO_CODEC_MIC_ONBOARD (0x04) // Onboard mic device +#define AUDIO_CODEC_MIC_RESERVED2 (0x08) // Mono mic +#define AUDIO_CODEC_MIC_RESERVED3 (0x10) // Line in +#define AUDIO_CODEC_MIC_RESERVED4 (0x20) // Onboard mic device +#define AUDIO_CODEC_MIC_RESERVED5 (0x40) // Mono mic +#define AUDIO_CODEC_MIC_RESERVED6 (0x80) // Line in +#define AUDIO_CODEC_MIC_ALL (0xFF) + + +#define AUDIO_CODEC_STATUS_I2C_FAIL 0xFF +#define AUDIO_CODEC_STATUS_SUCCESS 0x00 + + +uint8_t AudioCodecOpen(); + +void AudioCodecClose(); + + +/* + * Reset or initialize code + * codecId: Device id that need to reset/init + * arg: Pointer to user define structure/data type else NULL + * + */ +int AudioCodecReset(unsigned char codecId, void *arg); + +/* + * Configure audio codec for smaple rate, bits and number of channels + * codecId: Device id + * + * bitsPerSample: Bits per sample (8, 16, 24 etc..) + * Please ref Bits per sample Macro section + * bitsRate: Sampling rate in Hz. (8000, 16000, 44100 etc..) + * noOfChannels: Number of channels. (Mono, stereo etc..) + Please refer Number of Channels Macro section + * speaker: Audio out that need to configure. (headphone, line out, all etc..) + * Please refer Audio Out Macro section + * mic: Audio in that need to configure. (line in, mono mic, all etc..) + * Please refer Audio In Macro section + * + */ +int AudioCodecConfig(unsigned char codecId, unsigned char bitsPerSample, unsigned short bitRate, + unsigned char noOfChannels, unsigned char speaker, unsigned char mic); + +/* + * Configure volume level for specific audio out on a codec device + * codecId: Device id + * speaker: Audio out id. (headphone, line out, all etc..) + * Please refer Audio out Macro section + * volumeLevel: Volume level. 0-100 + * + */ +int AudioCodecSpeakerVolCtrl(unsigned char codecId, unsigned char speaker, signed char volumeLevel); + + +/* + * Mute Audio line out + * codecId: Device id + * speaker: Audio out id. (headphone, line out, all etc..) + * Please refer Audio out Macro section + * + */ +int AudioCodecSpeakerMute(unsigned char codecId, unsigned char speaker); + +/* + * Unmute audio line out + * codecId: Device id + * speaker: Audio out id. (headphone, line out, all etc..) + * Please refer Audio out Macro section + * + */ +int AudioCodecSpeakerUnmute(unsigned char codecId, unsigned char speaker); + +/* + * Configure volume level for specific audio in on a codec device + * codecId: Device id + * mic: Audio in id. (line in, mono mic, all etc..) + * Please refer Audio In Macro section + * volumeLevel: Volume level 0-100 + * + */ +int AudioCodecMicVolCtrl(unsigned char codecId, unsigned char mic, signed char volumeLevel); + +/* + * Mute Audio line in + * codecId: Device id + * mic: Audio in id. (line in, mono mic, all etc..) + * Please refer Audio In Macro section + * + */ +int AudioCodecMicMute(unsigned char codecId, unsigned char mic); + +/* + * Unmute audio line + * codecId: Device id + * mic: Audio in id. (line in, mono mic, all etc..) + * Please refer Audio In Macro section + * + */ +int AudioCodecMicUnmute(unsigned char codecId, unsigned char mic); + +#ifdef __cplusplus +} +#endif + +#endif /* AUDIOCODEC_H_ */ diff --git a/src/util/audio_codec/ti3254.h b/src/util/audio_codec/ti3254.h new file mode 100644 index 0000000..2aa34df --- /dev/null +++ b/src/util/audio_codec/ti3254.h @@ -0,0 +1,145 @@ +/* + * Filename: ti3254.h + * + * Description: Macro for TI3254 registers + * + * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +//***************************************************************************** + +#ifndef __TI3254_H__ +#define __TI3254_H__ + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +#define CODEC_I2C_SLAVE_ADDR ((0x30 >> 1)) +#define CRYSTAL_FREQ 40000000 +#define SYS_CLK CRYSTAL_FREQ + +#define TI3254_PAGE_0 0x00 +#define TI3254_PAGE_1 0x01 +#define TI3254_PAGE_8 0x08 +#define TI3254_PAGE_44 0x2C + +#define PAGE_CTRL_REG 0x00 + +// Page 0 +#define TI3254_PAGE_SEL_REG 0x00 +#define TI3254_SW_RESET_REG 0x01 +#define TI3254_CLK_MUX_REG 0x04 +#define TI3254_CLK_PLL_P_R_REG 0x05 +#define TI3254_CLK_PLL_J_REG 0x06 +#define TI3254_CLK_PLL_D_MSB_REG 0x07 +#define TI3254_CLK_PLL_D_LSB_REG 0x08 +#define TI3254_CLK_NDAC_REG 0x0B +#define TI3254_CLK_MDAC_REG 0x0C +#define TI3254_DAC_OSR_MSB_REG 0x0D +#define TI3254_DAC_OSR_LSB_REG 0x0E +#define TI3254_DSP_D_CTRL_1_REG 0x0F +#define TI3254_DSP_D_CTRL_2_REG 0x10 +#define TI3254_DSP_D_INTERPOL_REG 0x11 +#define TI3254_CLK_NADC_REG 0x12 +#define TI3254_CLK_MADC_REG 0x13 +#define TI3254_ADC_OSR_REG 0x14 +#define TI3254_DSP_A_CTRL_1_REG 0x15 +#define TI3254_DSP_A_CTRL_2_REG 0x16 +#define TI3254_DSP_A_DEC_FACT_REG 0x17 +#define TI3254_AUDIO_IF_1_REG 0x1B + +#define TI3254_DAC_SIG_P_BLK_CTRL_REG 0x3C +#define TI3254_ADC_SIG_P_BLK_CTRL_REG 0x3D + +#define TI3254_DAC_CHANNEL_SETUP_1_REG 0x3F +#define TI3254_DAC_CHANNEL_SETUP_2_REG 0x40 + +#define TI3254_LEFT_DAC_VOL_CTRL_REG 0x41 +#define TI3254_RIGHT_DAC_VOL_CTRL_REG 0x42 + +#define TI3254_ADC_CHANNEL_SETUP_REG 0x51 +#define TI3254_ADC_FINE_GAIN_ADJ_REG 0x52 + +#define TI3254_LEFT_ADC_VOL_CTRL_REG 0x53 +#define TI3254_RIGHT_ADC_VOL_CTRL_REG 0x54 + + + +//Page 1 + +#define TI3254_PWR_CTRL_REG 0x01 +#define TI3254_LDO_CTRL_REG 0x02 +#define TI3254_OP_DRV_PWR_CTRL_REG 0x09 +#define TI3254_HPL_ROUTING_SEL_REG 0x0C +#define TI3254_HPR_ROUTING_SEL_REG 0x0D +#define TI3254_LOL_ROUTING_SEL_REG 0x0E +#define TI3254_LOR_ROUTING_SEL_REG 0x0F +#define TI3254_HPL_DRV_GAIN_CTRL_REG 0x10 +#define TI3254_HPR_DRV_GAIN_CTRL_REG 0x11 +#define TI3254_LOL_DRV_GAIN_CTRL_REG 0x12 +#define TI3254_LOR_DRV_GAIN_CTRL_REG 0x13 +#define TI3254_HP_DRV_START_UP_CTRL_REG 0x14 + +#define TI3254_MICBIAS_CTRL_REG 0x33 +#define TI3254_LEFT_MICPGA_P_CTRL_REG 0x34 +#define TI3254_LEFT_MICPGA_N_CTRL_REG 0x36 +#define TI3254_RIGHT_MICPGA_P_CTRL_REG 0x37 +#define TI3254_RIGHT_MICPGA_N_CTRL_REG 0x39 +#define TI3254_FLOAT_IP_CTRL_REG 0x3a +#define TI3254_LEFT_MICPGA_VOL_CTRL_REG 0x3B +#define TI3254_RIGHT_MICPGA_VOL_CTRL_REG 0x3C + +#define TI3254_ANALOG_IP_QCHRG_CTRL_REG 0x47 +#define TI3254_REF_PWR_UP_CTRL_REG 0x7B + + +// Page 8 +#define TI3254_ADC_ADP_FILTER_CTRL_REG 0x01 + +// Page 44 +#define TI3254_DAC_ADP_FILTER_CTRL_REG 0x01 + + +#ifdef __cplusplus +} +#endif + + +#endif /* __TI3254_H__ */ diff --git a/src/util/sbc/sbc.c b/src/util/sbc/sbc.c new file mode 100644 index 0000000..69d452b --- /dev/null +++ b/src/util/sbc/sbc.c @@ -0,0 +1,1661 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2008 Brad Midgley + * Copyright (C) 2012-2013 Intel Corporation + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +//#include +#include + +#include "sbc_math.h" +#include "sbc_tables.h" + +#include "sbc.h" +#include "sbc_private.h" +#include "sbc_primitives.h" + +#define SBC_SYNCWORD 0x9C + +#define MSBC_SYNCWORD 0xAD +#define MSBC_BLOCKS 15 + +#define A2DP_SAMPLING_FREQ_16000 (1 << 3) +#define A2DP_SAMPLING_FREQ_32000 (1 << 2) +#define A2DP_SAMPLING_FREQ_44100 (1 << 1) +#define A2DP_SAMPLING_FREQ_48000 (1 << 0) + +#define A2DP_CHANNEL_MODE_MONO (1 << 3) +#define A2DP_CHANNEL_MODE_DUAL_CHANNEL (1 << 2) +#define A2DP_CHANNEL_MODE_STEREO (1 << 1) +#define A2DP_CHANNEL_MODE_JOINT_STEREO (1 << 0) + +#define A2DP_BLOCK_LENGTH_4 (1 << 3) +#define A2DP_BLOCK_LENGTH_8 (1 << 2) +#define A2DP_BLOCK_LENGTH_12 (1 << 1) +#define A2DP_BLOCK_LENGTH_16 (1 << 0) + +#define A2DP_SUBBANDS_4 (1 << 1) +#define A2DP_SUBBANDS_8 (1 << 0) + +#define A2DP_ALLOCATION_SNR (1 << 1) +#define A2DP_ALLOCATION_LOUDNESS (1 << 0) + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +struct a2dp_sbc { + uint8_t channel_mode:4; + uint8_t frequency:4; + uint8_t allocation_method:2; + uint8_t subbands:2; + uint8_t block_length:4; + uint8_t min_bitpool; + uint8_t max_bitpool; +} __attribute__ ((packed)); + +#elif __BYTE_ORDER == __BIG_ENDIAN + +struct a2dp_sbc { + uint8_t frequency:4; + uint8_t channel_mode:4; + uint8_t block_length:4; + uint8_t subbands:2; + uint8_t allocation_method:2; + uint8_t min_bitpool; + uint8_t max_bitpool; +} __attribute__ ((packed)); + +#else +#error "Unknown byte order" +#endif + +/* This structure contains an unpacked SBC frame. + Yes, there is probably quite some unused space herein */ +struct sbc_frame { +// uint8_t frequency; +// uint8_t block_mode; +// uint8_t blocks; +// enum { +// MONO = SBC_MODE_MONO, +// DUAL_CHANNEL = SBC_MODE_DUAL_CHANNEL, +// STEREO = SBC_MODE_STEREO, +// JOINT_STEREO = SBC_MODE_JOINT_STEREO +// } mode; +// uint8_t channels; +// enum { +// LOUDNESS = SBC_AM_LOUDNESS, +// SNR = SBC_AM_SNR +// } allocation; +// uint8_t subband_mode; +// uint8_t subbands; +// uint8_t bitpool; + uint16_t codesize; + uint8_t length; +// +// /* bit number x set means joint stereo has been used in subband x */ +// uint8_t joint; + + /* only the lower 4 bits of every element are to be used */ + uint32_t SBC_ALIGNED scale_factor[8]; //[2][8]; + +#ifdef MSBC_ENCODE + /* raw integer subband samples in the frame */ + int32_t SBC_ALIGNED sb_sample_f[16][8]; //[2][8]; +#endif //MSBC_ENCODE + + /* modified subband samples */ + int32_t SBC_ALIGNED sb_sample[16][8]; //[2][8]; + +#ifdef MSBC_DECODE + /* original pcm audio samples */ + int16_t SBC_ALIGNED pcm_sample/*[2]*/[16*8]; +#endif //MSBC_DECODE +}; + +struct sbc_decoder_state { + int subbands; + int32_t V/*[2]*/[170]; + int offset/*[2]*/[16]; +}; + +#ifndef ONLY_MSBC +/* + * Calculates the CRC-8 of the first len bits in data + */ +static const uint8_t crc_table[256] = { + 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, + 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB, + 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E, + 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76, + 0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4, + 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C, + 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19, + 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1, + 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40, + 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8, + 0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D, + 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65, + 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7, + 0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F, + 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A, + 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2, + 0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75, + 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D, + 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8, + 0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50, + 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2, + 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A, + 0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F, + 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7, + 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66, + 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E, + 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB, + 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43, + 0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1, + 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09, + 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C, + 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4 +}; + +static uint8_t sbc_crc8(const uint8_t *data, size_t len) +{ + uint8_t crc = 0x0f; + size_t i; + uint8_t octet; + + for (i = 0; i < len / 8; i++) + crc = crc_table[crc ^ data[i]]; + + octet = data[i]; + for (i = 0; i < len % 8; i++) { + char bit = ((octet ^ crc) & 0x80) >> 7; + + crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0); + + octet = octet << 1; + } + + return crc; +} +#endif //ONLY_MSBC + +/* + * Code straight from the spec to calculate the bits array + * Takes a pointer to the frame in question, a pointer to the bits array and + * the sampling frequency (as 2 bit integer) + */ +static SBC_ALWAYS_INLINE void sbc_calculate_bits_internal( + const struct sbc_frame *frame, int (*bits)/*[8]*/, int subbands) +{ + uint8_t sf = SBC_FREQ_16000; //frame->frequency; + +#ifndef ONLY_MSBC + if (frame->mode == MONO || frame->mode == DUAL_CHANNEL) { +#endif //ONLY_MSBC + int bitneed/*[2]*/[8], loudness, max_bitneed, bitcount, slicecount, bitslice; + int /*ch,*/ sb; + +// for (ch = 0; ch < frame->channels; ch++) { + max_bitneed = 0; +#ifndef ONLY_MSBC + if (frame->allocation == SNR) { + for (sb = 0; sb < subbands; sb++) { + bitneed[ch][sb] = frame->scale_factor[ch][sb]; + if (bitneed[ch][sb] > max_bitneed) + max_bitneed = bitneed[ch][sb]; + } + } else +#endif //ONLY_MSBC + { + for (sb = 0; sb < subbands; sb++) { + if (frame->scale_factor/*[ch]*/[sb] == 0) + bitneed/*[ch]*/[sb] = -5; + else { + if (subbands == 4) + loudness = frame->scale_factor/*[ch]*/[sb] - sbc_offset4[sf][sb]; + else + loudness = frame->scale_factor/*[ch]*/[sb] - sbc_offset8[sf][sb]; + if (loudness > 0) + bitneed/*[ch]*/[sb] = loudness / 2; + else + bitneed/*[ch]*/[sb] = loudness; + } + if (bitneed/*[ch]*/[sb] > max_bitneed) + max_bitneed = bitneed/*[ch]*/[sb]; + } + } + + bitcount = 0; + slicecount = 0; + bitslice = max_bitneed + 1; + do { + bitslice--; + bitcount += slicecount; + slicecount = 0; + for (sb = 0; sb < subbands; sb++) { + if ((bitneed/*[ch]*/[sb] > bitslice + 1) && (bitneed/*[ch]*/[sb] < bitslice + 16)) + slicecount++; + else if (bitneed/*[ch]*/[sb] == bitslice + 1) + slicecount += 2; + } + } while (bitcount + slicecount < 26/*frame->bitpool*/); + + if (bitcount + slicecount == 26/*frame->bitpool*/) { + bitcount += slicecount; + bitslice--; + } + + for (sb = 0; sb < subbands; sb++) { + if (bitneed/*[ch]*/[sb] < bitslice + 2) + bits/*[ch]*/[sb] = 0; + else { + bits/*[ch]*/[sb] = bitneed/*[ch]*/[sb] - bitslice; + if (bits/*[ch]*/[sb] > 16) + bits/*[ch]*/[sb] = 16; + } + } + + for (sb = 0; bitcount < 26/*frame->bitpool*/ && + sb < subbands; sb++) { + if ((bits/*[ch]*/[sb] >= 2) && (bits/*[ch]*/[sb] < 16)) { + bits/*[ch]*/[sb]++; + bitcount++; + } else if ((bitneed/*[ch]*/[sb] == bitslice + 1) && (26/*frame->bitpool*/ > bitcount + 1)) { + bits/*[ch]*/[sb] = 2; + bitcount += 2; + } + } + + for (sb = 0; bitcount < 26/*frame->bitpool*/ && + sb < subbands; sb++) { + if (bits/*[ch]*/[sb] < 16) { + bits/*[ch]*/[sb]++; + bitcount++; + } + } + +// } + +#ifndef ONLY_MSBC + } else if (frame->mode == STEREO || frame->mode == JOINT_STEREO) { + int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice; + int ch, sb; + + max_bitneed = 0; + if (frame->allocation == SNR) { + for (ch = 0; ch < 2; ch++) { + for (sb = 0; sb < subbands; sb++) { + bitneed[ch][sb] = frame->scale_factor[ch][sb]; + if (bitneed[ch][sb] > max_bitneed) + max_bitneed = bitneed[ch][sb]; + } + } + } else { + for (ch = 0; ch < 2; ch++) { + for (sb = 0; sb < subbands; sb++) { + if (frame->scale_factor[ch][sb] == 0) + bitneed[ch][sb] = -5; + else { + if (subbands == 4) + loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb]; + else + loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb]; + if (loudness > 0) + bitneed[ch][sb] = loudness / 2; + else + bitneed[ch][sb] = loudness; + } + if (bitneed[ch][sb] > max_bitneed) + max_bitneed = bitneed[ch][sb]; + } + } + } + + bitcount = 0; + slicecount = 0; + bitslice = max_bitneed + 1; + do { + bitslice--; + bitcount += slicecount; + slicecount = 0; + for (ch = 0; ch < 2; ch++) { + for (sb = 0; sb < subbands; sb++) { + if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16)) + slicecount++; + else if (bitneed[ch][sb] == bitslice + 1) + slicecount += 2; + } + } + } while (bitcount + slicecount < frame->bitpool); + + if (bitcount + slicecount == frame->bitpool) { + bitcount += slicecount; + bitslice--; + } + + for (ch = 0; ch < 2; ch++) { + for (sb = 0; sb < subbands; sb++) { + if (bitneed[ch][sb] < bitslice + 2) { + bits[ch][sb] = 0; + } else { + bits[ch][sb] = bitneed[ch][sb] - bitslice; + if (bits[ch][sb] > 16) + bits[ch][sb] = 16; + } + } + } + + ch = 0; + sb = 0; + while (bitcount < frame->bitpool) { + if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) { + bits[ch][sb]++; + bitcount++; + } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) { + bits[ch][sb] = 2; + bitcount += 2; + } + if (ch == 1) { + ch = 0; + sb++; + if (sb >= subbands) + break; + } else + ch = 1; + } + + ch = 0; + sb = 0; + while (bitcount < frame->bitpool) { + if (bits[ch][sb] < 16) { + bits[ch][sb]++; + bitcount++; + } + if (ch == 1) { + ch = 0; + sb++; + if (sb >= subbands) + break; + } else + ch = 1; + } + + } +#endif //ONLY_MSBC + +} + +static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)/*[8]*/) +{ +#ifndef ONLY_MSBC + if (frame->subbands == 4) + sbc_calculate_bits_internal(frame, bits, 4); + else +#endif //ONLY_MSBC + sbc_calculate_bits_internal(frame, bits, 8); +} + +#ifdef MSBC_DECODE +/* + * Unpacks a SBC frame at the beginning of the stream in data, + * which has at most len bytes into frame. + * Returns the length in bytes of the packed frame, or a negative + * value on error. The error codes are: + * + * -1 Data stream too short + * -2 Sync byte incorrect + * -3 CRC8 incorrect + * -4 Bitpool value out of bounds + */ +static int sbc_unpack_frame_internal(const uint8_t *data, + struct sbc_frame *frame, size_t len) +{ + unsigned int consumed; +// /* Will copy the parts of the header that are relevant to crc +// * calculation here */ +// uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +// int crc_pos = 0; +// int32_t temp; + + uint32_t audio_sample; + int /*ch,*/ sb, blk, bit; /* channel, subband, block and bit standard + counters */ + int bits/*[2]*/[8]; /* bits distribution */ + uint32_t levels/*[2]*/[8]; /* levels derived from that */ + + consumed = 32; + +// crc_header[0] = data[1]; +// crc_header[1] = data[2]; +// crc_pos = 16; + +#ifndef ONLY_MSBC + if (frame->mode == JOINT_STEREO) { + if (len * 8 < consumed + frame->subbands) + return -1; + + frame->joint = 0x00; + for (sb = 0; sb < frame->subbands - 1; sb++) + frame->joint |= ((data[4] >> (7 - sb)) & 0x01) << sb; + if (frame->subbands == 4) + crc_header[crc_pos / 8] = data[4] & 0xf0; + else + crc_header[crc_pos / 8] = data[4]; + + consumed += frame->subbands; + crc_pos += frame->subbands; + } +#endif //ONLY_MSBC + + if (len * 8 < consumed + (4 * 8/*frame->subbands*/ * 1/*frame->channels*/)) + return -1; + +// for (ch = 0; ch < frame->channels; ch++) { + for (sb = 0; sb < 8/*frame->subbands*/; sb++) { + /* FIXME assert(consumed % 4 == 0); */ + frame->scale_factor/*[ch]*/[sb] = + (data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F; +// crc_header[crc_pos >> 3] |= +// frame->scale_factor/*[ch]*/[sb] << (4 - (crc_pos & 0x7)); + + consumed += 4; +// crc_pos += 4; + } +// } + +// if (data[3] != sbc_crc8(crc_header, crc_pos)) +// return -3; + + sbc_calculate_bits(frame, bits); + +// for (ch = 0; ch < frame->channels; ch++) { + for (sb = 0; sb < 8/*frame->subbands*/; sb++) + levels/*[ch]*/[sb] = (1 << bits/*[ch]*/[sb]) - 1; +// } + + for (blk = 0; blk < MSBC_BLOCKS/*frame->blocks*/; blk++) { +// for (ch = 0; ch < frame->channels; ch++) { + for (sb = 0; sb < 8/*frame->subbands*/; sb++) { + uint32_t shift; + + if (levels/*[ch]*/[sb] == 0) { + frame->sb_sample[blk]/*[ch]*/[sb] = 0; + continue; + } + + shift = frame->scale_factor/*[ch]*/[sb] + + 1 + SBCDEC_FIXED_EXTRA_BITS; + + audio_sample = 0; + for (bit = 0; bit < bits/*[ch]*/[sb]; bit++) { + if (consumed > len * 8) + return -1; + + if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01) + audio_sample |= 1 << (bits/*[ch]*/[sb] - bit - 1); + + consumed++; + } + + frame->sb_sample[blk]/*[ch]*/[sb] = (int32_t) + (((((uint64_t) audio_sample << 1) | 1) << shift) / + levels/*[ch]*/[sb]) - (1 << shift); + } +// } + } + +#ifndef ONLY_MSBC + if (frame->mode == JOINT_STEREO) { + for (blk = 0; blk < frame->blocks; blk++) { + for (sb = 0; sb < 8/*frame->subbands*/; sb++) { + if (frame->joint & (0x01 << sb)) { + temp = frame->sb_sample[blk][0][sb] + + frame->sb_sample[blk][1][sb]; + frame->sb_sample[blk][1][sb] = + frame->sb_sample[blk][0][sb] - + frame->sb_sample[blk][1][sb]; + frame->sb_sample[blk][0][sb] = temp; + } + } + } + } +#endif //ONLY_MSBC + + if ((consumed & 0x7) != 0) + consumed += 8 - (consumed & 0x7); + + return consumed >> 3; +} + +#ifndef ONLY_MSBC +static int sbc_unpack_frame(const uint8_t *data, + struct sbc_frame *frame, size_t len) +{ + if (len < 4) + return -1; + + if (data[0] != SBC_SYNCWORD) + return -2; + + frame->frequency = (data[1] >> 6) & 0x03; + frame->block_mode = (data[1] >> 4) & 0x03; + + switch (frame->block_mode) { + case SBC_BLK_4: + frame->blocks = 4; + break; + case SBC_BLK_8: + frame->blocks = 8; + break; + case SBC_BLK_12: + frame->blocks = 12; + break; + case SBC_BLK_16: + frame->blocks = 16; + break; + } + + frame->mode = (data[1] >> 2) & 0x03; + + switch (frame->mode) { + case MONO: + frame->channels = 1; + break; + case DUAL_CHANNEL: /* fall-through */ + case STEREO: + case JOINT_STEREO: + frame->channels = 2; + break; + } + + frame->allocation = (data[1] >> 1) & 0x01; + + frame->subband_mode = (data[1] & 0x01); + frame->subbands = frame->subband_mode ? 8 : 4; + + frame->bitpool = data[2]; + + if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) && + frame->bitpool > 16 * frame->subbands) + return -4; + + if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) && + frame->bitpool > 32 * frame->subbands) + return -4; + + return sbc_unpack_frame_internal(data, frame, len); +} +#endif //ONLY_MSBC + +static int msbc_unpack_frame(const uint8_t *data, + struct sbc_frame *frame, size_t len) +{ + if (len < 4) + return -1; + + if (data[0] != MSBC_SYNCWORD) + return -2; +// if (data[1] != 0) +// return -2; + if (data[2] != 0) + return -2; + +#ifndef ONLY_MSBC + frame->frequency = SBC_FREQ_16000; + frame->block_mode = SBC_BLK_4; + frame->blocks = MSBC_BLOCKS; + frame->allocation = LOUDNESS; + frame->mode = MONO; + frame->channels = 1; + frame->subband_mode = 1; + frame->subbands = 8; + frame->bitpool = 26; +#endif //ONLY_MSBC + + return sbc_unpack_frame_internal(data, frame, len); +} + +static void sbc_decoder_init(struct sbc_decoder_state *state, + const struct sbc_frame *frame) +{ + int i/*, ch*/; + + memset(state->V, 0, sizeof(state->V)); + state->subbands = 8/*frame->subbands*/; + +// for (ch = 0; ch < 2; ch++) + for (i = 0; i < 8/*priv->frame.subbands*/ * 2; i++) + state->offset/*[ch]*/[i] = (10 * i + 10); +} + +static SBC_ALWAYS_INLINE int16_t sbc_clip16(int32_t s) +{ + if (s > 0x7FFF) + return 0x7FFF; + else if (s < -0x8000) + return -0x8000; + else + return s; +} + +#ifndef ONLY_MSBC +static inline void sbc_synthesize_four(struct sbc_decoder_state *state, + struct sbc_frame *frame, int ch, int blk) +{ + int i, k, idx; + int32_t *v = state->V[ch]; + int *offset = state->offset[ch]; + + for (i = 0; i < 8; i++) { + /* Shifting */ + offset[i]--; + if (offset[i] < 0) { + offset[i] = 79; + memcpy(v + 80, v, 9 * sizeof(*v)); + } + + /* Distribute the new matrix value to the shifted position */ + v[offset[i]] = SCALE4_STAGED1( + MULA(synmatrix4[i][0], frame->sb_sample[blk][ch][0], + MULA(synmatrix4[i][1], frame->sb_sample[blk][ch][1], + MULA(synmatrix4[i][2], frame->sb_sample[blk][ch][2], + MUL (synmatrix4[i][3], frame->sb_sample[blk][ch][3]))))); + } + + /* Compute the samples */ + for (idx = 0, i = 0; i < 4; i++, idx += 5) { + k = (i + 4) & 0xf; + + /* Store in output, Q0 */ + frame->pcm_sample[ch][blk * 4 + i] = sbc_clip16(SCALE4_STAGED1( + MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0], + MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0], + MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1], + MULA(v[offset[k] + 3], sbc_proto_4_40m1[idx + 1], + MULA(v[offset[i] + 4], sbc_proto_4_40m0[idx + 2], + MULA(v[offset[k] + 5], sbc_proto_4_40m1[idx + 2], + MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3], + MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3], + MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4], + MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4])))))))))))); + } +} +#endif //ONLY_MSBC + +static inline void sbc_synthesize_eight(struct sbc_decoder_state *state, + struct sbc_frame *frame,/* int ch,*/ int blk) +{ + int i, j, k, idx; + int *offset = state->offset/*[ch]*/; + + for (i = 0; i < 16; i++) { + /* Shifting */ + offset[i]--; + if (offset[i] < 0) { + offset[i] = 159; + for (j = 0; j < 9; j++) + state->V/*[ch]*/[j + 160] = state->V/*[ch]*/[j]; + } + + /* Distribute the new matrix value to the shifted position */ + state->V/*[ch]*/[offset[i]] = SCALE8_STAGED1( + MULA(synmatrix8[i][0], frame->sb_sample[blk]/*[ch]*/[0], + MULA(synmatrix8[i][1], frame->sb_sample[blk]/*[ch]*/[1], + MULA(synmatrix8[i][2], frame->sb_sample[blk]/*[ch]*/[2], + MULA(synmatrix8[i][3], frame->sb_sample[blk]/*[ch]*/[3], + MULA(synmatrix8[i][4], frame->sb_sample[blk]/*[ch]*/[4], + MULA(synmatrix8[i][5], frame->sb_sample[blk]/*[ch]*/[5], + MULA(synmatrix8[i][6], frame->sb_sample[blk]/*[ch]*/[6], + MUL( synmatrix8[i][7], frame->sb_sample[blk]/*[ch]*/[7]))))))))); + } + + /* Compute the samples */ + for (idx = 0, i = 0; i < 8; i++, idx += 5) { + k = (i + 8) & 0xf; + + /* Store in output, Q0 */ + frame->pcm_sample/*[ch]*/[blk * 8 + i] = sbc_clip16(SCALE8_STAGED1( + MULA(state->V/*[ch]*/[offset[i] + 0], sbc_proto_8_80m0[idx + 0], + MULA(state->V/*[ch]*/[offset[k] + 1], sbc_proto_8_80m1[idx + 0], + MULA(state->V/*[ch]*/[offset[i] + 2], sbc_proto_8_80m0[idx + 1], + MULA(state->V/*[ch]*/[offset[k] + 3], sbc_proto_8_80m1[idx + 1], + MULA(state->V/*[ch]*/[offset[i] + 4], sbc_proto_8_80m0[idx + 2], + MULA(state->V/*[ch]*/[offset[k] + 5], sbc_proto_8_80m1[idx + 2], + MULA(state->V/*[ch]*/[offset[i] + 6], sbc_proto_8_80m0[idx + 3], + MULA(state->V/*[ch]*/[offset[k] + 7], sbc_proto_8_80m1[idx + 3], + MULA(state->V/*[ch]*/[offset[i] + 8], sbc_proto_8_80m0[idx + 4], + MUL( state->V/*[ch]*/[offset[k] + 9], sbc_proto_8_80m1[idx + 4])))))))))))); + } +} + +static int sbc_synthesize_audio(struct sbc_decoder_state *state, + struct sbc_frame *frame) +{ + int /*ch,*/ blk; + +#ifndef ONLY_MSBC + switch (frame->subbands) { + case 4: + for (ch = 0; ch < frame->channels; ch++) { + for (blk = 0; blk < frame->blocks; blk++) + sbc_synthesize_four(state, frame, ch, blk); + } + return frame->blocks * 4; + + case 8: +#endif //ONLY_MSBC +// for (ch = 0; ch < frame->channels; ch++) { + for (blk = 0; blk < MSBC_BLOCKS/*frame->blocks*/; blk++) + sbc_synthesize_eight(state, frame,/* ch,*/ blk); +// } + return MSBC_BLOCKS/*frame->blocks*/ * 8; + +#ifndef ONLY_MSBC + default: + return -EIO; + } +#endif //ONLY_MSBC +} +#endif //MSBC_DECODE + +#ifdef MSBC_ENCODE +static int sbc_analyze_audio(struct sbc_encoder_state *state, + struct sbc_frame *frame) +{ + int /*ch,*/ blk; + int16_t *x; + +#ifndef ONLY_MSBC + switch (frame->subbands) { + case 4: + for (ch = 0; ch < frame->channels; ch++) { + x = &state->X[ch][state->position - 4 * + state->increment + frame->blocks * 4]; + for (blk = 0; blk < frame->blocks; + blk += state->increment) { + state->sbc_analyze_4s( + state, x, + frame->sb_sample_f[blk][ch], + frame->sb_sample_f[blk + 1][ch] - + frame->sb_sample_f[blk][ch]); + x -= 4 * state->increment; + } + } + return frame->blocks * 4; + + case 8: +#endif //ONLY_MSBC +// for (ch = 0; ch < 1/*frame->channels*/; ch++) { + x = &state->X/*[ch]*/[state->position - 8 * + state->increment + MSBC_BLOCKS/*frame->blocks*/ * 8]; + for (blk = 0; blk < MSBC_BLOCKS/*frame->blocks*/; + blk += state->increment) { + state->sbc_analyze_8s( + state, x, + frame->sb_sample_f[blk]/*[ch]*/, + frame->sb_sample_f[blk + 1]/*[ch]*/ - + frame->sb_sample_f[blk]/*[ch]*/); + x -= 8 * state->increment; + } +// } + return MSBC_BLOCKS/*frame->blocks*/ * 8; + +#ifndef ONLY_MSBC + default: + return -EIO; + } +#endif //ONLY_MSBC +} +#endif //MSBC_ENCODE + +/* Supplementary bitstream writing macros for 'sbc_pack_frame' */ + +#define PUT_BITS(data_ptr, bits_cache, bits_count, v, n) \ + do { \ + bits_cache = (v) | (bits_cache << (n)); \ + bits_count += (n); \ + if (bits_count >= 16) { \ + bits_count -= 8; \ + *data_ptr++ = (uint8_t) \ + (bits_cache >> bits_count); \ + bits_count -= 8; \ + *data_ptr++ = (uint8_t) \ + (bits_cache >> bits_count); \ + } \ + } while (0) + +#define FLUSH_BITS(data_ptr, bits_cache, bits_count) \ + do { \ + while (bits_count >= 8) { \ + bits_count -= 8; \ + *data_ptr++ = (uint8_t) \ + (bits_cache >> bits_count); \ + } \ + if (bits_count > 0) \ + *data_ptr++ = (uint8_t) \ + (bits_cache << (8 - bits_count)); \ + } while (0) + +#ifdef MSBC_ENCODE +/* + * Packs the SBC frame from frame into the memory at data. At most len + * bytes will be used, should more memory be needed an appropriate + * error code will be returned. Returns the length of the packed frame + * on success or a negative value on error. + * + * The error codes are: + * -1 Not enough memory reserved + * -2 Unsupported sampling rate + * -3 Unsupported number of blocks + * -4 Unsupported number of subbands + * -5 Bitpool value out of bounds + * -99 not implemented + */ +static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *data, + struct sbc_frame *frame, size_t len, + int frame_subbands, int frame_channels, + int joint) +{ + /* Bitstream writer starts from the fourth byte */ + uint8_t *data_ptr = data + 4; + uint32_t bits_cache = 0; + uint32_t bits_count = 0; + +// /* Will copy the header parts for CRC-8 calculation here */ +// uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +// int crc_pos = 0; + + uint32_t audio_sample; + + int /*ch,*/ sb, blk; /* channel, subband, block and bit counters */ + int bits/*[2]*/[8]; /* bits distribution */ + uint32_t levels/*[2]*/[8]; /* levels are derived from that */ + uint32_t sb_sample_delta/*[2]*/[8]; + + /* Can't fill in crc yet */ + +// crc_header[0] = data[1]; +// crc_header[1] = data[2]; +// crc_pos = 16; + +#ifndef ONLY_MSBC + if (frame->mode == JOINT_STEREO) { + PUT_BITS(data_ptr, bits_cache, bits_count, + joint, frame_subbands); + crc_header[crc_pos >> 3] = joint; + crc_pos += frame_subbands; + } +#endif //ONLY_MSBC + +// for (ch = 0; ch < frame_channels; ch++) { + for (sb = 0; sb < frame_subbands; sb++) { + PUT_BITS(data_ptr, bits_cache, bits_count, + frame->scale_factor/*[ch]*/[sb] & 0x0F, 4); +// crc_header[crc_pos >> 3] <<= 4; +// crc_header[crc_pos >> 3] |= frame->scale_factor/*[ch]*/[sb] & 0x0F; +// crc_pos += 4; + } +// } + +// /* align the last crc byte */ +// if (crc_pos % 8) +// crc_header[crc_pos >> 3] <<= 8 - (crc_pos % 8); + +// data[3] = sbc_crc8(crc_header, crc_pos); + + sbc_calculate_bits(frame, bits); + +// for (ch = 0; ch < frame_channels; ch++) { + for (sb = 0; sb < frame_subbands; sb++) { + levels/*[ch]*/[sb] = ((1 << bits/*[ch]*/[sb]) - 1) << + (32 - (frame->scale_factor/*[ch]*/[sb] + + SCALE_OUT_BITS + 2)); + sb_sample_delta/*[ch]*/[sb] = (uint32_t) 1 << + (frame->scale_factor/*[ch]*/[sb] + + SCALE_OUT_BITS + 1); + } +// } + + for (blk = 0; blk < MSBC_BLOCKS/*frame->blocks*/; blk++) { +// for (ch = 0; ch < frame_channels; ch++) { + for (sb = 0; sb < frame_subbands; sb++) { + + if (bits/*[ch]*/[sb] == 0) + continue; + + audio_sample = ((uint64_t) levels/*[ch]*/[sb] * + (sb_sample_delta/*[ch]*/[sb] + + frame->sb_sample_f[blk]/*[ch]*/[sb])) >> 32; + + PUT_BITS(data_ptr, bits_cache, bits_count, + audio_sample, bits/*[ch]*/[sb]); + } +// } + } + + FLUSH_BITS(data_ptr, bits_cache, bits_count); + + return data_ptr - data; +} +#endif //MSBC_ENCODE + +#ifndef ONLY_MSBC +static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len, + int joint) +{ + int frame_subbands = 4; + + data[0] = SBC_SYNCWORD; + + data[1] = (frame->frequency & 0x03) << 6; + data[1] |= (frame->block_mode & 0x03) << 4; + data[1] |= (frame->mode & 0x03) << 2; + data[1] |= (frame->allocation & 0x01) << 1; + + data[2] = frame->bitpool; + + if (frame->subbands != 4) + frame_subbands = 8; + + if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) && + frame->bitpool > frame_subbands << 4) + return -5; + + if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) && + frame->bitpool > frame_subbands << 5) + return -5; + + if (frame->subbands == 4) { + if (frame->channels == 1) + return sbc_pack_frame_internal( + data, frame, len, 4, 1, joint); + else + return sbc_pack_frame_internal( + data, frame, len, 4, 2, joint); + } else { + data[1] |= 0x01; + if (frame->channels == 1) + return sbc_pack_frame_internal( + data, frame, len, 8, 1, joint); + else + return sbc_pack_frame_internal( + data, frame, len, 8, 2, joint); + } +} +#endif //ONLY_MSBC + +#ifdef MSBC_ENCODE +static ssize_t msbc_pack_frame(uint8_t *data, struct sbc_frame *frame, + size_t len, int joint) +{ + data[0] = MSBC_SYNCWORD; +// data[1] = 0; + data[2] = 0; + + return sbc_pack_frame_internal(data, frame, len, 8, 1, joint); +} + +#ifndef ONLY_MSBC +static void sbc_encoder_init(bool msbc, struct sbc_encoder_state *state, + const struct sbc_frame *frame) +{ + memset(&state->X, 0, sizeof(state->X)); + state->position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7; + if (msbc) + state->increment = 1; + else + state->increment = 4; + + sbc_init_primitives(state); +} +#else +static void sbc_encoder_init(struct sbc_encoder_state *state, + const struct sbc_frame *frame) +{ + memset(&state->X, 0, sizeof(state->X)); + state->position = (SBC_X_BUFFER_SIZE - 8/*frame->subbands*/ * 9) & ~7; + state->increment = 1; + + sbc_init_primitives(state); +} +#endif //ONLY_MSBC +#endif //MSBC_ENCODE + +struct sbc_priv { + bool init; +#ifndef ONLY_MSBC + bool msbc; +#endif //ONLY_MSBC + struct SBC_ALIGNED sbc_frame frame; +#ifdef MSBC_DECODE + struct SBC_ALIGNED sbc_decoder_state dec_state; +#endif //MSBC_DECODE +#ifdef MSBC_ENCODE + struct SBC_ALIGNED sbc_encoder_state enc_state; +#endif //MSBC_ENCODE +#ifdef MSBC_DECODE + int (*unpack_frame)(const uint8_t *data, struct sbc_frame *frame, + size_t len); +#endif //MSBC_DECODE +#ifdef MSBC_ENCODE + ssize_t (*pack_frame)(uint8_t *data, struct sbc_frame *frame, + size_t len, int joint); +#endif //MSBC_ENCODE +}; + +#ifdef SBC_CC26XX +#ifdef __IAR_SYSTEMS_ICC__ +/* ----------- CCS Compiler ----------- */ +#elif defined __TI_COMPILER_VERSION || defined __TI_COMPILER_VERSION__ +/* ----------- Unrecognized Compiler ----------- */ +#else +#error "ERROR: Unknown compiler." +#endif +uint8_t sbc_mem[sizeof(struct sbc_priv) + SBC_ALIGN_MASK] = {0}; +#ifdef __IAR_SYSTEMS_ICC__ +#endif //__IAR_SYSTEMS_ICC__ +#endif //SBC_CC26XX + +static void sbc_set_defaults(sbc_t *sbc, unsigned long flags) +{ + struct sbc_priv *priv = sbc->priv; + +#ifndef ONLY_MSBC + if (priv->msbc) { +#endif //ONLY_MSBC +#ifdef MSBC_ENCODE + priv->pack_frame = msbc_pack_frame; +#endif //MSBC_ENCODE +#ifdef MSBC_DECODE + priv->unpack_frame = msbc_unpack_frame; +#endif //MSBC_DECODE +#ifndef ONLY_MSBC + } else { + priv->pack_frame = sbc_pack_frame; + priv->unpack_frame = sbc_unpack_frame; + } + + sbc->flags = flags; + sbc->frequency = SBC_FREQ_44100; + sbc->mode = SBC_MODE_STEREO; + sbc->subbands = SBC_SB_8; + sbc->blocks = SBC_BLK_16; + sbc->bitpool = 32; +#ifndef SBC_CC26XX +#if __BYTE_ORDER == __LITTLE_ENDIAN + sbc->endian = SBC_LE; +#elif __BYTE_ORDER == __BIG_ENDIAN + sbc->endian = SBC_BE; +#else +#error "Unknown byte order" +#endif +#endif //SBC_CC26XX +#endif //ONLY_MSBC +} + +SBC_EXPORT int sbc_init(sbc_t *sbc, unsigned long flags) +{ + if (!sbc) + return -EIO; + + memset(sbc, 0, sizeof(sbc_t)); + + sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK); + if (!sbc->priv_alloc_base) + return -ENOMEM; + + sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base + + SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK)); + + memset(sbc->priv, 0, sizeof(struct sbc_priv)); + + sbc_set_defaults(sbc, flags); + + return 0; +} + +SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags) +{ +#ifndef ONLY_MSBC + struct sbc_priv *priv; +#endif //ONLY_MSBC + + if (!sbc) + return -EIO; + + memset(sbc, 0, sizeof(sbc_t)); + +#ifndef SBC_CC26XX + System_printf("Allocate %d bytes\n", sizeof(struct sbc_priv) + SBC_ALIGN_MASK); + System_flush(); + sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK); + if (!sbc->priv_alloc_base) + return -ENOMEM; +#else + sbc->priv_alloc_base = (void *)sbc_mem; +#endif //SBC_CC26XX + + sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base + + SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK)); + + memset(sbc->priv, 0, sizeof(struct sbc_priv)); + +#ifndef ONLY_MSBC + priv = sbc->priv; + priv->msbc = true; +#endif //ONLY_MSBC + + sbc_set_defaults(sbc, flags); + +#ifndef ONLY_MSBC + sbc->frequency = SBC_FREQ_16000; + sbc->blocks = MSBC_BLOCKS; + sbc->subbands = SBC_SB_8; + sbc->mode = SBC_MODE_MONO; + sbc->allocation = SBC_AM_LOUDNESS; + sbc->bitpool = 26; +#endif //ONLY_MSBC + + return 0; +} + +#ifndef ONLY_MSBC +static int sbc_set_a2dp(sbc_t *sbc, unsigned long flags, + const void *conf, size_t conf_len) +{ + const struct a2dp_sbc *a2dp; + + if (conf_len != sizeof(*a2dp)) + return -EINVAL; + + a2dp = conf; + + switch (a2dp->frequency) { + case A2DP_SAMPLING_FREQ_16000: + sbc->frequency = SBC_FREQ_16000; + break; + case A2DP_SAMPLING_FREQ_32000: + sbc->frequency = SBC_FREQ_32000; + break; + case A2DP_SAMPLING_FREQ_44100: + sbc->frequency = SBC_FREQ_44100; + break; + case A2DP_SAMPLING_FREQ_48000: + sbc->frequency = SBC_FREQ_48000; + break; + default: + return -EINVAL; + } + + switch (a2dp->channel_mode) { + case A2DP_CHANNEL_MODE_MONO: + sbc->mode = SBC_MODE_MONO; + break; + case A2DP_CHANNEL_MODE_DUAL_CHANNEL: + sbc->mode = SBC_MODE_DUAL_CHANNEL; + break; + case A2DP_CHANNEL_MODE_STEREO: + sbc->mode = SBC_MODE_STEREO; + break; + case A2DP_CHANNEL_MODE_JOINT_STEREO: + sbc->mode = SBC_MODE_JOINT_STEREO; + break; + default: + return -EINVAL; + } + + switch (a2dp->allocation_method) { + case A2DP_ALLOCATION_SNR: + sbc->allocation = SBC_AM_SNR; + break; + case A2DP_ALLOCATION_LOUDNESS: + sbc->allocation = SBC_AM_LOUDNESS; + break; + default: + return -EINVAL; + } + + switch (a2dp->subbands) { + case A2DP_SUBBANDS_4: + sbc->subbands = SBC_SB_4; + break; + case A2DP_SUBBANDS_8: + sbc->subbands = SBC_SB_8; + break; + default: + return -EINVAL; + } + + switch (a2dp->block_length) { + case A2DP_BLOCK_LENGTH_4: + sbc->blocks = SBC_BLK_4; + break; + case A2DP_BLOCK_LENGTH_8: + sbc->blocks = SBC_BLK_8; + break; + case A2DP_BLOCK_LENGTH_12: + sbc->blocks = SBC_BLK_12; + break; + case A2DP_BLOCK_LENGTH_16: + sbc->blocks = SBC_BLK_16; + break; + default: + return -EINVAL; + } + + return 0; +} + +SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags, + const void *conf, size_t conf_len) +{ + int err; + + err = sbc_init(sbc, flags); + if (err < 0) + return err; + + err = sbc_set_a2dp(sbc, flags, conf, conf_len); + if (err < 0) { + sbc_finish(sbc); + return err; + } + + return 0; +} + +int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags, + const void *conf, size_t conf_len) +{ + int err; + + err = sbc_reinit(sbc, flags); + if (err < 0) + return err; + + return sbc_set_a2dp(sbc, flags, conf, conf_len); +} +#endif //ONLY_MSBC + +#ifdef MSBC_DECODE +SBC_EXPORT ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len) +{ + return sbc_decode(sbc, input, input_len, NULL, 0, NULL); +} + +SBC_EXPORT ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len, + void *output, size_t output_len, size_t *written) +{ + struct sbc_priv *priv; + char *ptr; + int i,/* ch,*/ framelen, samples; + + if (!sbc || !input) + return -EIO; + + priv = sbc->priv; + + framelen = priv->unpack_frame(input, &priv->frame, input_len); + + if (!priv->init) { + sbc_decoder_init(&priv->dec_state, &priv->frame); + priv->init = true; + +#ifndef ONLY_MSBC + sbc->frequency = priv->frame.frequency; + sbc->mode = priv->frame.mode; + sbc->subbands = priv->frame.subband_mode; + sbc->blocks = priv->frame.block_mode; + sbc->allocation = priv->frame.allocation; + sbc->bitpool = priv->frame.bitpool; +#endif //ONLY_MSBC + + priv->frame.codesize = sbc_get_codesize(sbc); + priv->frame.length = framelen; + } +#ifndef ONLY_MSBC + else if (priv->frame.bitpool != sbc->bitpool) { + priv->frame.length = framelen; + sbc->bitpool = priv->frame.bitpool; + } +#endif //ONLY_MSBC + + if (!output) + return framelen; + + if (written) + *written = 0; + + if (framelen <= 0) + return framelen; + + samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame); + + ptr = output; + + if (output_len < (size_t) (samples * 1/*priv->frame.channels*/ * 2)) + samples = output_len / (1/*priv->frame.channels*/ * 2); + + for (i = 0; i < samples; i++) { +// for (ch = 0; ch < priv->frame.channels; ch++) { + int16_t s; + s = priv->frame.pcm_sample/*[ch]*/[i]; + +#ifndef SBC_CC26XX + if (sbc->endian == SBC_BE) { + *ptr++ = (s & 0xff00) >> 8; + *ptr++ = (s & 0x00ff); + } else { +#endif //SBC_CC26XX + *ptr++ = (s & 0x00ff); + *ptr++ = (s & 0xff00) >> 8; +#ifndef SBC_CC26XX + } +#endif //SBC_CC26XX +// } + } + + if (written) + *written = samples * 1/*priv->frame.channels*/ * 2; + + return framelen; +} +#endif //MSBC_DECODE + +#ifdef MSBC_ENCODE +SBC_EXPORT ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len, + void *output, size_t output_len, ssize_t *written) +{ + struct sbc_priv *priv; + int samples; + ssize_t framelen; + int (*sbc_enc_process_input)(int position, + const uint8_t *pcm, int16_t X/*[2]*/[SBC_X_BUFFER_SIZE], + int nsamples, int nchannels); + + if (!sbc || !input) + return -EIO; + + priv = sbc->priv; + + if (written) + *written = 0; + + if (!priv->init) { +#ifndef ONLY_MSBC + priv->frame.frequency = sbc->frequency; + priv->frame.mode = sbc->mode; + priv->frame.channels = sbc->mode == SBC_MODE_MONO ? 1 : 2; + priv->frame.allocation = sbc->allocation; + priv->frame.subband_mode = sbc->subbands; + priv->frame.subbands = sbc->subbands ? 8 : 4; + priv->frame.block_mode = sbc->blocks; + if (priv->msbc) + priv->frame.blocks = MSBC_BLOCKS; + else + priv->frame.blocks = 4 + (sbc->blocks * 4); + priv->frame.bitpool = sbc->bitpool; +#endif //ONLY_MSBC + priv->frame.codesize = sbc_get_codesize(sbc); + priv->frame.length = sbc_get_frame_length(sbc); + +#ifndef ONLY_MSBC + sbc_encoder_init(priv->msbc, &priv->enc_state, &priv->frame); +#else + sbc_encoder_init(&priv->enc_state, &priv->frame); +#endif //ONLY_MSBC + priv->init = true; + } +#ifndef ONLY_MSBC + else if (priv->frame.bitpool != sbc->bitpool) { + priv->frame.length = sbc_get_frame_length(sbc); + priv->frame.bitpool = sbc->bitpool; + } +#endif //ONLY_MSBC + + /* input must be large enough to encode a complete frame */ + if (input_len < priv->frame.codesize) + return 0; + + /* output must be large enough to receive the encoded frame */ + if (!output || output_len < priv->frame.length) + return -ENOSPC; + +#ifndef ONLY_MSBC + /* Select the needed input data processing function and call it */ + if (priv->frame.subbands == 8) { + if (sbc->endian == SBC_BE) + sbc_enc_process_input = + priv->enc_state.sbc_enc_process_input_8s_be; + else + sbc_enc_process_input = + priv->enc_state.sbc_enc_process_input_8s_le; + } else { + if (sbc->endian == SBC_BE) + sbc_enc_process_input = + priv->enc_state.sbc_enc_process_input_4s_be; + else + sbc_enc_process_input = + priv->enc_state.sbc_enc_process_input_4s_le; + } +#else + sbc_enc_process_input = priv->enc_state.sbc_enc_process_input_8s_le; +#endif //ONLY_MSBC + + priv->enc_state.position = sbc_enc_process_input( + priv->enc_state.position, (const uint8_t *) input, + priv->enc_state.X, 8/*priv->frame.subbands*/ * MSBC_BLOCKS/*priv->frame.blocks*/, + 1/*priv->frame.channels*/); + + samples = sbc_analyze_audio(&priv->enc_state, &priv->frame); + +#ifndef ONLY_MSBC + if (priv->frame.mode == JOINT_STEREO) { + int j = priv->enc_state.sbc_calc_scalefactors_j( + priv->frame.sb_sample_f, priv->frame.scale_factor, + priv->frame.blocks, priv->frame.subbands); + framelen = priv->pack_frame(output, + &priv->frame, output_len, j); + } else +#endif //ONLY_MSBC + { + priv->enc_state.sbc_calc_scalefactors( + priv->frame.sb_sample_f, priv->frame.scale_factor, + MSBC_BLOCKS/*priv->frame.blocks*/, 1/*priv->frame.channels*/, + 8/*priv->frame.subbands*/); + framelen = priv->pack_frame(output, + &priv->frame, output_len, 0); + } + + if (written) + *written = framelen; + + return samples * 1/*priv->frame.channels*/ * 2; +} +#endif //MSBC_ENCODE + +SBC_EXPORT void sbc_finish(sbc_t *sbc) +{ + if (!sbc) + return; + +#ifndef SBC_CC26XX + free(sbc->priv_alloc_base); +#else + sbc->priv_alloc_base = NULL; +#endif //SBC_CC26XX + + memset(sbc, 0, sizeof(sbc_t)); +} + +SBC_EXPORT size_t sbc_get_frame_length(sbc_t *sbc) +{ + int ret; + uint8_t subbands, channels, blocks, joint, bitpool; + struct sbc_priv *priv; + + priv = sbc->priv; + if (priv->init) // && priv->frame.bitpool == sbc->bitpool) + return priv->frame.length; + +#ifndef ONLY_MSBC + subbands = sbc->subbands ? 8 : 4; + if (priv->msbc) +#else + subbands = 8; +#endif //ONLY_MSBC + blocks = MSBC_BLOCKS; +#ifndef ONLY_MSBC + else + blocks = 4 + (sbc->blocks * 4); +#endif //ONLY_MSBC + channels = 1; //sbc->mode == SBC_MODE_MONO ? 1 : 2; + joint = 0; //sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0; + bitpool = 26; //sbc->bitpool; + + ret = 4 + (4 * subbands * channels) / 8; + /* This term is not always evenly divide so we round it up */ + if (channels == 1) + ret += ((blocks * channels * bitpool) + 7) / 8; + else + ret += (((joint ? subbands : 0) + blocks * bitpool) + 7) / 8; + + return ret; +} + +SBC_EXPORT unsigned sbc_get_frame_duration(sbc_t *sbc) +{ + uint8_t subbands, blocks; + uint16_t frequency; + struct sbc_priv *priv; + + priv = sbc->priv; + if (!priv->init) { + subbands = 8; //sbc->subbands ? 8 : 4; +#ifndef ONLY_MSBC + if (priv->msbc) +#endif //ONLY_MSBC + blocks = MSBC_BLOCKS; +#ifndef ONLY_MSBC + else + blocks = 4 + (sbc->blocks * 4); +#endif //ONLY_MSBC + } else { + subbands = 8/*priv->frame.subbands*/; + blocks = MSBC_BLOCKS/*priv->frame.blocks*/; + } + +#ifndef ONLY_MSBC + switch (sbc->frequency) { + case SBC_FREQ_16000: +#endif //ONLY_MSBC + frequency = 16000; +#ifndef ONLY_MSBC + break; + + case SBC_FREQ_32000: + frequency = 32000; + break; + + case SBC_FREQ_44100: + frequency = 44100; + break; + + case SBC_FREQ_48000: + frequency = 48000; + break; + default: + return 0; + } +#endif //ONLY_MSBC + + return (1000000 * blocks * subbands) / frequency; +} + +SBC_EXPORT size_t sbc_get_codesize(sbc_t *sbc) +{ + uint16_t subbands, channels, blocks; + struct sbc_priv *priv; + + priv = sbc->priv; + if (!priv->init) { + subbands = 8; //sbc->subbands ? 8 : 4; +#ifndef ONLY_MSBC + if (priv->msbc) +#endif //ONLY_MSBC + blocks = MSBC_BLOCKS; +#ifndef ONLY_MSBC + else + blocks = 4 + (sbc->blocks * 4); +#endif //ONLY_MSBC + channels = 1; //sbc->mode == SBC_MODE_MONO ? 1 : 2; + } else { + subbands = 8/*priv->frame.subbands*/; + blocks = MSBC_BLOCKS/*priv->frame.blocks*/; + channels = 1/*priv->frame.channels*/; + } + + return subbands * blocks * channels * 2; +} + +#ifdef MSBC_ENCODE +SBC_EXPORT const char *sbc_get_implementation_info(sbc_t *sbc) +{ + struct sbc_priv *priv; + + if (!sbc) + return NULL; + + priv = sbc->priv; + if (!priv) + return NULL; + + return priv->enc_state.implementation_info; +} +#endif //MSBC_ENCODE + +SBC_EXPORT int sbc_reinit(sbc_t *sbc, unsigned long flags) +{ + struct sbc_priv *priv; + + if (!sbc || !sbc->priv) + return -EIO; + + priv = sbc->priv; + + if (priv->init) + memset(sbc->priv, 0, sizeof(struct sbc_priv)); + + sbc_set_defaults(sbc, flags); + + return 0; +} diff --git a/src/util/sbc/sbc.h b/src/util/sbc/sbc.h new file mode 100644 index 0000000..768f172 --- /dev/null +++ b/src/util/sbc/sbc.h @@ -0,0 +1,124 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2012-2014 Intel Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SBC_H +#define __SBC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "sbc_cc26xx_port.h" +#ifndef SBC_CC26XX +#include +#endif //SBC_CC26XX + +/* sampling frequency */ +#define SBC_FREQ_16000 0x00 +#define SBC_FREQ_32000 0x01 +#define SBC_FREQ_44100 0x02 +#define SBC_FREQ_48000 0x03 + +/* blocks */ +#define SBC_BLK_4 0x00 +#define SBC_BLK_8 0x01 +#define SBC_BLK_12 0x02 +#define SBC_BLK_16 0x03 + +/* channel mode */ +#define SBC_MODE_MONO 0x00 +#define SBC_MODE_DUAL_CHANNEL 0x01 +#define SBC_MODE_STEREO 0x02 +#define SBC_MODE_JOINT_STEREO 0x03 + +/* allocation method */ +#define SBC_AM_LOUDNESS 0x00 +#define SBC_AM_SNR 0x01 + +/* subbands */ +#define SBC_SB_4 0x00 +#define SBC_SB_8 0x01 + +/* data endianess */ +#define SBC_LE 0x00 +#define SBC_BE 0x01 + +struct sbc_struct { + unsigned long flags; + +#ifndef ONLY_MSBC + uint8_t frequency; + uint8_t blocks; + uint8_t subbands; + uint8_t mode; + uint8_t allocation; + uint8_t bitpool; + uint8_t endian; +#endif //ONLY_MSBC + + void *priv; + void *priv_alloc_base; +}; + +typedef struct sbc_struct sbc_t; + +int sbc_init(sbc_t *sbc, unsigned long flags); +int sbc_reinit(sbc_t *sbc, unsigned long flags); +int sbc_init_msbc(sbc_t *sbc, unsigned long flags); +int sbc_init_a2dp(sbc_t *sbc, unsigned long flags, + const void *conf, size_t conf_len); +int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags, + const void *conf, size_t conf_len); + +ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len); + +/* Decodes ONE input block into ONE output block */ +ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len, + void *output, size_t output_len, size_t *written); + +/* Encodes ONE input block into ONE output block */ +ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len, + void *output, size_t output_len, ssize_t *written); + +/* Returns the output block size in bytes */ +size_t sbc_get_frame_length(sbc_t *sbc); + +/* Returns the time one input/output block takes to play in msec*/ +unsigned sbc_get_frame_duration(sbc_t *sbc); + +/* Returns the input block size in bytes */ +size_t sbc_get_codesize(sbc_t *sbc); + +const char *sbc_get_implementation_info(sbc_t *sbc); +void sbc_finish(sbc_t *sbc); + +#ifdef __cplusplus +} +#endif + +#endif /* __SBC_H */ diff --git a/src/util/sbc/sbc_cc26xx_port.h b/src/util/sbc/sbc_cc26xx_port.h new file mode 100644 index 0000000..13a6962 --- /dev/null +++ b/src/util/sbc/sbc_cc26xx_port.h @@ -0,0 +1,65 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2016-2017 Texas Instruments + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2012-2014 Intel Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef SBC_CC26XX_PORT_H +#define SBC_CC26XX_PORT_H + +#include + +#ifndef SBC_CC26XX +#define SBC_CC26XX +#endif //SBC_CC26XX +#define ONLY_MSBC +//#define MSBC_ENCODE +//#define xMSBC_DECODE +#ifdef AUDIO_TRANSMITTER + #ifndef MSBC_ENCODE + #define MSBC_ENCODE + #endif //MSBC_ENCODE + #ifdef MSBC_DECODE + #undef MSBC_DECODE + #endif //MSBC_DECODE +#endif //AUDIO_TRANSMITTER + +#ifdef AUDIO_RECEIVER + #ifndef MSBC_DECODE + #define MSBC_DECODE + #endif //MSBC_DECODE + #ifdef MSBC_ENCODE + #undef MSBC_ENCODE + #endif //MSBC_ENCODE +#endif //AUDIO_RECEIVER + + +#define EIO (-1) +#define ENOMEM (-1) +#define EINVAL (-1) +#define ENOSPC (-1) + +typedef int32_t ssize_t; + +#endif //SBC_CC26XX_PORT_H diff --git a/src/util/sbc/sbc_math.h b/src/util/sbc/sbc_math.h new file mode 100644 index 0000000..5aa1965 --- /dev/null +++ b/src/util/sbc/sbc_math.h @@ -0,0 +1,71 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2008 Brad Midgley + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "sbc_cc26xx_port.h" + +#define fabs(x) ((x) < 0 ? -(x) : (x)) +/* C does not provide an explicit arithmetic shift right but this will + always be correct and every compiler *should* generate optimal code */ +#ifndef SBC_CC26XX +#define ASR(val, bits) ((-2 >> 1 == -1) ? \ + ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits))) +#else +//#define ASR(val, bits) ((val) >> (bits)) +#define ASR(val, bits) (((int32_t)val) >> (bits)) +//#define ASR(val, bits) (((uint32_t)val) >> (bits)) +#endif //SBC_CC26XX + +#define SCALE_SPROTO4_TBL 12 +#define SCALE_SPROTO8_TBL 14 +#define SCALE_NPROTO4_TBL 11 +#define SCALE_NPROTO8_TBL 11 +#define SCALE4_STAGED1_BITS 15 +#define SCALE4_STAGED2_BITS 16 +#define SCALE8_STAGED1_BITS 15 +#define SCALE8_STAGED2_BITS 16 + +#ifndef SBC_CC26XX +typedef int32_t sbc_fixed_t; +#endif //SBC_CC26XX + +#define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS) +#define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS) +#define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS) +#define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS) + +#define SBC_FIXED_0(val) { val = 0; } +#define MUL(a, b) ((a) * (b)) +#if defined(__arm__) && (!defined(__thumb__) || defined(__thumb2__)) +#define MULA(a, b, res) ({ \ + int tmp = res; \ + __asm__( \ + "mla %0, %2, %3, %0" \ + : "=&r" (tmp) \ + : "0" (tmp), "r" (a), "r" (b)); \ + tmp; }) +#else +#define MULA(a, b, res) ((a) * (b) + (res)) +#endif diff --git a/src/util/sbc/sbc_primitives.c b/src/util/sbc/sbc_primitives.c new file mode 100644 index 0000000..20b7d05 --- /dev/null +++ b/src/util/sbc/sbc_primitives.c @@ -0,0 +1,706 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * Copyright (C) 2012-2013 Intel Corporation + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#if defined(__IAR_SYSTEMS_ICC__) || defined(DOXYGEN) + #include +#endif +#include "sbc.h" +#include "sbc_math.h" +#include "sbc_tables.h" + +#include "sbc_primitives.h" +#ifndef SBC_CC26XX +#include "sbc_primitives_mmx.h" +#include "sbc_primitives_iwmmxt.h" +#include "sbc_primitives_neon.h" +#include "sbc_primitives_armv6.h" +#endif //SBC_CC26XX + +/* + * A reference C code of analysis filter with SIMD-friendly tables + * reordering and code layout. This code can be used to develop platform + * specific SIMD optimizations. Also it may be used as some kind of test + * for compiler autovectorization capabilities (who knows, if the compiler + * is very good at this stuff, hand optimized assembly may be not strictly + * needed for some platform). + * + * Note: It is also possible to make a simple variant of analysis filter, + * which needs only a single constants table without taking care about + * even/odd cases. This simple variant of filter can be implemented without + * input data permutation. The only thing that would be lost is the + * possibility to use pairwise SIMD multiplications. But for some simple + * CPU cores without SIMD extensions it can be useful. If anybody is + * interested in implementing such variant of a filter, sourcecode from + * bluez versions 4.26/4.27 can be used as a reference and the history of + * the changes in git repository done around that time may be worth checking. + */ + +#ifndef ONLY_MSBC +static inline void sbc_analyze_four_simd(const int16_t *in, int32_t *out, + const FIXED_T *consts) +{ + FIXED_A t1[4]; + FIXED_T t2[4]; + int hop = 0; + + /* rounding coefficient */ + t1[0] = t1[1] = t1[2] = t1[3] = + (FIXED_A) 1 << (SBC_PROTO_FIXED4_SCALE - 1); + + /* low pass polyphase filter */ + for (hop = 0; hop < 40; hop += 8) { + t1[0] += (FIXED_A) in[hop] * consts[hop]; + t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; + t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2]; + t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3]; + t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4]; + t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5]; + t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6]; + t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7]; + } + + /* scaling */ + t2[0] = t1[0] >> SBC_PROTO_FIXED4_SCALE; + t2[1] = t1[1] >> SBC_PROTO_FIXED4_SCALE; + t2[2] = t1[2] >> SBC_PROTO_FIXED4_SCALE; + t2[3] = t1[3] >> SBC_PROTO_FIXED4_SCALE; + + /* do the cos transform */ + t1[0] = (FIXED_A) t2[0] * consts[40 + 0]; + t1[0] += (FIXED_A) t2[1] * consts[40 + 1]; + t1[1] = (FIXED_A) t2[0] * consts[40 + 2]; + t1[1] += (FIXED_A) t2[1] * consts[40 + 3]; + t1[2] = (FIXED_A) t2[0] * consts[40 + 4]; + t1[2] += (FIXED_A) t2[1] * consts[40 + 5]; + t1[3] = (FIXED_A) t2[0] * consts[40 + 6]; + t1[3] += (FIXED_A) t2[1] * consts[40 + 7]; + + t1[0] += (FIXED_A) t2[2] * consts[40 + 8]; + t1[0] += (FIXED_A) t2[3] * consts[40 + 9]; + t1[1] += (FIXED_A) t2[2] * consts[40 + 10]; + t1[1] += (FIXED_A) t2[3] * consts[40 + 11]; + t1[2] += (FIXED_A) t2[2] * consts[40 + 12]; + t1[2] += (FIXED_A) t2[3] * consts[40 + 13]; + t1[3] += (FIXED_A) t2[2] * consts[40 + 14]; + t1[3] += (FIXED_A) t2[3] * consts[40 + 15]; + + out[0] = t1[0] >> + (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); + out[1] = t1[1] >> + (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); + out[2] = t1[2] >> + (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); + out[3] = t1[3] >> + (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); +} +#endif //ONLY_MSBC + +static inline void sbc_analyze_eight_simd(const int16_t *in, int32_t *out, + const FIXED_T *consts) +{ + FIXED_A t1[8]; + FIXED_T t2[8]; + int i, hop; + + /* rounding coefficient */ + t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = + (FIXED_A) 1 << (SBC_PROTO_FIXED8_SCALE-1); + + /* low pass polyphase filter */ + for (hop = 0; hop < 80; hop += 16) { + t1[0] += (FIXED_A) in[hop] * consts[hop]; + t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; + t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2]; + t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3]; + t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4]; + t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5]; + t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6]; + t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7]; + t1[4] += (FIXED_A) in[hop + 8] * consts[hop + 8]; + t1[4] += (FIXED_A) in[hop + 9] * consts[hop + 9]; + t1[5] += (FIXED_A) in[hop + 10] * consts[hop + 10]; + t1[5] += (FIXED_A) in[hop + 11] * consts[hop + 11]; + t1[6] += (FIXED_A) in[hop + 12] * consts[hop + 12]; + t1[6] += (FIXED_A) in[hop + 13] * consts[hop + 13]; + t1[7] += (FIXED_A) in[hop + 14] * consts[hop + 14]; + t1[7] += (FIXED_A) in[hop + 15] * consts[hop + 15]; + } + + /* scaling */ + t2[0] = t1[0] >> SBC_PROTO_FIXED8_SCALE; + t2[1] = t1[1] >> SBC_PROTO_FIXED8_SCALE; + t2[2] = t1[2] >> SBC_PROTO_FIXED8_SCALE; + t2[3] = t1[3] >> SBC_PROTO_FIXED8_SCALE; + t2[4] = t1[4] >> SBC_PROTO_FIXED8_SCALE; + t2[5] = t1[5] >> SBC_PROTO_FIXED8_SCALE; + t2[6] = t1[6] >> SBC_PROTO_FIXED8_SCALE; + t2[7] = t1[7] >> SBC_PROTO_FIXED8_SCALE; + + + /* do the cos transform */ + t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 0; + + for (i = 0; i < 4; i++) { + t1[0] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 0]; + t1[0] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 1]; + t1[1] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 2]; + t1[1] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 3]; + t1[2] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 4]; + t1[2] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 5]; + t1[3] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 6]; + t1[3] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 7]; + t1[4] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 8]; + t1[4] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 9]; + t1[5] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 10]; + t1[5] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 11]; + t1[6] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 12]; + t1[6] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 13]; + t1[7] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 14]; + t1[7] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 15]; + } + + for (i = 0; i < 8; i++) + out[i] = t1[i] >> + (SBC_COS_TABLE_FIXED8_SCALE - SCALE_OUT_BITS); +} + +#ifndef ONLY_MSBC +static inline void sbc_analyze_4b_4s_simd(struct sbc_encoder_state *state, + int16_t *x, int32_t *out, int out_stride) +{ + /* Analyze blocks */ + sbc_analyze_four_simd(x + 12, out, analysis_consts_fixed4_simd_odd); + out += out_stride; + sbc_analyze_four_simd(x + 8, out, analysis_consts_fixed4_simd_even); + out += out_stride; + sbc_analyze_four_simd(x + 4, out, analysis_consts_fixed4_simd_odd); + out += out_stride; + sbc_analyze_four_simd(x + 0, out, analysis_consts_fixed4_simd_even); +} + +static inline void sbc_analyze_4b_8s_simd(struct sbc_encoder_state *state, + int16_t *x, int32_t *out, int out_stride) +{ + /* Analyze blocks */ + sbc_analyze_eight_simd(x + 24, out, analysis_consts_fixed8_simd_odd); + out += out_stride; + sbc_analyze_eight_simd(x + 16, out, analysis_consts_fixed8_simd_even); + out += out_stride; + sbc_analyze_eight_simd(x + 8, out, analysis_consts_fixed8_simd_odd); + out += out_stride; + sbc_analyze_eight_simd(x + 0, out, analysis_consts_fixed8_simd_even); +} +#endif //ONLY_MSBC + +static inline void sbc_analyze_1b_8s_simd_even(struct sbc_encoder_state *state, + int16_t *x, int32_t *out, int out_stride); + +static inline void sbc_analyze_1b_8s_simd_odd(struct sbc_encoder_state *state, + int16_t *x, int32_t *out, int out_stride) +{ + sbc_analyze_eight_simd(x, out, analysis_consts_fixed8_simd_odd); + state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_even; +} + +static inline void sbc_analyze_1b_8s_simd_even(struct sbc_encoder_state *state, + int16_t *x, int32_t *out, int out_stride) +{ + sbc_analyze_eight_simd(x, out, analysis_consts_fixed8_simd_even); + state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd; +} + +#ifndef SBC_CC26XX +static inline int16_t unaligned16_be(const uint8_t *ptr) +{ + return (int16_t) ((ptr[0] << 8) | ptr[1]); +} +#endif //SBC_CC26XX + +static inline int16_t unaligned16_le(const uint8_t *ptr) +{ + return (int16_t) (ptr[0] | (ptr[1] << 8)); +} + +/* + * Internal helper functions for input data processing. In order to get + * optimal performance, it is important to have "nsamples", "nchannels" + * and "big_endian" arguments used with this inline function as compile + * time constants. + */ + +#ifndef ONLY_MSBC +static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s4_internal( + int position, + const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels, int big_endian) +{ + /* handle X buffer wraparound */ + if (position < nsamples) { + if (nchannels > 0) + memcpy(&X[0][SBC_X_BUFFER_SIZE - 40], &X[0][position], + 36 * sizeof(int16_t)); + if (nchannels > 1) + memcpy(&X[1][SBC_X_BUFFER_SIZE - 40], &X[1][position], + 36 * sizeof(int16_t)); + position = SBC_X_BUFFER_SIZE - 40; + } + + #define PCM(i) (big_endian ? \ + unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2)) + + /* copy/permutate audio samples */ + while ((nsamples -= 8) >= 0) { + position -= 8; + if (nchannels > 0) { + int16_t *x = &X[0][position]; + x[0] = PCM(0 + 7 * nchannels); + x[1] = PCM(0 + 3 * nchannels); + x[2] = PCM(0 + 6 * nchannels); + x[3] = PCM(0 + 4 * nchannels); + x[4] = PCM(0 + 0 * nchannels); + x[5] = PCM(0 + 2 * nchannels); + x[6] = PCM(0 + 1 * nchannels); + x[7] = PCM(0 + 5 * nchannels); + } + if (nchannels > 1) { + int16_t *x = &X[1][position]; + x[0] = PCM(1 + 7 * nchannels); + x[1] = PCM(1 + 3 * nchannels); + x[2] = PCM(1 + 6 * nchannels); + x[3] = PCM(1 + 4 * nchannels); + x[4] = PCM(1 + 0 * nchannels); + x[5] = PCM(1 + 2 * nchannels); + x[6] = PCM(1 + 1 * nchannels); + x[7] = PCM(1 + 5 * nchannels); + } + pcm += 16 * nchannels; + } + #undef PCM + + return position; +} +#endif //ONLY_MSBC + +#ifdef __IAR_SYSTEMS_ICC__ +#pragma optimize=none +#endif //__IAR_SYSTEMS_ICC__ +static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s8_internal( + int position, + const uint8_t *pcm, int16_t X/*[2]*/[SBC_X_BUFFER_SIZE], + int nsamples,/* int nchannels,*/ int big_endian) +{ +// System_printf("Position %d\n", position); +// /* SysMin will only print to the console when you call flush or exit */ +// System_flush(); + /* handle X buffer wraparound */ + if (position < nsamples) { +#ifndef ONLY_MSBC + if (nchannels > 0) +#endif //ONLY_MSBC + memcpy(&X/*[0]*/[SBC_X_BUFFER_SIZE - 72], &X/*[0]*/[position], + 72 * sizeof(int16_t)); +#ifndef ONLY_MSBC + if (nchannels > 1) + memcpy(&X[1][SBC_X_BUFFER_SIZE - 72], &X[1][position], + 72 * sizeof(int16_t)); +#endif //ONLY_MSBC + position = SBC_X_BUFFER_SIZE - 72; + } + +#ifndef SBC_CC26XX + #define PCM(i) (big_endian ? \ + unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2)) +#else + #define PCM(i) (unaligned16_le(pcm + (i) * 2)) +#endif //SBC_CC26XX + + if (position % 16 == 8) { + position -= 8; + nsamples -= 8; +#ifndef ONLY_MSBC + if (nchannels > 0) { +#endif //ONLY_MSBC + int16_t *x = &X/*[0]*/[position]; + x[0] = PCM(0 + (15-8)); // * nchannels); + x[2] = PCM(0 + (14-8)); // * nchannels); + x[3] = PCM(0 + (8-8)); // * nchannels); + x[4] = PCM(0 + (13-8)); // * nchannels); + x[5] = PCM(0 + (9-8)); // * nchannels); + x[6] = PCM(0 + (12-8)); // * nchannels); + x[7] = PCM(0 + (10-8)); // * nchannels); + x[8] = PCM(0 + (11-8)); // * nchannels); +#ifndef ONLY_MSBC + } + if (nchannels > 1) { + int16_t *x = &X[1][position]; + x[0] = PCM(1 + (15-8) * nchannels); + x[2] = PCM(1 + (14-8) * nchannels); + x[3] = PCM(1 + (8-8) * nchannels); + x[4] = PCM(1 + (13-8) * nchannels); + x[5] = PCM(1 + (9-8) * nchannels); + x[6] = PCM(1 + (12-8) * nchannels); + x[7] = PCM(1 + (10-8) * nchannels); + x[8] = PCM(1 + (11-8) * nchannels); + } +#endif //ONLY_MSBC + + pcm += 16; // * nchannels; + } + + /* copy/permutate audio samples */ + while (nsamples >= 16) { + position -= 16; +#ifndef ONLY_MSBC + if (nchannels > 0) { +#endif //ONLY_MSBC + int16_t *x = &X/*[0]*/[position]; + x[0] = PCM(0 + 15); // * nchannels); + x[1] = PCM(0 + 7); // * nchannels); + x[2] = PCM(0 + 14); // * nchannels); + x[3] = PCM(0 + 8); // * nchannels); + x[4] = PCM(0 + 13); // * nchannels); + x[5] = PCM(0 + 9); // * nchannels); + x[6] = PCM(0 + 12); // * nchannels); + x[7] = PCM(0 + 10); // * nchannels); + x[8] = PCM(0 + 11); // * nchannels); + x[9] = PCM(0 + 3); // * nchannels); + x[10] = PCM(0 + 6); // * nchannels); + x[11] = PCM(0 + 0); // * nchannels); + x[12] = PCM(0 + 5); // * nchannels); + x[13] = PCM(0 + 1); // * nchannels); + x[14] = PCM(0 + 4); // * nchannels); + x[15] = PCM(0 + 2); // * nchannels); +#ifndef ONLY_MSBC + } + if (nchannels > 1) { + int16_t *x = &X[1][position]; + x[0] = PCM(1 + 15 * nchannels); + x[1] = PCM(1 + 7 * nchannels); + x[2] = PCM(1 + 14 * nchannels); + x[3] = PCM(1 + 8 * nchannels); + x[4] = PCM(1 + 13 * nchannels); + x[5] = PCM(1 + 9 * nchannels); + x[6] = PCM(1 + 12 * nchannels); + x[7] = PCM(1 + 10 * nchannels); + x[8] = PCM(1 + 11 * nchannels); + x[9] = PCM(1 + 3 * nchannels); + x[10] = PCM(1 + 6 * nchannels); + x[11] = PCM(1 + 0 * nchannels); + x[12] = PCM(1 + 5 * nchannels); + x[13] = PCM(1 + 1 * nchannels); + x[14] = PCM(1 + 4 * nchannels); + x[15] = PCM(1 + 2 * nchannels); + } +#endif //ONLY_MSBC + pcm += 32; // * nchannels; + nsamples -= 16; + } + + if (nsamples == 8) { + position -= 8; +#ifndef ONLY_MSBC + if (nchannels > 0) { +#endif //ONLY_MSBC + int16_t *x = &X/*[0]*/[position]; + x[-7] = PCM(0 + 7); // * nchannels); + x[1] = PCM(0 + 3); // * nchannels); + x[2] = PCM(0 + 6); // * nchannels); + x[3] = PCM(0 + 0); // * nchannels); + x[4] = PCM(0 + 5); // * nchannels); + x[5] = PCM(0 + 1); // * nchannels); + x[6] = PCM(0 + 4); // * nchannels); + x[7] = PCM(0 + 2); // * nchannels); +#ifndef ONLY_MSBC + } + if (nchannels > 1) { + int16_t *x = &X[1][position]; + x[-7] = PCM(1 + 7 * nchannels); + x[1] = PCM(1 + 3 * nchannels); + x[2] = PCM(1 + 6 * nchannels); + x[3] = PCM(1 + 0 * nchannels); + x[4] = PCM(1 + 5 * nchannels); + x[5] = PCM(1 + 1 * nchannels); + x[6] = PCM(1 + 4 * nchannels); + x[7] = PCM(1 + 2 * nchannels); + } +#endif //ONLY_MSBC + } + #undef PCM + + return position; +} + +/* + * Input data processing functions. The data is endian converted if needed, + * channels are deintrleaved and audio samples are reordered for use in + * SIMD-friendly analysis filter function. The results are put into "X" + * array, getting appended to the previous data (or it is better to say + * prepended, as the buffer is filled from top to bottom). Old data is + * discarded when neededed, but availability of (10 * nrof_subbands) + * contiguous samples is always guaranteed for the input to the analysis + * filter. This is achieved by copying a sufficient part of old data + * to the top of the buffer on buffer wraparound. + */ + +#ifndef ONLY_MSBC +static int sbc_enc_process_input_4s_le(int position, + const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels) +{ + if (nchannels > 1) + return sbc_encoder_process_input_s4_internal( + position, pcm, X, nsamples, 2, 0); + else + return sbc_encoder_process_input_s4_internal( + position, pcm, X, nsamples, 1, 0); +} + +static int sbc_enc_process_input_4s_be(int position, + const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels) +{ + if (nchannels > 1) + return sbc_encoder_process_input_s4_internal( + position, pcm, X, nsamples, 2, 1); + else + return sbc_encoder_process_input_s4_internal( + position, pcm, X, nsamples, 1, 1); +} +#endif //ONLY_MSBC + +static int sbc_enc_process_input_8s_le(int position, + const uint8_t *pcm, int16_t X/*[2]*/[SBC_X_BUFFER_SIZE], + int nsamples, int nchannels) +{ +#ifndef ONLY_MSBC + if (nchannels > 1) + return sbc_encoder_process_input_s8_internal( + position, pcm, X, nsamples, 2, 0); + else +#endif //ONLY_MSBC + return sbc_encoder_process_input_s8_internal( + position, pcm, X, nsamples,/* 1,*/ 0); +} + +#ifndef SBC_CC26XX +static int sbc_enc_process_input_8s_be(int position, + const uint8_t *pcm, int16_t X/*[2]*/[SBC_X_BUFFER_SIZE], + int nsamples, int nchannels) +{ +#ifndef ONLY_MSBC + if (nchannels > 1) + return sbc_encoder_process_input_s8_internal( + position, pcm, X, nsamples, 2, 1); + else +#endif //ONLY_MSBC + return sbc_encoder_process_input_s8_internal( + position, pcm, X, nsamples,/* 1,*/ 1); +} +#endif //SBC_CC26XX + +/* Supplementary function to count the number of leading zeros */ + +static inline int sbc_clz(uint32_t x) +{ +#ifdef __GNUC__ + return __builtin_clz(x); +#elif defined __TI_COMPILER_VERSION || defined __TI_COMPILER_VERSION__ + return __clz(x); +#elif defined __IAR_SYSTEMS_ICC__ + return __CLZ(x); +#else + /* TODO: this should be replaced with something better if good + * performance is wanted when using compilers other than gcc */ + int cnt = 0; + while (x) { + cnt++; + x >>= 1; + } + return 32 - cnt; +#endif +} + +static void sbc_calc_scalefactors( + int32_t sb_sample_f[16]/*[2]*/[8], + uint32_t scale_factor/*[2]*/[8], + int blocks, int channels, int subbands) +{ + int /*ch,*/ sb, blk; +// for (ch = 0; ch < channels; ch++) { + for (sb = 0; sb < subbands; sb++) { + uint32_t x = 1 << SCALE_OUT_BITS; + for (blk = 0; blk < blocks; blk++) { + int32_t tmp = fabs(sb_sample_f[blk]/*[ch]*/[sb]); + if (tmp != 0) + x |= tmp - 1; + } + scale_factor/*[ch]*/[sb] = (31 - SCALE_OUT_BITS) - + sbc_clz(x); + } +// } +} + +#ifndef ONLY_MSBC +static int sbc_calc_scalefactors_j( + int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int subbands) +{ + int blk, joint = 0; + int32_t tmp0, tmp1; + uint32_t x, y; + + /* last subband does not use joint stereo */ + int sb = subbands - 1; + x = 1 << SCALE_OUT_BITS; + y = 1 << SCALE_OUT_BITS; + for (blk = 0; blk < blocks; blk++) { + tmp0 = fabs(sb_sample_f[blk][0][sb]); + tmp1 = fabs(sb_sample_f[blk][1][sb]); + if (tmp0 != 0) + x |= tmp0 - 1; + if (tmp1 != 0) + y |= tmp1 - 1; + } + scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x); + scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y); + + /* the rest of subbands can use joint stereo */ + while (--sb >= 0) { + int32_t sb_sample_j[16][2]; + x = 1 << SCALE_OUT_BITS; + y = 1 << SCALE_OUT_BITS; + for (blk = 0; blk < blocks; blk++) { + tmp0 = sb_sample_f[blk][0][sb]; + tmp1 = sb_sample_f[blk][1][sb]; + sb_sample_j[blk][0] = ASR(tmp0, 1) + ASR(tmp1, 1); + sb_sample_j[blk][1] = ASR(tmp0, 1) - ASR(tmp1, 1); + tmp0 = fabs(tmp0); + tmp1 = fabs(tmp1); + if (tmp0 != 0) + x |= tmp0 - 1; + if (tmp1 != 0) + y |= tmp1 - 1; + } + scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - + sbc_clz(x); + scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - + sbc_clz(y); + x = 1 << SCALE_OUT_BITS; + y = 1 << SCALE_OUT_BITS; + for (blk = 0; blk < blocks; blk++) { + tmp0 = fabs(sb_sample_j[blk][0]); + tmp1 = fabs(sb_sample_j[blk][1]); + if (tmp0 != 0) + x |= tmp0 - 1; + if (tmp1 != 0) + y |= tmp1 - 1; + } + x = (31 - SCALE_OUT_BITS) - sbc_clz(x); + y = (31 - SCALE_OUT_BITS) - sbc_clz(y); + + /* decide whether to use joint stereo for this subband */ + if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) { + joint |= 1 << (subbands - 1 - sb); + scale_factor[0][sb] = x; + scale_factor[1][sb] = y; + for (blk = 0; blk < blocks; blk++) { + sb_sample_f[blk][0][sb] = sb_sample_j[blk][0]; + sb_sample_f[blk][1][sb] = sb_sample_j[blk][1]; + } + } + } + + /* bitmask with the information about subbands using joint stereo */ + return joint; +} +#endif //ONLY_MSBC + +/* + * Detect CPU features and setup function pointers + */ +void sbc_init_primitives(struct sbc_encoder_state *state) +{ + /* Default implementation for analyze functions */ +#ifndef ONLY_MSBC + state->sbc_analyze_4s = sbc_analyze_4b_4s_simd; + if (state->increment == 1) +#endif //ONLY_MSBC + state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd; +#ifndef ONLY_MSBC + else + state->sbc_analyze_8s = sbc_analyze_4b_8s_simd; +#endif //ONLY_MSBC + + /* Default implementation for input reordering / deinterleaving */ +#ifndef ONLY_MSBC + state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le; + state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be; +#endif //ONLY_MSBC + state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le; +#ifndef SBC_CC26XX + state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be; +#endif //SBC_CC26XX + + /* Default implementation for scale factors calculation */ + state->sbc_calc_scalefactors = sbc_calc_scalefactors; +#ifndef ONLY_MSBC + state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j; +#endif //ONLY_MSBC +#ifndef SBC_CC26XX + state->implementation_info = "Generic C"; +#else + state->implementation_info = "CC26XX"; +#endif //ONLY_MSBC + + /* X86/AMD64 optimizations */ +#ifdef SBC_BUILD_WITH_MMX_SUPPORT + sbc_init_primitives_mmx(state); +#endif + + /* ARM optimizations */ +#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT + sbc_init_primitives_armv6(state); +#endif +#ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT + sbc_init_primitives_iwmmxt(state); +#endif +#ifdef SBC_BUILD_WITH_NEON_SUPPORT + sbc_init_primitives_neon(state); + + if (state->increment == 1) { + state->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd; + state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le; + state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be; + state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le; + state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be; + } +#endif +} diff --git a/src/util/sbc/sbc_primitives.h b/src/util/sbc/sbc_primitives.h new file mode 100644 index 0000000..e97113b --- /dev/null +++ b/src/util/sbc/sbc_primitives.h @@ -0,0 +1,92 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __SBC_PRIMITIVES_H +#define __SBC_PRIMITIVES_H + +#define SCALE_OUT_BITS 15 +#define SBC_X_BUFFER_SIZE 328 + +#ifdef __GNUC__ +#define SBC_ALWAYS_INLINE inline __attribute__((always_inline)) +#else +#define SBC_ALWAYS_INLINE inline +#endif + +struct sbc_encoder_state { + int position; + /* Number of consecutive blocks handled by the encoder */ + uint8_t increment; + int16_t SBC_ALIGNED X/*[2]*/[SBC_X_BUFFER_SIZE]; +#ifndef ONLY_MSBC + /* Polyphase analysis filter for 4 subbands configuration, + * it handles "increment" blocks at once */ + void (*sbc_analyze_4s)(struct sbc_encoder_state *state, + int16_t *x, int32_t *out, int out_stride); +#endif //ONLY_MSBC + /* Polyphase analysis filter for 8 subbands configuration, + * it handles "increment" blocks at once */ + void (*sbc_analyze_8s)(struct sbc_encoder_state *state, + int16_t *x, int32_t *out, int out_stride); + /* Process input data (deinterleave, endian conversion, reordering), + * depending on the number of subbands and input data byte order */ +#ifndef ONLY_MSBC + int (*sbc_enc_process_input_4s_le)(int position, + const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels); + int (*sbc_enc_process_input_4s_be)(int position, + const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels); +#endif //ONLY_MSBC + int (*sbc_enc_process_input_8s_le)(int position, + const uint8_t *pcm, int16_t X/*[2]*/[SBC_X_BUFFER_SIZE], + int nsamples, int nchannels); +#ifndef ONLY_MSBC + int (*sbc_enc_process_input_8s_be)(int position, + const uint8_t *pcm, int16_t X/*[2]*/[SBC_X_BUFFER_SIZE], + int nsamples, int nchannels); +#endif //ONLY_MSBC + /* Scale factors calculation */ + void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16]/*[2]*/[8], + uint32_t scale_factor/*[2]*/[8], + int blocks, int channels, int subbands); +#ifndef ONLY_MSBC + /* Scale factors calculation with joint stereo support */ + int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int subbands); +#endif //ONLY_MSBC + const char *implementation_info; +}; + +/* + * Initialize pointers to the functions which are the basic "building bricks" + * of SBC codec. Best implementation is selected based on target CPU + * capabilities. + */ +void sbc_init_primitives(struct sbc_encoder_state *encoder_state); + +#endif diff --git a/src/util/sbc/sbc_private.h b/src/util/sbc/sbc_private.h new file mode 100644 index 0000000..cbd1c49 --- /dev/null +++ b/src/util/sbc/sbc_private.h @@ -0,0 +1,30 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "sbc_cc26xx_port.h" +#ifndef SBC_CC26XX +#define SBC_EXPORT __attribute__ ((visibility("default"))) +#else +#define SBC_EXPORT +#endif //SBC_CC26XX diff --git a/src/util/sbc/sbc_tables.h b/src/util/sbc/sbc_tables.h new file mode 100644 index 0000000..5d7b4f8 --- /dev/null +++ b/src/util/sbc/sbc_tables.h @@ -0,0 +1,662 @@ +/* + * + * Bluetooth low-complexity, subband codec (SBC) library + * + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "sbc_cc26xx_port.h" + +/* A2DP specification: Appendix B, page 69 */ +static const int sbc_offset4[4][4] = { + { -1, 0, 0, 0 }, + { -2, 0, 0, 1 }, + { -2, 0, 0, 1 }, + { -2, 0, 0, 1 } +}; + +/* A2DP specification: Appendix B, page 69 */ +static const int sbc_offset8[4][8] = { + { -2, 0, 0, 0, 0, 0, 0, 1 }, + { -3, 0, 0, 0, 0, 0, 1, 2 }, + { -4, 0, 0, 0, 0, 0, 1, 2 }, + { -4, 0, 0, 0, 0, 0, 1, 2 } +}; + +/* extra bits of precision for the synthesis filter input data */ +#define SBCDEC_FIXED_EXTRA_BITS 2 + +#define SS4(val) ASR(val, SCALE_SPROTO4_TBL) +#define SS8(val) ASR(val, SCALE_SPROTO8_TBL) +#define SN4(val) ASR(val, SCALE_NPROTO4_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS) +#define SN8(val) ASR(val, SCALE_NPROTO8_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS) + +static const int32_t sbc_proto_4_40m0[] = { + SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8), + SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8), + SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330), + SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00), + SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7) +}; + +static const int32_t sbc_proto_4_40m1[] = { + SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475), + SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370), + SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b), + SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b), + SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7) +}; + +static const int32_t sbc_proto_8_80m0[] = { + SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100), + SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0), + SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c), + SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705), + SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db), + SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948), + SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200), + SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358), + SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31), + SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170) +}; + +static const int32_t sbc_proto_8_80m1[] = { + SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620), + SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40), + SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01), + SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94), + SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b), + SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68), + SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20), + SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410), + SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da), + SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a) +}; + +static const int32_t synmatrix4[8][4] = { + { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) }, + { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) }, + { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) }, + { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) }, + { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) }, + { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }, + { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) }, + { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) } +}; + +static const int32_t synmatrix8[16][8] = { + { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798), + SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) }, + { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988), + SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) }, + { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac), + SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) }, + { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10), + SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) }, + { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), + SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) }, + { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0), + SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) }, + { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54), + SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) }, + { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678), + SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) }, + { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868), + SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) }, + { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), + SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }, + { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), + SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, + { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), + SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, + { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), + SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) }, + { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), + SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, + { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), + SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, + { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), + SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) } +}; + +#ifdef SBC_HIGH_PRECISION +#define FIXED_A int64_t /* data type for fixed point accumulator */ +#define FIXED_T int32_t /* data type for fixed point constants */ +#define SBC_FIXED_EXTRA_BITS 16 +#else +#define FIXED_A int32_t /* data type for fixed point accumulator */ +#define FIXED_T int16_t /* data type for fixed point constants */ +#define SBC_FIXED_EXTRA_BITS 0 +#endif + +/* A2DP specification: Section 12.8 Tables + * + * Original values are premultiplied by 2 for better precision (that is the + * maximum which is possible without overflows) + * + * Note: in each block of 8 numbers sign was changed for elements 2 and 7 + * in order to compensate the same change applied to cos_table_fixed_4 + */ +#define SBC_PROTO_FIXED4_SCALE \ + ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1) +//#define F_PROTO4(x) (FIXED_A) ((x * 2) * \ +// ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) +#define F_PROTO4(x) (FIXED_A) ((x * 2) * \ + (1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) +#define F(x) F_PROTO4(x) +static const FIXED_T _sbc_proto_fixed4[40] = { + F(0.00000000E+00), F(5.36548976E-04), + -F(1.49188357E-03), F(2.73370904E-03), + F(3.83720193E-03), F(3.89205149E-03), + F(1.86581691E-03), F(3.06012286E-03), + + F(1.09137620E-02), F(2.04385087E-02), + -F(2.88757392E-02), F(3.21939290E-02), + F(2.58767811E-02), F(6.13245186E-03), + -F(2.88217274E-02), F(7.76463494E-02), + + F(1.35593274E-01), F(1.94987841E-01), + -F(2.46636662E-01), F(2.81828203E-01), + F(2.94315332E-01), F(2.81828203E-01), + F(2.46636662E-01), -F(1.94987841E-01), + + -F(1.35593274E-01), -F(7.76463494E-02), + F(2.88217274E-02), F(6.13245186E-03), + F(2.58767811E-02), F(3.21939290E-02), + F(2.88757392E-02), -F(2.04385087E-02), + + -F(1.09137620E-02), -F(3.06012286E-03), + -F(1.86581691E-03), F(3.89205149E-03), + F(3.83720193E-03), F(2.73370904E-03), + F(1.49188357E-03), -F(5.36548976E-04), +}; +#undef F + +/* + * To produce this cosine matrix in Octave: + * + * b = zeros(4, 8); + * for i = 0:3 + * for j = 0:7 b(i+1, j+1) = cos((i + 0.5) * (j - 2) * (pi/4)) + * endfor + * endfor; + * printf("%.10f, ", b'); + * + * Note: in each block of 8 numbers sign was changed for elements 2 and 7 + * + * Change of sign for element 2 allows to replace constant 1.0 (not + * representable in Q15 format) with -1.0 (fine with Q15). + * Changed sign for element 7 allows to have more similar constants + * and simplify subband filter function code. + */ +#define SBC_COS_TABLE_FIXED4_SCALE \ + ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) +#define F_COS4(x) (FIXED_A) ((x) * \ + ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) +#define F(x) F_COS4(x) +static const FIXED_T cos_table_fixed_4[32] = { + F(0.7071067812), F(0.9238795325), -F(1.0000000000), F(0.9238795325), + F(0.7071067812), F(0.3826834324), F(0.0000000000), F(0.3826834324), + + -F(0.7071067812), F(0.3826834324), -F(1.0000000000), F(0.3826834324), + -F(0.7071067812), -F(0.9238795325), -F(0.0000000000), -F(0.9238795325), + + -F(0.7071067812), -F(0.3826834324), -F(1.0000000000), -F(0.3826834324), + -F(0.7071067812), F(0.9238795325), F(0.0000000000), F(0.9238795325), + + F(0.7071067812), -F(0.9238795325), -F(1.0000000000), -F(0.9238795325), + F(0.7071067812), -F(0.3826834324), -F(0.0000000000), -F(0.3826834324), +}; +#undef F + +/* A2DP specification: Section 12.8 Tables + * + * Original values are premultiplied by 4 for better precision (that is the + * maximum which is possible without overflows) + * + * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 + * in order to compensate the same change applied to cos_table_fixed_8 + */ +#define SBC_PROTO_FIXED8_SCALE \ + ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1) +#define F_PROTO8(x) (FIXED_A) ((x * 2) * \ + ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) +#define F(x) F_PROTO8(x) +static const FIXED_T _sbc_proto_fixed8[80] = { + F(0.00000000E+00), F(1.56575398E-04), + F(3.43256425E-04), F(5.54620202E-04), + -F(8.23919506E-04), F(1.13992507E-03), + F(1.47640169E-03), F(1.78371725E-03), + F(2.01182542E-03), F(2.10371989E-03), + F(1.99454554E-03), F(1.61656283E-03), + F(9.02154502E-04), F(1.78805361E-04), + F(1.64973098E-03), F(3.49717454E-03), + + F(5.65949473E-03), F(8.02941163E-03), + F(1.04584443E-02), F(1.27472335E-02), + -F(1.46525263E-02), F(1.59045603E-02), + F(1.62208471E-02), F(1.53184106E-02), + F(1.29371806E-02), F(8.85757540E-03), + F(2.92408442E-03), -F(4.91578024E-03), + -F(1.46404076E-02), F(2.61098752E-02), + F(3.90751381E-02), F(5.31873032E-02), + + F(6.79989431E-02), F(8.29847578E-02), + F(9.75753918E-02), F(1.11196689E-01), + -F(1.23264548E-01), F(1.33264415E-01), + F(1.40753505E-01), F(1.45389847E-01), + F(1.46955068E-01), F(1.45389847E-01), + F(1.40753505E-01), F(1.33264415E-01), + F(1.23264548E-01), -F(1.11196689E-01), + -F(9.75753918E-02), -F(8.29847578E-02), + + -F(6.79989431E-02), -F(5.31873032E-02), + -F(3.90751381E-02), -F(2.61098752E-02), + F(1.46404076E-02), -F(4.91578024E-03), + F(2.92408442E-03), F(8.85757540E-03), + F(1.29371806E-02), F(1.53184106E-02), + F(1.62208471E-02), F(1.59045603E-02), + F(1.46525263E-02), -F(1.27472335E-02), + -F(1.04584443E-02), -F(8.02941163E-03), + + -F(5.65949473E-03), -F(3.49717454E-03), + -F(1.64973098E-03), -F(1.78805361E-04), + -F(9.02154502E-04), F(1.61656283E-03), + F(1.99454554E-03), F(2.10371989E-03), + F(2.01182542E-03), F(1.78371725E-03), + F(1.47640169E-03), F(1.13992507E-03), + F(8.23919506E-04), -F(5.54620202E-04), + -F(3.43256425E-04), -F(1.56575398E-04), +}; +#undef F + +/* + * To produce this cosine matrix in Octave: + * + * b = zeros(8, 16); + * for i = 0:7 + * for j = 0:15 b(i+1, j+1) = cos((i + 0.5) * (j - 4) * (pi/8)) + * endfor endfor; + * printf("%.10f, ", b'); + * + * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 + * + * Change of sign for element 4 allows to replace constant 1.0 (not + * representable in Q15 format) with -1.0 (fine with Q15). + * Changed signs for elements 13, 14, 15 allow to have more similar constants + * and simplify subband filter function code. + */ +#define SBC_COS_TABLE_FIXED8_SCALE \ + ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) +#define F_COS8(x) (FIXED_A) ((x) * \ + ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) +#define F(x) F_COS8(x) +static const FIXED_T cos_table_fixed_8[128] = { + F(0.7071067812), F(0.8314696123), F(0.9238795325), F(0.9807852804), + -F(1.0000000000), F(0.9807852804), F(0.9238795325), F(0.8314696123), + F(0.7071067812), F(0.5555702330), F(0.3826834324), F(0.1950903220), + F(0.0000000000), F(0.1950903220), F(0.3826834324), F(0.5555702330), + + -F(0.7071067812), -F(0.1950903220), F(0.3826834324), F(0.8314696123), + -F(1.0000000000), F(0.8314696123), F(0.3826834324), -F(0.1950903220), + -F(0.7071067812), -F(0.9807852804), -F(0.9238795325), -F(0.5555702330), + -F(0.0000000000), -F(0.5555702330), -F(0.9238795325), -F(0.9807852804), + + -F(0.7071067812), -F(0.9807852804), -F(0.3826834324), F(0.5555702330), + -F(1.0000000000), F(0.5555702330), -F(0.3826834324), -F(0.9807852804), + -F(0.7071067812), F(0.1950903220), F(0.9238795325), F(0.8314696123), + F(0.0000000000), F(0.8314696123), F(0.9238795325), F(0.1950903220), + + F(0.7071067812), -F(0.5555702330), -F(0.9238795325), F(0.1950903220), + -F(1.0000000000), F(0.1950903220), -F(0.9238795325), -F(0.5555702330), + F(0.7071067812), F(0.8314696123), -F(0.3826834324), -F(0.9807852804), + -F(0.0000000000), -F(0.9807852804), -F(0.3826834324), F(0.8314696123), + + F(0.7071067812), F(0.5555702330), -F(0.9238795325), -F(0.1950903220), + -F(1.0000000000), -F(0.1950903220), -F(0.9238795325), F(0.5555702330), + F(0.7071067812), -F(0.8314696123), -F(0.3826834324), F(0.9807852804), + F(0.0000000000), F(0.9807852804), -F(0.3826834324), -F(0.8314696123), + + -F(0.7071067812), F(0.9807852804), -F(0.3826834324), -F(0.5555702330), + -F(1.0000000000), -F(0.5555702330), -F(0.3826834324), F(0.9807852804), + -F(0.7071067812), -F(0.1950903220), F(0.9238795325), -F(0.8314696123), + -F(0.0000000000), -F(0.8314696123), F(0.9238795325), -F(0.1950903220), + + -F(0.7071067812), F(0.1950903220), F(0.3826834324), -F(0.8314696123), + -F(1.0000000000), -F(0.8314696123), F(0.3826834324), F(0.1950903220), + -F(0.7071067812), F(0.9807852804), -F(0.9238795325), F(0.5555702330), + -F(0.0000000000), F(0.5555702330), -F(0.9238795325), F(0.9807852804), + + F(0.7071067812), -F(0.8314696123), F(0.9238795325), -F(0.9807852804), + -F(1.0000000000), -F(0.9807852804), F(0.9238795325), -F(0.8314696123), + F(0.7071067812), -F(0.5555702330), F(0.3826834324), -F(0.1950903220), + -F(0.0000000000), -F(0.1950903220), F(0.3826834324), -F(0.5555702330), +}; +#undef F + +/* + * Enforce 16 byte alignment for the data, which is supposed to be used + * with SIMD optimized code. + */ + +#define SBC_ALIGN_BITS 4 +#define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1) + +#ifdef __GNUC__ +#define SBC_ALIGNED __attribute__((aligned(1 << (SBC_ALIGN_BITS)))) +#else +#define SBC_ALIGNED +#endif + +/* + * Constant tables for the use in SIMD optimized analysis filters + * Each table consists of two parts: + * 1. reordered "proto" table + * 2. reordered "cos" table + * + * Due to non-symmetrical reordering, separate tables for "even" + * and "odd" cases are needed + */ + +static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_even[40 + 16] = { +#define C0 1.0932568993 +#define C1 1.3056875580 +#define C2 1.3056875580 +#define C3 1.6772280856 + +#define F(x) F_PROTO4(x) + F(0.00000000E+00 * C0), F(3.83720193E-03 * C0), + F(5.36548976E-04 * C1), F(2.73370904E-03 * C1), + F(3.06012286E-03 * C2), F(3.89205149E-03 * C2), + F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3), + F(1.09137620E-02 * C0), F(2.58767811E-02 * C0), + F(2.04385087E-02 * C1), F(3.21939290E-02 * C1), + F(7.76463494E-02 * C2), F(6.13245186E-03 * C2), + F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3), + F(1.35593274E-01 * C0), F(2.94315332E-01 * C0), + F(1.94987841E-01 * C1), F(2.81828203E-01 * C1), + -F(1.94987841E-01 * C2), F(2.81828203E-01 * C2), + F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3), + -F(1.35593274E-01 * C0), F(2.58767811E-02 * C0), + -F(7.76463494E-02 * C1), F(6.13245186E-03 * C1), + -F(2.04385087E-02 * C2), F(3.21939290E-02 * C2), + F(0.00000000E+00 * C3), F(2.88217274E-02 * C3), + -F(1.09137620E-02 * C0), F(3.83720193E-03 * C0), + -F(3.06012286E-03 * C1), F(3.89205149E-03 * C1), + -F(5.36548976E-04 * C2), F(2.73370904E-03 * C2), + F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3), +#undef F +#define F(x) F_COS4(x) + F(0.7071067812 / C0), F(0.9238795325 / C1), + -F(0.7071067812 / C0), F(0.3826834324 / C1), + -F(0.7071067812 / C0), -F(0.3826834324 / C1), + F(0.7071067812 / C0), -F(0.9238795325 / C1), + F(0.3826834324 / C2), -F(1.0000000000 / C3), + -F(0.9238795325 / C2), -F(1.0000000000 / C3), + F(0.9238795325 / C2), -F(1.0000000000 / C3), + -F(0.3826834324 / C2), -F(1.0000000000 / C3), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +}; + +static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_odd[40 + 16] = { +#define C0 1.3056875580 +#define C1 1.6772280856 +#define C2 1.0932568993 +#define C3 1.3056875580 + +#define F(x) F_PROTO4(x) + F(2.73370904E-03 * C0), F(5.36548976E-04 * C0), + -F(1.49188357E-03 * C1), F(0.00000000E+00 * C1), + F(3.83720193E-03 * C2), F(1.09137620E-02 * C2), + F(3.89205149E-03 * C3), F(3.06012286E-03 * C3), + F(3.21939290E-02 * C0), F(2.04385087E-02 * C0), + -F(2.88757392E-02 * C1), F(0.00000000E+00 * C1), + F(2.58767811E-02 * C2), F(1.35593274E-01 * C2), + F(6.13245186E-03 * C3), F(7.76463494E-02 * C3), + F(2.81828203E-01 * C0), F(1.94987841E-01 * C0), + -F(2.46636662E-01 * C1), F(0.00000000E+00 * C1), + F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2), + F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3), + F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0), + F(2.88217274E-02 * C1), F(0.00000000E+00 * C1), + F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2), + F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3), + F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0), + -F(1.86581691E-03 * C1), F(0.00000000E+00 * C1), + F(3.83720193E-03 * C2), F(0.00000000E+00 * C2), + F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3), +#undef F +#define F(x) F_COS4(x) + F(0.9238795325 / C0), -F(1.0000000000 / C1), + F(0.3826834324 / C0), -F(1.0000000000 / C1), + -F(0.3826834324 / C0), -F(1.0000000000 / C1), + -F(0.9238795325 / C0), -F(1.0000000000 / C1), + F(0.7071067812 / C2), F(0.3826834324 / C3), + -F(0.7071067812 / C2), -F(0.9238795325 / C3), + -F(0.7071067812 / C2), F(0.9238795325 / C3), + F(0.7071067812 / C2), -F(0.3826834324 / C3), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +}; + +static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_even[80 + 64] = { +#define C0 2.7906148894 +#define C1 2.4270044280 +#define C2 2.8015616024 +#define C3 3.1710363741 +#define C4 2.5377944043 +#define C5 2.4270044280 +#define C6 2.8015616024 +#define C7 3.1710363741 + +#define F(x) F_PROTO8(x) + F(0.00000000E+00 * C0), F(2.01182542E-03 * C0), + F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), + F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), + F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), + -F(8.23919506E-04 * C4), F(0.00000000E+00 * C4), + F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), + F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), + F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), + F(5.65949473E-03 * C0), F(1.29371806E-02 * C0), + F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), + F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), + F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), + -F(1.46525263E-02 * C4), F(0.00000000E+00 * C4), + F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), + F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), + -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), + F(6.79989431E-02 * C0), F(1.46955068E-01 * C0), + F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), + F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), + F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), + -F(1.23264548E-01 * C4), F(0.00000000E+00 * C4), + F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), + F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), + F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), + -F(6.79989431E-02 * C0), F(1.29371806E-02 * C0), + -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), + -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), + -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), + F(1.46404076E-02 * C4), F(0.00000000E+00 * C4), + F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), + F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), + F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), + -F(5.65949473E-03 * C0), F(2.01182542E-03 * C0), + -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), + -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), + -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), + -F(9.02154502E-04 * C4), F(0.00000000E+00 * C4), + F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), + F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), + F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), +#undef F +#define F(x) F_COS8(x) + F(0.7071067812 / C0), F(0.8314696123 / C1), + -F(0.7071067812 / C0), -F(0.1950903220 / C1), + -F(0.7071067812 / C0), -F(0.9807852804 / C1), + F(0.7071067812 / C0), -F(0.5555702330 / C1), + F(0.7071067812 / C0), F(0.5555702330 / C1), + -F(0.7071067812 / C0), F(0.9807852804 / C1), + -F(0.7071067812 / C0), F(0.1950903220 / C1), + F(0.7071067812 / C0), -F(0.8314696123 / C1), + F(0.9238795325 / C2), F(0.9807852804 / C3), + F(0.3826834324 / C2), F(0.8314696123 / C3), + -F(0.3826834324 / C2), F(0.5555702330 / C3), + -F(0.9238795325 / C2), F(0.1950903220 / C3), + -F(0.9238795325 / C2), -F(0.1950903220 / C3), + -F(0.3826834324 / C2), -F(0.5555702330 / C3), + F(0.3826834324 / C2), -F(0.8314696123 / C3), + F(0.9238795325 / C2), -F(0.9807852804 / C3), + -F(1.0000000000 / C4), F(0.5555702330 / C5), + -F(1.0000000000 / C4), -F(0.9807852804 / C5), + -F(1.0000000000 / C4), F(0.1950903220 / C5), + -F(1.0000000000 / C4), F(0.8314696123 / C5), + -F(1.0000000000 / C4), -F(0.8314696123 / C5), + -F(1.0000000000 / C4), -F(0.1950903220 / C5), + -F(1.0000000000 / C4), F(0.9807852804 / C5), + -F(1.0000000000 / C4), -F(0.5555702330 / C5), + F(0.3826834324 / C6), F(0.1950903220 / C7), + -F(0.9238795325 / C6), -F(0.5555702330 / C7), + F(0.9238795325 / C6), F(0.8314696123 / C7), + -F(0.3826834324 / C6), -F(0.9807852804 / C7), + -F(0.3826834324 / C6), F(0.9807852804 / C7), + F(0.9238795325 / C6), -F(0.8314696123 / C7), + -F(0.9238795325 / C6), F(0.5555702330 / C7), + F(0.3826834324 / C6), -F(0.1950903220 / C7), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +}; + +static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_odd[80 + 64] = { +#define C0 2.5377944043 +#define C1 2.4270044280 +#define C2 2.8015616024 +#define C3 3.1710363741 +#define C4 2.7906148894 +#define C5 2.4270044280 +#define C6 2.8015616024 +#define C7 3.1710363741 + +#define F(x) F_PROTO8(x) + F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0), + F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), + F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), + F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), + F(2.01182542E-03 * C4), F(5.65949473E-03 * C4), + F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), + F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), + F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), + F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0), + F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), + F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), + F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), + F(1.29371806E-02 * C4), F(6.79989431E-02 * C4), + F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), + F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), + -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), + F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0), + F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), + F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), + F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), + F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4), + F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), + F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), + F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), + F(0.00000000E+00 * C0), F(1.46404076E-02 * C0), + -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), + -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), + -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), + F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4), + F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), + F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), + F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), + F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0), + -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), + -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), + -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), + F(2.01182542E-03 * C4), F(0.00000000E+00 * C4), + F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), + F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), + F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), +#undef F +#define F(x) F_COS8(x) + -F(1.0000000000 / C0), F(0.8314696123 / C1), + -F(1.0000000000 / C0), -F(0.1950903220 / C1), + -F(1.0000000000 / C0), -F(0.9807852804 / C1), + -F(1.0000000000 / C0), -F(0.5555702330 / C1), + -F(1.0000000000 / C0), F(0.5555702330 / C1), + -F(1.0000000000 / C0), F(0.9807852804 / C1), + -F(1.0000000000 / C0), F(0.1950903220 / C1), + -F(1.0000000000 / C0), -F(0.8314696123 / C1), + F(0.9238795325 / C2), F(0.9807852804 / C3), + F(0.3826834324 / C2), F(0.8314696123 / C3), + -F(0.3826834324 / C2), F(0.5555702330 / C3), + -F(0.9238795325 / C2), F(0.1950903220 / C3), + -F(0.9238795325 / C2), -F(0.1950903220 / C3), + -F(0.3826834324 / C2), -F(0.5555702330 / C3), + F(0.3826834324 / C2), -F(0.8314696123 / C3), + F(0.9238795325 / C2), -F(0.9807852804 / C3), + F(0.7071067812 / C4), F(0.5555702330 / C5), + -F(0.7071067812 / C4), -F(0.9807852804 / C5), + -F(0.7071067812 / C4), F(0.1950903220 / C5), + F(0.7071067812 / C4), F(0.8314696123 / C5), + F(0.7071067812 / C4), -F(0.8314696123 / C5), + -F(0.7071067812 / C4), -F(0.1950903220 / C5), + -F(0.7071067812 / C4), F(0.9807852804 / C5), + F(0.7071067812 / C4), -F(0.5555702330 / C5), + F(0.3826834324 / C6), F(0.1950903220 / C7), + -F(0.9238795325 / C6), -F(0.5555702330 / C7), + F(0.9238795325 / C6), F(0.8314696123 / C7), + -F(0.3826834324 / C6), -F(0.9807852804 / C7), + -F(0.3826834324 / C6), F(0.9807852804 / C7), + F(0.9238795325 / C6), -F(0.8314696123 / C7), + -F(0.9238795325 / C6), F(0.5555702330 / C7), + F(0.3826834324 / C6), -F(0.1950903220 / C7), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +}; diff --git a/tools/scripts/audio/SBC.dll b/tools/scripts/audio/SBC.dll new file mode 100644 index 0000000..ed00d8a Binary files /dev/null and b/tools/scripts/audio/SBC.dll differ diff --git a/tools/scripts/audio/SBC_x64.dll b/tools/scripts/audio/SBC_x64.dll new file mode 100644 index 0000000..4bb83bd Binary files /dev/null and b/tools/scripts/audio/SBC_x64.dll differ diff --git a/tools/scripts/audio/audio_frame_serial_print.py b/tools/scripts/audio/audio_frame_serial_print.py index ddea3a8..6994ae1 100644 --- a/tools/scripts/audio/audio_frame_serial_print.py +++ b/tools/scripts/audio/audio_frame_serial_print.py @@ -3,10 +3,11 @@ * Filename: audio_frame_serial_print.py * * Description: This tool is used to decode audio frames from the - * CC2650ARC and the CC2650STK development kits. These frames will saved - * to a wav file for playback + * CC2650ARC, the CC2650STK development kits and the CC2650 LaunchPad with + * CC3200AUDBOOST booster pack. These frames will saved to a wav file for + * playback. This script expects audio compressed in ADPCM format. * - * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ * * * Redistribution and use in source and binary forms, with or without @@ -47,6 +48,8 @@ from time import time import time import winsound +import os +import sys tic1_stepsize_Lut = [ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, @@ -65,6 +68,9 @@ SI_Dec = 0 PV_Dec = 0 +def get_script_path(): + return os.path.dirname(os.path.realpath(sys.argv[0])) + def tic1_DecodeSingle(nibble): global SI_Dec global PV_Dec @@ -115,13 +121,14 @@ def decode_adpcm(_buf): decoded.append(pack('h', tic1_DecodeSingle(b & 0xF))) decoded.append(pack('h', tic1_DecodeSingle(b >> 4))) + def save_wav(): global decoded filename = time.strftime("pdm_test_%Y-%m-%d_%H-%M-%S_adpcm") print "saving file" - w = wave.open(filename + ".wav", "w") + w = wave.open(get_script_path() + "/samples/" + filename + ".wav", "w") w.setnchannels(1) w.setframerate(16000) w.setsampwidth(2) @@ -138,6 +145,7 @@ def save_wav(): indata = '' inbuffer = '' frameNum = 1 +bufLen = 100 lastByteTime = 0 @@ -145,10 +153,12 @@ def save_wav(): missedFrames = 0 try: ser = None - ser = Serial("COM38", 400000, timeout=0.1) + ser = Serial("COM137", 460800, timeout=0.1) + readSoFar = 0 while True: - indata = ser.read() + indata = ser.read(bufLen - readSoFar) + readSoFar = len(indata) if not indata and len(decoded): if time.time() - lastByteTime > 2: #save wav file @@ -156,44 +166,31 @@ def save_wav(): elif indata: inbuffer += indata - if len(inbuffer) == 20: - if frameNum == 1: - - seqNum, SI_received, PV_received = struct.unpack('BBh', inbuffer[0:4]) - seqNum = (seqNum >> 3) - print "Frame sequence number: %d" % seqNum - - print "HDR_1 local: %d, HDR_1 received: %d" % (SI_Dec, SI_received) - print "HDR_2 local: %d, HDR_2 received: %d" % (PV_Dec, PV_received) + if len(inbuffer) == bufLen: + seqNum, SI_received, PV_received = struct.unpack('BBh', inbuffer[0:4]) + seqNum = (seqNum >> 3) + print "Frame sequence number: %d" % seqNum - #always use received PV and SI - PV_Dec = PV_received - SI_Dec = SI_received + print "HDR_1 local: %d, HDR_1 received: %d" % (SI_Dec, SI_received) + print "HDR_2 local: %d, HDR_2 received: %d" % (PV_Dec, PV_received) - if seqNum > prevSeqNum: - missedFrames = (seqNum - prevSeqNum -1) - else: - missedFrames = ((seqNum + 32) - prevSeqNum - 1) - - prevSeqNum = seqNum + if seqNum > prevSeqNum: + missedFrames = (seqNum - prevSeqNum -1) + else: + missedFrames = ((seqNum + 32) - prevSeqNum - 1) - if missedFrames > 0: - print "######################### MISSED #########################" - print missedFrames - print "##########################################################" + prevSeqNum = seqNum - decode_adpcm(inbuffer[4:]) - else: - decode_adpcm(inbuffer[0:]) + if missedFrames > 0: + print "######################### MISSED #########################" + print missedFrames + print "##########################################################" - #empty inbuffer + decode_adpcm(inbuffer[4:]) inbuffer = '' + readSoFar = 0 - frameNum += 1 - if frameNum > 5: - frameNum = 1 - - lastByteTime = time.time() + lastByteTime = time.time() except SerialException as e: print "Serial port error" diff --git a/tools/scripts/audio/pySBC27.py b/tools/scripts/audio/pySBC27.py new file mode 100644 index 0000000..ef64ced --- /dev/null +++ b/tools/scripts/audio/pySBC27.py @@ -0,0 +1,232 @@ +''' +/* + * Filename: pySBC27.py + * + * Description: This tool is used to decode audio frames from the + * CC2650ARC, the CC2650STK development kits and the CC2650 LaunchPad with + * CC3200AUDBOOST booster pack. These frames will saved to a wav file for + * playback. This script expects audio compressed in mSBC format. + * + * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * +*/ +''' + +import ctypes; +from ctypes import * +from struct import unpack, pack +import wave +from serial import Serial +from serial import SerialException +from time import time +import time +import winsound +import pyaudio +import speech_recognition as sr + +runOnce = 0 +compressedSize = 57 +pcmFrameLen = 120 +pcmFrameSize = 240 +pcmSampleWidth = 2 +sampleRate = 16000 +written = c_uint(0) +MsbcFrame = c_ubyte * compressedSize +firstFrame = MsbcFrame(0xad, 0x00, 0x00, 0x00, 0xea, 0x97, 0x77, 0x67, 0x7f, 0x7b, 0x55, 0x60, 0x1e, 0xd5, 0x58, 0x48, 0x35, 0x56, 0x26, 0x2c, 0x51, 0xa9, 0xa5, 0x81, 0xb7, 0x0b, 0x21, 0x98, 0x08, 0xb5, 0x54, 0x7d, 0xed, 0x55, 0x42, 0x7b, 0x55, 0x6e, 0x5e, 0xd5, 0x5e, 0x17, 0xb5, 0x56, 0x05, 0xed, 0x55, 0x1f, 0x7b, 0x55, 0x50, 0x9e, 0xd5, 0x5b, 0x97, 0xb5, 0x54) +secondFrame = MsbcFrame(0xad, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x01, 0x12, 0xe1, 0xeb, 0x31, 0x60, 0x76, 0xcd, 0x61, 0xf3, 0x40, 0xe5, 0x09, 0x38, 0xc4, 0xba, 0xa3, 0xa2, 0x38, 0x7b, 0x09, 0xb8, 0x1d, 0xdf, 0x30, 0x7c, 0xd1, 0xa2, 0x42, 0x4b, 0xe5, 0xae, 0xa9, 0x15, 0x9e, 0x1e, 0xc1, 0x62, 0x07, 0x6e, 0xb5, 0x1f, 0x33, 0x56, 0x90, 0x92, 0xf9, 0x7b, 0xaa, 0x35, 0xe0) +msbcFrame = MsbcFrame() +PcmFrame = c_short * pcmFrameLen +pcmFrame = PcmFrame() + +p = pyaudio.PyAudio() + +stream = p.open(format=p.get_format_from_width(pcmSampleWidth), + channels=1, + rate=sampleRate, + output=True) + +def beep(sound): + print "Playing sound" + winsound.PlaySound('%s.wav' % sound, winsound.SND_FILENAME) + +def start_wave(): + global filename + filename = time.strftime("samples/pdm_test_%Y-%m-%d_%H-%M-%S_wave") + print "Opening wave file for writing -- " + filename + global w + w = wave.open(filename + ".wav", "w") + w.setnchannels(1) + w.setframerate(sampleRate) + w.setsampwidth(pcmSampleWidth) + +def play_stream(pcmArray): + stream.write(pcmArray) + +def speech_to_text(filename): + audio_file = filename + ".wav" + r = sr.Recognizer() + with sr.AudioFile(audio_file) as source: + audio = r.record(source) + try: + # for testing purposes, we're just using the default API key + # to use another API key, use `r.recognize_google(audio, key="GOOGLE_SPEECH_RECOGNITION_API_KEY")` + # instead of `r.recognize_google(audio)` + print "\nGoogle Speech Recognition thinks you said \n" + r.recognize_google(audio) + "\n" + except sr.UnknownValueError: + print "Google Speech Recognition could not understand audio" + except sr.RequestError as e: + print "Could not request results from Google Speech Recognition service; {0}".format(e) + +def write_to_wave(_buf, bytesWritten): + global w + pcmArray = b'' +## print "Writing {0} bytes, {1} samples, to wave file".format(bytesWritten, len(_buf))) + for pcm in _buf: + pcmArray += pack('h', pcm) + w.writeframes(pcmArray) + play_stream(pcmArray) + +def close_wave(): + global w + global filename + print "Closing wave file" +## beep(filename) + speech_to_text(filename) + w.close() + +sbcDll = cdll.LoadLibrary(".\SBC.dll"); +print "Initializing decoder, mSBC" +sbcDll.c_init() + +indata = b'' +inbuffer = b'' +lastByteTime = 0 +startTime = 0 + +start_wave() + +print "Waiting for stream" + +waitingForEnd = 0 + +try: + ser = None + ser = Serial("COM91", 460800, timeout=0.2) + readSoFar = 0 + readNow = 0 + msbcData = bytearray(compressedSize) + index = 0 + +# startTime = time.time() +# endTime = startTime + 100 + + while True: + indata = ser.read(compressedSize - readSoFar) + readNow = len(indata) + readSoFar = readSoFar + readNow + msbcData[index:(index + readNow)] = indata +## indata = ser.read(388) + if not indata and len(inbuffer): # or time.time() - startTime > 10: + if time.time() - lastByteTime > 2 and waitingForEnd == 1: + print "Stream ended" + startTime = time.time() + close_wave() + waitingForEnd = 0 + start_wave() + elif indata: + limit = min(compressedSize,readSoFar) +## print "Read {0}, total {1} HEADER:[{2}, {3}, {4}], Current HEADER:[{5}, {6}, {7}], limit {8}".format(readNow, readSoFar, +## indata[0], indata[1] if (readNow > 1) else 0, +## indata[2] if (readNow > 2) else 0, +## msbcData[0], msbcData[1], msbcData[2], +## limit)) +## Find header [0xAD seqNum 0x00], start over + index = 0 + for byte in msbcData: + if (byte == 173): + if (msbcData[index+2] == 0): +## print "Found header, index {0}".format(index)) + break # Found wanted header + if (index < (limit - 2)): + index = index + 1 + else: +## print "Did not find header, index {0}".format(index)) + break # Did not find header + if (index > 0): +## print "Need to remove {0} of {1} bytes".format(index, readSoFar)) +## Received incorrect header, remove it + readSoFar = readSoFar - index + i = 0 + for j in range(index,limit): + msbcData[i] = msbcData[j] + i = i + 1 + index = i + + if (readSoFar == compressedSize): + if (readSoFar == compressedSize): + waitingForEnd = 1 + for i in range(0, compressedSize): + msbcFrame[i] = msbcData[i] +## print "msbcFrame[{0}]={1} -- firstFrame[{2}]={3}".format(i, msbcFrame[i], i, firstFrame[i])) + + sbcDll.c_decode(msbcFrame, compressedSize, pcmFrame, pcmFrameSize, byref(written)) + +## print "Packet #{0}, HEADER:[{1}, {2}, {3}], decoded {4} bytes".format(msbcData[1], msbcData[0], msbcData[1], msbcData[2], written.value)) + if runOnce == 0: +## sbcDll.c_decode(firstFrame, compressedSize, pcmFrame, pcmFrameSize, byref(written)) + # Dump first frame, simple removal of noise. It's only 7.5ms anyway + runOnce = 1 + else: + write_to_wave(pcmFrame, written.value) +## sbcDll.c_decode(secondFrame, compressedSize, pcmFrame, pcmFrameSize, byref(written)) + + readSoFar = 0 + inbuffer += indata[4:] + lastByteTime = time.time() + +## print "Reading up to {0} bytes".format(compressedSize - readSoFar)) + +except SerialException as e: + print "Serial port error" + print(e) + +finally: + if ser is not None: ser.close() + stream.stop_stream() + stream.close() + + p.terminate() + +##sbcDll.c_decode(secondFrame, len(secondFrame), pcmFrame, pcmFrameSize, byref(written)) +##for pcm in pcmFrame: +## print(str(pcm)) + diff --git a/tools/scripts/audio/samples/.gitignore b/tools/scripts/audio/samples/.gitignore new file mode 100644 index 0000000..9ea0c66 --- /dev/null +++ b/tools/scripts/audio/samples/.gitignore @@ -0,0 +1,5 @@ +# Ignore everything in this directory. +# This folder is required by the audio scripts. The output from the scripts are saved here, but should never be committed. +* +# Except this file +!.gitignore \ No newline at end of file