From f440728644ad3698ffd6af1abcfcc07aad5793c3 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Tue, 8 Aug 2023 23:10:02 -0400 Subject: [PATCH] initial commit * combine all source files into this monorepo * convert all third-party source packages into submodules * small fixes due to changes in latest third-part packages --- .gitignore | 13 + .gitmodules | 16 + README.md | 38 + firmware/ChibiOS | 1 + firmware/LICENSE | 620 + firmware/Makefile | 222 + firmware/openocd.cfg | 3 + firmware/source/board/board.mk | 17 + firmware/source/board/board_h7.c | 287 + firmware/source/board/board_l4.c | 307 + firmware/source/board/h7/board.h | 1642 + firmware/source/board/l4/board.h | 1509 + firmware/source/cfg/chconf.h | 756 + firmware/source/cfg/halconf.h | 531 + firmware/source/cfg/mcuconf.h | 7 + firmware/source/cfg/mcuconf_h7.h | 483 + firmware/source/cfg/mcuconf_l4.h | 360 + firmware/source/communication.cpp | 293 + firmware/source/communication.hpp | 29 + firmware/source/conversion.cpp | 218 + firmware/source/conversion.hpp | 64 + firmware/source/elf.h | 100 + firmware/source/elfload.cpp | 84 + firmware/source/elfload.hpp | 39 + firmware/source/error.cpp | 38 + firmware/source/error.hpp | 47 + firmware/source/handlers.cpp | 140 + firmware/source/handlers.hpp | 31 + firmware/source/ld/STM32H723xG.ld | 124 + firmware/source/ld/STM32L476xG.ld | 116 + firmware/source/main.cpp | 58 + firmware/source/monitor.cpp | 80 + firmware/source/monitor.hpp | 31 + firmware/source/periph/adc.cpp | 245 + firmware/source/periph/adc.hpp | 53 + firmware/source/periph/cordic.cpp | 113 + firmware/source/periph/cordic.hpp | 25 + firmware/source/periph/dac.cpp | 85 + firmware/source/periph/dac.hpp | 37 + firmware/source/periph/usbcfg.c | 346 + firmware/source/periph/usbcfg.h | 28 + firmware/source/periph/usbserial.cpp | 52 + firmware/source/periph/usbserial.hpp | 32 + firmware/source/runstatus.hpp | 11 + firmware/source/samplebuffer.cpp | 117 + firmware/source/samplebuffer.hpp | 51 + firmware/source/samples.cpp | 35 + firmware/source/samples.hpp | 26 + firmware/source/sclock.cpp | 78 + firmware/source/sclock.hpp | 47 + gui/LICENSE | 620 + gui/Makefile | 46 + gui/examples/1_convolve_simple.cpp | 30 + gui/examples/2_convolve_overlap_save.cpp | 47 + gui/examples/3_fir.cpp | 47 + gui/examples/4_fir_pro.cpp | 478 + gui/examples/5_fir_differentiator.cpp | 30 + gui/examples/6_iir_test.cpp | 23 + gui/examples/7_iir_echo.cpp | 30 + gui/fonts/LICENSE-2.0.txt | 202 + gui/fonts/Roboto-Medium.ttf | Bin 0 -> 162588 bytes gui/fonts/Roboto-Regular.ttf | Bin 0 -> 168260 bytes gui/fonts/RobotoMono-Regular.ttf | Bin 0 -> 86908 bytes gui/source/ImGuiColorTextEdit | 1 + gui/source/ImGuiFileDialog | 1 + gui/source/circular.hpp | 48 + gui/source/code.cpp | 172 + gui/source/code.hpp | 39 + gui/source/device.cpp | 481 + gui/source/device_formula.cpp | 86 + gui/source/exprtk.hpp | 40121 +++++++++++++++++++++ gui/source/file.cpp | 168 + gui/source/gui.cpp | 151 + gui/source/gui_code.cpp | 68 + gui/source/gui_device.cpp | 439 + gui/source/gui_help.cpp | 124 + gui/source/gui_help.hpp | 19 + gui/source/imgui | 1 + gui/source/logview.cpp | 82 + gui/source/logview.h | 26 + gui/source/main.cpp | 148 + gui/source/main.hpp | 20 + gui/source/serial | 1 + gui/source/stmdsp/stmdsp.cpp | 331 + gui/source/stmdsp/stmdsp.hpp | 166 + gui/source/stmdsp/stmdsp_code.hpp | 199 + gui/source/wav.hpp | 97 + hardware/DSP PAW add-on board.kicad_pro | 352 + hardware/DSP PAW add-on board.kicad_sch | 98 + hardware/DSP PAW add-on board.xml | 1962 + hardware/LICENSE | 290 + hardware/analog_io.kicad_sch | 2464 ++ hardware/board_connectors.kicad_sch | 2475 ++ hardware/power_regulation.kicad_sch | 2236 ++ hardware/user_io.kicad_sch | 1030 + 95 files changed, 65134 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 README.md create mode 160000 firmware/ChibiOS create mode 100644 firmware/LICENSE create mode 100644 firmware/Makefile create mode 100644 firmware/openocd.cfg create mode 100644 firmware/source/board/board.mk create mode 100644 firmware/source/board/board_h7.c create mode 100644 firmware/source/board/board_l4.c create mode 100644 firmware/source/board/h7/board.h create mode 100644 firmware/source/board/l4/board.h create mode 100644 firmware/source/cfg/chconf.h create mode 100644 firmware/source/cfg/halconf.h create mode 100644 firmware/source/cfg/mcuconf.h create mode 100644 firmware/source/cfg/mcuconf_h7.h create mode 100644 firmware/source/cfg/mcuconf_l4.h create mode 100644 firmware/source/communication.cpp create mode 100644 firmware/source/communication.hpp create mode 100644 firmware/source/conversion.cpp create mode 100644 firmware/source/conversion.hpp create mode 100644 firmware/source/elf.h create mode 100644 firmware/source/elfload.cpp create mode 100644 firmware/source/elfload.hpp create mode 100644 firmware/source/error.cpp create mode 100644 firmware/source/error.hpp create mode 100644 firmware/source/handlers.cpp create mode 100644 firmware/source/handlers.hpp create mode 100644 firmware/source/ld/STM32H723xG.ld create mode 100644 firmware/source/ld/STM32L476xG.ld create mode 100644 firmware/source/main.cpp create mode 100644 firmware/source/monitor.cpp create mode 100644 firmware/source/monitor.hpp create mode 100644 firmware/source/periph/adc.cpp create mode 100644 firmware/source/periph/adc.hpp create mode 100644 firmware/source/periph/cordic.cpp create mode 100644 firmware/source/periph/cordic.hpp create mode 100644 firmware/source/periph/dac.cpp create mode 100644 firmware/source/periph/dac.hpp create mode 100644 firmware/source/periph/usbcfg.c create mode 100644 firmware/source/periph/usbcfg.h create mode 100644 firmware/source/periph/usbserial.cpp create mode 100644 firmware/source/periph/usbserial.hpp create mode 100644 firmware/source/runstatus.hpp create mode 100644 firmware/source/samplebuffer.cpp create mode 100644 firmware/source/samplebuffer.hpp create mode 100644 firmware/source/samples.cpp create mode 100644 firmware/source/samples.hpp create mode 100644 firmware/source/sclock.cpp create mode 100644 firmware/source/sclock.hpp create mode 100644 gui/LICENSE create mode 100644 gui/Makefile create mode 100644 gui/examples/1_convolve_simple.cpp create mode 100644 gui/examples/2_convolve_overlap_save.cpp create mode 100644 gui/examples/3_fir.cpp create mode 100644 gui/examples/4_fir_pro.cpp create mode 100644 gui/examples/5_fir_differentiator.cpp create mode 100644 gui/examples/6_iir_test.cpp create mode 100644 gui/examples/7_iir_echo.cpp create mode 100644 gui/fonts/LICENSE-2.0.txt create mode 100644 gui/fonts/Roboto-Medium.ttf create mode 100644 gui/fonts/Roboto-Regular.ttf create mode 100644 gui/fonts/RobotoMono-Regular.ttf create mode 160000 gui/source/ImGuiColorTextEdit create mode 160000 gui/source/ImGuiFileDialog create mode 100644 gui/source/circular.hpp create mode 100644 gui/source/code.cpp create mode 100644 gui/source/code.hpp create mode 100644 gui/source/device.cpp create mode 100644 gui/source/device_formula.cpp create mode 100644 gui/source/exprtk.hpp create mode 100644 gui/source/file.cpp create mode 100644 gui/source/gui.cpp create mode 100644 gui/source/gui_code.cpp create mode 100644 gui/source/gui_device.cpp create mode 100644 gui/source/gui_help.cpp create mode 100644 gui/source/gui_help.hpp create mode 160000 gui/source/imgui create mode 100644 gui/source/logview.cpp create mode 100644 gui/source/logview.h create mode 100644 gui/source/main.cpp create mode 100644 gui/source/main.hpp create mode 160000 gui/source/serial create mode 100644 gui/source/stmdsp/stmdsp.cpp create mode 100644 gui/source/stmdsp/stmdsp.hpp create mode 100644 gui/source/stmdsp/stmdsp_code.hpp create mode 100644 gui/source/wav.hpp create mode 100755 hardware/DSP PAW add-on board.kicad_pro create mode 100755 hardware/DSP PAW add-on board.kicad_sch create mode 100755 hardware/DSP PAW add-on board.xml create mode 100644 hardware/LICENSE create mode 100755 hardware/analog_io.kicad_sch create mode 100755 hardware/board_connectors.kicad_sch create mode 100755 hardware/power_regulation.kicad_sch create mode 100755 hardware/user_io.kicad_sch diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60424bf --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.* +*.o +*.so +*.exe +*.dll +perf* + +firmware/build +gui/imgui.ini +gui/stmdspgui +gui/stmdspgui.exe +hardware/*-backups +hardware/*.kicad_prl diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..57329a9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,16 @@ +[submodule "firmware/ChibiOS"] + path = firmware/ChibiOS + url = https://github.com/ChibiOS/ChibiOS + branch = stable_20.3.x +[submodule "gui/source/serial"] + path = gui/source/serial + url = https://www.github.com/wjwwood/serial +[submodule "gui/source/imgui"] + path = gui/source/imgui + url = https://github.com/ocornut/imgui +[submodule "gui/source/ImGuiFileDialog"] + path = gui/source/ImGuiFileDialog + url = https://github.com/aiekick/ImGuiFileDialog +[submodule "gui/source/ImGuiColorTextEdit"] + path = gui/source/ImGuiColorTextEdit + url = https://github.com/BalazsJako/ImGuiColorTextEdit diff --git a/README.md b/README.md new file mode 100644 index 0000000..411f81e --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# dsp-paw + +This is the DSP PAW "monorepo", containing the microcontroller firmware, add-on board design files, and the source code for the computer graphical interface (GUI). + +*DSP PAW* (Digital Signal Processing Portable All-in-one Workstation) provides a solution for creating and studying DSP algorithms on embedded systems. Using the project's software and hardware with certain [NUCLEO development boards](https://www.st.com/en/evaluation-tools/stm32-nucleo-boards.html) will enable you to portably design DSP algorithms, without the need for external tools or laboratory equipment. + +## Project components + +1. [Firmware](https://code.bitgloo.com/bitgloo/dsp-paw/src/branch/main/firmware) that allows users to load and execute custom DSP algorithms for real-time signal processing. +2. [A custom add-on board](https://code.bitgloo.com/bitgloo/dsp-paw/src/branch/main/hardware) which provides the necessary circuitry for interfacing with external signals and the host computer. +3. [Computer software](https://code.bitgloo.com/bitgloo/dsp-paw/src/branch/main/gui) that facilitates algorithm design, execution, and detailed analysis. + +## Features + +* Real-time signal processing: signal read by the ADC are streamed through the loaded algorithm and output via the DAC. +* The core firmware facilitates algorithm uploads over USB, enabling a fast design and test process. +* Supports signal sampling rates from 8kS/s up to 96kS/s, with buffer size of up to 4,096 samples. +* Supports external signals between -2V and +2V. +* Two potentiometers for adjusting algorithm parameters while the algorithm is running. +* An on-board signal generator that eliminates the need for input signals from external hardware. +* Numerous analysis features, including signal visualization and algorithm execution time measurement, eliminate the need for other test equipment like oscilloscopes. + +## Build notes + +The add-on board was designed using [KiCad](https://www.kicad.org/). + +Both the firmware and user interface software are written in C++, and have single Makefiles for their build processes. Both also depend on git submodules, so be sure to fetch those before compilation. + +The firmware additionally requires the `arm-none-eabi` toolchain, and the GUI requires [SDL 2.0](https://www.libsdl.org/). + +## Learn more + +The [project's wiki](https://code.bitgloo.com/bitgloo/dsp-paw/wiki) will be updated over time with more information about all aspects of the project. + +### Licensing + +DSP PAW source code is licensed under version three of the GNU General Public License. The add-on board design files are licensed under the CERN Open Hardware License Version 2 - Strongly Reciprocal. See the `LICENSE` files in each component's folder for more information. + diff --git a/firmware/ChibiOS b/firmware/ChibiOS new file mode 160000 index 0000000..dd0783c --- /dev/null +++ b/firmware/ChibiOS @@ -0,0 +1 @@ +Subproject commit dd0783ca6f450486a96deadb98b6df01d6bb6e85 diff --git a/firmware/LICENSE b/firmware/LICENSE new file mode 100644 index 0000000..6a34f51 --- /dev/null +++ b/firmware/LICENSE @@ -0,0 +1,620 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000..0db249b --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,222 @@ +############################################################################## +# Build global options +# NOTE: Can be overridden externally. +# + +# Set the target platform, either L4, G4, or H7 +TARGET_PLATFORM = L4 + +# Compiler options here. +ifeq ($(USE_OPT),) + USE_OPT = -O0 -g3 -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nosys.specs +endif + +# C specific options here (added to USE_OPT). +ifeq ($(USE_COPT),) + USE_COPT = +endif + +# C++ specific options here (added to USE_OPT). +ifeq ($(USE_CPPOPT),) + USE_CPPOPT = -std=c++2a -fno-rtti -fno-exceptions +endif + +# Enable this if you want the linker to remove unused code and data. +ifeq ($(USE_LINK_GC),) + USE_LINK_GC = yes +endif + +# Linker extra options here. +ifeq ($(USE_LDOPT),) +# USE_LDOPT = -L.,-lzig +endif + +# Enable this if you want link time optimizations (LTO). +ifeq ($(USE_LTO),) + USE_LTO = yes +endif + +# Enable this if you want to see the full log while compiling. +ifeq ($(USE_VERBOSE_COMPILE),) + USE_VERBOSE_COMPILE = no +endif + +# If enabled, this option makes the build process faster by not compiling +# modules not used in the current configuration. +ifeq ($(USE_SMART_BUILD),) + USE_SMART_BUILD = yes +endif + +# +# Build global options +############################################################################## + +############################################################################## +# Architecture or project specific options +# + +# Stack size to be allocated to the Cortex-M process stack. This stack is +# the stack used by the main() thread. +ifeq ($(USE_PROCESS_STACKSIZE),) + USE_PROCESS_STACKSIZE = 1024 +endif + +# Stack size to the allocated to the Cortex-M main/exceptions stack. This +# stack is used for processing interrupts and exceptions. +ifeq ($(USE_EXCEPTIONS_STACKSIZE),) + USE_EXCEPTIONS_STACKSIZE = 2048 +endif + +# Enables the use of FPU (no, softfp, hard). +ifeq ($(USE_FPU),) + USE_FPU = hard +endif + +# FPU-related options. +ifeq ($(USE_FPU_OPT),) +ifeq ($(TARGET_PLATFORM),H7) + USE_FPU_OPT = -mfloat-abi=$(USE_FPU) -mfpu=fpv5-d16 +endif +ifeq ($(TARGET_PLATFORM),L4) + USE_FPU_OPT = -mfloat-abi=$(USE_FPU) -mfpu=fpv4-sp-d16 +endif +endif + +# +# Architecture or project specific options +############################################################################## + +############################################################################## +# Project, target, sources and paths +# + +# Define project name here +PROJECT = ch + +# Target settings. +ifeq ($(TARGET_PLATFORM),H7) + MCU = cortex-m7 +else + MCU = cortex-m4 +endif + +# Imported source files and paths. +CHIBIOS := ./ChibiOS +CONFDIR := ./source/cfg +BUILDDIR := ./build +DEPDIR := ./.dep + +# Licensing files. +include $(CHIBIOS)/os/license/license.mk +# Startup files. +ifeq ($(TARGET_PLATFORM),H7) + include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32h7xx.mk +else + include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32l4xx.mk +endif +# HAL-OSAL files (optional). +include $(CHIBIOS)/os/hal/hal.mk +ifeq ($(TARGET_PLATFORM),H7) + include $(CHIBIOS)/os/hal/ports/STM32/STM32H7xx/platform.mk +else + include $(CHIBIOS)/os/hal/ports/STM32/STM32L4xx/platform.mk +endif +include ./source/board/board.mk +include $(CHIBIOS)/os/hal/osal/rt-nil/osal.mk +# RTOS files (optional). +include $(CHIBIOS)/os/rt/rt.mk +include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk +# Auto-build files in ./source recursively. +#include $(CHIBIOS)/tools/mk/autobuild.mk +ALLCSRC += $(wildcard source/*.c) $(wildcard source/periph/*.c) +ALLCPPSRC += $(wildcard source/*.cpp) $(wildcard source/periph/*.cpp) +ALLASMSRC += $(wildcard source/*.s) +# Other files (optional). +#include $(CHIBIOS)/test/lib/test.mk +#include $(CHIBIOS)/test/rt/rt_test.mk +#include $(CHIBIOS)/test/oslib/oslib_test.mk + +# Define linker script file here +ifeq ($(TARGET_PLATFORM),H7) + LDSCRIPT = source/ld/STM32H723xG.ld +else + LDSCRIPT = source/ld/STM32L476xG.ld +endif + +# C sources that can be compiled in ARM or THUMB mode depending on the global +# setting. +CSRC = $(ALLCSRC) + +# C++ sources that can be compiled in ARM or THUMB mode depending on the global +# setting. +CPPSRC = $(ALLCPPSRC) + +# List ASM source files here. +ASMSRC = $(ALLASMSRC) + +# List ASM with preprocessor source files here. +ASMXSRC = $(ALLXASMSRC) + +# Inclusion directories. +INCDIR = $(CONFDIR) $(ALLINC) $(TESTINC) \ + source source/periph + +# Define C warning options here. +CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes -pedantic + +# Define C++ warning options here. +CPPWARN = -Wall -Wextra -Wundef -pedantic -Wno-volatile + +# +# Project, target, sources and paths +############################################################################## + +############################################################################## +# Start of user section +# + +# List all user C define here, like -D_DEBUG=1 +UDEFS = -DCORTEX_ENABLE_WFI_IDLE=TRUE \ + -DPORT_USE_SYSCALL=TRUE \ + -DPORT_USE_GUARD_MPU_REGION=MPU_REGION_0 \ + -DTARGET_PLATFORM_$(TARGET_PLATFORM) + +# Define ASM defines here +UADEFS = + +# List all user directories here +UINCDIR = + +# List the user directory to look for the libraries here +ULIBDIR = + +# List all user libraries here +ifeq ($(TARGET_PLATFORM),L4) + ULIBS = -lm +else + ULIBS = +endif + +# +# End of user section +############################################################################## + +############################################################################## +# Common rules +# + +RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk +include $(RULESPATH)/arm-none-eabi.mk +include $(RULESPATH)/rules.mk + +# +# Common rules +############################################################################## + +############################################################################## +# Custom rules +# + +# +# Custom rules +############################################################################## diff --git a/firmware/openocd.cfg b/firmware/openocd.cfg new file mode 100644 index 0000000..47e6c7d --- /dev/null +++ b/firmware/openocd.cfg @@ -0,0 +1,3 @@ +source [find interface/stlink.cfg] +source [find target/stm32l4x.cfg] + diff --git a/firmware/source/board/board.mk b/firmware/source/board/board.mk new file mode 100644 index 0000000..155285a --- /dev/null +++ b/firmware/source/board/board.mk @@ -0,0 +1,17 @@ +# List of all the board related files. +ifeq ($(TARGET_PLATFORM),H7) + BOARDSRC = ./source/board/board_h7.c +else + BOARDSRC = ./source/board/board_l4.c +endif + +# Required include directories +ifeq ($(TARGET_PLATFORM),H7) + BOARDINC = ./source/board/h7 +else + BOARDINC = ./source/board/l4 +endif + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/firmware/source/board/board_h7.c b/firmware/source/board/board_h7.c new file mode 100644 index 0000000..74285cf --- /dev/null +++ b/firmware/source/board/board_h7.c @@ -0,0 +1,287 @@ +/* + ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * This file has been automatically generated using ChibiStudio board + * generator plugin. Do not edit manually. + */ + +#include "hal.h" +#include "stm32_gpio.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Type of STM32 GPIO port setup. + */ +typedef struct { + uint32_t moder; + uint32_t otyper; + uint32_t ospeedr; + uint32_t pupdr; + uint32_t odr; + uint32_t afrl; + uint32_t afrh; +} gpio_setup_t; + +/** + * @brief Type of STM32 GPIO initialization data. + */ +typedef struct { +#if STM32_HAS_GPIOA || defined(__DOXYGEN__) + gpio_setup_t PAData; +#endif +#if STM32_HAS_GPIOB || defined(__DOXYGEN__) + gpio_setup_t PBData; +#endif +#if STM32_HAS_GPIOC || defined(__DOXYGEN__) + gpio_setup_t PCData; +#endif +#if STM32_HAS_GPIOD || defined(__DOXYGEN__) + gpio_setup_t PDData; +#endif +#if STM32_HAS_GPIOE || defined(__DOXYGEN__) + gpio_setup_t PEData; +#endif +#if STM32_HAS_GPIOF || defined(__DOXYGEN__) + gpio_setup_t PFData; +#endif +#if STM32_HAS_GPIOG || defined(__DOXYGEN__) + gpio_setup_t PGData; +#endif +#if STM32_HAS_GPIOH || defined(__DOXYGEN__) + gpio_setup_t PHData; +#endif +#if STM32_HAS_GPIOI || defined(__DOXYGEN__) + gpio_setup_t PIData; +#endif +#if STM32_HAS_GPIOJ || defined(__DOXYGEN__) + gpio_setup_t PJData; +#endif +#if STM32_HAS_GPIOK || defined(__DOXYGEN__) + gpio_setup_t PKData; +#endif +} gpio_config_t; + +/** + * @brief STM32 GPIO static initialization data. + */ +static const gpio_config_t gpio_default_config = { +#if STM32_HAS_GPIOA + {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, + VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH}, +#endif +#if STM32_HAS_GPIOB + {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR, + VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH}, +#endif +#if STM32_HAS_GPIOC + {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR, + VAL_GPIOC_ODR, VAL_GPIOC_AFRL, VAL_GPIOC_AFRH}, +#endif +#if STM32_HAS_GPIOD + {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR, + VAL_GPIOD_ODR, VAL_GPIOD_AFRL, VAL_GPIOD_AFRH}, +#endif +#if STM32_HAS_GPIOE + {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR, + VAL_GPIOE_ODR, VAL_GPIOE_AFRL, VAL_GPIOE_AFRH}, +#endif +#if STM32_HAS_GPIOF + {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR, + VAL_GPIOF_ODR, VAL_GPIOF_AFRL, VAL_GPIOF_AFRH}, +#endif +#if STM32_HAS_GPIOG + {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR, + VAL_GPIOG_ODR, VAL_GPIOG_AFRL, VAL_GPIOG_AFRH}, +#endif +#if STM32_HAS_GPIOH + {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR, + VAL_GPIOH_ODR, VAL_GPIOH_AFRL, VAL_GPIOH_AFRH}, +#endif +#if STM32_HAS_GPIOI + {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR, + VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH}, +#endif +#if STM32_HAS_GPIOJ + {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR, + VAL_GPIOJ_ODR, VAL_GPIOJ_AFRL, VAL_GPIOJ_AFRH}, +#endif +#if STM32_HAS_GPIOK + {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR, + VAL_GPIOK_ODR, VAL_GPIOK_AFRL, VAL_GPIOK_AFRH} +#endif +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) { + + gpiop->OTYPER = config->otyper; + gpiop->OSPEEDR = config->ospeedr; + gpiop->PUPDR = config->pupdr; + gpiop->ODR = config->odr; + gpiop->AFRL = config->afrl; + gpiop->AFRH = config->afrh; + gpiop->MODER = config->moder; +} + +static void stm32_gpio_init(void) { + + /* Enabling GPIO-related clocks, the mask comes from the + registry header file.*/ + rccResetAHB4(STM32_GPIO_EN_MASK); + rccEnableAHB4(STM32_GPIO_EN_MASK, true); + + /* Initializing all the defined GPIO ports.*/ +#if STM32_HAS_GPIOA + gpio_init(GPIOA, &gpio_default_config.PAData); +#endif +#if STM32_HAS_GPIOB + gpio_init(GPIOB, &gpio_default_config.PBData); +#endif +#if STM32_HAS_GPIOC + gpio_init(GPIOC, &gpio_default_config.PCData); +#endif +#if STM32_HAS_GPIOD + gpio_init(GPIOD, &gpio_default_config.PDData); +#endif +#if STM32_HAS_GPIOE + gpio_init(GPIOE, &gpio_default_config.PEData); +#endif +#if STM32_HAS_GPIOF + gpio_init(GPIOF, &gpio_default_config.PFData); +#endif +#if STM32_HAS_GPIOG + gpio_init(GPIOG, &gpio_default_config.PGData); +#endif +#if STM32_HAS_GPIOH + gpio_init(GPIOH, &gpio_default_config.PHData); +#endif +#if STM32_HAS_GPIOI + gpio_init(GPIOI, &gpio_default_config.PIData); +#endif +#if STM32_HAS_GPIOJ + gpio_init(GPIOJ, &gpio_default_config.PJData); +#endif +#if STM32_HAS_GPIOK + gpio_init(GPIOK, &gpio_default_config.PKData); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Early initialization code. + * @details GPIO ports and system clocks are initialized before everything + * else. + */ +void __early_init(void) { + + stm32_gpio_init(); + stm32_clock_init(); +} + +#if HAL_USE_SDC || defined(__DOXYGEN__) +/** + * @brief SDC card detection. + */ +bool sdc_lld_is_card_inserted(SDCDriver *sdcp) { + + (void)sdcp; + /* CHTODO: Fill the implementation.*/ + return true; +} + +/** + * @brief SDC card write protection detection. + */ +bool sdc_lld_is_write_protected(SDCDriver *sdcp) { + + (void)sdcp; + /* CHTODO: Fill the implementation.*/ + return false; +} +#endif /* HAL_USE_SDC */ + +#if HAL_USE_MMC_SPI || defined(__DOXYGEN__) +/** + * @brief MMC_SPI card detection. + */ +bool mmc_lld_is_card_inserted(MMCDriver *mmcp) { + + (void)mmcp; + /* CHTODO: Fill the implementation.*/ + return true; +} + +/** + * @brief MMC_SPI card write protection detection. + */ +bool mmc_lld_is_write_protected(MMCDriver *mmcp) { + + (void)mmcp; + /* CHTODO: Fill the implementation.*/ + return false; +} +#endif + +/** + * @brief Board-specific initialization code. + * @note You can add your board-specific code here. + */ +void boardInit(void) { + // Enable the FPU (floating-point unit) + SCB->CPACR |= 0xF << 20; + + // Setup the MPU (memory protection unit): + // Region 2: Data for algorithm thread + // Region 3: Code for algorithm thread + // Region 4: User algorithm code + mpuConfigureRegion(MPU_REGION_2, + 0x20000000, + MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_64K | + MPU_RASR_ENABLE); + mpuConfigureRegion(MPU_REGION_3, + 0x0807F800, + MPU_RASR_ATTR_AP_RO_RO | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_2K | + MPU_RASR_ENABLE); + mpuConfigureRegion(MPU_REGION_4, + 0x00000000, + MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_64K | + MPU_RASR_ENABLE); +} diff --git a/firmware/source/board/board_l4.c b/firmware/source/board/board_l4.c new file mode 100644 index 0000000..55af697 --- /dev/null +++ b/firmware/source/board/board_l4.c @@ -0,0 +1,307 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * This file has been automatically generated using ChibiStudio board + * generator plugin. Do not edit manually. + */ + +#include "hal.h" +#include "stm32_gpio.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Type of STM32 GPIO port setup. + */ +typedef struct { + uint32_t moder; + uint32_t otyper; + uint32_t ospeedr; + uint32_t pupdr; + uint32_t odr; + uint32_t afrl; + uint32_t afrh; + uint32_t ascr; + uint32_t lockr; +} gpio_setup_t; + +/** + * @brief Type of STM32 GPIO initialization data. + */ +typedef struct { +#if STM32_HAS_GPIOA || defined(__DOXYGEN__) + gpio_setup_t PAData; +#endif +#if STM32_HAS_GPIOB || defined(__DOXYGEN__) + gpio_setup_t PBData; +#endif +#if STM32_HAS_GPIOC || defined(__DOXYGEN__) + gpio_setup_t PCData; +#endif +#if STM32_HAS_GPIOD || defined(__DOXYGEN__) + gpio_setup_t PDData; +#endif +#if STM32_HAS_GPIOE || defined(__DOXYGEN__) + gpio_setup_t PEData; +#endif +#if STM32_HAS_GPIOF || defined(__DOXYGEN__) + gpio_setup_t PFData; +#endif +#if STM32_HAS_GPIOG || defined(__DOXYGEN__) + gpio_setup_t PGData; +#endif +#if STM32_HAS_GPIOH || defined(__DOXYGEN__) + gpio_setup_t PHData; +#endif +#if STM32_HAS_GPIOI || defined(__DOXYGEN__) + gpio_setup_t PIData; +#endif +#if STM32_HAS_GPIOJ || defined(__DOXYGEN__) + gpio_setup_t PJData; +#endif +#if STM32_HAS_GPIOK || defined(__DOXYGEN__) + gpio_setup_t PKData; +#endif +} gpio_config_t; + +/** + * @brief STM32 GPIO static initialization data. + */ +static const gpio_config_t gpio_default_config = { +#if STM32_HAS_GPIOA + {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, + VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH, VAL_GPIOA_ASCR, + VAL_GPIOA_LOCKR}, +#endif +#if STM32_HAS_GPIOB + {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR, + VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH, VAL_GPIOB_ASCR, + VAL_GPIOB_LOCKR}, +#endif +#if STM32_HAS_GPIOC + {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR, + VAL_GPIOC_ODR, VAL_GPIOC_AFRL, VAL_GPIOC_AFRH, VAL_GPIOC_ASCR, + VAL_GPIOC_LOCKR}, +#endif +#if STM32_HAS_GPIOD + {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR, + VAL_GPIOD_ODR, VAL_GPIOD_AFRL, VAL_GPIOD_AFRH, VAL_GPIOD_ASCR, + VAL_GPIOD_LOCKR}, +#endif +#if STM32_HAS_GPIOE + {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR, + VAL_GPIOE_ODR, VAL_GPIOE_AFRL, VAL_GPIOE_AFRH, VAL_GPIOE_ASCR, + VAL_GPIOE_LOCKR}, +#endif +#if STM32_HAS_GPIOF + {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR, + VAL_GPIOF_ODR, VAL_GPIOF_AFRL, VAL_GPIOF_AFRH, VAL_GPIOF_ASCR, + VAL_GPIOF_LOCKR}, +#endif +#if STM32_HAS_GPIOG + {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR, + VAL_GPIOG_ODR, VAL_GPIOG_AFRL, VAL_GPIOG_AFRH, VAL_GPIOG_ASCR, + VAL_GPIOG_LOCKR}, +#endif +#if STM32_HAS_GPIOH + {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR, + VAL_GPIOH_ODR, VAL_GPIOH_AFRL, VAL_GPIOH_AFRH, VAL_GPIOH_ASCR, + VAL_GPIOH_LOCKR}, +#endif +#if STM32_HAS_GPIOI + {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR, + VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH, VAL_GPIOI_ASCR, + VAL_GPIOI_LOCKR}, +#endif +#if STM32_HAS_GPIOJ + {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR, + VAL_GPIOJ_ODR, VAL_GPIOJ_AFRL, VAL_GPIOJ_AFRH, VAL_GPIOJ_ASCR, + VAL_GPIOJ_LOCKR}, +#endif +#if STM32_HAS_GPIOK + {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR, + VAL_GPIOK_ODR, VAL_GPIOK_AFRL, VAL_GPIOK_AFRH, VAL_GPIOK_ASCR, + VAL_GPIOK_LOCKR} +#endif +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) { + + gpiop->OTYPER = config->otyper; + gpiop->ASCR = config->ascr; + gpiop->OSPEEDR = config->ospeedr; + gpiop->PUPDR = config->pupdr; + gpiop->ODR = config->odr; + gpiop->AFRL = config->afrl; + gpiop->AFRH = config->afrh; + gpiop->MODER = config->moder; + gpiop->LOCKR = config->lockr; +} + +static void stm32_gpio_init(void) { + + /* Enabling GPIO-related clocks, the mask comes from the + registry header file.*/ + rccResetAHB2(STM32_GPIO_EN_MASK); + rccEnableAHB2(STM32_GPIO_EN_MASK, true); + + /* Initializing all the defined GPIO ports.*/ +#if STM32_HAS_GPIOA + gpio_init(GPIOA, &gpio_default_config.PAData); +#endif +#if STM32_HAS_GPIOB + gpio_init(GPIOB, &gpio_default_config.PBData); +#endif +#if STM32_HAS_GPIOC + gpio_init(GPIOC, &gpio_default_config.PCData); +#endif +#if STM32_HAS_GPIOD + gpio_init(GPIOD, &gpio_default_config.PDData); +#endif +#if STM32_HAS_GPIOE + gpio_init(GPIOE, &gpio_default_config.PEData); +#endif +#if STM32_HAS_GPIOF + gpio_init(GPIOF, &gpio_default_config.PFData); +#endif +#if STM32_HAS_GPIOG + gpio_init(GPIOG, &gpio_default_config.PGData); +#endif +#if STM32_HAS_GPIOH + gpio_init(GPIOH, &gpio_default_config.PHData); +#endif +#if STM32_HAS_GPIOI + gpio_init(GPIOI, &gpio_default_config.PIData); +#endif +#if STM32_HAS_GPIOJ + gpio_init(GPIOJ, &gpio_default_config.PJData); +#endif +#if STM32_HAS_GPIOK + gpio_init(GPIOK, &gpio_default_config.PKData); +#endif +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Early initialization code. + * @details GPIO ports and system clocks are initialized before everything + * else. + */ +void __early_init(void) { + + stm32_gpio_init(); + stm32_clock_init(); +} + +#if HAL_USE_SDC || defined(__DOXYGEN__) +/** + * @brief SDC card detection. + */ +bool sdc_lld_is_card_inserted(SDCDriver *sdcp) { + + (void)sdcp; + /* CHTODO: Fill the implementation.*/ + return true; +} + +/** + * @brief SDC card write protection detection. + */ +bool sdc_lld_is_write_protected(SDCDriver *sdcp) { + + (void)sdcp; + /* CHTODO: Fill the implementation.*/ + return false; +} +#endif /* HAL_USE_SDC */ + +#if HAL_USE_MMC_SPI || defined(__DOXYGEN__) +/** + * @brief MMC_SPI card detection. + */ +bool mmc_lld_is_card_inserted(MMCDriver *mmcp) { + + (void)mmcp; + /* CHTODO: Fill the implementation.*/ + return true; +} + +/** + * @brief MMC_SPI card write protection detection. + */ +bool mmc_lld_is_write_protected(MMCDriver *mmcp) { + + (void)mmcp; + /* CHTODO: Fill the implementation.*/ + return false; +} +#endif + +/** + * @brief Board-specific initialization code. + * @note You can add your board-specific code here. + */ +void boardInit(void) { + palSetLineMode(LINE_LED_RED, PAL_MODE_OUTPUT_PUSHPULL); + palSetLineMode(LINE_LED_GREEN, PAL_MODE_OUTPUT_PUSHPULL); + palSetLineMode(LINE_LED_BLUE, PAL_MODE_OUTPUT_PUSHPULL); + palClearLine(LINE_LED_RED); + palClearLine(LINE_LED_GREEN); + palClearLine(LINE_LED_BLUE); + + SCB->CPACR |= 0xF << 20; // Enable FPU + + // Region 2: Data for algorithm thread and ADC/DAC buffers + // Region 3: Code for algorithm thread + // Region 4: User algorithm code + mpuConfigureRegion(MPU_REGION_2, + 0x20008000, + MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_128K | + MPU_RASR_ENABLE); + mpuConfigureRegion(MPU_REGION_3, + 0x0807F800, + MPU_RASR_ATTR_AP_RO_RO | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_2K | + MPU_RASR_ENABLE); + mpuConfigureRegion(MPU_REGION_4, + 0x10000000, + MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_32K | + MPU_RASR_ENABLE); +} diff --git a/firmware/source/board/h7/board.h b/firmware/source/board/h7/board.h new file mode 100644 index 0000000..58ba40e --- /dev/null +++ b/firmware/source/board/h7/board.h @@ -0,0 +1,1642 @@ +/* + ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * This file has been automatically generated using ChibiStudio board + * generator plugin. Do not edit manually. + */ + +#ifndef BOARD_H +#define BOARD_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* + * Setup for STMicroelectronics STM32 Nucleo144-H743ZI board. + */ + +/* + * Board identifier. + */ +#define BOARD_ST_NUCLEO144_H743ZI +#define BOARD_NAME "STMicroelectronics STM32 Nucleo144-H743ZI" + +/* + * Ethernet PHY type. + */ +#define BOARD_PHY_ID MII_LAN8742A_ID +#define BOARD_PHY_RMII + +/* + * Board oscillators-related settings. + */ +#if !defined(STM32_LSECLK) +#define STM32_LSECLK 32768U +#endif + +#define STM32_LSEDRV (3U << 3U) + +#if !defined(STM32_HSECLK) +#define STM32_HSECLK 8000000U +#endif + +#define STM32_HSE_BYPASS + +/* + * MCU type as defined in the ST header. + */ +#define STM32H723xx + +/* + * IO pins assignments. + */ +#define GPIOA_PIN0 0U +#define GPIOA_RMII_REF_CLK 1U +#define GPIOA_RMII_MDIO 2U +#define GPIOA_PIN3 3U +#define GPIOA_PIN4 4U +#define GPIOA_PIN5 5U +#define GPIOA_PIN6 6U +#define GPIOA_RMII_CRS_DV 7U +#define GPIOA_USB_SOF 8U +#define GPIOA_MCO1 8U +#define GPIOA_USB_VBUS 9U +#define GPIOA_USB_ID 10U +#define GPIOA_USB_DM 11U +#define GPIOA_USB_DP 12U +#define GPIOA_SWDIO 13U +#define GPIOA_SWCLK 14U +#define GPIOA_T_JTDI 15U + +#define GPIOB_LED1 0U +#define GPIOB_LED_GREEN 0U +#define GPIOB_LED 0U +#define GPIOB_PIN1 1U +#define GPIOB_PIN2 2U +#define GPIOB_SWO 3U +#define GPIOB_PIN4 4U +#define GPIOB_PIN5 5U +#define GPIOB_PIN6 6U +#define GPIOB_PIN7 7U +#define GPIOB_PIN8 8U +#define GPIOB_PIN9 9U +#define GPIOB_PIN10 10U +#define GPIOB_PIN11 11U +#define GPIOB_PIN12 12U +#define GPIOB_RMII_TXD1 13U +#define GPIOB_LED3 14U +#define GPIOB_LED_RED 14U +#define GPIOB_PIN15 15U + +#define GPIOC_PIN0 0U +#define GPIOC_RMII_MDC 1U +#define GPIOC_PIN2 2U +#define GPIOC_PIN3 3U +#define GPIOC_RMII_RXD0 4U +#define GPIOC_RMII_RXD1 5U +#define GPIOC_PIN6 6U +#define GPIOC_PIN7 7U +#define GPIOC_PIN8 8U +#define GPIOC_PIN9 9U +#define GPIOC_PIN10 10U +#define GPIOC_PIN11 11U +#define GPIOC_PIN12 12U +#define GPIOC_BUTTON 13U +#define GPIOC_OSC32_IN 14U +#define GPIOC_OSC32_OUT 15U + +#define GPIOD_PIN0 0U +#define GPIOD_PIN1 1U +#define GPIOD_PIN2 2U +#define GPIOD_PIN3 3U +#define GPIOD_PIN4 4U +#define GPIOD_PIN5 5U +#define GPIOD_PIN6 6U +#define GPIOD_PIN7 7U +#define GPIOD_USART3_RX 8U +#define GPIOD_STLK_RX 8U +#define GPIOD_USART3_TX 9U +#define GPIOD_STLK_TX 9U +#define GPIOD_PIN10 10U +#define GPIOD_PIN11 11U +#define GPIOD_PIN12 12U +#define GPIOD_PIN13 13U +#define GPIOD_PIN14 14U +#define GPIOD_PIN15 15U + +#define GPIOE_PIN0 0U +#define GPIOE_LED2 1U +#define GPIOE_LED_YELLOW 1U +#define GPIOE_PIN2 2U +#define GPIOE_PIN3 3U +#define GPIOE_PIN4 4U +#define GPIOE_PIN5 5U +#define GPIOE_PIN6 6U +#define GPIOE_PIN7 7U +#define GPIOE_PIN8 8U +#define GPIOE_PIN9 9U +#define GPIOE_PIN10 10U +#define GPIOE_PIN11 11U +#define GPIOE_PIN12 12U +#define GPIOE_PIN13 13U +#define GPIOE_PIN14 14U +#define GPIOE_PIN15 15U + +#define GPIOF_PIN0 0U +#define GPIOF_PIN1 1U +#define GPIOF_PIN2 2U +#define GPIOF_PIN3 3U +#define GPIOF_PIN4 4U +#define GPIOF_PIN5 5U +#define GPIOF_PIN6 6U +#define GPIOF_PIN7 7U +#define GPIOF_PIN8 8U +#define GPIOF_PIN9 9U +#define GPIOF_PIN10 10U +#define GPIOF_PIN11 11U +#define GPIOF_PIN12 12U +#define GPIOF_PIN13 13U +#define GPIOF_PIN14 14U +#define GPIOF_PIN15 15U + +#define GPIOG_PIN0 0U +#define GPIOG_PIN1 1U +#define GPIOG_PIN2 2U +#define GPIOG_PIN3 3U +#define GPIOG_PIN4 4U +#define GPIOG_PIN5 5U +#define GPIOG_USB_FS_PWR_EN 6U +#define GPIOG_USB_FS_OVCR 7U +#define GPIOG_PIN8 8U +#define GPIOG_PIN9 9U +#define GPIOG_PIN10 10U +#define GPIOG_RMII_TX_EN 11U +#define GPIOG_PIN12 12U +#define GPIOG_RMII_TXD0 13U +#define GPIOG_PIN14 14U +#define GPIOG_PIN15 15U + +#define GPIOH_OSC_IN 0U +#define GPIOH_OSC_OUT 1U +#define GPIOH_PIN2 2U +#define GPIOH_PIN3 3U +#define GPIOH_PIN4 4U +#define GPIOH_PIN5 5U +#define GPIOH_PIN6 6U +#define GPIOH_PIN7 7U +#define GPIOH_PIN8 8U +#define GPIOH_PIN9 9U +#define GPIOH_PIN10 10U +#define GPIOH_PIN11 11U +#define GPIOH_PIN12 12U +#define GPIOH_PIN13 13U +#define GPIOH_PIN14 14U +#define GPIOH_PIN15 15U + +#define GPIOI_PIN0 0U +#define GPIOI_PIN1 1U +#define GPIOI_PIN2 2U +#define GPIOI_PIN3 3U +#define GPIOI_PIN4 4U +#define GPIOI_PIN5 5U +#define GPIOI_PIN6 6U +#define GPIOI_PIN7 7U +#define GPIOI_PIN8 8U +#define GPIOI_PIN9 9U +#define GPIOI_PIN10 10U +#define GPIOI_PIN11 11U +#define GPIOI_PIN12 12U +#define GPIOI_PIN13 13U +#define GPIOI_PIN14 14U +#define GPIOI_PIN15 15U + +#define GPIOJ_PIN0 0U +#define GPIOJ_PIN1 1U +#define GPIOJ_PIN2 2U +#define GPIOJ_PIN3 3U +#define GPIOJ_PIN4 4U +#define GPIOJ_PIN5 5U +#define GPIOJ_PIN6 6U +#define GPIOJ_PIN7 7U +#define GPIOJ_PIN8 8U +#define GPIOJ_PIN9 9U +#define GPIOJ_PIN10 10U +#define GPIOJ_PIN11 11U +#define GPIOJ_PIN12 12U +#define GPIOJ_PIN13 13U +#define GPIOJ_PIN14 14U +#define GPIOJ_PIN15 15U + +#define GPIOK_PIN0 0U +#define GPIOK_PIN1 1U +#define GPIOK_PIN2 2U +#define GPIOK_PIN3 3U +#define GPIOK_PIN4 4U +#define GPIOK_PIN5 5U +#define GPIOK_PIN6 6U +#define GPIOK_PIN7 7U +#define GPIOK_PIN8 8U +#define GPIOK_PIN9 9U +#define GPIOK_PIN10 10U +#define GPIOK_PIN11 11U +#define GPIOK_PIN12 12U +#define GPIOK_PIN13 13U +#define GPIOK_PIN14 14U +#define GPIOK_PIN15 15U + +/* + * IO lines assignments. + */ +#define LINE_RMII_REF_CLK PAL_LINE(GPIOA, 1U) +#define LINE_RMII_MDIO PAL_LINE(GPIOA, 2U) +#define LINE_RMII_CRS_DV PAL_LINE(GPIOA, 7U) +#define LINE_USB_SOF PAL_LINE(GPIOA, 8U) +#define LINE_MCO1 PAL_LINE(GPIOA, 8U) +#define LINE_USB_VBUS PAL_LINE(GPIOA, 9U) +#define LINE_USB_ID PAL_LINE(GPIOA, 10U) +#define LINE_USB_DM PAL_LINE(GPIOA, 11U) +#define LINE_USB_DP PAL_LINE(GPIOA, 12U) +#define LINE_SWDIO PAL_LINE(GPIOA, 13U) +#define LINE_SWCLK PAL_LINE(GPIOA, 14U) +#define LINE_T_JTDI PAL_LINE(GPIOA, 15U) +#define LINE_LED1 PAL_LINE(GPIOB, 0U) +#define LINE_LED_GREEN PAL_LINE(GPIOB, 0U) +#define LINE_LED PAL_LINE(GPIOB, 0U) +#define LINE_SWO PAL_LINE(GPIOB, 3U) +#define LINE_LED2 PAL_LINE(GPIOE, 1U) +#define LINE_LED_YELLOW PAL_LINE(GPIOE, 1U) +#define LINE_RMII_TXD1 PAL_LINE(GPIOB, 13U) +#define LINE_LED3 PAL_LINE(GPIOB, 14U) +#define LINE_LED_RED PAL_LINE(GPIOB, 14U) +#define LINE_RMII_MDC PAL_LINE(GPIOC, 1U) +#define LINE_RMII_RXD0 PAL_LINE(GPIOC, 4U) +#define LINE_RMII_RXD1 PAL_LINE(GPIOC, 5U) +#define LINE_BUTTON PAL_LINE(GPIOC, 13U) +#define LINE_OSC32_IN PAL_LINE(GPIOC, 14U) +#define LINE_OSC32_OUT PAL_LINE(GPIOC, 15U) +#define LINE_USART3_RX PAL_LINE(GPIOD, 8U) +#define LINE_STLK_RX PAL_LINE(GPIOD, 8U) +#define LINE_USART3_TX PAL_LINE(GPIOD, 9U) +#define LINE_STLK_TX PAL_LINE(GPIOD, 9U) +#define LINE_USB_FS_PWR_EN PAL_LINE(GPIOG, 6U) +#define LINE_USB_FS_OVCR PAL_LINE(GPIOG, 7U) +#define LINE_RMII_TX_EN PAL_LINE(GPIOG, 11U) +#define LINE_RMII_TXD0 PAL_LINE(GPIOG, 13U) +#define LINE_OSC_IN PAL_LINE(GPIOH, 0U) +#define LINE_OSC_OUT PAL_LINE(GPIOH, 1U) + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/* + * I/O ports initial setup, this configuration is established soon after reset + * in the initialization code. + * Please refer to the STM32 Reference Manual for details. + */ +#define PIN_MODE_INPUT(n) (0U << ((n) * 2U)) +#define PIN_MODE_OUTPUT(n) (1U << ((n) * 2U)) +#define PIN_MODE_ALTERNATE(n) (2U << ((n) * 2U)) +#define PIN_MODE_ANALOG(n) (3U << ((n) * 2U)) +#define PIN_ODR_LOW(n) (0U << (n)) +#define PIN_ODR_HIGH(n) (1U << (n)) +#define PIN_OTYPE_PUSHPULL(n) (0U << (n)) +#define PIN_OTYPE_OPENDRAIN(n) (1U << (n)) +#define PIN_OSPEED_VERYLOW(n) (0U << ((n) * 2U)) +#define PIN_OSPEED_LOW(n) (1U << ((n) * 2U)) +#define PIN_OSPEED_MEDIUM(n) (2U << ((n) * 2U)) +#define PIN_OSPEED_HIGH(n) (3U << ((n) * 2U)) +#define PIN_PUPDR_FLOATING(n) (0U << ((n) * 2U)) +#define PIN_PUPDR_PULLUP(n) (1U << ((n) * 2U)) +#define PIN_PUPDR_PULLDOWN(n) (2U << ((n) * 2U)) +#define PIN_AFIO_AF(n, v) ((v) << (((n) % 8U) * 4U)) + +/* + * GPIOA setup: + * + * PA0 - PIN0 (input pullup). + * PA1 - RMII_REF_CLK (alternate 11). + * PA2 - RMII_MDIO (alternate 11). + * PA3 - PIN3 (input pullup). + * PA4 - PIN4 (input pullup). + * PA5 - PIN5 (input pullup). + * PA6 - PIN6 (input pullup). + * PA7 - RMII_CRS_DV (alternate 11). + * PA8 - USB_SOF MCO1 (alternate 10). + * PA9 - USB_VBUS (analog). + * PA10 - USB_ID (alternate 10). + * PA11 - USB_DM (alternate 10). + * PA12 - USB_DP (alternate 10). + * PA13 - SWDIO (alternate 0). + * PA14 - SWCLK (alternate 0). + * PA15 - T_JTDI (alternate 0). + */ +#define VAL_GPIOA_MODER (PIN_MODE_INPUT(GPIOA_PIN0) | \ + PIN_MODE_ALTERNATE(GPIOA_RMII_REF_CLK) |\ + PIN_MODE_ALTERNATE(GPIOA_RMII_MDIO) | \ + PIN_MODE_INPUT(GPIOA_PIN3) | \ + PIN_MODE_INPUT(GPIOA_PIN4) | \ + PIN_MODE_INPUT(GPIOA_PIN5) | \ + PIN_MODE_INPUT(GPIOA_PIN6) | \ + PIN_MODE_ALTERNATE(GPIOA_RMII_CRS_DV) |\ + PIN_MODE_ALTERNATE(GPIOA_USB_SOF) | \ + PIN_MODE_ANALOG(GPIOA_USB_VBUS) | \ + PIN_MODE_ALTERNATE(GPIOA_USB_ID) | \ + PIN_MODE_ALTERNATE(GPIOA_USB_DM) | \ + PIN_MODE_ALTERNATE(GPIOA_USB_DP) | \ + PIN_MODE_ALTERNATE(GPIOA_SWDIO) | \ + PIN_MODE_ALTERNATE(GPIOA_SWCLK) | \ + PIN_MODE_ALTERNATE(GPIOA_T_JTDI)) +#define VAL_GPIOA_OTYPER (PIN_OTYPE_PUSHPULL(GPIOA_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOA_RMII_REF_CLK) |\ + PIN_OTYPE_PUSHPULL(GPIOA_RMII_MDIO) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOA_RMII_CRS_DV) |\ + PIN_OTYPE_PUSHPULL(GPIOA_USB_SOF) | \ + PIN_OTYPE_PUSHPULL(GPIOA_USB_VBUS) | \ + PIN_OTYPE_PUSHPULL(GPIOA_USB_ID) | \ + PIN_OTYPE_PUSHPULL(GPIOA_USB_DM) | \ + PIN_OTYPE_PUSHPULL(GPIOA_USB_DP) | \ + PIN_OTYPE_PUSHPULL(GPIOA_SWDIO) | \ + PIN_OTYPE_PUSHPULL(GPIOA_SWCLK) | \ + PIN_OTYPE_PUSHPULL(GPIOA_T_JTDI)) +#define VAL_GPIOA_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOA_PIN0) | \ + PIN_OSPEED_HIGH(GPIOA_RMII_REF_CLK) | \ + PIN_OSPEED_HIGH(GPIOA_RMII_MDIO) | \ + PIN_OSPEED_VERYLOW(GPIOA_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOA_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOA_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOA_PIN6) | \ + PIN_OSPEED_HIGH(GPIOA_RMII_CRS_DV) | \ + PIN_OSPEED_HIGH(GPIOA_USB_SOF) | \ + PIN_OSPEED_HIGH(GPIOA_USB_VBUS) | \ + PIN_OSPEED_HIGH(GPIOA_USB_ID) | \ + PIN_OSPEED_HIGH(GPIOA_USB_DM) | \ + PIN_OSPEED_HIGH(GPIOA_USB_DP) | \ + PIN_OSPEED_HIGH(GPIOA_SWDIO) | \ + PIN_OSPEED_HIGH(GPIOA_SWCLK) | \ + PIN_OSPEED_HIGH(GPIOA_T_JTDI)) +#define VAL_GPIOA_PUPDR (PIN_PUPDR_PULLUP(GPIOA_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOA_RMII_REF_CLK) |\ + PIN_PUPDR_PULLUP(GPIOA_RMII_MDIO) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOA_RMII_CRS_DV) | \ + PIN_PUPDR_FLOATING(GPIOA_USB_SOF) | \ + PIN_PUPDR_FLOATING(GPIOA_USB_VBUS) | \ + PIN_PUPDR_FLOATING(GPIOA_USB_ID) | \ + PIN_PUPDR_FLOATING(GPIOA_USB_DM) | \ + PIN_PUPDR_FLOATING(GPIOA_USB_DP) | \ + PIN_PUPDR_FLOATING(GPIOA_SWDIO) | \ + PIN_PUPDR_FLOATING(GPIOA_SWCLK) | \ + PIN_PUPDR_PULLUP(GPIOA_T_JTDI)) +#define VAL_GPIOA_ODR (PIN_ODR_HIGH(GPIOA_PIN0) | \ + PIN_ODR_HIGH(GPIOA_RMII_REF_CLK) | \ + PIN_ODR_HIGH(GPIOA_RMII_MDIO) | \ + PIN_ODR_HIGH(GPIOA_PIN3) | \ + PIN_ODR_HIGH(GPIOA_PIN4) | \ + PIN_ODR_HIGH(GPIOA_PIN5) | \ + PIN_ODR_HIGH(GPIOA_PIN6) | \ + PIN_ODR_HIGH(GPIOA_RMII_CRS_DV) | \ + PIN_ODR_HIGH(GPIOA_USB_SOF) | \ + PIN_ODR_HIGH(GPIOA_USB_VBUS) | \ + PIN_ODR_HIGH(GPIOA_USB_ID) | \ + PIN_ODR_HIGH(GPIOA_USB_DM) | \ + PIN_ODR_HIGH(GPIOA_USB_DP) | \ + PIN_ODR_HIGH(GPIOA_SWDIO) | \ + PIN_ODR_HIGH(GPIOA_SWCLK) | \ + PIN_ODR_HIGH(GPIOA_T_JTDI)) +#define VAL_GPIOA_AFRL (PIN_AFIO_AF(GPIOA_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOA_RMII_REF_CLK, 11U) | \ + PIN_AFIO_AF(GPIOA_RMII_MDIO, 11U) | \ + PIN_AFIO_AF(GPIOA_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOA_RMII_CRS_DV, 11U)) +#define VAL_GPIOA_AFRH (PIN_AFIO_AF(GPIOA_USB_SOF, 10U) | \ + PIN_AFIO_AF(GPIOA_USB_VBUS, 0U) | \ + PIN_AFIO_AF(GPIOA_USB_ID, 10U) | \ + PIN_AFIO_AF(GPIOA_USB_DM, 10U) | \ + PIN_AFIO_AF(GPIOA_USB_DP, 10U) | \ + PIN_AFIO_AF(GPIOA_SWDIO, 0U) | \ + PIN_AFIO_AF(GPIOA_SWCLK, 0U) | \ + PIN_AFIO_AF(GPIOA_T_JTDI, 0U)) + +/* + * GPIOB setup: + * + * PB0 - LED1 LED_GREEN LED (output pushpull maximum). + * PB1 - PIN1 (input pullup). + * PB2 - PIN2 (input pullup). + * PB3 - SWO (alternate 0). + * PB4 - PIN4 (input pullup). + * PB5 - PIN5 (input pullup). + * PB6 - PIN6 (input pullup). + * PB7 - PIN7 (input pullup). + * PB8 - PIN8 (input pullup). + * PB9 - PIN9 (input pullup). + * PB10 - PIN10 (input pullup). + * PB11 - PIN11 (input pullup). + * PB12 - PIN12 (input pullup). + * PB13 - RMII_TXD1 (alternate 11). + * PB14 - LED3 LED_RED (output pushpull maximum). + * PB15 - PIN15 (input pullup). + */ +#define VAL_GPIOB_MODER (PIN_MODE_OUTPUT(GPIOB_LED1) | \ + PIN_MODE_INPUT(GPIOB_PIN1) | \ + PIN_MODE_INPUT(GPIOB_PIN2) | \ + PIN_MODE_ALTERNATE(GPIOB_SWO) | \ + PIN_MODE_INPUT(GPIOB_PIN4) | \ + PIN_MODE_INPUT(GPIOB_PIN5) | \ + PIN_MODE_INPUT(GPIOB_PIN6) | \ + PIN_MODE_INPUT(GPIOB_PIN7) | \ + PIN_MODE_INPUT(GPIOB_PIN8) | \ + PIN_MODE_INPUT(GPIOB_PIN9) | \ + PIN_MODE_INPUT(GPIOB_PIN10) | \ + PIN_MODE_INPUT(GPIOB_PIN11) | \ + PIN_MODE_INPUT(GPIOB_PIN12) | \ + PIN_MODE_ALTERNATE(GPIOB_RMII_TXD1) | \ + PIN_MODE_OUTPUT(GPIOB_LED3) | \ + PIN_MODE_INPUT(GPIOB_PIN15)) +#define VAL_GPIOB_OTYPER (PIN_OTYPE_PUSHPULL(GPIOB_LED1) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_SWO) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOB_RMII_TXD1) | \ + PIN_OTYPE_PUSHPULL(GPIOB_LED3) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN15)) +#define VAL_GPIOB_OSPEEDR (PIN_OSPEED_HIGH(GPIOB_LED1) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN1) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN2) | \ + PIN_OSPEED_HIGH(GPIOB_SWO) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN12) | \ + PIN_OSPEED_HIGH(GPIOB_RMII_TXD1) | \ + PIN_OSPEED_HIGH(GPIOB_LED3) | \ + PIN_OSPEED_VERYLOW(GPIOB_PIN15)) +#define VAL_GPIOB_PUPDR (PIN_PUPDR_FLOATING(GPIOB_LED1) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOB_SWO) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOB_RMII_TXD1) | \ + PIN_PUPDR_FLOATING(GPIOB_LED3) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN15)) +#define VAL_GPIOB_ODR (PIN_ODR_LOW(GPIOB_LED1) | \ + PIN_ODR_HIGH(GPIOB_PIN1) | \ + PIN_ODR_HIGH(GPIOB_PIN2) | \ + PIN_ODR_HIGH(GPIOB_SWO) | \ + PIN_ODR_HIGH(GPIOB_PIN4) | \ + PIN_ODR_HIGH(GPIOB_PIN5) | \ + PIN_ODR_HIGH(GPIOB_PIN6) | \ + PIN_ODR_HIGH(GPIOB_PIN7) | \ + PIN_ODR_HIGH(GPIOB_PIN8) | \ + PIN_ODR_HIGH(GPIOB_PIN9) | \ + PIN_ODR_HIGH(GPIOB_PIN10) | \ + PIN_ODR_HIGH(GPIOB_PIN11) | \ + PIN_ODR_HIGH(GPIOB_PIN12) | \ + PIN_ODR_HIGH(GPIOB_RMII_TXD1) | \ + PIN_ODR_LOW(GPIOB_LED3) | \ + PIN_ODR_HIGH(GPIOB_PIN15)) +#define VAL_GPIOB_AFRL (PIN_AFIO_AF(GPIOB_LED1, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOB_SWO, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN7, 0U)) +#define VAL_GPIOB_AFRH (PIN_AFIO_AF(GPIOB_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOB_RMII_TXD1, 11U) | \ + PIN_AFIO_AF(GPIOB_LED3, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN15, 0U)) + +/* + * GPIOC setup: + * + * PC0 - PIN0 (input pullup). + * PC1 - RMII_MDC (alternate 11). + * PC2 - PIN2 (input pullup). + * PC3 - PIN3 (input pullup). + * PC4 - RMII_RXD0 (alternate 11). + * PC5 - RMII_RXD1 (alternate 11). + * PC6 - PIN6 (input pullup). + * PC7 - PIN7 (input pullup). + * PC8 - PIN8 (input pullup). + * PC9 - PIN9 (input pullup). + * PC10 - PIN10 (input pullup). + * PC11 - PIN11 (input pullup). + * PC12 - PIN12 (input pullup). + * PC13 - BUTTON (input floating). + * PC14 - OSC32_IN (input floating). + * PC15 - OSC32_OUT (input floating). + */ +#define VAL_GPIOC_MODER (PIN_MODE_INPUT(GPIOC_PIN0) | \ + PIN_MODE_ALTERNATE(GPIOC_RMII_MDC) | \ + PIN_MODE_INPUT(GPIOC_PIN2) | \ + PIN_MODE_INPUT(GPIOC_PIN3) | \ + PIN_MODE_ALTERNATE(GPIOC_RMII_RXD0) | \ + PIN_MODE_ALTERNATE(GPIOC_RMII_RXD1) | \ + PIN_MODE_INPUT(GPIOC_PIN6) | \ + PIN_MODE_INPUT(GPIOC_PIN7) | \ + PIN_MODE_INPUT(GPIOC_PIN8) | \ + PIN_MODE_INPUT(GPIOC_PIN9) | \ + PIN_MODE_INPUT(GPIOC_PIN10) | \ + PIN_MODE_INPUT(GPIOC_PIN11) | \ + PIN_MODE_INPUT(GPIOC_PIN12) | \ + PIN_MODE_INPUT(GPIOC_BUTTON) | \ + PIN_MODE_INPUT(GPIOC_OSC32_IN) | \ + PIN_MODE_INPUT(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_OTYPER (PIN_OTYPE_PUSHPULL(GPIOC_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOC_RMII_MDC) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOC_RMII_RXD0) | \ + PIN_OTYPE_PUSHPULL(GPIOC_RMII_RXD1) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOC_BUTTON) | \ + PIN_OTYPE_PUSHPULL(GPIOC_OSC32_IN) | \ + PIN_OTYPE_PUSHPULL(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOC_PIN0) | \ + PIN_OSPEED_HIGH(GPIOC_RMII_MDC) | \ + PIN_OSPEED_VERYLOW(GPIOC_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOC_PIN3) | \ + PIN_OSPEED_HIGH(GPIOC_RMII_RXD0) | \ + PIN_OSPEED_HIGH(GPIOC_RMII_RXD1) | \ + PIN_OSPEED_VERYLOW(GPIOC_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOC_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOC_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOC_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOC_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOC_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOC_PIN12) | \ + PIN_OSPEED_HIGH(GPIOC_BUTTON) | \ + PIN_OSPEED_VERYLOW(GPIOC_OSC32_IN) | \ + PIN_OSPEED_VERYLOW(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_PUPDR (PIN_PUPDR_PULLUP(GPIOC_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOC_RMII_MDC) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOC_RMII_RXD0) | \ + PIN_PUPDR_FLOATING(GPIOC_RMII_RXD1) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOC_BUTTON) | \ + PIN_PUPDR_FLOATING(GPIOC_OSC32_IN) | \ + PIN_PUPDR_FLOATING(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_ODR (PIN_ODR_HIGH(GPIOC_PIN0) | \ + PIN_ODR_HIGH(GPIOC_RMII_MDC) | \ + PIN_ODR_HIGH(GPIOC_PIN2) | \ + PIN_ODR_HIGH(GPIOC_PIN3) | \ + PIN_ODR_HIGH(GPIOC_RMII_RXD0) | \ + PIN_ODR_HIGH(GPIOC_RMII_RXD1) | \ + PIN_ODR_HIGH(GPIOC_PIN6) | \ + PIN_ODR_HIGH(GPIOC_PIN7) | \ + PIN_ODR_HIGH(GPIOC_PIN8) | \ + PIN_ODR_HIGH(GPIOC_PIN9) | \ + PIN_ODR_HIGH(GPIOC_PIN10) | \ + PIN_ODR_HIGH(GPIOC_PIN11) | \ + PIN_ODR_HIGH(GPIOC_PIN12) | \ + PIN_ODR_HIGH(GPIOC_BUTTON) | \ + PIN_ODR_HIGH(GPIOC_OSC32_IN) | \ + PIN_ODR_HIGH(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_AFRL (PIN_AFIO_AF(GPIOC_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOC_RMII_MDC, 11U) | \ + PIN_AFIO_AF(GPIOC_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOC_RMII_RXD0, 11U) | \ + PIN_AFIO_AF(GPIOC_RMII_RXD1, 11U) | \ + PIN_AFIO_AF(GPIOC_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN7, 0U)) +#define VAL_GPIOC_AFRH (PIN_AFIO_AF(GPIOC_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOC_BUTTON, 0U) | \ + PIN_AFIO_AF(GPIOC_OSC32_IN, 0U) | \ + PIN_AFIO_AF(GPIOC_OSC32_OUT, 0U)) + +/* + * GPIOD setup: + * + * PD0 - PIN0 (input pullup). + * PD1 - PIN1 (input pullup). + * PD2 - PIN2 (input pullup). + * PD3 - PIN3 (input pullup). + * PD4 - PIN4 (input pullup). + * PD5 - PIN5 (input pullup). + * PD6 - PIN6 (input pullup). + * PD7 - PIN7 (input pullup). + * PD8 - USART3_RX STLK_RX (alternate 7). + * PD9 - USART3_TX STLK_TX (alternate 7). + * PD10 - PIN10 (input pullup). + * PD11 - PIN11 (input pullup). + * PD12 - PIN12 (input pullup). + * PD13 - PIN13 (input pullup). + * PD14 - PIN14 (input pullup). + * PD15 - PIN15 (input pullup). + */ +#define VAL_GPIOD_MODER (PIN_MODE_INPUT(GPIOD_PIN0) | \ + PIN_MODE_INPUT(GPIOD_PIN1) | \ + PIN_MODE_INPUT(GPIOD_PIN2) | \ + PIN_MODE_INPUT(GPIOD_PIN3) | \ + PIN_MODE_INPUT(GPIOD_PIN4) | \ + PIN_MODE_INPUT(GPIOD_PIN5) | \ + PIN_MODE_INPUT(GPIOD_PIN6) | \ + PIN_MODE_INPUT(GPIOD_PIN7) | \ + PIN_MODE_ALTERNATE(GPIOD_USART3_RX) | \ + PIN_MODE_ALTERNATE(GPIOD_USART3_TX) | \ + PIN_MODE_INPUT(GPIOD_PIN10) | \ + PIN_MODE_INPUT(GPIOD_PIN11) | \ + PIN_MODE_INPUT(GPIOD_PIN12) | \ + PIN_MODE_INPUT(GPIOD_PIN13) | \ + PIN_MODE_INPUT(GPIOD_PIN14) | \ + PIN_MODE_INPUT(GPIOD_PIN15)) +#define VAL_GPIOD_OTYPER (PIN_OTYPE_PUSHPULL(GPIOD_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOD_USART3_RX) | \ + PIN_OTYPE_PUSHPULL(GPIOD_USART3_TX) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN15)) +#define VAL_GPIOD_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOD_PIN0) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN1) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN7) | \ + PIN_OSPEED_HIGH(GPIOD_USART3_RX) | \ + PIN_OSPEED_HIGH(GPIOD_USART3_TX) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN12) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN13) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOD_PIN15)) +#define VAL_GPIOD_PUPDR (PIN_PUPDR_PULLUP(GPIOD_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOD_USART3_RX) | \ + PIN_PUPDR_FLOATING(GPIOD_USART3_TX) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN13) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN15)) +#define VAL_GPIOD_ODR (PIN_ODR_HIGH(GPIOD_PIN0) | \ + PIN_ODR_HIGH(GPIOD_PIN1) | \ + PIN_ODR_HIGH(GPIOD_PIN2) | \ + PIN_ODR_HIGH(GPIOD_PIN3) | \ + PIN_ODR_HIGH(GPIOD_PIN4) | \ + PIN_ODR_HIGH(GPIOD_PIN5) | \ + PIN_ODR_HIGH(GPIOD_PIN6) | \ + PIN_ODR_HIGH(GPIOD_PIN7) | \ + PIN_ODR_HIGH(GPIOD_USART3_RX) | \ + PIN_ODR_HIGH(GPIOD_USART3_TX) | \ + PIN_ODR_HIGH(GPIOD_PIN10) | \ + PIN_ODR_HIGH(GPIOD_PIN11) | \ + PIN_ODR_HIGH(GPIOD_PIN12) | \ + PIN_ODR_HIGH(GPIOD_PIN13) | \ + PIN_ODR_HIGH(GPIOD_PIN14) | \ + PIN_ODR_HIGH(GPIOD_PIN15)) +#define VAL_GPIOD_AFRL (PIN_AFIO_AF(GPIOD_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN7, 0U)) +#define VAL_GPIOD_AFRH (PIN_AFIO_AF(GPIOD_USART3_RX, 7U) | \ + PIN_AFIO_AF(GPIOD_USART3_TX, 7U) | \ + PIN_AFIO_AF(GPIOD_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN15, 0U)) + +/* + * GPIOE setup: + * + * PE0 - PIN0 (input pullup). + * PE1 - PIN1 (input pullup). + * PE2 - PIN2 (input pullup). + * PE3 - PIN3 (input pullup). + * PE4 - PIN4 (input pullup). + * PE5 - PIN5 (input pullup). + * PE6 - PIN6 (input pullup). + * PE7 - PIN7 (input pullup). + * PE8 - PIN8 (input pullup). + * PE9 - PIN9 (input pullup). + * PE10 - PIN10 (input pullup). + * PE11 - PIN11 (input pullup). + * PE12 - PIN12 (input pullup). + * PE13 - PIN13 (input pullup). + * PE14 - PIN14 (input pullup). + * PE15 - PIN15 (input pullup). + */ +#define VAL_GPIOE_MODER (PIN_MODE_INPUT(GPIOE_PIN0) | \ + PIN_MODE_OUTPUT(GPIOE_LED2) | \ + PIN_MODE_INPUT(GPIOE_PIN2) | \ + PIN_MODE_INPUT(GPIOE_PIN3) | \ + PIN_MODE_INPUT(GPIOE_PIN4) | \ + PIN_MODE_INPUT(GPIOE_PIN5) | \ + PIN_MODE_INPUT(GPIOE_PIN6) | \ + PIN_MODE_INPUT(GPIOE_PIN7) | \ + PIN_MODE_INPUT(GPIOE_PIN8) | \ + PIN_MODE_INPUT(GPIOE_PIN9) | \ + PIN_MODE_INPUT(GPIOE_PIN10) | \ + PIN_MODE_INPUT(GPIOE_PIN11) | \ + PIN_MODE_INPUT(GPIOE_PIN12) | \ + PIN_MODE_INPUT(GPIOE_PIN13) | \ + PIN_MODE_INPUT(GPIOE_PIN14) | \ + PIN_MODE_INPUT(GPIOE_PIN15)) +#define VAL_GPIOE_OTYPER (PIN_OTYPE_PUSHPULL(GPIOE_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOE_LED2) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN15)) +#define VAL_GPIOE_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOE_PIN0) | \ + PIN_OSPEED_HIGH(GPIOE_LED2) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN12) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN13) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOE_PIN15)) +#define VAL_GPIOE_PUPDR (PIN_PUPDR_PULLUP(GPIOE_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOE_LED2) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN13) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOE_PIN15)) +#define VAL_GPIOE_ODR (PIN_ODR_HIGH(GPIOE_PIN0) | \ + PIN_ODR_LOW(GPIOE_LED2) | \ + PIN_ODR_HIGH(GPIOE_PIN2) | \ + PIN_ODR_HIGH(GPIOE_PIN3) | \ + PIN_ODR_HIGH(GPIOE_PIN4) | \ + PIN_ODR_HIGH(GPIOE_PIN5) | \ + PIN_ODR_HIGH(GPIOE_PIN6) | \ + PIN_ODR_HIGH(GPIOE_PIN7) | \ + PIN_ODR_HIGH(GPIOE_PIN8) | \ + PIN_ODR_HIGH(GPIOE_PIN9) | \ + PIN_ODR_HIGH(GPIOE_PIN10) | \ + PIN_ODR_HIGH(GPIOE_PIN11) | \ + PIN_ODR_HIGH(GPIOE_PIN12) | \ + PIN_ODR_HIGH(GPIOE_PIN13) | \ + PIN_ODR_HIGH(GPIOE_PIN14) | \ + PIN_ODR_HIGH(GPIOE_PIN15)) +#define VAL_GPIOE_AFRL (PIN_AFIO_AF(GPIOE_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOE_LED2, 0U)) | \ + PIN_AFIO_AF(GPIOE_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN7, 0U) +#define VAL_GPIOE_AFRH (PIN_AFIO_AF(GPIOE_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN15, 0U)) + +/* + * GPIOF setup: + * + * PF0 - PIN0 (input pullup). + * PF1 - PIN1 (input pullup). + * PF2 - PIN2 (input pullup). + * PF3 - PIN3 (input pullup). + * PF4 - PIN4 (input pullup). + * PF5 - PIN5 (input pullup). + * PF6 - PIN6 (input pullup). + * PF7 - PIN7 (input pullup). + * PF8 - PIN8 (input pullup). + * PF9 - PIN9 (input pullup). + * PF10 - PIN10 (input pullup). + * PF11 - PIN11 (input pullup). + * PF12 - PIN12 (input pullup). + * PF13 - PIN13 (input pullup). + * PF14 - PIN14 (input pullup). + * PF15 - PIN15 (input pullup). + */ +#define VAL_GPIOF_MODER (PIN_MODE_INPUT(GPIOF_PIN0) | \ + PIN_MODE_INPUT(GPIOF_PIN1) | \ + PIN_MODE_INPUT(GPIOF_PIN2) | \ + PIN_MODE_INPUT(GPIOF_PIN3) | \ + PIN_MODE_INPUT(GPIOF_PIN4) | \ + PIN_MODE_INPUT(GPIOF_PIN5) | \ + PIN_MODE_INPUT(GPIOF_PIN6) | \ + PIN_MODE_INPUT(GPIOF_PIN7) | \ + PIN_MODE_INPUT(GPIOF_PIN8) | \ + PIN_MODE_INPUT(GPIOF_PIN9) | \ + PIN_MODE_INPUT(GPIOF_PIN10) | \ + PIN_MODE_INPUT(GPIOF_PIN11) | \ + PIN_MODE_INPUT(GPIOF_PIN12) | \ + PIN_MODE_INPUT(GPIOF_PIN13) | \ + PIN_MODE_INPUT(GPIOF_PIN14) | \ + PIN_MODE_INPUT(GPIOF_PIN15)) +#define VAL_GPIOF_OTYPER (PIN_OTYPE_PUSHPULL(GPIOF_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN15)) +#define VAL_GPIOF_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOF_PIN0) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN1) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN12) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN13) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOF_PIN15)) +#define VAL_GPIOF_PUPDR (PIN_PUPDR_PULLUP(GPIOF_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN13) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOF_PIN15)) +#define VAL_GPIOF_ODR (PIN_ODR_HIGH(GPIOF_PIN0) | \ + PIN_ODR_HIGH(GPIOF_PIN1) | \ + PIN_ODR_HIGH(GPIOF_PIN2) | \ + PIN_ODR_HIGH(GPIOF_PIN3) | \ + PIN_ODR_HIGH(GPIOF_PIN4) | \ + PIN_ODR_HIGH(GPIOF_PIN5) | \ + PIN_ODR_HIGH(GPIOF_PIN6) | \ + PIN_ODR_HIGH(GPIOF_PIN7) | \ + PIN_ODR_HIGH(GPIOF_PIN8) | \ + PIN_ODR_HIGH(GPIOF_PIN9) | \ + PIN_ODR_HIGH(GPIOF_PIN10) | \ + PIN_ODR_HIGH(GPIOF_PIN11) | \ + PIN_ODR_HIGH(GPIOF_PIN12) | \ + PIN_ODR_HIGH(GPIOF_PIN13) | \ + PIN_ODR_HIGH(GPIOF_PIN14) | \ + PIN_ODR_HIGH(GPIOF_PIN15)) +#define VAL_GPIOF_AFRL (PIN_AFIO_AF(GPIOF_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN7, 0U)) +#define VAL_GPIOF_AFRH (PIN_AFIO_AF(GPIOF_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN15, 0U)) + +/* + * GPIOG setup: + * + * PG0 - PIN0 (input pullup). + * PG1 - PIN1 (input pullup). + * PG2 - PIN2 (input pullup). + * PG3 - PIN3 (input pullup). + * PG4 - PIN4 (input pullup). + * PG5 - PIN5 (input pullup). + * PG6 - USB_FS_PWR_EN (output pushpull minimum). + * PG7 - USB_FS_OVCR (input floating). + * PG8 - PIN8 (input pullup). + * PG9 - PIN9 (input pullup). + * PG10 - PIN10 (input pullup). + * PG11 - RMII_TX_EN (alternate 11). + * PG12 - PIN12 (input pullup). + * PG13 - RMII_TXD0 (alternate 11). + * PG14 - PIN14 (input pullup). + * PG15 - PIN15 (input pullup). + */ +#define VAL_GPIOG_MODER (PIN_MODE_INPUT(GPIOG_PIN0) | \ + PIN_MODE_INPUT(GPIOG_PIN1) | \ + PIN_MODE_INPUT(GPIOG_PIN2) | \ + PIN_MODE_INPUT(GPIOG_PIN3) | \ + PIN_MODE_INPUT(GPIOG_PIN4) | \ + PIN_MODE_INPUT(GPIOG_PIN5) | \ + PIN_MODE_OUTPUT(GPIOG_USB_FS_PWR_EN) | \ + PIN_MODE_INPUT(GPIOG_USB_FS_OVCR) | \ + PIN_MODE_INPUT(GPIOG_PIN8) | \ + PIN_MODE_INPUT(GPIOG_PIN9) | \ + PIN_MODE_INPUT(GPIOG_PIN10) | \ + PIN_MODE_ALTERNATE(GPIOG_RMII_TX_EN) | \ + PIN_MODE_INPUT(GPIOG_PIN12) | \ + PIN_MODE_ALTERNATE(GPIOG_RMII_TXD0) | \ + PIN_MODE_INPUT(GPIOG_PIN14) | \ + PIN_MODE_INPUT(GPIOG_PIN15)) +#define VAL_GPIOG_OTYPER (PIN_OTYPE_PUSHPULL(GPIOG_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOG_USB_FS_PWR_EN) |\ + PIN_OTYPE_PUSHPULL(GPIOG_USB_FS_OVCR) |\ + PIN_OTYPE_PUSHPULL(GPIOG_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOG_RMII_TX_EN) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOG_RMII_TXD0) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN15)) +#define VAL_GPIOG_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOG_PIN0) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN1) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOG_USB_FS_PWR_EN) |\ + PIN_OSPEED_VERYLOW(GPIOG_USB_FS_OVCR) |\ + PIN_OSPEED_VERYLOW(GPIOG_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN10) | \ + PIN_OSPEED_HIGH(GPIOG_RMII_TX_EN) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN12) | \ + PIN_OSPEED_HIGH(GPIOG_RMII_TXD0) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN15)) +#define VAL_GPIOG_PUPDR (PIN_PUPDR_PULLUP(GPIOG_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOG_USB_FS_PWR_EN) |\ + PIN_PUPDR_FLOATING(GPIOG_USB_FS_OVCR) |\ + PIN_PUPDR_PULLUP(GPIOG_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOG_RMII_TX_EN) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOG_RMII_TXD0) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOG_PIN15)) +#define VAL_GPIOG_ODR (PIN_ODR_HIGH(GPIOG_PIN0) | \ + PIN_ODR_HIGH(GPIOG_PIN1) | \ + PIN_ODR_HIGH(GPIOG_PIN2) | \ + PIN_ODR_HIGH(GPIOG_PIN3) | \ + PIN_ODR_HIGH(GPIOG_PIN4) | \ + PIN_ODR_HIGH(GPIOG_PIN5) | \ + PIN_ODR_LOW(GPIOG_USB_FS_PWR_EN) | \ + PIN_ODR_HIGH(GPIOG_USB_FS_OVCR) | \ + PIN_ODR_HIGH(GPIOG_PIN8) | \ + PIN_ODR_HIGH(GPIOG_PIN9) | \ + PIN_ODR_HIGH(GPIOG_PIN10) | \ + PIN_ODR_HIGH(GPIOG_RMII_TX_EN) | \ + PIN_ODR_HIGH(GPIOG_PIN12) | \ + PIN_ODR_HIGH(GPIOG_RMII_TXD0) | \ + PIN_ODR_HIGH(GPIOG_PIN14) | \ + PIN_ODR_HIGH(GPIOG_PIN15)) +#define VAL_GPIOG_AFRL (PIN_AFIO_AF(GPIOG_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOG_USB_FS_PWR_EN, 0U) | \ + PIN_AFIO_AF(GPIOG_USB_FS_OVCR, 0U)) +#define VAL_GPIOG_AFRH (PIN_AFIO_AF(GPIOG_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOG_RMII_TX_EN, 11U) | \ + PIN_AFIO_AF(GPIOG_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOG_RMII_TXD0, 11U) | \ + PIN_AFIO_AF(GPIOG_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN15, 0U)) + +/* + * GPIOH setup: + * + * PH0 - OSC_IN (input floating). + * PH1 - OSC_OUT (input floating). + * PH2 - PIN2 (input pullup). + * PH3 - PIN3 (input pullup). + * PH4 - PIN4 (input pullup). + * PH5 - PIN5 (input pullup). + * PH6 - PIN6 (input pullup). + * PH7 - PIN7 (input pullup). + * PH8 - PIN8 (input pullup). + * PH9 - PIN9 (input pullup). + * PH10 - PIN10 (input pullup). + * PH11 - PIN11 (input pullup). + * PH12 - PIN12 (input pullup). + * PH13 - PIN13 (input pullup). + * PH14 - PIN14 (input pullup). + * PH15 - PIN15 (input pullup). + */ +#define VAL_GPIOH_MODER (PIN_MODE_INPUT(GPIOH_OSC_IN) | \ + PIN_MODE_INPUT(GPIOH_OSC_OUT) | \ + PIN_MODE_INPUT(GPIOH_PIN2) | \ + PIN_MODE_INPUT(GPIOH_PIN3) | \ + PIN_MODE_INPUT(GPIOH_PIN4) | \ + PIN_MODE_INPUT(GPIOH_PIN5) | \ + PIN_MODE_INPUT(GPIOH_PIN6) | \ + PIN_MODE_INPUT(GPIOH_PIN7) | \ + PIN_MODE_INPUT(GPIOH_PIN8) | \ + PIN_MODE_INPUT(GPIOH_PIN9) | \ + PIN_MODE_INPUT(GPIOH_PIN10) | \ + PIN_MODE_INPUT(GPIOH_PIN11) | \ + PIN_MODE_INPUT(GPIOH_PIN12) | \ + PIN_MODE_INPUT(GPIOH_PIN13) | \ + PIN_MODE_INPUT(GPIOH_PIN14) | \ + PIN_MODE_INPUT(GPIOH_PIN15)) +#define VAL_GPIOH_OTYPER (PIN_OTYPE_PUSHPULL(GPIOH_OSC_IN) | \ + PIN_OTYPE_PUSHPULL(GPIOH_OSC_OUT) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN15)) +#define VAL_GPIOH_OSPEEDR (PIN_OSPEED_HIGH(GPIOH_OSC_IN) | \ + PIN_OSPEED_HIGH(GPIOH_OSC_OUT) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN12) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN13) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN15)) +#define VAL_GPIOH_PUPDR (PIN_PUPDR_FLOATING(GPIOH_OSC_IN) | \ + PIN_PUPDR_FLOATING(GPIOH_OSC_OUT) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN13) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOH_PIN15)) +#define VAL_GPIOH_ODR (PIN_ODR_HIGH(GPIOH_OSC_IN) | \ + PIN_ODR_HIGH(GPIOH_OSC_OUT) | \ + PIN_ODR_HIGH(GPIOH_PIN2) | \ + PIN_ODR_HIGH(GPIOH_PIN3) | \ + PIN_ODR_HIGH(GPIOH_PIN4) | \ + PIN_ODR_HIGH(GPIOH_PIN5) | \ + PIN_ODR_HIGH(GPIOH_PIN6) | \ + PIN_ODR_HIGH(GPIOH_PIN7) | \ + PIN_ODR_HIGH(GPIOH_PIN8) | \ + PIN_ODR_HIGH(GPIOH_PIN9) | \ + PIN_ODR_HIGH(GPIOH_PIN10) | \ + PIN_ODR_HIGH(GPIOH_PIN11) | \ + PIN_ODR_HIGH(GPIOH_PIN12) | \ + PIN_ODR_HIGH(GPIOH_PIN13) | \ + PIN_ODR_HIGH(GPIOH_PIN14) | \ + PIN_ODR_HIGH(GPIOH_PIN15)) +#define VAL_GPIOH_AFRL (PIN_AFIO_AF(GPIOH_OSC_IN, 0U) | \ + PIN_AFIO_AF(GPIOH_OSC_OUT, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN7, 0U)) +#define VAL_GPIOH_AFRH (PIN_AFIO_AF(GPIOH_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN15, 0U)) + +/* + * GPIOI setup: + * + * PI0 - PIN0 (input pullup). + * PI1 - PIN1 (input pullup). + * PI2 - PIN2 (input pullup). + * PI3 - PIN3 (input pullup). + * PI4 - PIN4 (input pullup). + * PI5 - PIN5 (input pullup). + * PI6 - PIN6 (input pullup). + * PI7 - PIN7 (input pullup). + * PI8 - PIN8 (input pullup). + * PI9 - PIN9 (input pullup). + * PI10 - PIN10 (input pullup). + * PI11 - PIN11 (input pullup). + * PI12 - PIN12 (input pullup). + * PI13 - PIN13 (input pullup). + * PI14 - PIN14 (input pullup). + * PI15 - PIN15 (input pullup). + */ +#define VAL_GPIOI_MODER (PIN_MODE_INPUT(GPIOI_PIN0) | \ + PIN_MODE_INPUT(GPIOI_PIN1) | \ + PIN_MODE_INPUT(GPIOI_PIN2) | \ + PIN_MODE_INPUT(GPIOI_PIN3) | \ + PIN_MODE_INPUT(GPIOI_PIN4) | \ + PIN_MODE_INPUT(GPIOI_PIN5) | \ + PIN_MODE_INPUT(GPIOI_PIN6) | \ + PIN_MODE_INPUT(GPIOI_PIN7) | \ + PIN_MODE_INPUT(GPIOI_PIN8) | \ + PIN_MODE_INPUT(GPIOI_PIN9) | \ + PIN_MODE_INPUT(GPIOI_PIN10) | \ + PIN_MODE_INPUT(GPIOI_PIN11) | \ + PIN_MODE_INPUT(GPIOI_PIN12) | \ + PIN_MODE_INPUT(GPIOI_PIN13) | \ + PIN_MODE_INPUT(GPIOI_PIN14) | \ + PIN_MODE_INPUT(GPIOI_PIN15)) +#define VAL_GPIOI_OTYPER (PIN_OTYPE_PUSHPULL(GPIOI_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN15)) +#define VAL_GPIOI_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOI_PIN0) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN1) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN12) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN13) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOI_PIN15)) +#define VAL_GPIOI_PUPDR (PIN_PUPDR_PULLUP(GPIOI_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN13) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOI_PIN15)) +#define VAL_GPIOI_ODR (PIN_ODR_HIGH(GPIOI_PIN0) | \ + PIN_ODR_HIGH(GPIOI_PIN1) | \ + PIN_ODR_HIGH(GPIOI_PIN2) | \ + PIN_ODR_HIGH(GPIOI_PIN3) | \ + PIN_ODR_HIGH(GPIOI_PIN4) | \ + PIN_ODR_HIGH(GPIOI_PIN5) | \ + PIN_ODR_HIGH(GPIOI_PIN6) | \ + PIN_ODR_HIGH(GPIOI_PIN7) | \ + PIN_ODR_HIGH(GPIOI_PIN8) | \ + PIN_ODR_HIGH(GPIOI_PIN9) | \ + PIN_ODR_HIGH(GPIOI_PIN10) | \ + PIN_ODR_HIGH(GPIOI_PIN11) | \ + PIN_ODR_HIGH(GPIOI_PIN12) | \ + PIN_ODR_HIGH(GPIOI_PIN13) | \ + PIN_ODR_HIGH(GPIOI_PIN14) | \ + PIN_ODR_HIGH(GPIOI_PIN15)) +#define VAL_GPIOI_AFRL (PIN_AFIO_AF(GPIOI_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN7, 0U)) +#define VAL_GPIOI_AFRH (PIN_AFIO_AF(GPIOI_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOI_PIN15, 0U)) + +/* + * GPIOJ setup: + * + * PJ0 - PIN0 (input pullup). + * PJ1 - PIN1 (input pullup). + * PJ2 - PIN2 (input pullup). + * PJ3 - PIN3 (input pullup). + * PJ4 - PIN4 (input pullup). + * PJ5 - PIN5 (input pullup). + * PJ6 - PIN6 (input pullup). + * PJ7 - PIN7 (input pullup). + * PJ8 - PIN8 (input pullup). + * PJ9 - PIN9 (input pullup). + * PJ10 - PIN10 (input pullup). + * PJ11 - PIN11 (input pullup). + * PJ12 - PIN12 (input pullup). + * PJ13 - PIN13 (input pullup). + * PJ14 - PIN14 (input pullup). + * PJ15 - PIN15 (input pullup). + */ +#define VAL_GPIOJ_MODER (PIN_MODE_INPUT(GPIOJ_PIN0) | \ + PIN_MODE_INPUT(GPIOJ_PIN1) | \ + PIN_MODE_INPUT(GPIOJ_PIN2) | \ + PIN_MODE_INPUT(GPIOJ_PIN3) | \ + PIN_MODE_INPUT(GPIOJ_PIN4) | \ + PIN_MODE_INPUT(GPIOJ_PIN5) | \ + PIN_MODE_INPUT(GPIOJ_PIN6) | \ + PIN_MODE_INPUT(GPIOJ_PIN7) | \ + PIN_MODE_INPUT(GPIOJ_PIN8) | \ + PIN_MODE_INPUT(GPIOJ_PIN9) | \ + PIN_MODE_INPUT(GPIOJ_PIN10) | \ + PIN_MODE_INPUT(GPIOJ_PIN11) | \ + PIN_MODE_INPUT(GPIOJ_PIN12) | \ + PIN_MODE_INPUT(GPIOJ_PIN13) | \ + PIN_MODE_INPUT(GPIOJ_PIN14) | \ + PIN_MODE_INPUT(GPIOJ_PIN15)) +#define VAL_GPIOJ_OTYPER (PIN_OTYPE_PUSHPULL(GPIOJ_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOJ_PIN15)) +#define VAL_GPIOJ_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOJ_PIN0) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN1) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN12) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN13) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOJ_PIN15)) +#define VAL_GPIOJ_PUPDR (PIN_PUPDR_PULLUP(GPIOJ_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN13) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOJ_PIN15)) +#define VAL_GPIOJ_ODR (PIN_ODR_HIGH(GPIOJ_PIN0) | \ + PIN_ODR_HIGH(GPIOJ_PIN1) | \ + PIN_ODR_HIGH(GPIOJ_PIN2) | \ + PIN_ODR_HIGH(GPIOJ_PIN3) | \ + PIN_ODR_HIGH(GPIOJ_PIN4) | \ + PIN_ODR_HIGH(GPIOJ_PIN5) | \ + PIN_ODR_HIGH(GPIOJ_PIN6) | \ + PIN_ODR_HIGH(GPIOJ_PIN7) | \ + PIN_ODR_HIGH(GPIOJ_PIN8) | \ + PIN_ODR_HIGH(GPIOJ_PIN9) | \ + PIN_ODR_HIGH(GPIOJ_PIN10) | \ + PIN_ODR_HIGH(GPIOJ_PIN11) | \ + PIN_ODR_HIGH(GPIOJ_PIN12) | \ + PIN_ODR_HIGH(GPIOJ_PIN13) | \ + PIN_ODR_HIGH(GPIOJ_PIN14) | \ + PIN_ODR_HIGH(GPIOJ_PIN15)) +#define VAL_GPIOJ_AFRL (PIN_AFIO_AF(GPIOJ_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN7, 0U)) +#define VAL_GPIOJ_AFRH (PIN_AFIO_AF(GPIOJ_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOJ_PIN15, 0U)) + +/* + * GPIOK setup: + * + * PK0 - PIN0 (input pullup). + * PK1 - PIN1 (input pullup). + * PK2 - PIN2 (input pullup). + * PK3 - PIN3 (input pullup). + * PK4 - PIN4 (input pullup). + * PK5 - PIN5 (input pullup). + * PK6 - PIN6 (input pullup). + * PK7 - PIN7 (input pullup). + * PK8 - PIN8 (input pullup). + * PK9 - PIN9 (input pullup). + * PK10 - PIN10 (input pullup). + * PK11 - PIN11 (input pullup). + * PK12 - PIN12 (input pullup). + * PK13 - PIN13 (input pullup). + * PK14 - PIN14 (input pullup). + * PK15 - PIN15 (input pullup). + */ +#define VAL_GPIOK_MODER (PIN_MODE_INPUT(GPIOK_PIN0) | \ + PIN_MODE_INPUT(GPIOK_PIN1) | \ + PIN_MODE_INPUT(GPIOK_PIN2) | \ + PIN_MODE_INPUT(GPIOK_PIN3) | \ + PIN_MODE_INPUT(GPIOK_PIN4) | \ + PIN_MODE_INPUT(GPIOK_PIN5) | \ + PIN_MODE_INPUT(GPIOK_PIN6) | \ + PIN_MODE_INPUT(GPIOK_PIN7) | \ + PIN_MODE_INPUT(GPIOK_PIN8) | \ + PIN_MODE_INPUT(GPIOK_PIN9) | \ + PIN_MODE_INPUT(GPIOK_PIN10) | \ + PIN_MODE_INPUT(GPIOK_PIN11) | \ + PIN_MODE_INPUT(GPIOK_PIN12) | \ + PIN_MODE_INPUT(GPIOK_PIN13) | \ + PIN_MODE_INPUT(GPIOK_PIN14) | \ + PIN_MODE_INPUT(GPIOK_PIN15)) +#define VAL_GPIOK_OTYPER (PIN_OTYPE_PUSHPULL(GPIOK_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOK_PIN15)) +#define VAL_GPIOK_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOK_PIN0) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN1) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN12) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN13) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOK_PIN15)) +#define VAL_GPIOK_PUPDR (PIN_PUPDR_PULLUP(GPIOK_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN13) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOK_PIN15)) +#define VAL_GPIOK_ODR (PIN_ODR_HIGH(GPIOK_PIN0) | \ + PIN_ODR_HIGH(GPIOK_PIN1) | \ + PIN_ODR_HIGH(GPIOK_PIN2) | \ + PIN_ODR_HIGH(GPIOK_PIN3) | \ + PIN_ODR_HIGH(GPIOK_PIN4) | \ + PIN_ODR_HIGH(GPIOK_PIN5) | \ + PIN_ODR_HIGH(GPIOK_PIN6) | \ + PIN_ODR_HIGH(GPIOK_PIN7) | \ + PIN_ODR_HIGH(GPIOK_PIN8) | \ + PIN_ODR_HIGH(GPIOK_PIN9) | \ + PIN_ODR_HIGH(GPIOK_PIN10) | \ + PIN_ODR_HIGH(GPIOK_PIN11) | \ + PIN_ODR_HIGH(GPIOK_PIN12) | \ + PIN_ODR_HIGH(GPIOK_PIN13) | \ + PIN_ODR_HIGH(GPIOK_PIN14) | \ + PIN_ODR_HIGH(GPIOK_PIN15)) +#define VAL_GPIOK_AFRL (PIN_AFIO_AF(GPIOK_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN7, 0U)) +#define VAL_GPIOK_AFRH (PIN_AFIO_AF(GPIOK_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOK_PIN15, 0U)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(_FROM_ASM_) +#ifdef __cplusplus +extern "C" { +#endif + void boardInit(void); +#ifdef __cplusplus +} +#endif +#endif /* _FROM_ASM_ */ + +#endif /* BOARD_H */ diff --git a/firmware/source/board/l4/board.h b/firmware/source/board/l4/board.h new file mode 100644 index 0000000..4b2642a --- /dev/null +++ b/firmware/source/board/l4/board.h @@ -0,0 +1,1509 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * This file has been automatically generated using ChibiStudio board + * generator plugin. Do not edit manually. + */ + +#ifndef BOARD_H +#define BOARD_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* + * Setup for STMicroelectronics STM32 Nucleo64-L476RG board. + */ + +/* + * Board identifier. + */ +#define BOARD_ST_NUCLEO64_L476RG +#define BOARD_NAME "STMicroelectronics STM32 Nucleo64-L476RG" + +/* + * Board oscillators-related settings. + */ +#if !defined(STM32_LSECLK) +#define STM32_LSECLK 32768U +#endif + +#define STM32_LSEDRV (3U << 3U) + +#if !defined(STM32_HSECLK) +#define STM32_HSECLK 8000000U +#endif + +#define STM32_HSE_BYPASS + +/* + * Board voltages. + * Required for performance limits calculation. + */ +#define STM32_VDD 300U + +/* + * MCU type as defined in the ST header. + */ +#define STM32L476xx + +/* + * IO pins assignments. + */ +#define GPIOA_ARD_A0 0U +#define GPIOA_ACD12_IN5 0U +#define GPIOA_ARD_A1 1U +#define GPIOA_ACD12_IN6 1U +#define GPIOA_ARD_D1 2U +#define GPIOA_USART2_TX 2U +#define GPIOA_ARD_D0 3U +#define GPIOA_USART2_RX 3U +#define GPIOA_ARD_A2 4U +#define GPIOA_ACD12_IN9 4U +#define GPIOA_ARD_D13 5U +#define GPIOA_LED_GREEN 5U +#define GPIOA_ARD_D12 6U +#define GPIOA_ARD_D11 7U +#define GPIOA_ARD_D7 8U +#define GPIOA_ARD_D8 9U +#define GPIOA_ARD_D2 10U +#define GPIOA_PIN11 11U +#define GPIOA_PIN12 12U +#define GPIOA_SWDIO 13U +#define GPIOA_SWCLK 14U +#define GPIOA_PIN15 15U + +#define GPIOB_ARD_A3 0U +#define GPIOB_ACD12_IN15 0U +#define GPIOB_PIN1 1U +#define GPIOB_PIN2 2U +#define GPIOB_ARD_D3 3U +#define GPIOB_SWO 3U +#define GPIOB_ARD_D5 4U +#define GPIOB_ARD_D4 5U +#define GPIOB_ARD_D10 6U +#define GPIOB_PIN7 7U +#define GPIOB_ARD_D15 8U +#define GPIOB_ARD_D14 9U +#define GPIOB_ARD_D6 10U +#define GPIOB_PIN11 11U +#define GPIOB_PIN12 12U +#define GPIOB_PIN13 13U +#define GPIOB_PIN14 14U +#define GPIOB_PIN15 15U + +#define GPIOC_ARD_A5 0U +#define GPIOC_ACD123_IN1 0U +#define GPIOC_ARD_A4 1U +#define GPIOC_ACD123_IN2 1U +#define GPIOC_PIN2 2U +#define GPIOC_PIN3 3U +#define GPIOC_PIN4 4U +#define GPIOC_PIN5 5U +#define GPIOC_PIN6 6U +#define GPIOC_ARD_D9 7U +#define GPIOC_PIN8 8U +#define GPIOC_PIN9 9U +#define GPIOC_PIN10 10U +#define GPIOC_PIN11 11U +#define GPIOC_PIN12 12U +#define GPIOC_BUTTON 13U +#define GPIOC_OSC32_IN 14U +#define GPIOC_OSC32_OUT 15U + +#define GPIOD_PIN0 0U +#define GPIOD_PIN1 1U +#define GPIOD_PIN2 2U +#define GPIOD_PIN3 3U +#define GPIOD_PIN4 4U +#define GPIOD_PIN5 5U +#define GPIOD_PIN6 6U +#define GPIOD_PIN7 7U +#define GPIOD_PIN8 8U +#define GPIOD_PIN9 9U +#define GPIOD_PIN10 10U +#define GPIOD_PIN11 11U +#define GPIOD_PIN12 12U +#define GPIOD_PIN13 13U +#define GPIOD_PIN14 14U +#define GPIOD_PIN15 15U + +#define GPIOE_PIN0 0U +#define GPIOE_PIN1 1U +#define GPIOE_PIN2 2U +#define GPIOE_PIN3 3U +#define GPIOE_PIN4 4U +#define GPIOE_PIN5 5U +#define GPIOE_PIN6 6U +#define GPIOE_PIN7 7U +#define GPIOE_PIN8 8U +#define GPIOE_PIN9 9U +#define GPIOE_PIN10 10U +#define GPIOE_PIN11 11U +#define GPIOE_PIN12 12U +#define GPIOE_PIN13 13U +#define GPIOE_PIN14 14U +#define GPIOE_PIN15 15U + +#define GPIOF_PIN0 0U +#define GPIOF_PIN1 1U +#define GPIOF_PIN2 2U +#define GPIOF_PIN3 3U +#define GPIOF_PIN4 4U +#define GPIOF_PIN5 5U +#define GPIOF_PIN6 6U +#define GPIOF_PIN7 7U +#define GPIOF_PIN8 8U +#define GPIOF_PIN9 9U +#define GPIOF_PIN10 10U +#define GPIOF_PIN11 11U +#define GPIOF_PIN12 12U +#define GPIOF_PIN13 13U +#define GPIOF_PIN14 14U +#define GPIOF_PIN15 15U + +#define GPIOG_PIN0 0U +#define GPIOG_PIN1 1U +#define GPIOG_PIN2 2U +#define GPIOG_PIN3 3U +#define GPIOG_PIN4 4U +#define GPIOG_PIN5 5U +#define GPIOG_PIN6 6U +#define GPIOG_PIN7 7U +#define GPIOG_PIN8 8U +#define GPIOG_PIN9 9U +#define GPIOG_PIN10 10U +#define GPIOG_PIN11 11U +#define GPIOG_PIN12 12U +#define GPIOG_PIN13 13U +#define GPIOG_PIN14 14U +#define GPIOG_PIN15 15U + +#define GPIOH_OSC_IN 0U +#define GPIOH_OSC_OUT 1U +#define GPIOH_PIN2 2U +#define GPIOH_PIN3 3U +#define GPIOH_PIN4 4U +#define GPIOH_PIN5 5U +#define GPIOH_PIN6 6U +#define GPIOH_PIN7 7U +#define GPIOH_PIN8 8U +#define GPIOH_PIN9 9U +#define GPIOH_PIN10 10U +#define GPIOH_PIN11 11U +#define GPIOH_PIN12 12U +#define GPIOH_PIN13 13U +#define GPIOH_PIN14 14U +#define GPIOH_PIN15 15U + +/* + * IO lines assignments. + */ +#define LINE_ARD_A0 PAL_LINE(GPIOA, 0U) +#define LINE_ACD12_IN5 PAL_LINE(GPIOA, 0U) +#define LINE_ARD_A1 PAL_LINE(GPIOA, 1U) +#define LINE_ACD12_IN6 PAL_LINE(GPIOA, 1U) +#define LINE_ARD_D1 PAL_LINE(GPIOA, 2U) +#define LINE_USART2_TX PAL_LINE(GPIOA, 2U) +#define LINE_ARD_D0 PAL_LINE(GPIOA, 3U) +#define LINE_USART2_RX PAL_LINE(GPIOA, 3U) +#define LINE_ARD_A2 PAL_LINE(GPIOA, 4U) +#define LINE_ACD12_IN9 PAL_LINE(GPIOA, 4U) +#define LINE_ARD_D13 PAL_LINE(GPIOA, 5U) +//#define LINE_LED_GREEN PAL_LINE(GPIOA, 5U) +#define LINE_ARD_D12 PAL_LINE(GPIOA, 6U) +#define LINE_ARD_D11 PAL_LINE(GPIOA, 7U) +#define LINE_ARD_D7 PAL_LINE(GPIOA, 8U) +#define LINE_ARD_D8 PAL_LINE(GPIOA, 9U) +#define LINE_ARD_D2 PAL_LINE(GPIOA, 10U) +#define LINE_SWDIO PAL_LINE(GPIOA, 13U) +#define LINE_SWCLK PAL_LINE(GPIOA, 14U) +#define LINE_ARD_A3 PAL_LINE(GPIOB, 0U) +#define LINE_ACD12_IN15 PAL_LINE(GPIOB, 0U) +#define LINE_ARD_D3 PAL_LINE(GPIOB, 3U) +#define LINE_SWO PAL_LINE(GPIOB, 3U) +#define LINE_ARD_D5 PAL_LINE(GPIOB, 4U) +#define LINE_ARD_D4 PAL_LINE(GPIOB, 5U) +#define LINE_ARD_D10 PAL_LINE(GPIOB, 6U) +#define LINE_ARD_D15 PAL_LINE(GPIOB, 8U) +#define LINE_ARD_D14 PAL_LINE(GPIOB, 9U) +#define LINE_ARD_D6 PAL_LINE(GPIOB, 10U) +#define LINE_ARD_A5 PAL_LINE(GPIOC, 0U) +#define LINE_ACD123_IN1 PAL_LINE(GPIOC, 0U) +#define LINE_ARD_A4 PAL_LINE(GPIOC, 1U) +#define LINE_ACD123_IN2 PAL_LINE(GPIOC, 1U) +#define LINE_ARD_D9 PAL_LINE(GPIOC, 7U) +#define LINE_BUTTON PAL_LINE(GPIOC, 13U) +#define LINE_OSC32_IN PAL_LINE(GPIOC, 14U) +#define LINE_OSC32_OUT PAL_LINE(GPIOC, 15U) +#define LINE_OSC_IN PAL_LINE(GPIOH, 0U) +#define LINE_OSC_OUT PAL_LINE(GPIOH, 1U) + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/* + * I/O ports initial setup, this configuration is established soon after reset + * in the initialization code. + * Please refer to the STM32 Reference Manual for details. + */ +#define PIN_MODE_INPUT(n) (0U << ((n) * 2U)) +#define PIN_MODE_OUTPUT(n) (1U << ((n) * 2U)) +#define PIN_MODE_ALTERNATE(n) (2U << ((n) * 2U)) +#define PIN_MODE_ANALOG(n) (3U << ((n) * 2U)) +#define PIN_ODR_LOW(n) (0U << (n)) +#define PIN_ODR_HIGH(n) (1U << (n)) +#define PIN_OTYPE_PUSHPULL(n) (0U << (n)) +#define PIN_OTYPE_OPENDRAIN(n) (1U << (n)) +#define PIN_OSPEED_VERYLOW(n) (0U << ((n) * 2U)) +#define PIN_OSPEED_LOW(n) (1U << ((n) * 2U)) +#define PIN_OSPEED_MEDIUM(n) (2U << ((n) * 2U)) +#define PIN_OSPEED_HIGH(n) (3U << ((n) * 2U)) +#define PIN_PUPDR_FLOATING(n) (0U << ((n) * 2U)) +#define PIN_PUPDR_PULLUP(n) (1U << ((n) * 2U)) +#define PIN_PUPDR_PULLDOWN(n) (2U << ((n) * 2U)) +#define PIN_AFIO_AF(n, v) ((v) << (((n) % 8U) * 4U)) +#define PIN_ASCR_DISABLED(n) (0U << (n)) +#define PIN_ASCR_ENABLED(n) (1U << (n)) +#define PIN_LOCKR_DISABLED(n) (0U << (n)) +#define PIN_LOCKR_ENABLED(n) (1U << (n)) + +/* + * GPIOA setup: + * + * PA0 - ARD_A0 ACD12_IN5 (analog). + * PA1 - ARD_A1 ACD12_IN6 (analog). + * PA2 - ARD_D1 USART2_TX (alternate 7). + * PA3 - ARD_D0 USART2_RX (alternate 7). + * PA4 - ARD_A2 ACD12_IN9 (analog). + * PA5 - ARD_D13 LED_GREEN (output pushpull maximum). + * PA6 - ARD_D12 (analog). + * PA7 - ARD_D11 (analog). + * PA8 - ARD_D7 (analog). + * PA9 - ARD_D8 (analog). + * PA10 - ARD_D2 (analog). + * PA11 - PIN11 (analog). + * PA12 - PIN12 (analog). + * PA13 - SWDIO (alternate 0). + * PA14 - SWCLK (alternate 0). + * PA15 - PIN15 (analog). + */ +#define VAL_GPIOA_MODER (PIN_MODE_ANALOG(GPIOA_ARD_A0) | \ + PIN_MODE_ANALOG(GPIOA_ARD_A1) | \ + PIN_MODE_ALTERNATE(GPIOA_ARD_D1) | \ + PIN_MODE_ALTERNATE(GPIOA_ARD_D0) | \ + PIN_MODE_ANALOG(GPIOA_ARD_A2) | \ + PIN_MODE_OUTPUT(GPIOA_ARD_D13) | \ + PIN_MODE_ANALOG(GPIOA_ARD_D12) | \ + PIN_MODE_ANALOG(GPIOA_ARD_D11) | \ + PIN_MODE_ANALOG(GPIOA_ARD_D7) | \ + PIN_MODE_ANALOG(GPIOA_ARD_D8) | \ + PIN_MODE_ANALOG(GPIOA_ARD_D2) | \ + PIN_MODE_ANALOG(GPIOA_PIN11) | \ + PIN_MODE_ANALOG(GPIOA_PIN12) | \ + PIN_MODE_ALTERNATE(GPIOA_SWDIO) | \ + PIN_MODE_ALTERNATE(GPIOA_SWCLK) | \ + PIN_MODE_ANALOG(GPIOA_PIN15)) +#define VAL_GPIOA_OTYPER (PIN_OTYPE_PUSHPULL(GPIOA_ARD_A0) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_A1) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_D1) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_D0) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_A2) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_D13) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_D12) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_D11) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_D7) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_D8) | \ + PIN_OTYPE_PUSHPULL(GPIOA_ARD_D2) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOA_SWDIO) | \ + PIN_OTYPE_PUSHPULL(GPIOA_SWCLK) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN15)) +#define VAL_GPIOA_OSPEEDR (PIN_OSPEED_HIGH(GPIOA_ARD_A0) | \ + PIN_OSPEED_HIGH(GPIOA_ARD_A1) | \ + PIN_OSPEED_MEDIUM(GPIOA_ARD_D1) | \ + PIN_OSPEED_MEDIUM(GPIOA_ARD_D0) | \ + PIN_OSPEED_HIGH(GPIOA_ARD_A2) | \ + PIN_OSPEED_HIGH(GPIOA_ARD_D13) | \ + PIN_OSPEED_HIGH(GPIOA_ARD_D12) | \ + PIN_OSPEED_HIGH(GPIOA_ARD_D11) | \ + PIN_OSPEED_HIGH(GPIOA_ARD_D7) | \ + PIN_OSPEED_HIGH(GPIOA_ARD_D8) | \ + PIN_OSPEED_HIGH(GPIOA_ARD_D2) | \ + PIN_OSPEED_HIGH(GPIOA_PIN11) | \ + PIN_OSPEED_HIGH(GPIOA_PIN12) | \ + PIN_OSPEED_HIGH(GPIOA_SWDIO) | \ + PIN_OSPEED_HIGH(GPIOA_SWCLK) | \ + PIN_OSPEED_HIGH(GPIOA_PIN15)) +#define VAL_GPIOA_PUPDR (PIN_PUPDR_FLOATING(GPIOA_ARD_A0) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_A1) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_D1) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_D0) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_A2) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_D13) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_D12) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_D11) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_D7) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_D8) | \ + PIN_PUPDR_FLOATING(GPIOA_ARD_D2) | \ + PIN_PUPDR_FLOATING(GPIOA_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOA_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOA_SWDIO) | \ + PIN_PUPDR_PULLDOWN(GPIOA_SWCLK) | \ + PIN_PUPDR_FLOATING(GPIOA_PIN15)) +#define VAL_GPIOA_ODR (PIN_ODR_HIGH(GPIOA_ARD_A0) | \ + PIN_ODR_HIGH(GPIOA_ARD_A1) | \ + PIN_ODR_HIGH(GPIOA_ARD_D1) | \ + PIN_ODR_HIGH(GPIOA_ARD_D0) | \ + PIN_ODR_HIGH(GPIOA_ARD_A2) | \ + PIN_ODR_LOW(GPIOA_ARD_D13) | \ + PIN_ODR_HIGH(GPIOA_ARD_D12) | \ + PIN_ODR_HIGH(GPIOA_ARD_D11) | \ + PIN_ODR_HIGH(GPIOA_ARD_D7) | \ + PIN_ODR_HIGH(GPIOA_ARD_D8) | \ + PIN_ODR_HIGH(GPIOA_ARD_D2) | \ + PIN_ODR_HIGH(GPIOA_PIN11) | \ + PIN_ODR_HIGH(GPIOA_PIN12) | \ + PIN_ODR_HIGH(GPIOA_SWDIO) | \ + PIN_ODR_HIGH(GPIOA_SWCLK) | \ + PIN_ODR_HIGH(GPIOA_PIN15)) +#define VAL_GPIOA_AFRL (PIN_AFIO_AF(GPIOA_ARD_A0, 0U) | \ + PIN_AFIO_AF(GPIOA_ARD_A1, 0U) | \ + PIN_AFIO_AF(GPIOA_ARD_D1, 7U) | \ + PIN_AFIO_AF(GPIOA_ARD_D0, 7U) | \ + PIN_AFIO_AF(GPIOA_ARD_A2, 0U) | \ + PIN_AFIO_AF(GPIOA_ARD_D13, 0U) | \ + PIN_AFIO_AF(GPIOA_ARD_D12, 0U) | \ + PIN_AFIO_AF(GPIOA_ARD_D11, 0U)) +#define VAL_GPIOA_AFRH (PIN_AFIO_AF(GPIOA_ARD_D7, 0U) | \ + PIN_AFIO_AF(GPIOA_ARD_D8, 0U) | \ + PIN_AFIO_AF(GPIOA_ARD_D2, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOA_SWDIO, 0U) | \ + PIN_AFIO_AF(GPIOA_SWCLK, 0U) | \ + PIN_AFIO_AF(GPIOA_PIN15, 0U)) +#define VAL_GPIOA_ASCR (PIN_ASCR_DISABLED(GPIOA_ARD_A0) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_A1) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_D1) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_D0) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_A2) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_D13) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_D12) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_D11) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_D7) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_D8) | \ + PIN_ASCR_DISABLED(GPIOA_ARD_D2) | \ + PIN_ASCR_DISABLED(GPIOA_PIN11) | \ + PIN_ASCR_DISABLED(GPIOA_PIN12) | \ + PIN_ASCR_DISABLED(GPIOA_SWDIO) | \ + PIN_ASCR_DISABLED(GPIOA_SWCLK) | \ + PIN_ASCR_DISABLED(GPIOA_PIN15)) +#define VAL_GPIOA_LOCKR (PIN_LOCKR_DISABLED(GPIOA_ARD_A0) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_A1) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_D1) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_D0) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_A2) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_D13) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_D12) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_D11) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_D7) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_D8) | \ + PIN_LOCKR_DISABLED(GPIOA_ARD_D2) | \ + PIN_LOCKR_DISABLED(GPIOA_PIN11) | \ + PIN_LOCKR_DISABLED(GPIOA_PIN12) | \ + PIN_LOCKR_DISABLED(GPIOA_SWDIO) | \ + PIN_LOCKR_DISABLED(GPIOA_SWCLK) | \ + PIN_LOCKR_DISABLED(GPIOA_PIN15)) + +/* + * GPIOB setup: + * + * PB0 - ARD_A3 ACD12_IN15 (analog). + * PB1 - PIN1 (analog). + * PB2 - PIN2 (analog). + * PB3 - ARD_D3 SWO (analog). + * PB4 - ARD_D5 (analog). + * PB5 - ARD_D4 (analog). + * PB6 - ARD_D10 (analog). + * PB7 - PIN7 (analog). + * PB8 - ARD_D15 (analog). + * PB9 - ARD_D14 (analog). + * PB10 - ARD_D6 (analog). + * PB11 - PIN11 (analog). + * PB12 - PIN12 (analog). + * PB13 - PIN13 (analog). + * PB14 - PIN14 (analog). + * PB15 - PIN15 (analog). + */ +#define VAL_GPIOB_MODER (PIN_MODE_ANALOG(GPIOB_ARD_A3) | \ + PIN_MODE_ANALOG(GPIOB_PIN1) | \ + PIN_MODE_ANALOG(GPIOB_PIN2) | \ + PIN_MODE_ANALOG(GPIOB_ARD_D3) | \ + PIN_MODE_ANALOG(GPIOB_ARD_D5) | \ + PIN_MODE_ANALOG(GPIOB_ARD_D4) | \ + PIN_MODE_ANALOG(GPIOB_ARD_D10) | \ + PIN_MODE_ANALOG(GPIOB_PIN7) | \ + PIN_MODE_ANALOG(GPIOB_ARD_D15) | \ + PIN_MODE_ANALOG(GPIOB_ARD_D14) | \ + PIN_MODE_ANALOG(GPIOB_ARD_D6) | \ + PIN_MODE_ANALOG(GPIOB_PIN11) | \ + PIN_MODE_ANALOG(GPIOB_PIN12) | \ + PIN_MODE_ANALOG(GPIOB_PIN13) | \ + PIN_MODE_ANALOG(GPIOB_PIN14) | \ + PIN_MODE_ANALOG(GPIOB_PIN15)) +#define VAL_GPIOB_OTYPER (PIN_OTYPE_PUSHPULL(GPIOB_ARD_A3) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_ARD_D3) | \ + PIN_OTYPE_PUSHPULL(GPIOB_ARD_D5) | \ + PIN_OTYPE_PUSHPULL(GPIOB_ARD_D4) | \ + PIN_OTYPE_PUSHPULL(GPIOB_ARD_D10) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOB_ARD_D15) | \ + PIN_OTYPE_PUSHPULL(GPIOB_ARD_D14) | \ + PIN_OTYPE_PUSHPULL(GPIOB_ARD_D6) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN15)) +#define VAL_GPIOB_OSPEEDR (PIN_OSPEED_HIGH(GPIOB_ARD_A3) | \ + PIN_OSPEED_HIGH(GPIOB_PIN1) | \ + PIN_OSPEED_HIGH(GPIOB_PIN2) | \ + PIN_OSPEED_HIGH(GPIOB_ARD_D3) | \ + PIN_OSPEED_HIGH(GPIOB_ARD_D5) | \ + PIN_OSPEED_HIGH(GPIOB_ARD_D4) | \ + PIN_OSPEED_HIGH(GPIOB_ARD_D10) | \ + PIN_OSPEED_HIGH(GPIOB_PIN7) | \ + PIN_OSPEED_HIGH(GPIOB_ARD_D15) | \ + PIN_OSPEED_HIGH(GPIOB_ARD_D14) | \ + PIN_OSPEED_HIGH(GPIOB_ARD_D6) | \ + PIN_OSPEED_HIGH(GPIOB_PIN11) | \ + PIN_OSPEED_HIGH(GPIOB_PIN12) | \ + PIN_OSPEED_HIGH(GPIOB_PIN13) | \ + PIN_OSPEED_HIGH(GPIOB_PIN14) | \ + PIN_OSPEED_HIGH(GPIOB_PIN15)) +#define VAL_GPIOB_PUPDR (PIN_PUPDR_FLOATING(GPIOB_ARD_A3) | \ + PIN_PUPDR_FLOATING(GPIOB_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOB_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOB_ARD_D3) | \ + PIN_PUPDR_FLOATING(GPIOB_ARD_D5) | \ + PIN_PUPDR_FLOATING(GPIOB_ARD_D4) | \ + PIN_PUPDR_FLOATING(GPIOB_ARD_D10) | \ + PIN_PUPDR_FLOATING(GPIOB_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOB_ARD_D15) | \ + PIN_PUPDR_FLOATING(GPIOB_ARD_D14) | \ + PIN_PUPDR_FLOATING(GPIOB_ARD_D6) | \ + PIN_PUPDR_FLOATING(GPIOB_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOB_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOB_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOB_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOB_PIN15)) +#define VAL_GPIOB_ODR (PIN_ODR_HIGH(GPIOB_ARD_A3) | \ + PIN_ODR_HIGH(GPIOB_PIN1) | \ + PIN_ODR_HIGH(GPIOB_PIN2) | \ + PIN_ODR_HIGH(GPIOB_ARD_D3) | \ + PIN_ODR_HIGH(GPIOB_ARD_D5) | \ + PIN_ODR_HIGH(GPIOB_ARD_D4) | \ + PIN_ODR_HIGH(GPIOB_ARD_D10) | \ + PIN_ODR_HIGH(GPIOB_PIN7) | \ + PIN_ODR_HIGH(GPIOB_ARD_D15) | \ + PIN_ODR_HIGH(GPIOB_ARD_D14) | \ + PIN_ODR_HIGH(GPIOB_ARD_D6) | \ + PIN_ODR_HIGH(GPIOB_PIN11) | \ + PIN_ODR_HIGH(GPIOB_PIN12) | \ + PIN_ODR_HIGH(GPIOB_PIN13) | \ + PIN_ODR_HIGH(GPIOB_PIN14) | \ + PIN_ODR_HIGH(GPIOB_PIN15)) +#define VAL_GPIOB_AFRL (PIN_AFIO_AF(GPIOB_ARD_A3, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOB_ARD_D3, 0U) | \ + PIN_AFIO_AF(GPIOB_ARD_D5, 0U) | \ + PIN_AFIO_AF(GPIOB_ARD_D4, 0U) | \ + PIN_AFIO_AF(GPIOB_ARD_D10, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN7, 0U)) +#define VAL_GPIOB_AFRH (PIN_AFIO_AF(GPIOB_ARD_D15, 0U) | \ + PIN_AFIO_AF(GPIOB_ARD_D14, 0U) | \ + PIN_AFIO_AF(GPIOB_ARD_D6, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOB_PIN15, 0U)) +#define VAL_GPIOB_ASCR (PIN_ASCR_DISABLED(GPIOB_ARD_A3) | \ + PIN_ASCR_DISABLED(GPIOB_PIN1) | \ + PIN_ASCR_DISABLED(GPIOB_PIN2) | \ + PIN_ASCR_DISABLED(GPIOB_ARD_D3) | \ + PIN_ASCR_DISABLED(GPIOB_ARD_D5) | \ + PIN_ASCR_DISABLED(GPIOB_ARD_D4) | \ + PIN_ASCR_DISABLED(GPIOB_ARD_D10) | \ + PIN_ASCR_DISABLED(GPIOB_PIN7) | \ + PIN_ASCR_DISABLED(GPIOB_ARD_D15) | \ + PIN_ASCR_DISABLED(GPIOB_ARD_D14) | \ + PIN_ASCR_DISABLED(GPIOB_ARD_D6) | \ + PIN_ASCR_DISABLED(GPIOB_PIN11) | \ + PIN_ASCR_DISABLED(GPIOB_PIN12) | \ + PIN_ASCR_DISABLED(GPIOB_PIN13) | \ + PIN_ASCR_DISABLED(GPIOB_PIN14) | \ + PIN_ASCR_DISABLED(GPIOB_PIN15)) +#define VAL_GPIOB_LOCKR (PIN_LOCKR_DISABLED(GPIOB_ARD_A3) | \ + PIN_LOCKR_DISABLED(GPIOB_PIN1) | \ + PIN_LOCKR_DISABLED(GPIOB_PIN2) | \ + PIN_LOCKR_DISABLED(GPIOB_ARD_D3) | \ + PIN_LOCKR_DISABLED(GPIOB_ARD_D5) | \ + PIN_LOCKR_DISABLED(GPIOB_ARD_D4) | \ + PIN_LOCKR_DISABLED(GPIOB_ARD_D10) | \ + PIN_LOCKR_DISABLED(GPIOB_PIN7) | \ + PIN_LOCKR_DISABLED(GPIOB_ARD_D15) | \ + PIN_LOCKR_DISABLED(GPIOB_ARD_D14) | \ + PIN_LOCKR_DISABLED(GPIOB_ARD_D6) | \ + PIN_LOCKR_DISABLED(GPIOB_PIN11) | \ + PIN_LOCKR_DISABLED(GPIOB_PIN12) | \ + PIN_LOCKR_DISABLED(GPIOB_PIN13) | \ + PIN_LOCKR_DISABLED(GPIOB_PIN14) | \ + PIN_LOCKR_DISABLED(GPIOB_PIN15)) + +/* + * GPIOC setup: + * + * PC0 - ARD_A5 ACD123_IN1 (analog). + * PC1 - ARD_A4 ACD123_IN2 (analog). + * PC2 - PIN2 (analog). + * PC3 - PIN3 (analog). + * PC4 - PIN4 (analog). + * PC5 - PIN5 (analog). + * PC6 - PIN6 (analog). + * PC7 - ARD_D9 (analog). + * PC8 - PIN8 (analog). + * PC9 - PIN9 (analog). + * PC10 - PIN10 (analog). + * PC11 - PIN11 (analog). + * PC12 - PIN12 (analog). + * PC13 - BUTTON (input floating). + * PC14 - OSC32_IN (input floating). + * PC15 - OSC32_OUT (input floating). + */ +#define VAL_GPIOC_MODER (PIN_MODE_ANALOG(GPIOC_ARD_A5) | \ + PIN_MODE_ANALOG(GPIOC_ARD_A4) | \ + PIN_MODE_ANALOG(GPIOC_PIN2) | \ + PIN_MODE_ANALOG(GPIOC_PIN3) | \ + PIN_MODE_ANALOG(GPIOC_PIN4) | \ + PIN_MODE_ANALOG(GPIOC_PIN5) | \ + PIN_MODE_ANALOG(GPIOC_PIN6) | \ + PIN_MODE_ANALOG(GPIOC_ARD_D9) | \ + PIN_MODE_ANALOG(GPIOC_PIN8) | \ + PIN_MODE_ANALOG(GPIOC_PIN9) | \ + PIN_MODE_ANALOG(GPIOC_PIN10) | \ + PIN_MODE_ANALOG(GPIOC_PIN11) | \ + PIN_MODE_ANALOG(GPIOC_PIN12) | \ + PIN_MODE_INPUT(GPIOC_BUTTON) | \ + PIN_MODE_INPUT(GPIOC_OSC32_IN) | \ + PIN_MODE_INPUT(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_OTYPER (PIN_OTYPE_PUSHPULL(GPIOC_ARD_A5) | \ + PIN_OTYPE_PUSHPULL(GPIOC_ARD_A4) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOC_ARD_D9) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOC_BUTTON) | \ + PIN_OTYPE_PUSHPULL(GPIOC_OSC32_IN) | \ + PIN_OTYPE_PUSHPULL(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_OSPEEDR (PIN_OSPEED_HIGH(GPIOC_ARD_A5) | \ + PIN_OSPEED_HIGH(GPIOC_ARD_A4) | \ + PIN_OSPEED_HIGH(GPIOC_PIN2) | \ + PIN_OSPEED_HIGH(GPIOC_PIN3) | \ + PIN_OSPEED_HIGH(GPIOC_PIN4) | \ + PIN_OSPEED_HIGH(GPIOC_PIN5) | \ + PIN_OSPEED_HIGH(GPIOC_PIN6) | \ + PIN_OSPEED_HIGH(GPIOC_ARD_D9) | \ + PIN_OSPEED_HIGH(GPIOC_PIN8) | \ + PIN_OSPEED_HIGH(GPIOC_PIN9) | \ + PIN_OSPEED_HIGH(GPIOC_PIN10) | \ + PIN_OSPEED_HIGH(GPIOC_PIN11) | \ + PIN_OSPEED_HIGH(GPIOC_PIN12) | \ + PIN_OSPEED_HIGH(GPIOC_BUTTON) | \ + PIN_OSPEED_HIGH(GPIOC_OSC32_IN) | \ + PIN_OSPEED_HIGH(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_PUPDR (PIN_PUPDR_FLOATING(GPIOC_ARD_A5) | \ + PIN_PUPDR_FLOATING(GPIOC_ARD_A4) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOC_ARD_D9) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOC_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOC_BUTTON) | \ + PIN_PUPDR_FLOATING(GPIOC_OSC32_IN) | \ + PIN_PUPDR_FLOATING(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_ODR (PIN_ODR_HIGH(GPIOC_ARD_A5) | \ + PIN_ODR_HIGH(GPIOC_ARD_A4) | \ + PIN_ODR_HIGH(GPIOC_PIN2) | \ + PIN_ODR_HIGH(GPIOC_PIN3) | \ + PIN_ODR_HIGH(GPIOC_PIN4) | \ + PIN_ODR_HIGH(GPIOC_PIN5) | \ + PIN_ODR_HIGH(GPIOC_PIN6) | \ + PIN_ODR_HIGH(GPIOC_ARD_D9) | \ + PIN_ODR_HIGH(GPIOC_PIN8) | \ + PIN_ODR_HIGH(GPIOC_PIN9) | \ + PIN_ODR_HIGH(GPIOC_PIN10) | \ + PIN_ODR_HIGH(GPIOC_PIN11) | \ + PIN_ODR_HIGH(GPIOC_PIN12) | \ + PIN_ODR_HIGH(GPIOC_BUTTON) | \ + PIN_ODR_HIGH(GPIOC_OSC32_IN) | \ + PIN_ODR_HIGH(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_AFRL (PIN_AFIO_AF(GPIOC_ARD_A5, 0U) | \ + PIN_AFIO_AF(GPIOC_ARD_A4, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOC_ARD_D9, 0U)) +#define VAL_GPIOC_AFRH (PIN_AFIO_AF(GPIOC_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOC_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOC_BUTTON, 0U) | \ + PIN_AFIO_AF(GPIOC_OSC32_IN, 0U) | \ + PIN_AFIO_AF(GPIOC_OSC32_OUT, 0U)) +#define VAL_GPIOC_ASCR (PIN_ASCR_DISABLED(GPIOC_ARD_A5) | \ + PIN_ASCR_DISABLED(GPIOC_ARD_A4) | \ + PIN_ASCR_DISABLED(GPIOC_PIN2) | \ + PIN_ASCR_DISABLED(GPIOC_PIN3) | \ + PIN_ASCR_DISABLED(GPIOC_PIN4) | \ + PIN_ASCR_DISABLED(GPIOC_PIN5) | \ + PIN_ASCR_DISABLED(GPIOC_PIN6) | \ + PIN_ASCR_DISABLED(GPIOC_ARD_D9) | \ + PIN_ASCR_DISABLED(GPIOC_PIN8) | \ + PIN_ASCR_DISABLED(GPIOC_PIN9) | \ + PIN_ASCR_DISABLED(GPIOC_PIN10) | \ + PIN_ASCR_DISABLED(GPIOC_PIN11) | \ + PIN_ASCR_DISABLED(GPIOC_PIN12) | \ + PIN_ASCR_DISABLED(GPIOC_BUTTON) | \ + PIN_ASCR_DISABLED(GPIOC_OSC32_IN) | \ + PIN_ASCR_DISABLED(GPIOC_OSC32_OUT)) +#define VAL_GPIOC_LOCKR (PIN_LOCKR_DISABLED(GPIOC_ARD_A5) | \ + PIN_LOCKR_DISABLED(GPIOC_ARD_A4) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN2) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN3) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN4) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN5) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN6) | \ + PIN_LOCKR_DISABLED(GPIOC_ARD_D9) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN8) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN9) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN10) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN11) | \ + PIN_LOCKR_DISABLED(GPIOC_PIN12) | \ + PIN_LOCKR_DISABLED(GPIOC_BUTTON) | \ + PIN_LOCKR_DISABLED(GPIOC_OSC32_IN) | \ + PIN_LOCKR_DISABLED(GPIOC_OSC32_OUT)) + +/* + * GPIOD setup: + * + * PD0 - PIN0 (analog). + * PD1 - PIN1 (analog). + * PD2 - PIN2 (analog). + * PD3 - PIN3 (analog). + * PD4 - PIN4 (analog). + * PD5 - PIN5 (analog). + * PD6 - PIN6 (analog). + * PD7 - PIN7 (analog). + * PD8 - PIN8 (analog). + * PD9 - PIN9 (analog). + * PD10 - PIN10 (analog). + * PD11 - PIN11 (analog). + * PD12 - PIN12 (analog). + * PD13 - PIN13 (analog). + * PD14 - PIN14 (analog). + * PD15 - PIN15 (analog). + */ +#define VAL_GPIOD_MODER (PIN_MODE_ANALOG(GPIOD_PIN0) | \ + PIN_MODE_ANALOG(GPIOD_PIN1) | \ + PIN_MODE_ANALOG(GPIOD_PIN2) | \ + PIN_MODE_ANALOG(GPIOD_PIN3) | \ + PIN_MODE_ANALOG(GPIOD_PIN4) | \ + PIN_MODE_ANALOG(GPIOD_PIN5) | \ + PIN_MODE_ANALOG(GPIOD_PIN6) | \ + PIN_MODE_ANALOG(GPIOD_PIN7) | \ + PIN_MODE_ANALOG(GPIOD_PIN8) | \ + PIN_MODE_ANALOG(GPIOD_PIN9) | \ + PIN_MODE_ANALOG(GPIOD_PIN10) | \ + PIN_MODE_ANALOG(GPIOD_PIN11) | \ + PIN_MODE_ANALOG(GPIOD_PIN12) | \ + PIN_MODE_ANALOG(GPIOD_PIN13) | \ + PIN_MODE_ANALOG(GPIOD_PIN14) | \ + PIN_MODE_ANALOG(GPIOD_PIN15)) +#define VAL_GPIOD_OTYPER (PIN_OTYPE_PUSHPULL(GPIOD_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN15)) +#define VAL_GPIOD_OSPEEDR (PIN_OSPEED_HIGH(GPIOD_PIN0) | \ + PIN_OSPEED_HIGH(GPIOD_PIN1) | \ + PIN_OSPEED_HIGH(GPIOD_PIN2) | \ + PIN_OSPEED_HIGH(GPIOD_PIN3) | \ + PIN_OSPEED_HIGH(GPIOD_PIN4) | \ + PIN_OSPEED_HIGH(GPIOD_PIN5) | \ + PIN_OSPEED_HIGH(GPIOD_PIN6) | \ + PIN_OSPEED_HIGH(GPIOD_PIN7) | \ + PIN_OSPEED_HIGH(GPIOD_PIN8) | \ + PIN_OSPEED_HIGH(GPIOD_PIN9) | \ + PIN_OSPEED_HIGH(GPIOD_PIN10) | \ + PIN_OSPEED_HIGH(GPIOD_PIN11) | \ + PIN_OSPEED_HIGH(GPIOD_PIN12) | \ + PIN_OSPEED_HIGH(GPIOD_PIN13) | \ + PIN_OSPEED_HIGH(GPIOD_PIN14) | \ + PIN_OSPEED_HIGH(GPIOD_PIN15)) +#define VAL_GPIOD_PUPDR (PIN_PUPDR_FLOATING(GPIOD_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN15)) +#define VAL_GPIOD_ODR (PIN_ODR_HIGH(GPIOD_PIN0) | \ + PIN_ODR_HIGH(GPIOD_PIN1) | \ + PIN_ODR_HIGH(GPIOD_PIN2) | \ + PIN_ODR_HIGH(GPIOD_PIN3) | \ + PIN_ODR_HIGH(GPIOD_PIN4) | \ + PIN_ODR_HIGH(GPIOD_PIN5) | \ + PIN_ODR_HIGH(GPIOD_PIN6) | \ + PIN_ODR_HIGH(GPIOD_PIN7) | \ + PIN_ODR_HIGH(GPIOD_PIN8) | \ + PIN_ODR_HIGH(GPIOD_PIN9) | \ + PIN_ODR_HIGH(GPIOD_PIN10) | \ + PIN_ODR_HIGH(GPIOD_PIN11) | \ + PIN_ODR_HIGH(GPIOD_PIN12) | \ + PIN_ODR_HIGH(GPIOD_PIN13) | \ + PIN_ODR_HIGH(GPIOD_PIN14) | \ + PIN_ODR_HIGH(GPIOD_PIN15)) +#define VAL_GPIOD_AFRL (PIN_AFIO_AF(GPIOD_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN7, 0U)) +#define VAL_GPIOD_AFRH (PIN_AFIO_AF(GPIOD_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOD_PIN15, 0U)) +#define VAL_GPIOD_ASCR (PIN_ASCR_DISABLED(GPIOD_PIN0) | \ + PIN_ASCR_DISABLED(GPIOD_PIN1) | \ + PIN_ASCR_DISABLED(GPIOD_PIN2) | \ + PIN_ASCR_DISABLED(GPIOD_PIN3) | \ + PIN_ASCR_DISABLED(GPIOD_PIN4) | \ + PIN_ASCR_DISABLED(GPIOD_PIN5) | \ + PIN_ASCR_DISABLED(GPIOD_PIN6) | \ + PIN_ASCR_DISABLED(GPIOD_PIN7) | \ + PIN_ASCR_DISABLED(GPIOD_PIN8) | \ + PIN_ASCR_DISABLED(GPIOD_PIN9) | \ + PIN_ASCR_DISABLED(GPIOD_PIN10) | \ + PIN_ASCR_DISABLED(GPIOD_PIN11) | \ + PIN_ASCR_DISABLED(GPIOD_PIN12) | \ + PIN_ASCR_DISABLED(GPIOD_PIN13) | \ + PIN_ASCR_DISABLED(GPIOD_PIN14) | \ + PIN_ASCR_DISABLED(GPIOD_PIN15)) +#define VAL_GPIOD_LOCKR (PIN_LOCKR_DISABLED(GPIOD_PIN0) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN1) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN2) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN3) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN4) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN5) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN6) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN7) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN8) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN9) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN10) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN11) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN12) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN13) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN14) | \ + PIN_LOCKR_DISABLED(GPIOD_PIN15)) + +/* + * GPIOE setup: + * + * PE0 - PIN0 (analog). + * PE1 - PIN1 (analog). + * PE2 - PIN2 (analog). + * PE3 - PIN3 (analog). + * PE4 - PIN4 (analog). + * PE5 - PIN5 (analog). + * PE6 - PIN6 (analog). + * PE7 - PIN7 (analog). + * PE8 - PIN8 (analog). + * PE9 - PIN9 (analog). + * PE10 - PIN10 (analog). + * PE11 - PIN11 (analog). + * PE12 - PIN12 (analog). + * PE13 - PIN13 (analog). + * PE14 - PIN14 (analog). + * PE15 - PIN15 (analog). + */ +#define VAL_GPIOE_MODER (PIN_MODE_ANALOG(GPIOE_PIN0) | \ + PIN_MODE_ANALOG(GPIOE_PIN1) | \ + PIN_MODE_ANALOG(GPIOE_PIN2) | \ + PIN_MODE_ANALOG(GPIOE_PIN3) | \ + PIN_MODE_ANALOG(GPIOE_PIN4) | \ + PIN_MODE_ANALOG(GPIOE_PIN5) | \ + PIN_MODE_ANALOG(GPIOE_PIN6) | \ + PIN_MODE_ANALOG(GPIOE_PIN7) | \ + PIN_MODE_ANALOG(GPIOE_PIN8) | \ + PIN_MODE_ANALOG(GPIOE_PIN9) | \ + PIN_MODE_ANALOG(GPIOE_PIN10) | \ + PIN_MODE_ANALOG(GPIOE_PIN11) | \ + PIN_MODE_ANALOG(GPIOE_PIN12) | \ + PIN_MODE_ANALOG(GPIOE_PIN13) | \ + PIN_MODE_ANALOG(GPIOE_PIN14) | \ + PIN_MODE_ANALOG(GPIOE_PIN15)) +#define VAL_GPIOE_OTYPER (PIN_OTYPE_PUSHPULL(GPIOE_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN15)) +#define VAL_GPIOE_OSPEEDR (PIN_OSPEED_HIGH(GPIOE_PIN0) | \ + PIN_OSPEED_HIGH(GPIOE_PIN1) | \ + PIN_OSPEED_HIGH(GPIOE_PIN2) | \ + PIN_OSPEED_HIGH(GPIOE_PIN3) | \ + PIN_OSPEED_HIGH(GPIOE_PIN4) | \ + PIN_OSPEED_HIGH(GPIOE_PIN5) | \ + PIN_OSPEED_HIGH(GPIOE_PIN6) | \ + PIN_OSPEED_HIGH(GPIOE_PIN7) | \ + PIN_OSPEED_HIGH(GPIOE_PIN8) | \ + PIN_OSPEED_HIGH(GPIOE_PIN9) | \ + PIN_OSPEED_HIGH(GPIOE_PIN10) | \ + PIN_OSPEED_HIGH(GPIOE_PIN11) | \ + PIN_OSPEED_HIGH(GPIOE_PIN12) | \ + PIN_OSPEED_HIGH(GPIOE_PIN13) | \ + PIN_OSPEED_HIGH(GPIOE_PIN14) | \ + PIN_OSPEED_HIGH(GPIOE_PIN15)) +#define VAL_GPIOE_PUPDR (PIN_PUPDR_FLOATING(GPIOE_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN15)) +#define VAL_GPIOE_ODR (PIN_ODR_HIGH(GPIOE_PIN0) | \ + PIN_ODR_HIGH(GPIOE_PIN1) | \ + PIN_ODR_HIGH(GPIOE_PIN2) | \ + PIN_ODR_HIGH(GPIOE_PIN3) | \ + PIN_ODR_HIGH(GPIOE_PIN4) | \ + PIN_ODR_HIGH(GPIOE_PIN5) | \ + PIN_ODR_HIGH(GPIOE_PIN6) | \ + PIN_ODR_HIGH(GPIOE_PIN7) | \ + PIN_ODR_HIGH(GPIOE_PIN8) | \ + PIN_ODR_HIGH(GPIOE_PIN9) | \ + PIN_ODR_HIGH(GPIOE_PIN10) | \ + PIN_ODR_HIGH(GPIOE_PIN11) | \ + PIN_ODR_HIGH(GPIOE_PIN12) | \ + PIN_ODR_HIGH(GPIOE_PIN13) | \ + PIN_ODR_HIGH(GPIOE_PIN14) | \ + PIN_ODR_HIGH(GPIOE_PIN15)) +#define VAL_GPIOE_AFRL (PIN_AFIO_AF(GPIOE_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN7, 0U)) +#define VAL_GPIOE_AFRH (PIN_AFIO_AF(GPIOE_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOE_PIN15, 0U)) +#define VAL_GPIOE_ASCR (PIN_ASCR_DISABLED(GPIOE_PIN0) | \ + PIN_ASCR_DISABLED(GPIOE_PIN1) | \ + PIN_ASCR_DISABLED(GPIOE_PIN2) | \ + PIN_ASCR_DISABLED(GPIOE_PIN3) | \ + PIN_ASCR_DISABLED(GPIOE_PIN4) | \ + PIN_ASCR_DISABLED(GPIOE_PIN5) | \ + PIN_ASCR_DISABLED(GPIOE_PIN6) | \ + PIN_ASCR_DISABLED(GPIOE_PIN7) | \ + PIN_ASCR_DISABLED(GPIOE_PIN8) | \ + PIN_ASCR_DISABLED(GPIOE_PIN9) | \ + PIN_ASCR_DISABLED(GPIOE_PIN10) | \ + PIN_ASCR_DISABLED(GPIOE_PIN11) | \ + PIN_ASCR_DISABLED(GPIOE_PIN12) | \ + PIN_ASCR_DISABLED(GPIOE_PIN13) | \ + PIN_ASCR_DISABLED(GPIOE_PIN14) | \ + PIN_ASCR_DISABLED(GPIOE_PIN15)) +#define VAL_GPIOE_LOCKR (PIN_LOCKR_DISABLED(GPIOE_PIN0) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN1) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN2) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN3) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN4) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN5) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN6) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN7) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN8) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN9) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN10) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN11) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN12) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN13) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN14) | \ + PIN_LOCKR_DISABLED(GPIOE_PIN15)) + +/* + * GPIOF setup: + * + * PF0 - PIN0 (analog). + * PF1 - PIN1 (analog). + * PF2 - PIN2 (analog). + * PF3 - PIN3 (analog). + * PF4 - PIN4 (analog). + * PF5 - PIN5 (analog). + * PF6 - PIN6 (analog). + * PF7 - PIN7 (analog). + * PF8 - PIN8 (analog). + * PF9 - PIN9 (analog). + * PF10 - PIN10 (analog). + * PF11 - PIN11 (analog). + * PF12 - PIN12 (analog). + * PF13 - PIN13 (analog). + * PF14 - PIN14 (analog). + * PF15 - PIN15 (analog). + */ +#define VAL_GPIOF_MODER (PIN_MODE_ANALOG(GPIOF_PIN0) | \ + PIN_MODE_ANALOG(GPIOF_PIN1) | \ + PIN_MODE_ANALOG(GPIOF_PIN2) | \ + PIN_MODE_ANALOG(GPIOF_PIN3) | \ + PIN_MODE_ANALOG(GPIOF_PIN4) | \ + PIN_MODE_ANALOG(GPIOF_PIN5) | \ + PIN_MODE_ANALOG(GPIOF_PIN6) | \ + PIN_MODE_ANALOG(GPIOF_PIN7) | \ + PIN_MODE_ANALOG(GPIOF_PIN8) | \ + PIN_MODE_ANALOG(GPIOF_PIN9) | \ + PIN_MODE_ANALOG(GPIOF_PIN10) | \ + PIN_MODE_ANALOG(GPIOF_PIN11) | \ + PIN_MODE_ANALOG(GPIOF_PIN12) | \ + PIN_MODE_ANALOG(GPIOF_PIN13) | \ + PIN_MODE_ANALOG(GPIOF_PIN14) | \ + PIN_MODE_ANALOG(GPIOF_PIN15)) +#define VAL_GPIOF_OTYPER (PIN_OTYPE_PUSHPULL(GPIOF_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN15)) +#define VAL_GPIOF_OSPEEDR (PIN_OSPEED_HIGH(GPIOF_PIN0) | \ + PIN_OSPEED_HIGH(GPIOF_PIN1) | \ + PIN_OSPEED_HIGH(GPIOF_PIN2) | \ + PIN_OSPEED_HIGH(GPIOF_PIN3) | \ + PIN_OSPEED_HIGH(GPIOF_PIN4) | \ + PIN_OSPEED_HIGH(GPIOF_PIN5) | \ + PIN_OSPEED_HIGH(GPIOF_PIN6) | \ + PIN_OSPEED_HIGH(GPIOF_PIN7) | \ + PIN_OSPEED_HIGH(GPIOF_PIN8) | \ + PIN_OSPEED_HIGH(GPIOF_PIN9) | \ + PIN_OSPEED_HIGH(GPIOF_PIN10) | \ + PIN_OSPEED_HIGH(GPIOF_PIN11) | \ + PIN_OSPEED_HIGH(GPIOF_PIN12) | \ + PIN_OSPEED_HIGH(GPIOF_PIN13) | \ + PIN_OSPEED_HIGH(GPIOF_PIN14) | \ + PIN_OSPEED_HIGH(GPIOF_PIN15)) +#define VAL_GPIOF_PUPDR (PIN_PUPDR_FLOATING(GPIOF_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN15)) +#define VAL_GPIOF_ODR (PIN_ODR_HIGH(GPIOF_PIN0) | \ + PIN_ODR_HIGH(GPIOF_PIN1) | \ + PIN_ODR_HIGH(GPIOF_PIN2) | \ + PIN_ODR_HIGH(GPIOF_PIN3) | \ + PIN_ODR_HIGH(GPIOF_PIN4) | \ + PIN_ODR_HIGH(GPIOF_PIN5) | \ + PIN_ODR_HIGH(GPIOF_PIN6) | \ + PIN_ODR_HIGH(GPIOF_PIN7) | \ + PIN_ODR_HIGH(GPIOF_PIN8) | \ + PIN_ODR_HIGH(GPIOF_PIN9) | \ + PIN_ODR_HIGH(GPIOF_PIN10) | \ + PIN_ODR_HIGH(GPIOF_PIN11) | \ + PIN_ODR_HIGH(GPIOF_PIN12) | \ + PIN_ODR_HIGH(GPIOF_PIN13) | \ + PIN_ODR_HIGH(GPIOF_PIN14) | \ + PIN_ODR_HIGH(GPIOF_PIN15)) +#define VAL_GPIOF_AFRL (PIN_AFIO_AF(GPIOF_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN7, 0U)) +#define VAL_GPIOF_AFRH (PIN_AFIO_AF(GPIOF_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOF_PIN15, 0U)) +#define VAL_GPIOF_ASCR (PIN_ASCR_DISABLED(GPIOF_PIN0) | \ + PIN_ASCR_DISABLED(GPIOF_PIN1) | \ + PIN_ASCR_DISABLED(GPIOF_PIN2) | \ + PIN_ASCR_DISABLED(GPIOF_PIN3) | \ + PIN_ASCR_DISABLED(GPIOF_PIN4) | \ + PIN_ASCR_DISABLED(GPIOF_PIN5) | \ + PIN_ASCR_DISABLED(GPIOF_PIN6) | \ + PIN_ASCR_DISABLED(GPIOF_PIN7) | \ + PIN_ASCR_DISABLED(GPIOF_PIN8) | \ + PIN_ASCR_DISABLED(GPIOF_PIN9) | \ + PIN_ASCR_DISABLED(GPIOF_PIN10) | \ + PIN_ASCR_DISABLED(GPIOF_PIN11) | \ + PIN_ASCR_DISABLED(GPIOF_PIN12) | \ + PIN_ASCR_DISABLED(GPIOF_PIN13) | \ + PIN_ASCR_DISABLED(GPIOF_PIN14) | \ + PIN_ASCR_DISABLED(GPIOF_PIN15)) +#define VAL_GPIOF_LOCKR (PIN_LOCKR_DISABLED(GPIOF_PIN0) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN1) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN2) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN3) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN4) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN5) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN6) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN7) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN8) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN9) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN10) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN11) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN12) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN13) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN14) | \ + PIN_LOCKR_DISABLED(GPIOF_PIN15)) + +/* + * GPIOG setup: + * + * PG0 - PIN0 (analog). + * PG1 - PIN1 (analog). + * PG2 - PIN2 (analog). + * PG3 - PIN3 (analog). + * PG4 - PIN4 (analog). + * PG5 - PIN5 (analog). + * PG6 - PIN6 (analog). + * PG7 - PIN7 (analog). + * PG8 - PIN8 (analog). + * PG9 - PIN9 (analog). + * PG10 - PIN10 (analog). + * PG11 - PIN11 (analog). + * PG12 - PIN12 (analog). + * PG13 - PIN13 (analog). + * PG14 - PIN14 (analog). + * PG15 - PIN15 (analog). + */ +#define VAL_GPIOG_MODER (PIN_MODE_ANALOG(GPIOG_PIN0) | \ + PIN_MODE_ANALOG(GPIOG_PIN1) | \ + PIN_MODE_ANALOG(GPIOG_PIN2) | \ + PIN_MODE_ANALOG(GPIOG_PIN3) | \ + PIN_MODE_ANALOG(GPIOG_PIN4) | \ + PIN_MODE_ANALOG(GPIOG_PIN5) | \ + PIN_MODE_ANALOG(GPIOG_PIN6) | \ + PIN_MODE_ANALOG(GPIOG_PIN7) | \ + PIN_MODE_ANALOG(GPIOG_PIN8) | \ + PIN_MODE_ANALOG(GPIOG_PIN9) | \ + PIN_MODE_ANALOG(GPIOG_PIN10) | \ + PIN_MODE_ANALOG(GPIOG_PIN11) | \ + PIN_MODE_ANALOG(GPIOG_PIN12) | \ + PIN_MODE_ANALOG(GPIOG_PIN13) | \ + PIN_MODE_ANALOG(GPIOG_PIN14) | \ + PIN_MODE_ANALOG(GPIOG_PIN15)) +#define VAL_GPIOG_OTYPER (PIN_OTYPE_PUSHPULL(GPIOG_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN15)) +#define VAL_GPIOG_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOG_PIN0) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN1) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN12) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN13) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOG_PIN15)) +#define VAL_GPIOG_PUPDR (PIN_PUPDR_FLOATING(GPIOG_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN15)) +#define VAL_GPIOG_ODR (PIN_ODR_HIGH(GPIOG_PIN0) | \ + PIN_ODR_HIGH(GPIOG_PIN1) | \ + PIN_ODR_HIGH(GPIOG_PIN2) | \ + PIN_ODR_HIGH(GPIOG_PIN3) | \ + PIN_ODR_HIGH(GPIOG_PIN4) | \ + PIN_ODR_HIGH(GPIOG_PIN5) | \ + PIN_ODR_HIGH(GPIOG_PIN6) | \ + PIN_ODR_HIGH(GPIOG_PIN7) | \ + PIN_ODR_HIGH(GPIOG_PIN8) | \ + PIN_ODR_HIGH(GPIOG_PIN9) | \ + PIN_ODR_HIGH(GPIOG_PIN10) | \ + PIN_ODR_HIGH(GPIOG_PIN11) | \ + PIN_ODR_HIGH(GPIOG_PIN12) | \ + PIN_ODR_HIGH(GPIOG_PIN13) | \ + PIN_ODR_HIGH(GPIOG_PIN14) | \ + PIN_ODR_HIGH(GPIOG_PIN15)) +#define VAL_GPIOG_AFRL (PIN_AFIO_AF(GPIOG_PIN0, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN1, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN7, 0U)) +#define VAL_GPIOG_AFRH (PIN_AFIO_AF(GPIOG_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOG_PIN15, 0U)) +#define VAL_GPIOG_ASCR (PIN_ASCR_DISABLED(GPIOG_PIN0) | \ + PIN_ASCR_DISABLED(GPIOG_PIN1) | \ + PIN_ASCR_DISABLED(GPIOG_PIN2) | \ + PIN_ASCR_DISABLED(GPIOG_PIN3) | \ + PIN_ASCR_DISABLED(GPIOG_PIN4) | \ + PIN_ASCR_DISABLED(GPIOG_PIN5) | \ + PIN_ASCR_DISABLED(GPIOG_PIN6) | \ + PIN_ASCR_DISABLED(GPIOG_PIN7) | \ + PIN_ASCR_DISABLED(GPIOG_PIN8) | \ + PIN_ASCR_DISABLED(GPIOG_PIN9) | \ + PIN_ASCR_DISABLED(GPIOG_PIN10) | \ + PIN_ASCR_DISABLED(GPIOG_PIN11) | \ + PIN_ASCR_DISABLED(GPIOG_PIN12) | \ + PIN_ASCR_DISABLED(GPIOG_PIN13) | \ + PIN_ASCR_DISABLED(GPIOG_PIN14) | \ + PIN_ASCR_DISABLED(GPIOG_PIN15)) +#define VAL_GPIOG_LOCKR (PIN_LOCKR_DISABLED(GPIOG_PIN0) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN1) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN2) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN3) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN4) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN5) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN6) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN7) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN8) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN9) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN10) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN11) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN12) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN13) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN14) | \ + PIN_LOCKR_DISABLED(GPIOG_PIN15)) + +/* + * GPIOH setup: + * + * PH0 - OSC_IN (input floating). + * PH1 - OSC_OUT (input floating). + * PH2 - PIN2 (analog). + * PH3 - PIN3 (analog). + * PH4 - PIN4 (analog). + * PH5 - PIN5 (analog). + * PH6 - PIN6 (analog). + * PH7 - PIN7 (analog). + * PH8 - PIN8 (analog). + * PH9 - PIN9 (analog). + * PH10 - PIN10 (analog). + * PH11 - PIN11 (analog). + * PH12 - PIN12 (analog). + * PH13 - PIN13 (analog). + * PH14 - PIN14 (analog). + * PH15 - PIN15 (analog). + */ +#define VAL_GPIOH_MODER (PIN_MODE_INPUT(GPIOH_OSC_IN) | \ + PIN_MODE_INPUT(GPIOH_OSC_OUT) | \ + PIN_MODE_ANALOG(GPIOH_PIN2) | \ + PIN_MODE_ANALOG(GPIOH_PIN3) | \ + PIN_MODE_ANALOG(GPIOH_PIN4) | \ + PIN_MODE_ANALOG(GPIOH_PIN5) | \ + PIN_MODE_ANALOG(GPIOH_PIN6) | \ + PIN_MODE_ANALOG(GPIOH_PIN7) | \ + PIN_MODE_ANALOG(GPIOH_PIN8) | \ + PIN_MODE_ANALOG(GPIOH_PIN9) | \ + PIN_MODE_ANALOG(GPIOH_PIN10) | \ + PIN_MODE_ANALOG(GPIOH_PIN11) | \ + PIN_MODE_ANALOG(GPIOH_PIN12) | \ + PIN_MODE_ANALOG(GPIOH_PIN13) | \ + PIN_MODE_ANALOG(GPIOH_PIN14) | \ + PIN_MODE_ANALOG(GPIOH_PIN15)) +#define VAL_GPIOH_OTYPER (PIN_OTYPE_PUSHPULL(GPIOH_OSC_IN) | \ + PIN_OTYPE_PUSHPULL(GPIOH_OSC_OUT) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN15)) +#define VAL_GPIOH_OSPEEDR (PIN_OSPEED_HIGH(GPIOH_OSC_IN) | \ + PIN_OSPEED_HIGH(GPIOH_OSC_OUT) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN2) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN3) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN4) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN5) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN6) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN7) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN8) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN9) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN10) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN11) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN12) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN13) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN14) | \ + PIN_OSPEED_VERYLOW(GPIOH_PIN15)) +#define VAL_GPIOH_PUPDR (PIN_PUPDR_FLOATING(GPIOH_OSC_IN) | \ + PIN_PUPDR_FLOATING(GPIOH_OSC_OUT) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN15)) +#define VAL_GPIOH_ODR (PIN_ODR_HIGH(GPIOH_OSC_IN) | \ + PIN_ODR_HIGH(GPIOH_OSC_OUT) | \ + PIN_ODR_HIGH(GPIOH_PIN2) | \ + PIN_ODR_HIGH(GPIOH_PIN3) | \ + PIN_ODR_HIGH(GPIOH_PIN4) | \ + PIN_ODR_HIGH(GPIOH_PIN5) | \ + PIN_ODR_HIGH(GPIOH_PIN6) | \ + PIN_ODR_HIGH(GPIOH_PIN7) | \ + PIN_ODR_HIGH(GPIOH_PIN8) | \ + PIN_ODR_HIGH(GPIOH_PIN9) | \ + PIN_ODR_HIGH(GPIOH_PIN10) | \ + PIN_ODR_HIGH(GPIOH_PIN11) | \ + PIN_ODR_HIGH(GPIOH_PIN12) | \ + PIN_ODR_HIGH(GPIOH_PIN13) | \ + PIN_ODR_HIGH(GPIOH_PIN14) | \ + PIN_ODR_HIGH(GPIOH_PIN15)) +#define VAL_GPIOH_AFRL (PIN_AFIO_AF(GPIOH_OSC_IN, 0U) | \ + PIN_AFIO_AF(GPIOH_OSC_OUT, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN2, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN3, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN4, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN5, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN6, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN7, 0U)) +#define VAL_GPIOH_AFRH (PIN_AFIO_AF(GPIOH_PIN8, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN9, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN10, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN11, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN12, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN13, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN14, 0U) | \ + PIN_AFIO_AF(GPIOH_PIN15, 0U)) +#define VAL_GPIOH_ASCR (PIN_ASCR_DISABLED(GPIOH_OSC_IN) | \ + PIN_ASCR_DISABLED(GPIOH_OSC_OUT) | \ + PIN_ASCR_DISABLED(GPIOH_PIN2) | \ + PIN_ASCR_DISABLED(GPIOH_PIN3) | \ + PIN_ASCR_DISABLED(GPIOH_PIN4) | \ + PIN_ASCR_DISABLED(GPIOH_PIN5) | \ + PIN_ASCR_DISABLED(GPIOH_PIN6) | \ + PIN_ASCR_DISABLED(GPIOH_PIN7) | \ + PIN_ASCR_DISABLED(GPIOH_PIN8) | \ + PIN_ASCR_DISABLED(GPIOH_PIN9) | \ + PIN_ASCR_DISABLED(GPIOH_PIN10) | \ + PIN_ASCR_DISABLED(GPIOH_PIN11) | \ + PIN_ASCR_DISABLED(GPIOH_PIN12) | \ + PIN_ASCR_DISABLED(GPIOH_PIN13) | \ + PIN_ASCR_DISABLED(GPIOH_PIN14) | \ + PIN_ASCR_DISABLED(GPIOH_PIN15)) +#define VAL_GPIOH_LOCKR (PIN_LOCKR_DISABLED(GPIOH_OSC_IN) | \ + PIN_LOCKR_DISABLED(GPIOH_OSC_OUT) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN2) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN3) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN4) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN5) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN6) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN7) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN8) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN9) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN10) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN11) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN12) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN13) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN14) | \ + PIN_LOCKR_DISABLED(GPIOH_PIN15)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(_FROM_ASM_) +#ifdef __cplusplus +extern "C" { +#endif + void boardInit(void); +#ifdef __cplusplus +} +#endif +#endif /* _FROM_ASM_ */ + +#define LINE_LED_RED PAL_LINE(GPIOC_BASE, 10U) +#define LINE_LED_GREEN PAL_LINE(GPIOC_BASE, 11U) +#define LINE_LED_BLUE PAL_LINE(GPIOC_BASE, 12U) + +#endif /* BOARD_H */ diff --git a/firmware/source/cfg/chconf.h b/firmware/source/cfg/chconf.h new file mode 100644 index 0000000..628d7e8 --- /dev/null +++ b/firmware/source/cfg/chconf.h @@ -0,0 +1,756 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file rt/templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef CHCONF_H +#define CHCONF_H + +#define _CHIBIOS_RT_CONF_ +#define _CHIBIOS_RT_CONF_VER_6_1_ + +/*===========================================================================*/ +/** + * @name System timers settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System time counter resolution. + * @note Allowed values are 16 or 32 bits. + */ +#if !defined(CH_CFG_ST_RESOLUTION) +#define CH_CFG_ST_RESOLUTION 32 +#endif + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + */ +#if !defined(CH_CFG_ST_FREQUENCY) +#define CH_CFG_ST_FREQUENCY 10000 +#endif + +/** + * @brief Time intervals data size. + * @note Allowed values are 16, 32 or 64 bits. + */ +#if !defined(CH_CFG_INTERVALS_SIZE) +#define CH_CFG_INTERVALS_SIZE 32 +#endif + +/** + * @brief Time types data size. + * @note Allowed values are 16 or 32 bits. + */ +#if !defined(CH_CFG_TIME_TYPES_SIZE) +#define CH_CFG_TIME_TYPES_SIZE 32 +#endif + +/** + * @brief Time delta constant for the tick-less mode. + * @note If this value is zero then the system uses the classic + * periodic tick. This value represents the minimum number + * of ticks that is safe to specify in a timeout directive. + * The value one is not valid, timeouts are rounded up to + * this value. + */ +#if !defined(CH_CFG_ST_TIMEDELTA) +#define CH_CFG_ST_TIMEDELTA 2 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + * @note The round robin preemption is not supported in tickless mode and + * must be set to zero in that case. + */ +#if !defined(CH_CFG_TIME_QUANTUM) +#define CH_CFG_TIME_QUANTUM 0 +#endif + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread. The application @p main() + * function becomes the idle thread and must implement an + * infinite loop. + */ +#if !defined(CH_CFG_NO_IDLE_THREAD) +#define CH_CFG_NO_IDLE_THREAD FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_OPTIMIZE_SPEED) +#define CH_CFG_OPTIMIZE_SPEED TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Time Measurement APIs. + * @details If enabled then the time measurement APIs are included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TM) +#define CH_CFG_USE_TM TRUE +#endif + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_REGISTRY) +#define CH_CFG_USE_REGISTRY TRUE +#endif + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_WAITEXIT) +#define CH_CFG_USE_WAITEXIT TRUE +#endif + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_SEMAPHORES) +#define CH_CFG_USE_SEMAPHORES TRUE +#endif + +/** + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY) +#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MUTEXES) +#define CH_CFG_USE_MUTEXES TRUE +#endif + +/** + * @brief Enables recursive behavior on mutexes. + * @note Recursive mutexes are heavier and have an increased + * memory footprint. + * + * @note The default is @p FALSE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE) +#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE +#endif + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_CONDVARS) +#define CH_CFG_USE_CONDVARS TRUE +#endif + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_CONDVARS. + */ +#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT) +#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE +#endif + +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_EVENTS) +#define CH_CFG_USE_EVENTS TRUE +#endif + +/** + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_EVENTS. + */ +#if !defined(CH_CFG_USE_EVENTS_TIMEOUT) +#define CH_CFG_USE_EVENTS_TIMEOUT TRUE +#endif + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MESSAGES) +#define CH_CFG_USE_MESSAGES TRUE +#endif + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_MESSAGES. + */ +#if !defined(CH_CFG_USE_MESSAGES_PRIORITY) +#define CH_CFG_USE_MESSAGES_PRIORITY FALSE +#endif + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_WAITEXIT. + * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS. + */ +#if !defined(CH_CFG_USE_DYNAMIC) +#define CH_CFG_USE_DYNAMIC TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name OSLIB options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_MAILBOXES) +#define CH_CFG_USE_MAILBOXES TRUE +#endif + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCORE) +#define CH_CFG_USE_MEMCORE TRUE +#endif + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_CFG_USE_MEMCORE. + */ +#if !defined(CH_CFG_MEMCORE_SIZE) +#define CH_CFG_MEMCORE_SIZE 0 +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or + * @p CH_CFG_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#if !defined(CH_CFG_USE_HEAP) +#define CH_CFG_USE_HEAP TRUE +#endif + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMPOOLS) +#define CH_CFG_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Objects FIFOs APIs. + * @details If enabled then the objects FIFOs APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_FIFOS) +#define CH_CFG_USE_OBJ_FIFOS TRUE +#endif + +/** + * @brief Pipes APIs. + * @details If enabled then the pipes APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_PIPES) +#define CH_CFG_USE_PIPES TRUE +#endif + +/** + * @brief Objects Caches APIs. + * @details If enabled then the objects caches APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_CACHES) +#define CH_CFG_USE_OBJ_CACHES TRUE +#endif + +/** + * @brief Delegate threads APIs. + * @details If enabled then the delegate threads APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_DELEGATES) +#define CH_CFG_USE_DELEGATES TRUE +#endif + +/** + * @brief Jobs Queues APIs. + * @details If enabled then the jobs queues APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_JOBS) +#define CH_CFG_USE_JOBS TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Objects factory options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Objects Factory APIs. + * @details If enabled then the objects factory APIs are included in the + * kernel. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_CFG_USE_FACTORY) +#define CH_CFG_USE_FACTORY TRUE +#endif + +/** + * @brief Maximum length for object names. + * @details If the specified length is zero then the name is stored by + * pointer but this could have unintended side effects. + */ +#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH) +#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8 +#endif + +/** + * @brief Enables the registry of generic objects. + */ +#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY) +#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE +#endif + +/** + * @brief Enables factory for generic buffers. + */ +#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS) +#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE +#endif + +/** + * @brief Enables factory for semaphores. + */ +#if !defined(CH_CFG_FACTORY_SEMAPHORES) +#define CH_CFG_FACTORY_SEMAPHORES TRUE +#endif + +/** + * @brief Enables factory for mailboxes. + */ +#if !defined(CH_CFG_FACTORY_MAILBOXES) +#define CH_CFG_FACTORY_MAILBOXES TRUE +#endif + +/** + * @brief Enables factory for objects FIFOs. + */ +#if !defined(CH_CFG_FACTORY_OBJ_FIFOS) +#define CH_CFG_FACTORY_OBJ_FIFOS TRUE +#endif + +/** + * @brief Enables factory for Pipes. + */ +#if !defined(CH_CFG_FACTORY_PIPES) || defined(__DOXYGEN__) +#define CH_CFG_FACTORY_PIPES TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, kernel statistics. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_STATISTICS) +#define CH_DBG_STATISTICS FALSE +#endif + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) +#define CH_DBG_SYSTEM_STATE_CHECK TRUE +#endif + +/** + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) +#define CH_DBG_ENABLE_CHECKS TRUE +#endif + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) +#define CH_DBG_ENABLE_ASSERTS TRUE +#endif + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the trace buffer is activated. + * + * @note The default is @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_MASK) +#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_NONE +#endif + +/** + * @brief Trace buffer entries. + * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is + * different from @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_BUFFER_SIZE) +#define CH_DBG_TRACE_BUFFER_SIZE 128 +#endif + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) +#define CH_DBG_ENABLE_STACK_CHECK FALSE +#endif + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_FILL_THREADS) +#define CH_DBG_FILL_THREADS FALSE +#endif + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p thread_t structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p FALSE. + * @note This debug option is not currently compatible with the + * tickless mode. + */ +#if !defined(CH_DBG_THREADS_PROFILING) +#define CH_DBG_THREADS_PROFILING FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System structure extension. + * @details User fields added to the end of the @p ch_system_t structure. + */ +#define CH_CFG_SYSTEM_EXTRA_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief System initialization hook. + * @details User initialization code added to the @p chSysInit() function + * just before interrupts are enabled globally. + */ +#define CH_CFG_SYSTEM_INIT_HOOK() { \ + /* Add threads initialization code here.*/ \ +} + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p thread_t structure. + */ +#define CH_CFG_THREAD_EXTRA_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p _thread_init() function. + * + * @note It is invoked from within @p _thread_init() and implicitly from all + * the threads creation APIs. + */ +#define CH_CFG_THREAD_INIT_HOOK(tp) { \ + /* Add threads initialization code here.*/ \ +} + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + */ +#define CH_CFG_THREAD_EXIT_HOOK(tp) { \ + /* Add threads finalization code here.*/ \ +} + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + */ +#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \ + /* Context switch code here.*/ \ +} + +/** + * @brief ISR enter hook. + */ +#define CH_CFG_IRQ_PROLOGUE_HOOK() { \ + /* IRQ prologue code here.*/ \ +} + +/** + * @brief ISR exit hook. + */ +#define CH_CFG_IRQ_EPILOGUE_HOOK() { \ + /* IRQ epilogue code here.*/ \ +} + +/** + * @brief Idle thread enter hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to activate a power saving mode. + */ +#define CH_CFG_IDLE_ENTER_HOOK() { \ + /* Idle-enter code here.*/ \ +} + +/** + * @brief Idle thread leave hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to deactivate a power saving mode. + */ +#define CH_CFG_IDLE_LEAVE_HOOK() { \ + /* Idle-leave code here.*/ \ +} + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#define CH_CFG_IDLE_LOOP_HOOK() { \ + /* Idle loop code here.*/ \ +} + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#define CH_CFG_SYSTEM_TICK_HOOK() { \ + /* System tick event code here.*/ \ +} + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \ + /* System halt code here.*/ \ +} + +/** + * @brief Trace hook. + * @details This hook is invoked each time a new record is written in the + * trace buffer. + */ +#define CH_CFG_TRACE_HOOK(tep) { \ + /* Trace code here.*/ \ +} + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#endif /* CHCONF_H */ + +/** @} */ diff --git a/firmware/source/cfg/halconf.h b/firmware/source/cfg/halconf.h new file mode 100644 index 0000000..24c6fde --- /dev/null +++ b/firmware/source/cfg/halconf.h @@ -0,0 +1,531 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file templates/halconf.h + * @brief HAL configuration header. + * @details HAL configuration file, this file allows to enable or disable the + * various device drivers from your application. You may also use + * this file in order to override the device drivers default settings. + * + * @addtogroup HAL_CONF + * @{ + */ + +#ifndef HALCONF_H +#define HALCONF_H + +#define _CHIBIOS_HAL_CONF_ +#define _CHIBIOS_HAL_CONF_VER_7_1_ + +#include "mcuconf.h" + +/** + * @brief Enables the PAL subsystem. + */ +#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) +#define HAL_USE_PAL TRUE +#endif + +/** + * @brief Enables the ADC subsystem. + */ +#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) +#define HAL_USE_ADC TRUE +#endif + +/** + * @brief Enables the CAN subsystem. + */ +#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) +#define HAL_USE_CAN FALSE +#endif + +/** + * @brief Enables the cryptographic subsystem. + */ +#if !defined(HAL_USE_CRY) || defined(__DOXYGEN__) +#define HAL_USE_CRY FALSE +#endif + +/** + * @brief Enables the DAC subsystem. + */ +#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__) +#define HAL_USE_DAC TRUE +#endif + +/** + * @brief Enables the EFlash subsystem. + */ +#if !defined(HAL_USE_EFL) || defined(__DOXYGEN__) +#define HAL_USE_EFL FALSE +#endif + +/** + * @brief Enables the GPT subsystem. + */ +#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) +#define HAL_USE_GPT TRUE +#endif + +/** + * @brief Enables the I2C subsystem. + */ +#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) +#define HAL_USE_I2C FALSE +#endif + +/** + * @brief Enables the I2S subsystem. + */ +#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__) +#define HAL_USE_I2S FALSE +#endif + +/** + * @brief Enables the ICU subsystem. + */ +#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) +#define HAL_USE_ICU FALSE +#endif + +/** + * @brief Enables the MAC subsystem. + */ +#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) +#define HAL_USE_MAC FALSE +#endif + +/** + * @brief Enables the MMC_SPI subsystem. + */ +#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) +#define HAL_USE_MMC_SPI FALSE +#endif + +/** + * @brief Enables the PWM subsystem. + */ +#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) +#define HAL_USE_PWM FALSE +#endif + +/** + * @brief Enables the RTC subsystem. + */ +#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) +#define HAL_USE_RTC FALSE +#endif + +/** + * @brief Enables the SDC subsystem. + */ +#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) +#define HAL_USE_SDC FALSE +#endif + +/** + * @brief Enables the SERIAL subsystem. + */ +#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL FALSE +#endif + +/** + * @brief Enables the SERIAL over USB subsystem. + */ +#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL_USB TRUE +#endif + +/** + * @brief Enables the SIO subsystem. + */ +#if !defined(HAL_USE_SIO) || defined(__DOXYGEN__) +#define HAL_USE_SIO FALSE +#endif + +/** + * @brief Enables the SPI subsystem. + */ +#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) +#define HAL_USE_SPI FALSE +#endif + +/** + * @brief Enables the TRNG subsystem. + */ +#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__) +#define HAL_USE_TRNG FALSE +#endif + +/** + * @brief Enables the UART subsystem. + */ +#if !defined(HAL_USE_UART) || defined(__DOXYGEN__) +#define HAL_USE_UART FALSE +#endif + +/** + * @brief Enables the USB subsystem. + */ +#if !defined(HAL_USE_USB) || defined(__DOXYGEN__) +#define HAL_USE_USB TRUE +#endif + +/** + * @brief Enables the WDG subsystem. + */ +#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__) +#define HAL_USE_WDG FALSE +#endif + +/** + * @brief Enables the WSPI subsystem. + */ +#if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__) +#define HAL_USE_WSPI FALSE +#endif + +/*===========================================================================*/ +/* PAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__) +#define PAL_USE_CALLBACKS FALSE +#endif + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__) +#define PAL_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* ADC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) +#define ADC_USE_WAIT FALSE +#endif + +/** + * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define ADC_USE_MUTUAL_EXCLUSION FALSE +#endif + +/*===========================================================================*/ +/* CAN driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + */ +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif + +/** + * @brief Enforces the driver to use direct callbacks rather than OSAL events. + */ +#if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__) +#define CAN_ENFORCE_USE_CALLBACKS FALSE +#endif + +/*===========================================================================*/ +/* CRY driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the SW fall-back of the cryptographic driver. + * @details When enabled, this option, activates a fall-back software + * implementation for algorithms not supported by the underlying + * hardware. + * @note Fall-back implementations may not be present for all algorithms. + */ +#if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_USE_FALLBACK FALSE +#endif + +/** + * @brief Makes the driver forcibly use the fall-back implementations. + */ +#if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_ENFORCE_FALLBACK FALSE +#endif + +/*===========================================================================*/ +/* DAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__) +#define DAC_USE_WAIT FALSE +#endif + +/** + * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define DAC_USE_MUTUAL_EXCLUSION FALSE +#endif + +/*===========================================================================*/ +/* I2C driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the mutual exclusion APIs on the I2C bus. + */ +#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define I2C_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* MAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the zero-copy API. + */ +#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__) +#define MAC_USE_ZERO_COPY FALSE +#endif + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) +#define MAC_USE_EVENTS TRUE +#endif + +/*===========================================================================*/ +/* MMC_SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + * This option is recommended also if the SPI driver does not + * use a DMA channel and heavily loads the CPU. + */ +#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__) +#define MMC_NICE_WAITING TRUE +#endif + +/*===========================================================================*/ +/* SDC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intervals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + +/** + * @brief OCR initialization constant for V20 cards. + */ +#if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__) +#define SDC_INIT_OCR_V20 0x50FF8000U +#endif + +/** + * @brief OCR initialization constant for non-V20 cards. + */ +#if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__) +#define SDC_INIT_OCR 0x80100000U +#endif + +/*===========================================================================*/ +/* SERIAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SERIAL_DEFAULT_BITRATE 38400 +#endif + +/** + * @brief Serial buffers size. + * @details Configuration parameter, you can change the depth of the queue + * buffers depending on the requirements of your application. + * @note The default is 16 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_BUFFERS_SIZE 16 +#endif + +/*===========================================================================*/ +/* SERIAL_USB driver related setting. */ +/*===========================================================================*/ + +/** + * @brief Serial over USB buffers size. + * @details Configuration parameter, the buffer size must be a multiple of + * the USB data endpoint maximum packet size. + * @note The default is 256 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_SIZE 256 +#endif + +/** + * @brief Serial over USB number of buffers. + * @note The default is 2 buffers. + */ +#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_NUMBER 2 +#endif + +/*===========================================================================*/ +/* SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) +#define SPI_USE_WAIT TRUE +#endif + +/** + * @brief Enables circular transfers APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_CIRCULAR) || defined(__DOXYGEN__) +#define SPI_USE_CIRCULAR FALSE +#endif + +/** + * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define SPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +/** + * @brief Handling method for SPI CS line. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__) +#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD +#endif + +/*===========================================================================*/ +/* UART driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__) +#define UART_USE_WAIT FALSE +#endif + +/** + * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define UART_USE_MUTUAL_EXCLUSION FALSE +#endif + +/*===========================================================================*/ +/* USB driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__) +#define USB_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* WSPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__) +#define WSPI_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define WSPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +#endif /* HALCONF_H */ + +/** @} */ diff --git a/firmware/source/cfg/mcuconf.h b/firmware/source/cfg/mcuconf.h new file mode 100644 index 0000000..0d4d5c1 --- /dev/null +++ b/firmware/source/cfg/mcuconf.h @@ -0,0 +1,7 @@ +#if defined(TARGET_PLATFORM_L4) +#include "mcuconf_l4.h" +#elif defined(TARGET_PLATFORM_H7) +#include "mcuconf_h7.h" +#elif defined(TARGET_PLATFORM_G4) +#include "mcuconf_g4.h" +#endif diff --git a/firmware/source/cfg/mcuconf_h7.h b/firmware/source/cfg/mcuconf_h7.h new file mode 100644 index 0000000..c6a254b --- /dev/null +++ b/firmware/source/cfg/mcuconf_h7.h @@ -0,0 +1,483 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * STM32H7xx drivers configuration. + * The following settings override the default settings present in + * the various device driver implementation headers. + * Note that the settings for each driver only have effect if the whole + * driver is enabled in halconf.h. + * + * IRQ priorities: + * 15...0 Lowest...Highest. + * + * DMA priorities: + * 0...3 Lowest...Highest. + */ + +#define STM32H7xx_MCUCONF +#define STM32H723_MCUCONF +#define STM32H725_MCUCONF +//#define STM32H743_MCUCONF + +/* + * General settings. + */ +#define STM32_NO_INIT FALSE +#define STM32_TARGET_CORE 1 + +/* + * Memory attributes settings. + */ +#define STM32_NOCACHE_MPU_REGION MPU_REGION_1 +#define STM32_NOCACHE_SRAM1_SRAM2 FALSE +#define STM32_NOCACHE_SRAM3 FALSE +#define STM32_NOCACHE_ALLSRAM TRUE + +/* + * PWR system settings. + * Reading STM32 Reference Manual is required, settings in PWR_CR3 are + * very critical. + * Register constants are taken from the ST header. + */ +#define STM32_VOS STM32_VOS_SCALE1 +#define STM32_PWR_CR1 (PWR_CR1_SVOS_1 | PWR_CR1_SVOS_0) +#define STM32_PWR_CR2 (PWR_CR2_BREN) +#define STM32_PWR_CR3 (PWR_CR3_LDOEN | PWR_CR3_USB33DEN) +#define STM32_PWR_CPUCR 0 + +/* + * Clock tree static settings. + * Reading STM32 Reference Manual is required. + */ +#define STM32_HSI_ENABLED TRUE +#define STM32_LSI_ENABLED TRUE +#define STM32_CSI_ENABLED FALSE +#define STM32_HSI48_ENABLED TRUE +#define STM32_HSE_ENABLED FALSE +#define STM32_LSE_ENABLED FALSE +#define STM32_HSIDIV STM32_HSIDIV_DIV8 // HSI = 8MHz + +/* + * PLLs static settings. + * Reading STM32 Reference Manual is required. + */ +#define STM32_PLLSRC STM32_PLLSRC_HSI_CK +#define STM32_PLLCFGR_MASK ~0 +#define STM32_PLL1_ENABLED TRUE +#define STM32_PLL1_P_ENABLED TRUE +#define STM32_PLL1_Q_ENABLED FALSE +#define STM32_PLL1_R_ENABLED FALSE +#define STM32_PLL1_DIVM_VALUE 4 // 8 / 4 = 2MHz +#define STM32_PLL1_DIVN_VALUE 240 // = 2 * 240 +#define STM32_PLL1_FRACN_VALUE 0 +#define STM32_PLL1_DIVP_VALUE 1 // = 480MHz +#define STM32_PLL1_DIVQ_VALUE 16 +#define STM32_PLL1_DIVR_VALUE 8 +#define STM32_PLL2_ENABLED TRUE // PLL2 adjusted by adc.cpp +#define STM32_PLL2_P_ENABLED TRUE +#define STM32_PLL2_Q_ENABLED FALSE +#define STM32_PLL2_R_ENABLED FALSE +#define STM32_PLL2_DIVM_VALUE 4 +#define STM32_PLL2_DIVN_VALUE 80 +#define STM32_PLL2_FRACN_VALUE 0 +#define STM32_PLL2_DIVP_VALUE 20 +#define STM32_PLL2_DIVQ_VALUE 8 +#define STM32_PLL2_DIVR_VALUE 8 +#define STM32_PLL3_ENABLED FALSE +#define STM32_PLL3_P_ENABLED FALSE +#define STM32_PLL3_Q_ENABLED FALSE +#define STM32_PLL3_R_ENABLED FALSE +#define STM32_PLL3_DIVM_VALUE 4 +#define STM32_PLL3_DIVN_VALUE 400 +#define STM32_PLL3_FRACN_VALUE 0 +#define STM32_PLL3_DIVP_VALUE 8 +#define STM32_PLL3_DIVQ_VALUE 8 +#define STM32_PLL3_DIVR_VALUE 8 + +/* + * Core clocks dynamic settings (can be changed at runtime). + * Reading STM32 Reference Manual is required. + */ +#define STM32_SW STM32_SW_PLL1_P_CK +#define STM32_RTCSEL STM32_RTCSEL_LSI_CK +#define STM32_D1CPRE STM32_D1CPRE_DIV1 +#define STM32_D1HPRE STM32_D1HPRE_DIV2 // /2 = 240MHz +#define STM32_D1PPRE3 STM32_D1PPRE3_DIV2 +#define STM32_D2PPRE1 STM32_D2PPRE1_DIV2 +#define STM32_D2PPRE2 STM32_D2PPRE2_DIV2 +#define STM32_D3PPRE4 STM32_D3PPRE4_DIV2 + +/* + * Peripherals clocks static settings. + * Reading STM32 Reference Manual is required. + */ +#define STM32_MCO1SEL STM32_MCO1SEL_HSI_CK +#define STM32_MCO1PRE_VALUE 4 +#define STM32_MCO2SEL STM32_MCO2SEL_SYS_CK +#define STM32_MCO2PRE_VALUE 4 +#define STM32_TIMPRE_ENABLE TRUE +#define STM32_HRTIMSEL 0 +#define STM32_STOPKERWUCK 0 +#define STM32_STOPWUCK 0 +#define STM32_RTCPRE_VALUE 8 +#define STM32_CKPERSEL STM32_CKPERSEL_HSI_CK +#define STM32_SDMMCSEL STM32_SDMMCSEL_PLL1_Q_CK +//#define STM32_OCTOSPISEL STM32_OCTOSPISEL_HCLK +//#define STM32_FMCSEL STM32_OCTOSPISEL_HCLK +#define STM32_SWPSEL STM32_SWPSEL_PCLK1 +#define STM32_FDCANSEL STM32_FDCANSEL_HSE_CK +#define STM32_DFSDM1SEL STM32_DFSDM1SEL_PCLK2 +#define STM32_SPDIFSEL STM32_SPDIFSEL_PLL1_Q_CK +#define STM32_SPI45SEL STM32_SPI45SEL_PCLK2 +#define STM32_SPI123SEL STM32_SPI123SEL_PLL1_Q_CK +//#define STM32_SAI23SEL STM32_SAI23SEL_PLL1_Q_CK +#define STM32_SAI1SEL STM32_SAI1SEL_PLL1_Q_CK +#define STM32_LPTIM1SEL STM32_LPTIM1SEL_PCLK1 +#define STM32_CECSEL STM32_CECSEL_LSE_CK +#define STM32_USBSEL STM32_USBSEL_HSI48_CK +#define STM32_I2C1235SEL STM32_I2C1235SEL_PCLK1 +#define STM32_RNGSEL STM32_RNGSEL_HSI48_CK +#define STM32_USART16910SEL STM32_USART16910SEL_PCLK2 +#define STM32_USART234578SEL STM32_USART234578SEL_PCLK1 +#define STM32_SPI6SEL STM32_SPI6SEL_PCLK4 +#define STM32_SAI4BSEL STM32_SAI4BSEL_PLL1_Q_CK +#define STM32_SAI4ASEL STM32_SAI4ASEL_PLL1_Q_CK +#define STM32_ADCSEL STM32_ADCSEL_PLL2_P_CK +#define STM32_LPTIM345SEL STM32_LPTIM345SEL_PCLK4 +#define STM32_LPTIM2SEL STM32_LPTIM2SEL_PCLK4 +#define STM32_I2C4SEL STM32_I2C4SEL_PCLK4 +#define STM32_LPUART1SEL STM32_LPUART1SEL_PCLK4 + +/* + * IRQ system settings. + */ +#define STM32_IRQ_EXTI0_PRIORITY 6 +#define STM32_IRQ_EXTI1_PRIORITY 6 +#define STM32_IRQ_EXTI2_PRIORITY 6 +#define STM32_IRQ_EXTI3_PRIORITY 6 +#define STM32_IRQ_EXTI4_PRIORITY 6 +#define STM32_IRQ_EXTI5_9_PRIORITY 6 +#define STM32_IRQ_EXTI10_15_PRIORITY 6 +#define STM32_IRQ_EXTI16_PRIORITY 6 +#define STM32_IRQ_EXTI17_PRIORITY 6 +#define STM32_IRQ_EXTI18_PRIORITY 6 +#define STM32_IRQ_EXTI19_PRIORITY 6 +#define STM32_IRQ_EXTI20_21_PRIORITY 6 + +#define STM32_IRQ_FDCAN1_PRIORITY 10 +#define STM32_IRQ_FDCAN2_PRIORITY 10 + +#define STM32_IRQ_MDMA_PRIORITY 9 + +#define STM32_IRQ_QUADSPI1_PRIORITY 10 + +#define STM32_IRQ_SDMMC1_PRIORITY 9 +#define STM32_IRQ_SDMMC2_PRIORITY 9 + +#define STM32_IRQ_TIM1_UP_PRIORITY 7 +#define STM32_IRQ_TIM1_CC_PRIORITY 7 +#define STM32_IRQ_TIM2_PRIORITY 7 +#define STM32_IRQ_TIM3_PRIORITY 7 +#define STM32_IRQ_TIM4_PRIORITY 7 +#define STM32_IRQ_TIM5_PRIORITY 7 +#define STM32_IRQ_TIM6_PRIORITY 7 +#define STM32_IRQ_TIM7_PRIORITY 7 +#define STM32_IRQ_TIM8_BRK_TIM12_PRIORITY 7 +#define STM32_IRQ_TIM8_UP_TIM13_PRIORITY 7 +#define STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY 7 +#define STM32_IRQ_TIM8_CC_PRIORITY 7 +#define STM32_IRQ_TIM15_PRIORITY 7 +#define STM32_IRQ_TIM16_PRIORITY 7 +#define STM32_IRQ_TIM17_PRIORITY 7 + +#define STM32_IRQ_USART1_PRIORITY 12 +#define STM32_IRQ_USART2_PRIORITY 12 +#define STM32_IRQ_USART3_PRIORITY 12 +#define STM32_IRQ_UART4_PRIORITY 12 +#define STM32_IRQ_UART5_PRIORITY 12 +#define STM32_IRQ_USART6_PRIORITY 12 +#define STM32_IRQ_UART7_PRIORITY 12 +#define STM32_IRQ_UART8_PRIORITY 12 +#define STM32_IRQ_LPUART1_PRIORITY 12 + +/* + * ADC driver system settings. + */ +#define STM32_ADC_DUAL_MODE FALSE +#define STM32_ADC_COMPACT_SAMPLES FALSE +#define STM32_ADC_USE_ADC12 FALSE +#define STM32_ADC_USE_ADC3 TRUE +#define STM32_ADC_ADC12_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_ADC_ADC3_BDMA_STREAM STM32_BDMA_STREAM_ID_ANY +#define STM32_ADC_ADC12_DMA_PRIORITY 2 +#define STM32_ADC_ADC3_DMA_PRIORITY 2 +#define STM32_ADC_ADC12_IRQ_PRIORITY 5 +#define STM32_ADC_ADC3_IRQ_PRIORITY 5 +#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV4 +#define STM32_ADC_ADC3_CLOCK_MODE ADC_CCR_CKMODE_ADCCK +#define STM32_ADC_ADC3_PRESC (5 << ADC_CCR_PRESC_Pos) // /10 + +/* + * CAN driver system settings. + */ +#define STM32_CAN_USE_FDCAN1 FALSE +#define STM32_CAN_USE_FDCAN2 FALSE + +/* + * DAC driver system settings. + */ +#define STM32_DAC_DUAL_MODE FALSE +#define STM32_DAC_USE_DAC1_CH1 TRUE +#define STM32_DAC_USE_DAC1_CH2 TRUE +#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10 +#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10 +#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2 +#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2 +#define STM32_DAC_DAC1_CH1_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_DAC_DAC1_CH2_DMA_STREAM STM32_DMA_STREAM_ID_ANY + +/* + * GPT driver system settings. + */ +#define STM32_GPT_USE_TIM1 FALSE +#define STM32_GPT_USE_TIM2 FALSE +#define STM32_GPT_USE_TIM3 FALSE +#define STM32_GPT_USE_TIM4 FALSE +#define STM32_GPT_USE_TIM5 FALSE +#define STM32_GPT_USE_TIM6 TRUE +#define STM32_GPT_USE_TIM7 FALSE +#define STM32_GPT_USE_TIM8 FALSE +#define STM32_GPT_USE_TIM12 FALSE +#define STM32_GPT_USE_TIM13 FALSE +#define STM32_GPT_USE_TIM14 FALSE +#define STM32_GPT_USE_TIM15 FALSE +#define STM32_GPT_USE_TIM16 FALSE +#define STM32_GPT_USE_TIM17 FALSE + +/* + * I2C driver system settings. + */ +#define STM32_I2C_USE_I2C1 FALSE +#define STM32_I2C_USE_I2C2 FALSE +#define STM32_I2C_USE_I2C3 FALSE +#define STM32_I2C_USE_I2C4 FALSE +#define STM32_I2C_BUSY_TIMEOUT 50 +#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_I2C_I2C4_RX_BDMA_STREAM STM32_BDMA_STREAM_ID_ANY +#define STM32_I2C_I2C4_TX_BDMA_STREAM STM32_BDMA_STREAM_ID_ANY +#define STM32_I2C_I2C1_IRQ_PRIORITY 5 +#define STM32_I2C_I2C2_IRQ_PRIORITY 5 +#define STM32_I2C_I2C3_IRQ_PRIORITY 5 +#define STM32_I2C_I2C4_IRQ_PRIORITY 5 +#define STM32_I2C_I2C1_DMA_PRIORITY 3 +#define STM32_I2C_I2C2_DMA_PRIORITY 3 +#define STM32_I2C_I2C3_DMA_PRIORITY 3 +#define STM32_I2C_I2C4_DMA_PRIORITY 3 +#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") + +/* + * ICU driver system settings. + */ +#define STM32_ICU_USE_TIM1 FALSE +#define STM32_ICU_USE_TIM2 FALSE +#define STM32_ICU_USE_TIM3 FALSE +#define STM32_ICU_USE_TIM4 FALSE +#define STM32_ICU_USE_TIM5 FALSE +#define STM32_ICU_USE_TIM8 FALSE +#define STM32_ICU_USE_TIM12 FALSE +#define STM32_ICU_USE_TIM13 FALSE +#define STM32_ICU_USE_TIM14 FALSE +#define STM32_ICU_USE_TIM15 FALSE +#define STM32_ICU_USE_TIM16 FALSE +#define STM32_ICU_USE_TIM17 FALSE + +/* + * MAC driver system settings. + */ +#define STM32_MAC_TRANSMIT_BUFFERS 2 +#define STM32_MAC_RECEIVE_BUFFERS 4 +#define STM32_MAC_BUFFERS_SIZE 1522 +#define STM32_MAC_PHY_TIMEOUT 100 +#define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE +#define STM32_MAC_ETH1_IRQ_PRIORITY 13 +#define STM32_MAC_IP_CHECKSUM_OFFLOAD 0 + +/* + * PWM driver system settings. + */ +#define STM32_PWM_USE_ADVANCED FALSE +#define STM32_PWM_USE_TIM1 FALSE +#define STM32_PWM_USE_TIM2 FALSE +#define STM32_PWM_USE_TIM3 FALSE +#define STM32_PWM_USE_TIM4 FALSE +#define STM32_PWM_USE_TIM5 FALSE +#define STM32_PWM_USE_TIM8 FALSE +#define STM32_PWM_USE_TIM12 FALSE +#define STM32_PWM_USE_TIM13 FALSE +#define STM32_PWM_USE_TIM14 FALSE +#define STM32_PWM_USE_TIM15 FALSE +#define STM32_PWM_USE_TIM16 FALSE +#define STM32_PWM_USE_TIM17 FALSE + +/* + * RTC driver system settings. + */ +#define STM32_RTC_PRESA_VALUE 32 +#define STM32_RTC_PRESS_VALUE 1024 +#define STM32_RTC_CR_INIT 0 +#define STM32_RTC_TAMPCR_INIT 0 + +/* + * SDC driver system settings. + */ +#define STM32_SDC_USE_SDMMC1 FALSE +#define STM32_SDC_USE_SDMMC2 FALSE +#define STM32_SDC_SDMMC_UNALIGNED_SUPPORT TRUE +#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000000 +#define STM32_SDC_SDMMC_READ_TIMEOUT 1000000 +#define STM32_SDC_SDMMC_CLOCK_DELAY 10 +#define STM32_SDC_SDMMC_PWRSAV TRUE + +/* + * SERIAL driver system settings. + */ +#define STM32_SERIAL_USE_USART1 FALSE +#define STM32_SERIAL_USE_USART2 FALSE +#define STM32_SERIAL_USE_USART3 FALSE +#define STM32_SERIAL_USE_UART4 FALSE +#define STM32_SERIAL_USE_UART5 FALSE +#define STM32_SERIAL_USE_USART6 FALSE +#define STM32_SERIAL_USE_UART7 FALSE +#define STM32_SERIAL_USE_UART8 FALSE + +/* + * SPI driver system settings. + */ +#define STM32_SPI_USE_SPI1 FALSE +#define STM32_SPI_USE_SPI2 FALSE +#define STM32_SPI_USE_SPI3 FALSE +#define STM32_SPI_USE_SPI4 FALSE +#define STM32_SPI_USE_SPI5 FALSE +#define STM32_SPI_USE_SPI6 FALSE +#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI4_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI4_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI5_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI5_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_SPI_SPI6_RX_BDMA_STREAM STM32_BDMA_STREAM_ID_ANY +#define STM32_SPI_SPI6_TX_BDMA_STREAM STM32_BDMA_STREAM_ID_ANY +#define STM32_SPI_SPI1_DMA_PRIORITY 1 +#define STM32_SPI_SPI2_DMA_PRIORITY 1 +#define STM32_SPI_SPI3_DMA_PRIORITY 1 +#define STM32_SPI_SPI4_DMA_PRIORITY 1 +#define STM32_SPI_SPI5_DMA_PRIORITY 1 +#define STM32_SPI_SPI6_DMA_PRIORITY 1 +#define STM32_SPI_SPI1_IRQ_PRIORITY 10 +#define STM32_SPI_SPI2_IRQ_PRIORITY 10 +#define STM32_SPI_SPI3_IRQ_PRIORITY 10 +#define STM32_SPI_SPI4_IRQ_PRIORITY 10 +#define STM32_SPI_SPI5_IRQ_PRIORITY 10 +#define STM32_SPI_SPI6_IRQ_PRIORITY 10 +#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") + +/* + * ST driver system settings. + */ +#define STM32_ST_IRQ_PRIORITY 8 +#define STM32_ST_USE_TIMER 2 + +/* + * TRNG driver system settings. + */ +#define STM32_TRNG_USE_RNG1 FALSE + +/* + * UART driver system settings. + */ +#define STM32_UART_USE_USART1 FALSE +#define STM32_UART_USE_USART2 FALSE +#define STM32_UART_USE_USART3 FALSE +#define STM32_UART_USE_UART4 FALSE +#define STM32_UART_USE_UART5 FALSE +#define STM32_UART_USE_USART6 FALSE +#define STM32_UART_USE_UART7 FALSE +#define STM32_UART_USE_UART8 FALSE +#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART7_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART7_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART8_RX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_UART8_TX_DMA_STREAM STM32_DMA_STREAM_ID_ANY +#define STM32_UART_USART1_DMA_PRIORITY 0 +#define STM32_UART_USART2_DMA_PRIORITY 0 +#define STM32_UART_USART3_DMA_PRIORITY 0 +#define STM32_UART_UART4_DMA_PRIORITY 0 +#define STM32_UART_UART5_DMA_PRIORITY 0 +#define STM32_UART_USART6_DMA_PRIORITY 0 +#define STM32_UART_UART7_DMA_PRIORITY 0 +#define STM32_UART_UART8_DMA_PRIORITY 0 +#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") + +/* + * USB driver system settings. + */ +#define STM32_USB_USE_OTG1 FALSE +#define STM32_USB_USE_OTG2 TRUE +#define STM32_USB_OTG1_IRQ_PRIORITY 14 +#define STM32_USB_OTG2_IRQ_PRIORITY 14 +#define STM32_USB_OTG1_RX_FIFO_SIZE 512 +#define STM32_USB_OTG2_RX_FIFO_SIZE 1024 +#define STM32_USB_HOST_WAKEUP_DURATION 2 + +/* + * WDG driver system settings. + */ +#define STM32_WDG_USE_IWDG FALSE + +/* + * WSPI driver system settings. + */ +#define STM32_WSPI_USE_QUADSPI1 FALSE +#define STM32_WSPI_QUADSPI1_PRESCALER_VALUE 1 +#define STM32_WSPI_QUADSPI1_MDMA_CHANNEL STM32_MDMA_CHANNEL_ID_ANY +#define STM32_WSPI_QUADSPI1_MDMA_PRIORITY 1 +#define STM32_WSPI_MDMA_ERROR_HOOK(qspip) osalSysHalt("MDMA failure") + +#endif /* MCUCONF_H */ diff --git a/firmware/source/cfg/mcuconf_l4.h b/firmware/source/cfg/mcuconf_l4.h new file mode 100644 index 0000000..bf19f7a --- /dev/null +++ b/firmware/source/cfg/mcuconf_l4.h @@ -0,0 +1,360 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * STM32L4xx drivers configuration. + * The following settings override the default settings present in + * the various device driver implementation headers. + * Note that the settings for each driver only have effect if the whole + * driver is enabled in halconf.h. + * + * IRQ priorities: + * 15...0 Lowest...Highest. + * + * DMA priorities: + * 0...3 Lowest...Highest. + */ + +#ifndef MCUCONF_H +#define MCUCONF_H + +#define STM32L4xx_MCUCONF +#define STM32L476_MCUCONF +//#define STM32L432_MCUCONF + +/* + * HAL driver system settings. + */ +#define STM32_NO_INIT FALSE +#define STM32_VOS STM32_VOS_RANGE1 +#define STM32_PVD_ENABLE FALSE +#define STM32_PLS STM32_PLS_LEV0 +#define STM32_HSI16_ENABLED FALSE +#define STM32_LSI_ENABLED TRUE +#define STM32_HSE_ENABLED FALSE +#define STM32_LSE_ENABLED FALSE +#define STM32_MSIPLL_ENABLED FALSE +#define STM32_MSIRANGE STM32_MSIRANGE_4M +#define STM32_MSISRANGE STM32_MSISRANGE_4M +#define STM32_SW STM32_SW_PLL +#define STM32_PLLSRC STM32_PLLSRC_MSI +#define STM32_PLLM_VALUE 1 +#define STM32_PLLN_VALUE 72 +#define STM32_PLLP_VALUE 7 +#define STM32_PLLQ_VALUE 6 +#define STM32_PLLR_VALUE 4 +#define STM32_HPRE STM32_HPRE_DIV1 +#define STM32_PPRE1 STM32_PPRE1_DIV1 +#define STM32_PPRE2 STM32_PPRE2_DIV1 +#define STM32_STOPWUCK STM32_STOPWUCK_MSI +#define STM32_MCOSEL STM32_MCOSEL_NOCLOCK +#define STM32_MCOPRE STM32_MCOPRE_DIV1 +#define STM32_LSCOSEL STM32_LSCOSEL_NOCLOCK +#define STM32_PLLSAI1N_VALUE 24 +#define STM32_PLLSAI1P_VALUE 7 +#define STM32_PLLSAI1Q_VALUE 2 +#define STM32_PLLSAI1R_VALUE 4 +#define STM32_PLLSAI2N_VALUE 24 +#define STM32_PLLSAI2P_VALUE 7 +#define STM32_PLLSAI2R_VALUE 8 + +/* + * Peripherals clock sources. + */ +#define STM32_USART1SEL STM32_USART1SEL_SYSCLK +#define STM32_USART2SEL STM32_USART2SEL_SYSCLK +#define STM32_USART3SEL STM32_USART3SEL_SYSCLK +#define STM32_UART4SEL STM32_UART4SEL_SYSCLK +#define STM32_UART5SEL STM32_UART5SEL_SYSCLK +#define STM32_LPUART1SEL STM32_LPUART1SEL_SYSCLK +#define STM32_I2C1SEL STM32_I2C1SEL_SYSCLK +#define STM32_I2C2SEL STM32_I2C2SEL_SYSCLK +#define STM32_I2C3SEL STM32_I2C3SEL_SYSCLK +#define STM32_LPTIM1SEL STM32_LPTIM1SEL_PCLK1 +#define STM32_LPTIM2SEL STM32_LPTIM2SEL_PCLK1 +#define STM32_SAI1SEL STM32_SAI1SEL_OFF +#define STM32_SAI2SEL STM32_SAI2SEL_OFF +#define STM32_CLK48SEL STM32_CLK48SEL_PLLSAI1 +#define STM32_ADCSEL STM32_ADCSEL_PLLSAI2 +#define STM32_SWPMI1SEL STM32_SWPMI1SEL_PCLK1 +#define STM32_DFSDMSEL STM32_DFSDMSEL_PCLK2 +#define STM32_RTCSEL STM32_RTCSEL_LSI + +/* + * IRQ system settings. + */ +#define STM32_IRQ_EXTI0_PRIORITY 6 +#define STM32_IRQ_EXTI1_PRIORITY 6 +#define STM32_IRQ_EXTI2_PRIORITY 6 +#define STM32_IRQ_EXTI3_PRIORITY 6 +#define STM32_IRQ_EXTI4_PRIORITY 6 +#define STM32_IRQ_EXTI5_9_PRIORITY 6 +#define STM32_IRQ_EXTI10_15_PRIORITY 6 +#define STM32_IRQ_EXTI1635_38_PRIORITY 6 +#define STM32_IRQ_EXTI18_PRIORITY 6 +#define STM32_IRQ_EXTI19_PRIORITY 6 +#define STM32_IRQ_EXTI20_PRIORITY 6 +#define STM32_IRQ_EXTI21_22_PRIORITY 15 + +#define STM32_IRQ_TIM1_BRK_TIM15_PRIORITY 7 +#define STM32_IRQ_TIM1_UP_TIM16_PRIORITY 7 +#define STM32_IRQ_TIM1_TRGCO_TIM17_PRIORITY 7 +#define STM32_IRQ_TIM1_CC_PRIORITY 7 +#define STM32_IRQ_TIM2_PRIORITY 7 +#define STM32_IRQ_TIM3_PRIORITY 7 +#define STM32_IRQ_TIM4_PRIORITY 7 +#define STM32_IRQ_TIM5_PRIORITY 7 +#define STM32_IRQ_TIM6_PRIORITY 7 +#define STM32_IRQ_TIM7_PRIORITY 7 +#define STM32_IRQ_TIM8_UP_PRIORITY 7 +#define STM32_IRQ_TIM8_CC_PRIORITY 7 + +#define STM32_IRQ_USART1_PRIORITY 12 +#define STM32_IRQ_USART2_PRIORITY 12 +#define STM32_IRQ_USART3_PRIORITY 12 +#define STM32_IRQ_UART4_PRIORITY 12 +#define STM32_IRQ_UART5_PRIORITY 12 +#define STM32_IRQ_LPUART1_PRIORITY 12 + +/* + * ADC driver system settings. + */ +#define STM32_ADC_DUAL_MODE FALSE +#define STM32_ADC_COMPACT_SAMPLES FALSE +#define STM32_ADC_USE_ADC1 TRUE +#define STM32_ADC_USE_ADC2 FALSE +#define STM32_ADC_USE_ADC3 TRUE +#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(1, 1) +#define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#define STM32_ADC_ADC1_DMA_PRIORITY 2 +#define STM32_ADC_ADC2_DMA_PRIORITY 2 +#define STM32_ADC_ADC3_DMA_PRIORITY 2 +#define STM32_ADC_ADC12_IRQ_PRIORITY 5 +#define STM32_ADC_ADC3_IRQ_PRIORITY 5 +#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 5 +#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 5 +#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 5 +#define STM32_ADC_ADC123_CLOCK_MODE ADC_CCR_CKMODE_ADCCK +#define STM32_ADC_ADC123_PRESC ADC_CCR_PRESC_DIV10 + +//#define ADC123_PRESC_VALUE 1 + +/* + * CAN driver system settings. + */ +#define STM32_CAN_USE_CAN1 FALSE +#define STM32_CAN_CAN1_IRQ_PRIORITY 11 + +/* + * DAC driver system settings. + */ +#define STM32_DAC_DUAL_MODE FALSE +#define STM32_DAC_USE_DAC1_CH1 TRUE +#define STM32_DAC_USE_DAC1_CH2 TRUE +#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10 +#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10 +#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2 +#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2 +#define STM32_DAC_DAC1_CH1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) +#define STM32_DAC_DAC1_CH2_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) + +/* + * GPT driver system settings. + */ +#define STM32_GPT_USE_TIM1 FALSE +#define STM32_GPT_USE_TIM2 FALSE +#define STM32_GPT_USE_TIM3 FALSE +#define STM32_GPT_USE_TIM4 FALSE +#define STM32_GPT_USE_TIM5 FALSE +#define STM32_GPT_USE_TIM6 TRUE +#define STM32_GPT_USE_TIM7 TRUE +#define STM32_GPT_USE_TIM8 FALSE +#define STM32_GPT_USE_TIM15 FALSE +#define STM32_GPT_USE_TIM16 FALSE +#define STM32_GPT_USE_TIM17 FALSE + +/* + * I2C driver system settings. + */ +#define STM32_I2C_USE_I2C1 FALSE +#define STM32_I2C_USE_I2C2 FALSE +#define STM32_I2C_USE_I2C3 FALSE +#define STM32_I2C_BUSY_TIMEOUT 50 +#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) +#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) +#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#define STM32_I2C_I2C1_IRQ_PRIORITY 5 +#define STM32_I2C_I2C2_IRQ_PRIORITY 5 +#define STM32_I2C_I2C3_IRQ_PRIORITY 5 +#define STM32_I2C_I2C1_DMA_PRIORITY 3 +#define STM32_I2C_I2C2_DMA_PRIORITY 3 +#define STM32_I2C_I2C3_DMA_PRIORITY 3 +#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") + +/* + * ICU driver system settings. + */ +#define STM32_ICU_USE_TIM1 FALSE +#define STM32_ICU_USE_TIM2 FALSE +#define STM32_ICU_USE_TIM3 FALSE +#define STM32_ICU_USE_TIM4 FALSE +#define STM32_ICU_USE_TIM5 FALSE +#define STM32_ICU_USE_TIM8 FALSE +#define STM32_ICU_USE_TIM15 FALSE +#define STM32_ICU_USE_TIM16 FALSE +#define STM32_ICU_USE_TIM17 FALSE + +/* + * PWM driver system settings. + */ +#define STM32_PWM_USE_ADVANCED FALSE +#define STM32_PWM_USE_TIM1 FALSE +#define STM32_PWM_USE_TIM2 FALSE +#define STM32_PWM_USE_TIM3 FALSE +#define STM32_PWM_USE_TIM4 FALSE +#define STM32_PWM_USE_TIM5 FALSE +#define STM32_PWM_USE_TIM8 FALSE +#define STM32_PWM_USE_TIM15 FALSE +#define STM32_PWM_USE_TIM16 FALSE +#define STM32_PWM_USE_TIM17 FALSE + +/* + * RTC driver system settings. + */ +#define STM32_RTC_PRESA_VALUE 32 +#define STM32_RTC_PRESS_VALUE 1024 +#define STM32_RTC_CR_INIT 0 +#define STM32_RTC_TAMPCR_INIT 0 + +/* + * SDC driver system settings. + */ +#define STM32_SDC_USE_SDMMC1 FALSE +#define STM32_SDC_SDMMC_UNALIGNED_SUPPORT TRUE +#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000 +#define STM32_SDC_SDMMC_READ_TIMEOUT 1000 +#define STM32_SDC_SDMMC_CLOCK_DELAY 10 +#define STM32_SDC_SDMMC1_DMA_PRIORITY 3 +#define STM32_SDC_SDMMC1_IRQ_PRIORITY 9 +#define STM32_SDC_SDMMC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) + +/* + * SERIAL driver system settings. + */ +#define STM32_SERIAL_USE_USART1 FALSE +#define STM32_SERIAL_USE_USART2 TRUE +#define STM32_SERIAL_USE_USART3 FALSE +#define STM32_SERIAL_USE_UART4 FALSE +#define STM32_SERIAL_USE_UART5 FALSE +#define STM32_SERIAL_USE_LPUART1 FALSE +#define STM32_SERIAL_USART1_PRIORITY 12 +#define STM32_SERIAL_USART2_PRIORITY 12 +#define STM32_SERIAL_USART3_PRIORITY 12 +#define STM32_SERIAL_UART4_PRIORITY 12 +#define STM32_SERIAL_UART5_PRIORITY 12 +#define STM32_SERIAL_LPUART1_PRIORITY 12 + +/* + * SPI driver system settings. + */ +#define STM32_SPI_USE_SPI1 FALSE +#define STM32_SPI_USE_SPI2 FALSE +#define STM32_SPI_USE_SPI3 FALSE +#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) +#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) +#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) +#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 1) +#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) +#define STM32_SPI_SPI1_DMA_PRIORITY 1 +#define STM32_SPI_SPI2_DMA_PRIORITY 1 +#define STM32_SPI_SPI3_DMA_PRIORITY 1 +#define STM32_SPI_SPI1_IRQ_PRIORITY 10 +#define STM32_SPI_SPI2_IRQ_PRIORITY 10 +#define STM32_SPI_SPI3_IRQ_PRIORITY 10 +#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") + +/* + * ST driver system settings. + */ +#define STM32_ST_IRQ_PRIORITY 8 +#define STM32_ST_USE_TIMER 2 + +/* + * TRNG driver system settings. + */ +#define STM32_TRNG_USE_RNG1 FALSE + +/* + * UART driver system settings. + */ +#define STM32_UART_USE_USART1 FALSE +#define STM32_UART_USE_USART2 FALSE +#define STM32_UART_USE_USART3 FALSE +#define STM32_UART_USE_UART4 FALSE +#define STM32_UART_USE_UART5 FALSE +#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) +#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 6) +#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) +#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) +#define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) +#define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) +#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 1) +#define STM32_UART_USART1_IRQ_PRIORITY 12 +#define STM32_UART_USART2_IRQ_PRIORITY 12 +#define STM32_UART_USART3_IRQ_PRIORITY 12 +#define STM32_UART_UART4_IRQ_PRIORITY 12 +#define STM32_UART_UART5_IRQ_PRIORITY 12 +#define STM32_UART_USART1_DMA_PRIORITY 0 +#define STM32_UART_USART2_DMA_PRIORITY 0 +#define STM32_UART_USART3_DMA_PRIORITY 0 +#define STM32_UART_UART4_DMA_PRIORITY 0 +#define STM32_UART_UART5_DMA_PRIORITY 0 +#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") + +/* + * USB driver system settings. + */ +#ifdef STM32L476_MCUCONF +#define STM32_USB_USE_OTG1 TRUE +#define STM32_USB_OTG1_IRQ_PRIORITY 14 +#define STM32_USB_OTG1_RX_FIFO_SIZE 512 +#else +#define STM32_USB_USE_USB1 TRUE +#define STM32_USB_LOW_POWER_ON_SUSPEND FALSE +#define STM32_USB_USB1_HP_IRQ_PRIORITY 13 +#define STM32_USB_USB1_LP_IRQ_PRIORITY 14 +#endif // STM32L476_MCUCONF + +/* + * WDG driver system settings. + */ +#define STM32_WDG_USE_IWDG FALSE + +/* + * WSPI driver system settings. + */ +#define STM32_WSPI_USE_QUADSPI1 FALSE +#define STM32_WSPI_QUADSPI1_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) + +#endif /* MCUCONF_H */ diff --git a/firmware/source/communication.cpp b/firmware/source/communication.cpp new file mode 100644 index 0000000..e85828b --- /dev/null +++ b/firmware/source/communication.cpp @@ -0,0 +1,293 @@ +#include "communication.hpp" + +#include "ch.h" +#include "hal.h" + +#include "periph/adc.hpp" +#include "periph/dac.hpp" +#include "periph/usbserial.hpp" +#include "elfload.hpp" +#include "error.hpp" +#include "conversion.hpp" +#include "runstatus.hpp" +#include "samples.hpp" + +#include +#include + +__attribute__((section(".stacks"))) +std::array CommunicationManager::m_thread_stack = {}; + +void CommunicationManager::begin() +{ + chThdCreateStatic(m_thread_stack.data(), + m_thread_stack.size(), + NORMALPRIO, + threadComm, + nullptr); +} + +static void writeADCBuffer(unsigned char *); +static void setBufferSize(unsigned char *); +static void updateGenerator(unsigned char *); +static void loadAlgorithm(unsigned char *); +static void readStatus(unsigned char *); +static void measureConversion(unsigned char *); +static void startConversion(unsigned char *); +static void stopConversion(unsigned char *); +static void startGenerator(unsigned char *); +static void readADCBuffer(unsigned char *); +static void readDACBuffer(unsigned char *); +static void unloadAlgorithm(unsigned char *); +static void readIdentifier(unsigned char *); +static void readExecTime(unsigned char *); +static void sampleRate(unsigned char *); +static void readConversionResults(unsigned char *); +static void readConversionInput(unsigned char *); +static void readMessage(unsigned char *); +static void stopGenerator(unsigned char *); + +static const std::array, 19> commandTable {{ + {'A', writeADCBuffer}, + {'B', setBufferSize}, + {'D', updateGenerator}, + {'E', loadAlgorithm}, + {'I', readStatus}, + {'M', measureConversion}, + {'R', startConversion}, + {'S', stopConversion}, + {'W', startGenerator}, + {'a', readADCBuffer}, + {'d', readDACBuffer}, + {'e', unloadAlgorithm}, + {'i', readIdentifier}, + {'m', readExecTime}, + {'r', sampleRate}, + {'s', readConversionResults}, + {'t', readConversionInput}, + {'u', readMessage}, + {'w', stopGenerator} +}}; + +void CommunicationManager::threadComm(void *) +{ + while (1) { + if (USBSerial::isActive()) { + // Attempt to receive a command packet + if (unsigned char cmd[3]; USBSerial::read(&cmd[0], 1) > 0) { + // Packet received, first byte represents the desired command/action + auto func = std::find_if(commandTable.cbegin(), commandTable.cend(), + [&cmd](const auto& f) { return f.first == cmd[0]; }); + if (func != commandTable.cend()) + func->second(cmd); + } + } + + chThdSleepMicroseconds(100); + } +} + +void writeADCBuffer(unsigned char *) +{ + USBSerial::read(Samples::In.bytedata(), Samples::In.bytesize()); +} + +void setBufferSize(unsigned char *cmd) +{ + if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle) && + EM.assert(USBSerial::read(&cmd[1], 2) == 2, Error::BadParamSize)) + { + // count is multiplied by two since this command receives size of buffer + // for each algorithm application. + unsigned int count = (cmd[1] | (cmd[2] << 8)) * 2; + if (EM.assert(count <= MAX_SAMPLE_BUFFER_SIZE, Error::BadParam)) { + Samples::In.setSize(count); + Samples::Out.setSize(count); + } + } +} + +void updateGenerator(unsigned char *cmd) +{ + if (EM.assert(USBSerial::read(&cmd[1], 2) == 2, Error::BadParamSize)) { + unsigned int count = cmd[1] | (cmd[2] << 8); + if (EM.assert(count <= MAX_SAMPLE_BUFFER_SIZE, Error::BadParam)) { + if (!DAC::isSigGenRunning()) { + Samples::Generator.setSize(count); + USBSerial::read( + reinterpret_cast(Samples::Generator.data()), + Samples::Generator.bytesize()); + } else { + const int more = DAC::sigGenWantsMore(); + if (more == -1) { + USBSerial::write(reinterpret_cast("\0"), 1); + } else { + USBSerial::write(reinterpret_cast("\1"), 1); + + // Receive streamed samples in half-buffer chunks. + USBSerial::read(reinterpret_cast( + more == 0 ? Samples::Generator.data() : Samples::Generator.middata()), + Samples::Generator.bytesize() / 2); + } + } + } + } +} + +void loadAlgorithm(unsigned char *cmd) +{ + if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle) && + EM.assert(USBSerial::read(&cmd[1], 2) == 2, Error::BadParamSize)) + { + // Only load the binary if it can fit in the memory reserved for it. + unsigned int size = cmd[1] | (cmd[2] << 8); + if (EM.assert(size < MAX_ELF_FILE_SIZE, Error::BadUserCodeSize)) { + USBSerial::read(ELFManager::fileBuffer(), size); + auto success = ELFManager::loadFromInternalBuffer(); + EM.assert(success, Error::BadUserCodeLoad); + } + } +} + +void readStatus(unsigned char *) +{ + unsigned char buf[2] = { + static_cast(run_status), + static_cast(EM.pop()) + }; + + USBSerial::write(buf, sizeof(buf)); +} + +void measureConversion(unsigned char *) +{ + if (EM.assert(run_status == RunStatus::Running, Error::NotRunning)) + ConversionManager::startMeasurement(); +} + +void startConversion(unsigned char *) +{ + if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle)) { + run_status = RunStatus::Running; + ConversionManager::start(); + } +} + +void stopConversion(unsigned char *) +{ + if (EM.assert(run_status == RunStatus::Running, Error::NotRunning)) { + ConversionManager::stop(); + run_status = RunStatus::Idle; + } +} + +void startGenerator(unsigned char *) +{ + DAC::start(1, Samples::Generator.data(), Samples::Generator.size()); +} + +void readADCBuffer(unsigned char *) +{ + USBSerial::write(Samples::In.bytedata(), Samples::In.bytesize()); +} + +void readDACBuffer(unsigned char *) +{ + + USBSerial::write(Samples::Out.bytedata(), Samples::Out.bytesize()); +} + +void unloadAlgorithm(unsigned char *) +{ + ELFManager::unload(); +} + +void readIdentifier(unsigned char *) +{ +#if defined(TARGET_PLATFORM_H7) + USBSerial::write(reinterpret_cast("stmdsph"), 7); +#else + USBSerial::write(reinterpret_cast("stmdspl"), 7); +#endif +} + +void readExecTime(unsigned char *) +{ + // Stores the measured execution time. + extern time_measurement_t conversion_time_measurement; + USBSerial::write(reinterpret_cast(&conversion_time_measurement.last), + sizeof(rtcnt_t)); +} + +void sampleRate(unsigned char *cmd) +{ + if (EM.assert(USBSerial::read(&cmd[1], 1) == 1, Error::BadParamSize)) { + if (cmd[1] == 0xFF) { + unsigned char r = SClock::getRate(); + USBSerial::write(&r, 1); + } else { + auto r = static_cast(cmd[1]); + SClock::setRate(r); + ADC::setRate(r); + } + } +} + +void readConversionResults(unsigned char *) +{ + if (auto samps = Samples::Out.modified(); samps != nullptr) { + unsigned char buf[2] = { + static_cast(Samples::Out.size() / 2 & 0xFF), + static_cast(((Samples::Out.size() / 2) >> 8) & 0xFF) + }; + USBSerial::write(buf, 2); + unsigned int total = Samples::Out.bytesize() / 2; + unsigned int offset = 0; + unsigned char unused; + while (total > 512) { + USBSerial::write(reinterpret_cast(samps) + offset, 512); + while (USBSerial::read(&unused, 1) == 0); + offset += 512; + total -= 512; + } + USBSerial::write(reinterpret_cast(samps) + offset, total); + while (USBSerial::read(&unused, 1) == 0); + } else { + USBSerial::write(reinterpret_cast("\0\0"), 2); + } +} + +void readConversionInput(unsigned char *) +{ + if (auto samps = Samples::In.modified(); samps != nullptr) { + unsigned char buf[2] = { + static_cast(Samples::In.size() / 2 & 0xFF), + static_cast(((Samples::In.size() / 2) >> 8) & 0xFF) + }; + USBSerial::write(buf, 2); + unsigned int total = Samples::In.bytesize() / 2; + unsigned int offset = 0; + unsigned char unused; + while (total > 512) { + USBSerial::write(reinterpret_cast(samps) + offset, 512); + while (USBSerial::read(&unused, 1) == 0); + offset += 512; + total -= 512; + } + USBSerial::write(reinterpret_cast(samps) + offset, total); + while (USBSerial::read(&unused, 1) == 0); + } else { + USBSerial::write(reinterpret_cast("\0\0"), 2); + } +} + +void readMessage(unsigned char *) +{ + //USBSerial::write(reinterpret_cast(userMessageBuffer), userMessageSize); +} + +void stopGenerator(unsigned char *) +{ + DAC::stop(1); +} + diff --git a/firmware/source/communication.hpp b/firmware/source/communication.hpp new file mode 100644 index 0000000..03220b8 --- /dev/null +++ b/firmware/source/communication.hpp @@ -0,0 +1,29 @@ +/** + * @file communication.hpp + * @brief Manages communication with the host computer. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_COMMUNICATION_HPP +#define STMDSP_COMMUNICATION_HPP + +#include + +class CommunicationManager +{ +public: + static void begin(); + +private: + static void threadComm(void *); + + static std::array m_thread_stack; +}; + +#endif // STMDSP_COMMUNICATION_HPP + diff --git a/firmware/source/conversion.cpp b/firmware/source/conversion.cpp new file mode 100644 index 0000000..56a689e --- /dev/null +++ b/firmware/source/conversion.cpp @@ -0,0 +1,218 @@ +/** + * @file conversion.cpp + * @brief Manages algorithm application (converts input samples to output). + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "conversion.hpp" + +#include "periph/adc.hpp" +#include "periph/dac.hpp" +#include "elfload.hpp" +#include "error.hpp" +#include "runstatus.hpp" +#include "samples.hpp" + +// MSG_* things below are macros rather than constexpr +// to ensure inlining. + +#define MSG_CONVFIRST (1) +#define MSG_CONVSECOND (2) +#define MSG_CONVFIRST_MEASURE (3) +#define MSG_CONVSECOND_MEASURE (4) + +#define MSG_FOR_FIRST(msg) (msg & 1) +#define MSG_FOR_MEASURE(msg) (msg > 2) + +__attribute__((section(".convdata"))) +thread_t *ConversionManager::m_thread_monitor = nullptr; +thread_t *ConversionManager::m_thread_runner = nullptr; + +__attribute__((section(".stacks"))) +std::array ConversionManager::m_thread_monitor_stack = {}; +__attribute__((section(".stacks"))) +std::array ConversionManager::m_thread_runner_entry_stack = {}; +__attribute__((section(".convdata"))) +std::array ConversionManager::m_thread_runner_stack = {}; + +std::array ConversionManager::m_mailbox_buffer; +mailbox_t ConversionManager::m_mailbox = _MAILBOX_DATA(m_mailbox, m_mailbox_buffer.data(), m_mailbox_buffer.size()); + +void ConversionManager::begin() +{ + m_thread_monitor = chThdCreateStatic(m_thread_monitor_stack.data(), + m_thread_monitor_stack.size(), + NORMALPRIO + 1, + threadMonitor, + nullptr); + auto runner_stack_end = &m_thread_runner_stack[CONVERSION_THREAD_STACK_SIZE]; + m_thread_runner = chThdCreateStatic(m_thread_runner_entry_stack.data(), + m_thread_runner_entry_stack.size(), + HIGHPRIO, + threadRunnerEntry, + runner_stack_end); +} + +void ConversionManager::start() +{ + Samples::Out.clear(); + ADC::start(Samples::In.data(), Samples::In.size(), adcReadHandler); + DAC::start(0, Samples::Out.data(), Samples::Out.size()); +} + +void ConversionManager::startMeasurement() +{ + ADC::setOperation(adcReadHandlerMeasure); +} + +void ConversionManager::stop() +{ + DAC::stop(0); + ADC::stop(); +} + +thread_t *ConversionManager::getMonitorHandle() +{ + return m_thread_monitor; +} + +void ConversionManager::abort(bool fpu_stacked) +{ + ELFManager::unload(); + EM.add(Error::ConversionAborted); + //run_status = RunStatus::Recovering; + + // Confirm that the exception return thread is the algorithm... + uint32_t *psp; + asm("mrs %0, psp" : "=r" (psp)); + + bool isRunnerStack = + (uint32_t)psp >= reinterpret_cast(m_thread_runner_stack.data()) && + (uint32_t)psp <= reinterpret_cast(m_thread_runner_stack.data() + + m_thread_runner_stack.size()); + + if (isRunnerStack) + { + // If it is, we can force the algorithm to exit by "resetting" its thread. + // We do this by rebuilding the thread's stacked exception return. + auto newpsp = reinterpret_cast(m_thread_runner_stack.data() + + m_thread_runner_stack.size() - + (fpu_stacked ? 26 : 8) * sizeof(uint32_t)); + // Set the LR register to the thread's entry point. + newpsp[5] = reinterpret_cast(threadRunner); + // Overwrite the instruction we'll return to with "bx lr" (jump to address in LR). + newpsp[6] = psp[6]; + *reinterpret_cast(newpsp[6]) = 0x4770; // "bx lr" + // Keep PSR contents (bit set forces Thumb mode, just in case). + newpsp[7] = psp[7] | (1 << 24); + // Set the new stack pointer. + asm("msr psp, %0" :: "r" (newpsp)); + } +} + +void ConversionManager::threadMonitor(void *) +{ + while (1) { + msg_t message; + msg_t fetch = chMBFetchTimeout(&m_mailbox, &message, TIME_INFINITE); + if (fetch == MSG_OK) + chMsgSend(m_thread_runner, message); + } +} + +void ConversionManager::threadRunnerEntry(void *stack) +{ + ELFManager::unload(); + port_unprivileged_jump(reinterpret_cast(threadRunner), + reinterpret_cast(stack)); +} + +__attribute__((section(".convcode"))) +void ConversionManager::threadRunner(void *) +{ + while (1) { + // Sleep until we receive a mailbox message. + msg_t message; + asm("svc 0; mov %0, r0" : "=r" (message)); + + if (message != 0) { + auto samples = MSG_FOR_FIRST(message) ? Samples::In.data() + : Samples::In.middata(); + auto size = Samples::In.size() / 2; + + auto entry = ELFManager::loadedElf(); + if (entry) { + // Below, we remember the stack pointer just in case the + // loaded algorithm messes things up. + uint32_t sp; + + if (!MSG_FOR_MEASURE(message)) { + asm("mov %0, sp" : "=r" (sp)); + samples = entry(samples, size); + asm("mov sp, %0" :: "r" (sp)); + volatile auto testRead = *samples; + } else { + // Start execution timer: + asm("mov %0, sp; eor r0, r0; svc 2" : "=r" (sp)); + samples = entry(samples, size); + // Stop execution timer: + asm("mov r0, #1; svc 2; mov sp, %0" :: "r" (sp)); + volatile auto testRead = *samples; + } + } + + // Update the sample out buffer with the transformed samples. + if (samples != nullptr) { + if (MSG_FOR_FIRST(message)) + Samples::Out.modify(samples, size); + else + Samples::Out.midmodify(samples, size); + } + } + } +} + +void ConversionManager::adcReadHandler(adcsample_t *buffer, size_t) +{ + chSysLockFromISR(); + + // If previous request hasn't been handled, then we're going too slow. + // We'll need to abort. + if (chMBGetUsedCountI(&m_mailbox) > 1) { + chMBResetI(&m_mailbox); + chMBResumeX(&m_mailbox); + chSysUnlockFromISR(); + abort(); + } else { + // Mark the modified samples as 'fresh' or ready for manipulation. + if (buffer == Samples::In.data()) { + Samples::In.setModified(); + chMBPostI(&m_mailbox, MSG_CONVFIRST); + } else { + Samples::In.setMidmodified(); + chMBPostI(&m_mailbox, MSG_CONVSECOND); + } + chSysUnlockFromISR(); + } +} + +void ConversionManager::adcReadHandlerMeasure(adcsample_t *buffer, size_t) +{ + chSysLockFromISR(); + if (buffer == Samples::In.data()) { + Samples::In.setModified(); + chMBPostI(&m_mailbox, MSG_CONVFIRST_MEASURE); + } else { + Samples::In.setMidmodified(); + chMBPostI(&m_mailbox, MSG_CONVSECOND_MEASURE); + } + chSysUnlockFromISR(); + + ADC::setOperation(adcReadHandler); +} + diff --git a/firmware/source/conversion.hpp b/firmware/source/conversion.hpp new file mode 100644 index 0000000..ca0054a --- /dev/null +++ b/firmware/source/conversion.hpp @@ -0,0 +1,64 @@ +/** + * @file conversion.hpp + * @brief Manages algorithm application (converts input samples to output). + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_CONVERSION_HPP +#define STMDSP_CONVERSION_HPP + +#include "ch.h" +#include "hal.h" + +#include + +constexpr unsigned int CONVERSION_THREAD_STACK_SIZE = +#if defined(TARGET_PLATFORM_H7) + 62 * 1024; +#else + 15 * 1024; +#endif + +class ConversionManager +{ +public: + static void begin(); + + // Begins sample conversion. + static void start(); + // Prepare to measure execution time of next conversion. + static void startMeasurement(); + // Stops conversion. + static void stop(); + + static thread_t *getMonitorHandle(); + + // Internal only: Aborts a running conversion. + static void abort(bool fpu_stacked = true); + +private: + static void threadMonitor(void *); + static void threadRunnerEntry(void *stack); + + static void threadRunner(void *); + static void adcReadHandler(adcsample_t *buffer, size_t); + static void adcReadHandlerMeasure(adcsample_t *buffer, size_t); + + static thread_t *m_thread_monitor; + static thread_t *m_thread_runner; + + static std::array m_thread_monitor_stack; + static std::array m_thread_runner_entry_stack; + static std::array m_thread_runner_stack; + + static std::array m_mailbox_buffer; + static mailbox_t m_mailbox; +}; + +#endif // STMDSP_CONVERSION_HPP + diff --git a/firmware/source/elf.h b/firmware/source/elf.h new file mode 100644 index 0000000..998356d --- /dev/null +++ b/firmware/source/elf.h @@ -0,0 +1,100 @@ +/** + * @file elf.h + * @brief Defines ELF binary format info. + * + * Free to use, written by Clyne Sullivan. + */ + +#ifndef STMDSP_ELF_HPP +#define STMDSP_ELF_HPP + +#include + +#define EI_NIDENT 16 + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_RESERVED 0x70000000 + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i) & 0xF) +#define ELF32_ST_INFO(b, t) (((b) << 4) + ((t) & 0xF)) + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((i) & 0xFF) +#define ELF32_R_INFO(s, t) (((s) << 8) + ((t) & 0xFF)) + +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef uint32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} __attribute__((packed)) Elf32_Ehdr; + +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} __attribute__((packed)) Elf32_Shdr; + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} __attribute__((packed)) Elf32_Sym; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} __attribute__((packed)) Elf32_Rel; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} __attribute__((packed)) Elf32_Rela; + +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} __attribute__((packed)) Elf32_Phdr; + +#endif // STMDSP_ELF_HPP + diff --git a/firmware/source/elfload.cpp b/firmware/source/elfload.cpp new file mode 100644 index 0000000..87461e4 --- /dev/null +++ b/firmware/source/elfload.cpp @@ -0,0 +1,84 @@ +/** + * @file elfload.cpp + * @brief Loads ELF binary data into memory for execution. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "elfload.hpp" +#include "elf.h" + +#include +#include + +__attribute__((section(".convdata"))) +ELFManager::EntryFunc ELFManager::m_entry = nullptr; +std::array ELFManager::m_file_buffer = {}; + +static const unsigned char elf_header[] = { '\177', 'E', 'L', 'F' }; + +__attribute__((section(".convcode"))) +ELFManager::EntryFunc ELFManager::loadedElf() +{ + return m_entry; +} + +unsigned char *ELFManager::fileBuffer() +{ + return m_file_buffer.data(); +} + +void ELFManager::unload() +{ + m_entry = nullptr; +} + +template +constexpr static auto ptr_from_offset(void *base, uint32_t offset) +{ + return reinterpret_cast(reinterpret_cast(base) + offset); +} + +bool ELFManager::loadFromInternalBuffer() +{ + m_entry = nullptr; + + auto elf_data = m_file_buffer.data(); + + // Check the ELF's header signature + auto ehdr = reinterpret_cast(elf_data); + if (!std::equal(ehdr->e_ident, ehdr->e_ident + 4, elf_header)) + return false; + + // Iterate through program header LOAD sections + bool loaded = false; + auto phdr = ptr_from_offset(elf_data, ehdr->e_phoff); + for (Elf32_Half i = 0; i < ehdr->e_phnum; i++) { + if (phdr->p_type == PT_LOAD) { + if (phdr->p_filesz == 0) { + std::memset(reinterpret_cast(phdr->p_vaddr), + 0, + phdr->p_memsz); + } else { + std::memcpy(reinterpret_cast(phdr->p_vaddr), + ptr_from_offset(elf_data, phdr->p_offset), + phdr->p_filesz); + if (!loaded) + loaded = true; + } + } + + phdr = ptr_from_offset(phdr, ehdr->e_phentsize); + } + + + if (loaded) + m_entry = reinterpret_cast(ehdr->e_entry); + + return loaded; +} + diff --git a/firmware/source/elfload.hpp b/firmware/source/elfload.hpp new file mode 100644 index 0000000..10d95d7 --- /dev/null +++ b/firmware/source/elfload.hpp @@ -0,0 +1,39 @@ +/** + * @file elfload.hpp + * @brief Loads ELF binary data into memory for execution. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef ELF_LOAD_HPP_ +#define ELF_LOAD_HPP_ + +#include "samplebuffer.hpp" + +#include +#include + +constexpr unsigned int MAX_ELF_FILE_SIZE = 16 * 1024; + +class ELFManager +{ +public: + using EntryFunc = Sample *(*)(Sample *, size_t); + + static bool loadFromInternalBuffer(); + static EntryFunc loadedElf(); + static unsigned char *fileBuffer(); + static void unload(); + +private: + static EntryFunc m_entry; + + static std::array m_file_buffer; +}; + +#endif // ELF_LOAD_HPP_ + diff --git a/firmware/source/error.cpp b/firmware/source/error.cpp new file mode 100644 index 0000000..9f2e98f --- /dev/null +++ b/firmware/source/error.cpp @@ -0,0 +1,38 @@ +/** + * @file error.cpp + * @brief Tracks and reports non-critical errors. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "error.hpp" + +ErrorManager EM; + +void ErrorManager::add(Error error) +{ + if (m_index < m_queue.size()) + m_queue[m_index++] = error; +} + +bool ErrorManager::assert(bool condition, Error error) +{ + if (!condition) + add(error); + return condition; +} + +bool ErrorManager::hasError() +{ + return m_index > 0; +} + +Error ErrorManager::pop() +{ + return m_index == 0 ? Error::None : m_queue[--m_index]; +} + diff --git a/firmware/source/error.hpp b/firmware/source/error.hpp new file mode 100644 index 0000000..c6a7f5c --- /dev/null +++ b/firmware/source/error.hpp @@ -0,0 +1,47 @@ +/** + * @file error.hpp + * @brief Tracks and reports non-critical errors. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_ERROR_HPP +#define STMDSP_ERROR_HPP + +#include + +enum class Error : char +{ + None = 0, + BadParam, + BadParamSize, + BadUserCodeLoad, + BadUserCodeSize, + NotIdle, + ConversionAborted, + NotRunning +}; + +class ErrorManager +{ + constexpr static unsigned int MAX_ERROR_QUEUE_SIZE = 8; + +public: + void add(Error error); + bool assert(bool condition, Error error); + bool hasError(); + Error pop(); + +private: + std::array m_queue; + unsigned int m_index = 0; +}; + +extern ErrorManager EM; + +#endif // STMDSP_ERROR_HPP + diff --git a/firmware/source/handlers.cpp b/firmware/source/handlers.cpp new file mode 100644 index 0000000..43e65c3 --- /dev/null +++ b/firmware/source/handlers.cpp @@ -0,0 +1,140 @@ +#include "handlers.hpp" + +#include "adc.hpp" +#include "conversion.hpp" +#include "cordic.hpp" +#include "runstatus.hpp" + +extern "C" { + +time_measurement_t conversion_time_measurement; + +__attribute__((naked)) +void port_syscall(struct port_extctx *ctxp, uint32_t n) +{ + switch (n) { + + // Sleeps the current thread until a message is received. + // Used the algorithm runner to wait for new data. + case 0: + { + chSysLock(); + chMsgWaitS(); + auto monitor = ConversionManager::getMonitorHandle(); + auto msg = chMsgGet(monitor); + chMsgReleaseS(monitor, MSG_OK); + chSysUnlock(); + ctxp->r0 = msg; + } + break; + + // Provides access to advanced math functions. + // A service call like this is required for some hardware targets that + // provide hardware-accelerated math computations (e.g. CORDIC). + case 1: + { + using mathcall = void (*)(); + static mathcall funcs[3] = { + reinterpret_cast(cordic::sin), + reinterpret_cast(cordic::cos), + reinterpret_cast(cordic::tan), + }; +#if defined(PLATFORM_H7) + asm("vmov.f64 d0, %0, %1" :: "r" (ctxp->r1), "r" (ctxp->r2)); + if (ctxp->r0 < 3) { + funcs[ctxp->r0](); + asm("vmov.f64 %0, %1, d0" : "=r" (ctxp->r1), "=r" (ctxp->r2)); + } else { + asm("eor r0, r0; vmov.f64 d0, r0, r0"); + } +#else + asm("vmov.f32 s0, %0" :: "r" (ctxp->r1)); + if (ctxp->r0 < 3) { + funcs[ctxp->r0](); + asm("vmov.f32 %0, s0" : "=r" (ctxp->r1)); + } else { + asm("eor r0, r0; vmov.f32 s0, r0"); + } +#endif + } + break; + + // Starts or stops precise cycle time measurement. + // Used to measure algorithm execution time. + case 2: + if (ctxp->r0 == 0) { + chTMStartMeasurementX(&conversion_time_measurement); + } else { + chTMStopMeasurementX(&conversion_time_measurement); + // Subtract measurement overhead from the result. + // Running an empty algorithm ("bx lr") takes 196 cycles as of 2/4/21. + // Only measures algorithm code time (loading args/storing result takes 9 cycles). + constexpr rtcnt_t measurement_overhead = 196 - 1; + if (conversion_time_measurement.last > measurement_overhead) + conversion_time_measurement.last -= measurement_overhead; + } + break; + + // Reads one of the analog inputs made available for algorithm run-time input. + case 3: + ctxp->r0 = ADC::readAlt(ctxp->r0); + break; + + //case 4: + // { + // const char *str = reinterpret_cast(ctxp->r0); + // auto src = str; + // auto dst = userMessageBuffer; + // while (*src) + // *dst++ = *src++; + // *dst = '\0'; + // userMessageSize = src - str; + // } + // break; + default: + while (1); + break; + } + + asm("svc 0"); + while (1); +} + +__attribute__((naked)) +void MemManage_Handler() +{ + // 1. Get the stack pointer. + uint32_t lr; + asm("mov %0, lr" : "=r" (lr)); + + // 2. Recover from the fault. + ConversionManager::abort((lr & (1 << 4)) ? false : true); + + // 3. Return. + asm("mov lr, %0; bx lr" :: "r" (lr)); +} + +__attribute__((naked)) +void HardFault_Handler() +{ + // Get the stack pointer. + //uint32_t *stack; + uint32_t lr; + asm("mov %0, lr" : "=r" (lr)); + /*asm("\ + tst lr, #4; \ + ite eq; \ + mrseq %0, msp; \ + mrsne %0, psp; \ + mov %1, lr; \ + " : "=r" (stack), "=r" (lr));*/ + + // If coming from the algorithm, attempt to recover; otherwise, give up. + if (run_status != RunStatus::Running && (lr & 4) != 0) + MemManage_Handler(); + + while (1); +} + +} // extern "C" + diff --git a/firmware/source/handlers.hpp b/firmware/source/handlers.hpp new file mode 100644 index 0000000..fd7e10c --- /dev/null +++ b/firmware/source/handlers.hpp @@ -0,0 +1,31 @@ +/** + * @file handlers.hpp + * @brief Interrupt service routine handlers. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_HANDLERS_HPP +#define STMDSP_HANDLERS_HPP + +#include "ch.h" + +extern "C" { + +__attribute__((naked)) +void port_syscall(struct port_extctx *ctxp, uint32_t n); + +__attribute__((naked)) +void MemManage_Handler(); + +__attribute__((naked)) +void HardFault_Handler(); + +} + +#endif // STMDSP_HANDLERS_HPP + diff --git a/firmware/source/ld/STM32H723xG.ld b/firmware/source/ld/STM32H723xG.ld new file mode 100644 index 0000000..7d5bafb --- /dev/null +++ b/firmware/source/ld/STM32H723xG.ld @@ -0,0 +1,124 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * AXI SRAM - BSS, Data, Heap. + * SRAM1 - SIGGEN. + * SRAM2 - DAC. + * SRAM4 - ADC. + * DTCM-RAM - Process stacks. + * ITCM-RAM - STMDSP Algorithm. + * BCKP SRAM - None. + */ +MEMORY +{ + flash0 (rx) : org = 0x08000000, len = 1M /* Flash bank1 + bank2 */ + flash1 (rx) : org = 0x08000000, len = 510K /* Flash bank 1 */ + flashc (rx) : org = 0x0807F800, len = 2K /* Unprivileged firmware */ + flash2 (rx) : org = 0x08080000, len = 512K /* Flash bank 2 */ + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + ram0 (wx) : org = 0x24000000, len = 320K /* AXI SRAM */ + ram1 (wx) : org = 0x30000000, len = 16K /* AHB SRAM1 */ + ram2 (wx) : org = 0x30004000, len = 16K /* AHB SRAM2 */ + ram3 (wx) : org = 0x38000000, len = 16K /* AHB SRAM4 */ + ram4 (wx) : org = 0x00000000, len = 0 + ramc (wx) : org = 0x20000000, len = 64K /* Unprivileged data */ + ram5 (wx) : org = 0x20010000, len = 64K /* DTCM-RAM */ + ram6 (wx) : org = 0x00000000, len = 64K /* ITCM-RAM */ + ram7 (wx) : org = 0x38800000, len = 4K /* BCKP SRAM */ +} + +/* For each data/text section two region are defined, a virtual region + and a load region (_LMA suffix).*/ + +/* Flash region to be used for exception vectors.*/ +REGION_ALIAS("VECTORS_FLASH", flash0); +REGION_ALIAS("VECTORS_FLASH_LMA", flash0); + +/* Flash region to be used for constructors and destructors.*/ +REGION_ALIAS("XTORS_FLASH", flash0); +REGION_ALIAS("XTORS_FLASH_LMA", flash0); + +/* Flash region to be used for code text.*/ +REGION_ALIAS("TEXT_FLASH", flash0); +REGION_ALIAS("TEXT_FLASH_LMA", flash0); + +/* Flash region to be used for read only data.*/ +REGION_ALIAS("RODATA_FLASH", flash0); +REGION_ALIAS("RODATA_FLASH_LMA", flash0); + +/* Flash region to be used for various.*/ +REGION_ALIAS("VARIOUS_FLASH", flash0); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash0); + +/* Flash region to be used for RAM(n) initialization data.*/ +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("MAIN_STACK_RAM", ram5); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram5); + +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash0); + +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); + +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); + +/* Stack rules inclusion.*/ +INCLUDE rules_stacks.ld + +SECTIONS +{ + .convdata : ALIGN(4) + { + *(.convdata) + . = ALIGN(4); + } > ramc + + .stacks : ALIGN(4) + { + *(.stacks) + . = ALIGN(4); + } > ram5 + + .convcode : ALIGN(4) + { + *(.convcode) + . = ALIGN(4); + } > flashc +} + +/* Code rules inclusion.*/ +INCLUDE rules_code.ld + +/* Data rules inclusion.*/ +INCLUDE rules_data.ld + +/* Memory rules inclusion.*/ +INCLUDE rules_memory.ld + diff --git a/firmware/source/ld/STM32L476xG.ld b/firmware/source/ld/STM32L476xG.ld new file mode 100644 index 0000000..b3a332d --- /dev/null +++ b/firmware/source/ld/STM32L476xG.ld @@ -0,0 +1,116 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * STM32L476xG memory setup. + * A total of 1MB of flash is available. + * Firmware uses first 510K, then 2K after is used for unprivileged code. + * A total of 128K of RAM is available. + * SRAM2 (32K) is used for ELF binary loading. + * 32K of SRAM1 is used for system RAM. + * 48K is used for ADC and DAC buffers. + * 16K is used for unprivileged data (incl. 8K stack). + */ +MEMORY +{ + flash0 (rx) : org = 0x08000000, len = 510K /* Flash bank 1 (reduced from 1M to 510K) */ + flash1 (rx) : org = 0x00000000, len = 0 + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + ram0 (wx) : org = 0x20000000, len = 32K /* SRAM (actual total = 96K) */ + ram1 (wx) : org = 0x20008000, len = 48K /* ADC/DAC buffers (16K * 3) */ + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x10000000, len = 32K /* User algorithm */ + ram5 (wx) : org = 0x00000000, len = 0 + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x00000000, len = 0 + flashc (rx) : org = 0x0807F800, len = 2K /* Unprivileged firmware */ + ramc (wx) : org = 0x20014000, len = 16K /* Unprivileged data */ +} + +/* For each data/text section two region are defined, a virtual region + and a load region (_LMA suffix).*/ + +/* Flash region to be used for exception vectors.*/ +REGION_ALIAS("VECTORS_FLASH", flash0); +REGION_ALIAS("VECTORS_FLASH_LMA", flash0); + +/* Flash region to be used for constructors and destructors.*/ +REGION_ALIAS("XTORS_FLASH", flash0); +REGION_ALIAS("XTORS_FLASH_LMA", flash0); + +/* Flash region to be used for code text.*/ +REGION_ALIAS("TEXT_FLASH", flash0); +REGION_ALIAS("TEXT_FLASH_LMA", flash0); + +/* Flash region to be used for read only data.*/ +REGION_ALIAS("RODATA_FLASH", flash0); +REGION_ALIAS("RODATA_FLASH_LMA", flash0); + +/* Flash region to be used for various.*/ +REGION_ALIAS("VARIOUS_FLASH", flash0); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash0); + +/* Flash region to be used for RAM(n) initialization data.*/ +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("MAIN_STACK_RAM", ram0); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram0); + +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash0); + +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); + +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); + +SECTIONS +{ + .convdata : ALIGN(4) + { + *(.convdata) + . = ALIGN(4); + } > ramc + + /*.stacks : ALIGN(4) + { + *(.stacks) + . = ALIGN(4); + } > ram5*/ + + .convcode : ALIGN(4) + { + *(.convcode) + . = ALIGN(4); + } > flashc +} + + +/* Generic rules inclusion.*/ +INCLUDE rules.ld diff --git a/firmware/source/main.cpp b/firmware/source/main.cpp new file mode 100644 index 0000000..9a22a73 --- /dev/null +++ b/firmware/source/main.cpp @@ -0,0 +1,58 @@ +/** + * @file main.cpp + * @brief Program entry point. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "ch.h" +#include "hal.h" + +#include "adc.hpp" +#include "cordic.hpp" +#include "dac.hpp" +#include "error.hpp" +#include "sclock.hpp" +#include "usbserial.hpp" + +#include "runstatus.hpp" +RunStatus run_status = RunStatus::Idle; + +// Other variables +// +//static char userMessageBuffer[128]; +//static unsigned char userMessageSize = 0; + +#include "conversion.hpp" +#include "communication.hpp" +#include "monitor.hpp" + +int main() +{ + // Initialize ChibiOS + halInit(); + chSysInit(); + + // Init peripherials + ADC::begin(); + DAC::begin(); + SClock::begin(); + USBSerial::begin(); + cordic::init(); + + SClock::setRate(SClock::Rate::R32K); + ADC::setRate(SClock::Rate::R32K); + + // Start our threads. + ConversionManager::begin(); + CommunicationManager::begin(); + Monitor::begin(); + + chThdExit(0); + return 0; +} + diff --git a/firmware/source/monitor.cpp b/firmware/source/monitor.cpp new file mode 100644 index 0000000..6ef97e9 --- /dev/null +++ b/firmware/source/monitor.cpp @@ -0,0 +1,80 @@ +/** + * @file monitor.cpp + * @brief Manages the device monitoring thread (status LEDs, etc.). + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "monitor.hpp" + +#include "error.hpp" +#include "runstatus.hpp" + +#include "hal.h" + +__attribute__((section(".stacks"))) +std::array Monitor::m_thread_stack = {}; + +void Monitor::begin() +{ + chThdCreateStatic(m_thread_stack.data(), + m_thread_stack.size(), + LOWPRIO, + threadMonitor, + nullptr); +} + +void Monitor::threadMonitor(void *) +{ + palSetLineMode(LINE_BUTTON, PAL_MODE_INPUT_PULLUP); + auto readButton = [] { +#ifdef TARGET_PLATFORM_L4 + return !palReadLine(LINE_BUTTON); +#else + return palReadLine(LINE_BUTTON); +#endif + }; + + palSetLine(LINE_LED_RED); + palSetLine(LINE_LED_GREEN); + palSetLine(LINE_LED_BLUE); + + while (1) { + bool isidle = run_status == RunStatus::Idle; + auto led = isidle ? LINE_LED_GREEN : LINE_LED_BLUE; + auto delay = isidle ? 500 : 250; + + palToggleLine(led); + chThdSleepMilliseconds(delay); + palToggleLine(led); + chThdSleepMilliseconds(delay); + + if (isidle && readButton()) { + palClearLine(LINE_LED_GREEN); + palClearLine(LINE_LED_BLUE); + chSysLock(); + while (readButton()) + asm("nop"); + while (!readButton()) + asm("nop"); + chSysUnlock(); + palSetLine(LINE_LED_GREEN); + palSetLine(LINE_LED_BLUE); + chThdSleepMilliseconds(500); + } + + static bool erroron = false; + if (auto err = EM.hasError(); err ^ erroron) { + erroron = err; + if (err) + palClearLine(LINE_LED_RED); + else + palSetLine(LINE_LED_RED); + } + } +} + diff --git a/firmware/source/monitor.hpp b/firmware/source/monitor.hpp new file mode 100644 index 0000000..93f75e3 --- /dev/null +++ b/firmware/source/monitor.hpp @@ -0,0 +1,31 @@ +/** + * @file monitor.hpp + * @brief Manages the device monitoring thread (status LEDs, etc.). + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_MONITOR_HPP +#define STMDSP_MONITOR_HPP + +#include "ch.h" + +#include + +class Monitor +{ +public: + static void begin(); + +private: + static void threadMonitor(void *); + + static std::array m_thread_stack; +}; + +#endif // STMDSP_MONITOR_HPP + diff --git a/firmware/source/periph/adc.cpp b/firmware/source/periph/adc.cpp new file mode 100644 index 0000000..4667307 --- /dev/null +++ b/firmware/source/periph/adc.cpp @@ -0,0 +1,245 @@ +/** + * @file adc.cpp + * @brief Manages signal reading through the ADC. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "adc.hpp" + +#if defined(TARGET_PLATFORM_L4) +ADCDriver *ADC::m_driver = &ADCD1; +ADCDriver *ADC::m_driver2 = &ADCD3; +#else +ADCDriver *ADC::m_driver = &ADCD3; +//ADCDriver *ADC::m_driver2 = &ADCD1; // TODO +#endif + +const ADCConfig ADC::m_config = { + .difsel = 0, +#if defined(TARGET_PLATFORM_H7) + .calibration = 0, +#endif +}; + +const ADCConfig ADC::m_config2 = { + .difsel = 0, +#if defined(TARGET_PLATFORM_H7) + .calibration = 0, +#endif +}; + +ADCConversionGroup ADC::m_group_config = { + .circular = true, + .num_channels = 1, + .end_cb = ADC::conversionCallback, + .error_cb = nullptr, + .cfgr = ADC_CFGR_EXTEN_RISING | ADC_CFGR_EXTSEL_SRC(13), /* TIM6_TRGO */ + .cfgr2 = 0,//ADC_CFGR2_ROVSE | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSS_0, // Oversampling 2x +#if defined(TARGET_PLATFORM_H7) + .ccr = 0, + .pcsel = 0, + .ltr1 = 0, .htr1 = 4095, + .ltr2 = 0, .htr2 = 4095, + .ltr3 = 0, .htr3 = 4095, +#else + .tr1 = ADC_TR(0, 4095), + .tr2 = ADC_TR(0, 4095), + .tr3 = ADC_TR(0, 4095), + .awd2cr = 0, + .awd3cr = 0, +#endif + .smpr = { + ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5), 0 + }, + .sqr = { + ADC_SQR1_SQ1_N(ADC_CHANNEL_IN5), + 0, 0, 0 + }, +}; + +static bool readAltDone = false; +static void readAltCallback(ADCDriver *) +{ + readAltDone = true; +} +ADCConversionGroup ADC::m_group_config2 = { + .circular = false, + .num_channels = 2, + .end_cb = readAltCallback, + .error_cb = nullptr, + .cfgr = ADC_CFGR_EXTEN_RISING | ADC_CFGR_EXTSEL_SRC(13), /* TIM6_TRGO */ + .cfgr2 = 0,//ADC_CFGR2_ROVSE | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSS_0, // Oversampling 2x +#if defined(TARGET_PLATFORM_H7) + .ccr = 0, + .pcsel = 0, + .ltr1 = 0, .htr1 = 4095, + .ltr2 = 0, .htr2 = 4095, + .ltr3 = 0, .htr3 = 4095, +#else + .tr1 = ADC_TR(0, 4095), + .tr2 = ADC_TR(0, 4095), + .tr3 = ADC_TR(0, 4095), + .awd2cr = 0, + .awd3cr = 0, +#endif + .smpr = { + ADC_SMPR1_SMP_AN1(ADC_SMPR_SMP_2P5) | ADC_SMPR1_SMP_AN2(ADC_SMPR_SMP_2P5), 0 + }, + .sqr = { + ADC_SQR1_SQ1_N(ADC_CHANNEL_IN1) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN2), + 0, 0, 0 + }, +}; + +adcsample_t *ADC::m_current_buffer = nullptr; +size_t ADC::m_current_buffer_size = 0; +ADC::Operation ADC::m_operation = nullptr; + +void ADC::begin() +{ +#if defined(TARGET_PLATFORM_H7) + palSetPadMode(GPIOF, 3, PAL_MODE_INPUT_ANALOG); +#else + palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG); // Algorithm in + palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); // Potentiometer 1 + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); // Potentiometer 2 +#endif + + adcStart(m_driver, &m_config); + adcStart(m_driver2, &m_config2); +} + +void ADC::start(adcsample_t *buffer, size_t count, Operation operation) +{ + m_current_buffer = buffer; + m_current_buffer_size = count; + m_operation = operation; + + adcStartConversion(m_driver, &m_group_config, buffer, count); + SClock::start(); +} + +void ADC::stop() +{ + SClock::stop(); + adcStopConversion(m_driver); + + m_current_buffer = nullptr; + m_current_buffer_size = 0; + m_operation = nullptr; +} + +adcsample_t ADC::readAlt(unsigned int id) +{ + if (id > 1) + return 0; + static adcsample_t result[16] = {}; + readAltDone = false; + adcStartConversion(m_driver2, &m_group_config2, result, 8); + while (!readAltDone); + //__WFI(); + adcStopConversion(m_driver2); + return result[id]; +} + +void ADC::setRate(SClock::Rate rate) +{ +#if defined(TARGET_PLATFORM_H7) + std::array, 6> m_rate_presets = {{ + // Rate PLL N PLL P + {/* 8k */ 80, 20}, + {/* 16k */ 80, 10}, + {/* 20k */ 80, 8}, + {/* 32k */ 80, 5}, + {/* 48k */ 96, 4}, + {/* 96k */ 288, 10} + }}; + + auto& preset = m_rate_presets[static_cast(rate)]; + auto pllbits = (preset[0] << RCC_PLL2DIVR_N2_Pos) | + (preset[1] << RCC_PLL2DIVR_P2_Pos); + + adcStop(m_driver); + + // Adjust PLL2 + RCC->CR &= ~(RCC_CR_PLL2ON); + while ((RCC->CR & RCC_CR_PLL2RDY) == RCC_CR_PLL2RDY); + auto pll2divr = RCC->PLL2DIVR & + ~(RCC_PLL2DIVR_N2_Msk | RCC_PLL2DIVR_P2_Msk); + pll2divr |= pllbits; + RCC->PLL2DIVR = pll2divr; + RCC->CR |= RCC_CR_PLL2ON; + while ((RCC->CR & RCC_CR_PLL2RDY) != RCC_CR_PLL2RDY); + + m_group_config.smpr[0] = rate != SClock::Rate::R96K ? ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5) + : ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_2P5); + + adcStart(m_driver, &m_config); +#elif defined(TARGET_PLATFORM_L4) + std::array, 6> m_rate_presets = {{ + // PLLSAI2 sources MSI of 4MHz, divided by PLLM of /1 = 4MHz. + // 4MHz is then multiplied by PLLSAI2N (x8 to x86), with result + // between 64 and 344 MHz. + // + // SAI2N MUST BE AT LEAST 16 TO MAKE 64MHz MINIMUM. + // + // That is then divided by PLLSAI2R: + // R of 0 = /2; 1 = /4, 2 = /6, 3 = /8. + // PLLSAI2 then feeds into the ADC, which has a prescaler of /10. + // Finally, the ADC's SMP value produces the desired sample rate. + // + // 4MHz * N / R / 10 / SMP = sample rate. + // + // With oversampling, must create faster clock + // (x2 oversampling requires x2 sample rate clock). + // + // Rate PLLSAI2N R SMPR + {/* 8k */ 16, 1, ADC_SMPR_SMP_12P5}, // R3=32k (min), R1=64k + {/* 16k */ 16, 0, ADC_SMPR_SMP_12P5}, + {/* 20k */ 20, 0, ADC_SMPR_SMP_12P5}, + {/* 32k */ 32, 0, ADC_SMPR_SMP_12P5}, + {/* 48k */ 48, 0, ADC_SMPR_SMP_12P5}, + {/* 96k */ 73, 0, ADC_SMPR_SMP_6P5} // Technically 96.05263kS/s + }}; + + auto& preset = m_rate_presets[static_cast(rate)]; + auto pllnr = (preset[0] << RCC_PLLSAI2CFGR_PLLSAI2N_Pos) | + (preset[1] << RCC_PLLSAI2CFGR_PLLSAI2R_Pos); + auto smpr = preset[2]; + + // Adjust PLLSAI2 + RCC->CR &= ~(RCC_CR_PLLSAI2ON); + while ((RCC->CR & RCC_CR_PLLSAI2RDY) == RCC_CR_PLLSAI2RDY); + RCC->PLLSAI2CFGR = (RCC->PLLSAI2CFGR & ~(RCC_PLLSAI2CFGR_PLLSAI2N_Msk | RCC_PLLSAI2CFGR_PLLSAI2R_Msk)) | pllnr; + RCC->CR |= RCC_CR_PLLSAI2ON; + while ((RCC->CR & RCC_CR_PLLSAI2RDY) != RCC_CR_PLLSAI2RDY); + + m_group_config.smpr[0] = ADC_SMPR1_SMP_AN5(smpr); + + // 8x oversample + m_group_config.cfgr2 = ADC_CFGR2_ROVSE | (2 << ADC_CFGR2_OVSR_Pos) | (3 << ADC_CFGR2_OVSS_Pos); + m_group_config2.cfgr2 = ADC_CFGR2_ROVSE | (2 << ADC_CFGR2_OVSR_Pos) | (3 << ADC_CFGR2_OVSS_Pos); +#endif +} + +void ADC::setOperation(ADC::Operation operation) +{ + m_operation = operation; +} + +void ADC::conversionCallback(ADCDriver *driver) +{ + if (m_operation != nullptr) { + auto half_size = m_current_buffer_size / 2; + if (adcIsBufferComplete(driver)) + m_operation(m_current_buffer + half_size, half_size); + else + m_operation(m_current_buffer, half_size); + } +} + diff --git a/firmware/source/periph/adc.hpp b/firmware/source/periph/adc.hpp new file mode 100644 index 0000000..5f7fa08 --- /dev/null +++ b/firmware/source/periph/adc.hpp @@ -0,0 +1,53 @@ +/** + * @file adc.hpp + * @brief Manages signal reading through the ADC. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_ADC_HPP_ +#define STMDSP_ADC_HPP_ + +#include "hal.h" +#include "sclock.hpp" + +#include + +class ADC +{ +public: + using Operation = void (*)(adcsample_t *buffer, size_t count); + + static void begin(); + + static void start(adcsample_t *buffer, size_t count, Operation operation); + static void stop(); + + static adcsample_t readAlt(unsigned int id); + + static void setRate(SClock::Rate rate); + static void setOperation(Operation operation); + +private: + static ADCDriver *m_driver; + static ADCDriver *m_driver2; + + static const ADCConfig m_config; + static const ADCConfig m_config2; + static ADCConversionGroup m_group_config; + static ADCConversionGroup m_group_config2; + + static adcsample_t *m_current_buffer; + static size_t m_current_buffer_size; + static Operation m_operation; + +public: + static void conversionCallback(ADCDriver *); +}; + +#endif // STMDSP_ADC_HPP_ + diff --git a/firmware/source/periph/cordic.cpp b/firmware/source/periph/cordic.cpp new file mode 100644 index 0000000..29ee068 --- /dev/null +++ b/firmware/source/periph/cordic.cpp @@ -0,0 +1,113 @@ +#include "cordic.hpp" +#include "hal.h" + +#if !defined(TARGET_PLATFORM_L4) +namespace cordic { + +void init() +{ + RCC->AHB2ENR |= RCC_AHB2ENR_CORDICEN; +} + +static void prepare() { + while (CORDIC->CSR & CORDIC_CSR_RRDY) + asm("mov r0, %0" :: "r" (CORDIC->RDATA)); +} + +static uint32_t dtoq(double) { + uint32_t res; + asm("vcvt.s32.f64 d0, d0, #31;" + "vmov %0, r5, d0" + : "=r" (res)); + return res; +} +__attribute__((naked)) +static double qtod(uint32_t) { + asm("eor r1, r1;" + "vmov d0, r0, r1;" + "vcvt.f64.s32 d0, d0, #31;" + "bx lr"); + return 0; +} +__attribute__((naked)) +double mod(double, double) { + asm("vdiv.f64 d2, d0, d1;" + "vrintz.f64 d2;" + "vmul.f64 d1, d1, d2;" + "vsub.f64 d0, d0, d1;" + "bx lr"); + return 0; +} + +double cos(double x) { + x = mod(x, 2 * math::PI) / math::PI; + auto input = dtoq(x > 1. ? x - 2 : x); + + prepare(); + CORDIC->CSR = CORDIC_CSR_NARGS | CORDIC_CSR_NRES | + (6 << CORDIC_CSR_PRECISION_Pos) | + (0 << CORDIC_CSR_FUNC_Pos); + + CORDIC->WDATA = input; + CORDIC->WDATA = input; + while (!(CORDIC->CSR & CORDIC_CSR_RRDY)); + + double cosx = qtod(CORDIC->RDATA) / x; + [[maybe_unused]] auto sinx = CORDIC->RDATA; + return cosx; +} + +double sin(double x) { + x = mod(x, 2 * math::PI) / math::PI; + auto input = dtoq(x > 1. ? x - 2 : x); + + prepare(); + CORDIC->CSR = CORDIC_CSR_NARGS | CORDIC_CSR_NRES | + (6 << CORDIC_CSR_PRECISION_Pos) | + (1 << CORDIC_CSR_FUNC_Pos); + + CORDIC->WDATA = input; + CORDIC->WDATA = input; + while (!(CORDIC->CSR & CORDIC_CSR_RRDY)); + + double sinx = qtod(CORDIC->RDATA) / x; + [[maybe_unused]] auto cosx = CORDIC->RDATA; + return sinx; +} + +double tan(double x) { + x = mod(x, 2 * math::PI) / math::PI; + auto input = dtoq(x > 1. ? x - 2 : x); + + prepare(); + CORDIC->CSR = CORDIC_CSR_NARGS | CORDIC_CSR_NRES | + (6 << CORDIC_CSR_PRECISION_Pos) | + (1 << CORDIC_CSR_FUNC_Pos); + + CORDIC->WDATA = input; + CORDIC->WDATA = input; + while (!(CORDIC->CSR & CORDIC_CSR_RRDY)); + + double sinx = qtod(CORDIC->RDATA) / x; + double tanx = sinx * x / qtod(CORDIC->RDATA); + return tanx; +} + +} +#else // L4 +#include +namespace cordic { + +void init() {} + +float mod(float a, float b) { + return a - (b * std::floor(a / b)); +} + +float cos(float x) { return std::cos(x); } +float sin(float x) { return std::sin(x); } +float tan(float x) { return std::tan(x); } + +} +#endif + diff --git a/firmware/source/periph/cordic.hpp b/firmware/source/periph/cordic.hpp new file mode 100644 index 0000000..5d640cc --- /dev/null +++ b/firmware/source/periph/cordic.hpp @@ -0,0 +1,25 @@ +#ifndef CORDIC_HPP_ +#define CORDIC_HPP_ + +namespace cordic { + constexpr double PI = 3.1415926535L; + + void init(); + +#if !defined(TARGET_PLATFORM_L4) + double mod(double n, double d); + + double cos(double x); + double sin(double x); + double tan(double x); +#else + float mod(float n, float d); + + float cos(float x); + float sin(float x); + float tan(float x); +#endif +} + +#endif // CORDIC_HPP_ + diff --git a/firmware/source/periph/dac.cpp b/firmware/source/periph/dac.cpp new file mode 100644 index 0000000..35c2908 --- /dev/null +++ b/firmware/source/periph/dac.cpp @@ -0,0 +1,85 @@ +/** + * @file dac.cpp + * @brief Manages signal creation using the DAC. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "dac.hpp" +#include "sclock.hpp" + +DACDriver *DAC::m_driver[2] = { + &DACD1, &DACD2 +}; + +const DACConfig DAC::m_config = { + .init = 2048, + .datamode = DAC_DHRM_12BIT_RIGHT, + .cr = 0 +}; + +static int dacIsDone = -1; +static void dacEndCallback(DACDriver *dacd) +{ + if (dacd == &DACD2) + dacIsDone = dacIsBufferComplete(dacd) ? 1 : 0; +} + +const DACConversionGroup DAC::m_group_config = { + .num_channels = 1, + .end_cb = dacEndCallback, + .error_cb = nullptr, +#if defined(TARGET_PLATFORM_H7) + .trigger = 5 // TIM6_TRGO +#elif defined(TARGET_PLATFORM_L4) + .trigger = 0 // TIM6_TRGO +#endif +}; + +void DAC::begin() +{ + palSetPadMode(GPIOA, 4, PAL_STM32_MODE_ANALOG); + palSetPadMode(GPIOA, 5, PAL_STM32_MODE_ANALOG); + + dacStart(m_driver[0], &m_config); + dacStart(m_driver[1], &m_config); +} + +void DAC::start(int channel, dacsample_t *buffer, size_t count) +{ + if (channel >= 0 && channel < 2) { + if (channel == 1) + dacIsDone = -1; + dacStartConversion(m_driver[channel], &m_group_config, buffer, count); + SClock::start(); + } +} + +int DAC::sigGenWantsMore() +{ + if (dacIsDone != -1) { + int tmp = dacIsDone; + dacIsDone = -1; + return tmp; + } else { + return -1; + } +} + +int DAC::isSigGenRunning() +{ + return m_driver[1]->state == DAC_ACTIVE; +} + +void DAC::stop(int channel) +{ + if (channel >= 0 && channel < 2) { + dacStopConversion(m_driver[channel]); + SClock::stop(); + } +} + diff --git a/firmware/source/periph/dac.hpp b/firmware/source/periph/dac.hpp new file mode 100644 index 0000000..7250a52 --- /dev/null +++ b/firmware/source/periph/dac.hpp @@ -0,0 +1,37 @@ +/** + * @file dac.hpp + * @brief Manages signal creation using the DAC. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_DAC_HPP_ +#define STMDSP_DAC_HPP_ + +#include "hal.h" +#undef DAC + +class DAC +{ +public: + static void begin(); + + static void start(int channel, dacsample_t *buffer, size_t count); + static void stop(int channel); + + static int sigGenWantsMore(); + static int isSigGenRunning(); + +private: + static DACDriver *m_driver[2]; + + static const DACConfig m_config; + static const DACConversionGroup m_group_config; +}; + +#endif // STMDSP_DAC_HPP_ + diff --git a/firmware/source/periph/usbcfg.c b/firmware/source/periph/usbcfg.c new file mode 100644 index 0000000..b726e23 --- /dev/null +++ b/firmware/source/periph/usbcfg.c @@ -0,0 +1,346 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" + +/* Virtual serial port over USB.*/ +SerialUSBDriver SDU1; + +/* + * Endpoints to be used for USBD1. + */ +#define USBD1_DATA_REQUEST_EP 1 +#define USBD1_DATA_AVAILABLE_EP 1 +#define USBD1_INTERRUPT_REQUEST_EP 2 + +/* + * USB Device Descriptor. + */ +static const uint8_t vcom_device_descriptor_data[18] = { + USB_DESC_DEVICE (0x0110, /* bcdUSB (1.1). */ + 0x02, /* bDeviceClass (CDC). */ + 0x00, /* bDeviceSubClass. */ + 0x00, /* bDeviceProtocol. */ + 0x40, /* bMaxPacketSize. */ + 0x0483, /* idVendor (ST). */ + 0x5740, /* idProduct. */ + 0x0200, /* bcdDevice. */ + 1, /* iManufacturer. */ + 2, /* iProduct. */ + 3, /* iSerialNumber. */ + 1) /* bNumConfigurations. */ +}; + +/* + * Device Descriptor wrapper. + */ +static const USBDescriptor vcom_device_descriptor = { + sizeof vcom_device_descriptor_data, + vcom_device_descriptor_data +}; + +/* Configuration Descriptor tree for a CDC.*/ +static const uint8_t vcom_configuration_descriptor_data[67] = { + /* Configuration Descriptor.*/ + USB_DESC_CONFIGURATION(67, /* wTotalLength. */ + 0x02, /* bNumInterfaces. */ + 0x01, /* bConfigurationValue. */ + 0, /* iConfiguration. */ + 0xC0, /* bmAttributes (self powered). */ + 50), /* bMaxPower (100mA). */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x01, /* bNumEndpoints. */ + 0x02, /* bInterfaceClass (Communications + Interface Class, CDC section + 4.2). */ + 0x02, /* bInterfaceSubClass (Abstract + Control Model, CDC section 4.3). */ + 0x01, /* bInterfaceProtocol (AT commands, + CDC section 4.4). */ + 0), /* iInterface. */ + /* Header Functional Descriptor (CDC section 5.2.3).*/ + USB_DESC_BYTE (5), /* bLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x00), /* bDescriptorSubtype (Header + Functional Descriptor. */ + USB_DESC_BCD (0x0110), /* bcdCDC. */ + /* Call Management Functional Descriptor. */ + USB_DESC_BYTE (5), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x01), /* bDescriptorSubtype (Call Management + Functional Descriptor). */ + USB_DESC_BYTE (0x00), /* bmCapabilities (D0+D1). */ + USB_DESC_BYTE (0x01), /* bDataInterface. */ + /* ACM Functional Descriptor.*/ + USB_DESC_BYTE (4), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x02), /* bDescriptorSubtype (Abstract + Control Management Descriptor). */ + USB_DESC_BYTE (0x02), /* bmCapabilities. */ + /* Union Functional Descriptor.*/ + USB_DESC_BYTE (5), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x06), /* bDescriptorSubtype (Union + Functional Descriptor). */ + USB_DESC_BYTE (0x00), /* bMasterInterface (Communication + Class Interface). */ + USB_DESC_BYTE (0x01), /* bSlaveInterface0 (Data Class + Interface). */ + /* Endpoint 2 Descriptor.*/ + USB_DESC_ENDPOINT (USBD1_INTERRUPT_REQUEST_EP|0x80, + 0x03, /* bmAttributes (Interrupt). */ + 0x0008, /* wMaxPacketSize. */ + 0xFF), /* bInterval. */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x01, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x02, /* bNumEndpoints. */ + 0x0A, /* bInterfaceClass (Data Class + Interface, CDC section 4.5). */ + 0x00, /* bInterfaceSubClass (CDC section + 4.6). */ + 0x00, /* bInterfaceProtocol (CDC section + 4.7). */ + 0x00), /* iInterface. */ + /* Endpoint 3 Descriptor.*/ + USB_DESC_ENDPOINT (USBD1_DATA_AVAILABLE_EP, /* bEndpointAddress.*/ + 0x02, /* bmAttributes (Bulk). */ + 0x0040, /* wMaxPacketSize. */ + 0x00), /* bInterval. */ + /* Endpoint 1 Descriptor.*/ + USB_DESC_ENDPOINT (USBD1_DATA_REQUEST_EP|0x80, /* bEndpointAddress.*/ + 0x02, /* bmAttributes (Bulk). */ + 0x0040, /* wMaxPacketSize. */ + 0x00) /* bInterval. */ +}; + +/* + * Configuration Descriptor wrapper. + */ +static const USBDescriptor vcom_configuration_descriptor = { + sizeof vcom_configuration_descriptor_data, + vcom_configuration_descriptor_data +}; + +/* + * U.S. English language identifier. + */ +static const uint8_t vcom_string0[] = { + USB_DESC_BYTE(4), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ +}; + +/* + * Vendor string. + */ +static const uint8_t vcom_string1[] = { + USB_DESC_BYTE(38), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, + 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, + 'c', 0, 's', 0 +}; + +/* + * Device Description string. + */ +static const uint8_t vcom_string2[] = { + USB_DESC_BYTE(56), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, + 'R', 0, 'T', 0, ' ', 0, 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, + 'a', 0, 'l', 0, ' ', 0, 'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0, + 'o', 0, 'r', 0, 't', 0 +}; + +/* + * Serial Number string. + */ +static const uint8_t vcom_string3[] = { + USB_DESC_BYTE(8), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + '0' + CH_KERNEL_MAJOR, 0, + '0' + CH_KERNEL_MINOR, 0, + '0' + CH_KERNEL_PATCH, 0 +}; + +/* + * Strings wrappers array. + */ +static const USBDescriptor vcom_strings[] = { + {sizeof vcom_string0, vcom_string0}, + {sizeof vcom_string1, vcom_string1}, + {sizeof vcom_string2, vcom_string2}, + {sizeof vcom_string3, vcom_string3} +}; + +/* + * Handles the GET_DESCRIPTOR callback. All required descriptors must be + * handled here. + */ +static const USBDescriptor *get_descriptor(USBDriver *usbp, + uint8_t dtype, + uint8_t dindex, + uint16_t lang) { + + (void)usbp; + (void)lang; + switch (dtype) { + case USB_DESCRIPTOR_DEVICE: + return &vcom_device_descriptor; + case USB_DESCRIPTOR_CONFIGURATION: + return &vcom_configuration_descriptor; + case USB_DESCRIPTOR_STRING: + if (dindex < 4) + return &vcom_strings[dindex]; + } + return NULL; +} + +/** + * @brief IN EP1 state. + */ +static USBInEndpointState ep1instate; + +/** + * @brief OUT EP1 state. + */ +static USBOutEndpointState ep1outstate; + +/** + * @brief EP1 initialization structure (both IN and OUT). + */ +static const USBEndpointConfig ep1config = { + USB_EP_MODE_TYPE_BULK, + NULL, + sduDataTransmitted, + sduDataReceived, + 0x0040, + 0x0040, + &ep1instate, + &ep1outstate, + 1, + NULL +}; + +/** + * @brief IN EP2 state. + */ +static USBInEndpointState ep2instate; + +/** + * @brief EP2 initialization structure (IN only). + */ +static const USBEndpointConfig ep2config = { + USB_EP_MODE_TYPE_INTR, + NULL, + sduInterruptTransmitted, + NULL, + 0x0010, + 0x0000, + &ep2instate, + NULL, + 1, + NULL +}; + +/* + * Handles the USB driver global events. + */ +static void usb_event(USBDriver *usbp, usbevent_t event) { + extern SerialUSBDriver SDU1; + + switch (event) { + case USB_EVENT_ADDRESS: + return; + case USB_EVENT_CONFIGURED: + chSysLockFromISR(); + + /* Enables the endpoints specified into the configuration. + Note, this callback is invoked from an ISR so I-Class functions + must be used.*/ + usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP, &ep1config); + usbInitEndpointI(usbp, USBD1_INTERRUPT_REQUEST_EP, &ep2config); + + /* Resetting the state of the CDC subsystem.*/ + sduConfigureHookI(&SDU1); + + chSysUnlockFromISR(); + return; + case USB_EVENT_RESET: + /* Falls into.*/ + case USB_EVENT_UNCONFIGURED: + /* Falls into.*/ + case USB_EVENT_SUSPEND: + chSysLockFromISR(); + + /* Disconnection event on suspend.*/ + sduSuspendHookI(&SDU1); + + chSysUnlockFromISR(); + return; + case USB_EVENT_WAKEUP: + chSysLockFromISR(); + + /* Connection event on wakeup.*/ + sduWakeupHookI(&SDU1); + + chSysUnlockFromISR(); + return; + case USB_EVENT_STALLED: + return; + } + return; +} + +/* + * Handles the USB driver global events. + */ +static void sof_handler(USBDriver *usbp) { + + (void)usbp; + + osalSysLockFromISR(); + sduSOFHookI(&SDU1); + osalSysUnlockFromISR(); +} + +/* + * USB driver configuration. + */ +const USBConfig usbcfg = { + usb_event, + get_descriptor, + sduRequestsHook, + sof_handler +}; + +/* + * Serial over USB driver configuration. + */ +const SerialUSBConfig serusbcfg = { +#if defined(TARGET_PLATFORM_H7) + &USBD2, +#else + &USBD1, +#endif + USBD1_DATA_REQUEST_EP, + USBD1_DATA_AVAILABLE_EP, + USBD1_INTERRUPT_REQUEST_EP +}; diff --git a/firmware/source/periph/usbcfg.h b/firmware/source/periph/usbcfg.h new file mode 100644 index 0000000..2fceccb --- /dev/null +++ b/firmware/source/periph/usbcfg.h @@ -0,0 +1,28 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef USBCFG_H +#define USBCFG_H + +#include "hal.h" + +extern const USBConfig usbcfg; +extern SerialUSBConfig serusbcfg; +extern SerialUSBDriver SDU1; + +#endif /* USBCFG_H */ + +/** @} */ diff --git a/firmware/source/periph/usbserial.cpp b/firmware/source/periph/usbserial.cpp new file mode 100644 index 0000000..775a911 --- /dev/null +++ b/firmware/source/periph/usbserial.cpp @@ -0,0 +1,52 @@ +/** + * @file usbserial.cpp + * @brief Wrapper for ChibiOS's SerialUSBDriver. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "usbserial.hpp" + +SerialUSBDriver *USBSerial::m_driver = &SDU1; + +void USBSerial::begin() +{ + palSetPadMode(GPIOA, 11, PAL_MODE_ALTERNATE(10)); + palSetPadMode(GPIOA, 12, PAL_MODE_ALTERNATE(10)); + + sduObjectInit(m_driver); + sduStart(m_driver, &serusbcfg); + + // Reconnect bus so device can re-enumerate on reset + usbDisconnectBus(serusbcfg.usbp); + chThdSleepMilliseconds(1500); + usbStart(serusbcfg.usbp, &usbcfg); + usbConnectBus(serusbcfg.usbp); +} + +bool USBSerial::isActive() +{ + if (auto config = m_driver->config; config != nullptr) { + if (auto usbp = config->usbp; usbp != nullptr) + return usbp->state == USB_ACTIVE && !ibqIsEmptyI(&m_driver->ibqueue); + } + + return false; +} + +size_t USBSerial::read(unsigned char *buffer, size_t count) +{ + auto bss = reinterpret_cast(m_driver); + return streamRead(bss, buffer, count); +} + +size_t USBSerial::write(const unsigned char *buffer, size_t count) +{ + auto bss = reinterpret_cast(m_driver); + return streamWrite(bss, buffer, count); +} + diff --git a/firmware/source/periph/usbserial.hpp b/firmware/source/periph/usbserial.hpp new file mode 100644 index 0000000..58113c9 --- /dev/null +++ b/firmware/source/periph/usbserial.hpp @@ -0,0 +1,32 @@ +/** + * @file usbserial.hpp + * @brief Wrapper for ChibiOS's SerialUSBDriver. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_USBSERIAL_HPP_ +#define STMDSP_USBSERIAL_HPP_ + +#include "usbcfg.h" + +class USBSerial +{ +public: + static void begin(); + + static bool isActive(); + + static size_t read(unsigned char *buffer, size_t count); + static size_t write(const unsigned char *buffer, size_t count); + +private: + static SerialUSBDriver *m_driver; +}; + +#endif // STMDSP_USBSERIAL_HPP_ + diff --git a/firmware/source/runstatus.hpp b/firmware/source/runstatus.hpp new file mode 100644 index 0000000..ab269b4 --- /dev/null +++ b/firmware/source/runstatus.hpp @@ -0,0 +1,11 @@ +// Run status +// +enum class RunStatus : char +{ + Idle = '1', + Running, + Recovering +}; + +extern RunStatus run_status; + diff --git a/firmware/source/samplebuffer.cpp b/firmware/source/samplebuffer.cpp new file mode 100644 index 0000000..74c6778 --- /dev/null +++ b/firmware/source/samplebuffer.cpp @@ -0,0 +1,117 @@ +/** + * @file samplebuffer.cpp + * @brief Manages ADC/DAC buffer data. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "samplebuffer.hpp" + +SampleBuffer::SampleBuffer(Sample *buffer) : + m_buffer(buffer) {} + +void SampleBuffer::clear() { + std::fill(m_buffer, m_buffer + m_size, 2048); +} +__attribute__((section(".convcode"))) +void SampleBuffer::modify(Sample *data, unsigned int srcsize) { + auto size = srcsize < m_size ? srcsize : m_size; + size = (size + 15) & (~15); + + m_modified = m_buffer; + const int *src = reinterpret_cast(data); + const int * const srcend = src + (size / 2); + int *dst = reinterpret_cast(m_buffer); + do { + int a = src[0]; + int b = src[1]; + int c = src[2]; + int d = src[3]; + int e = src[4]; + int f = src[5]; + int g = src[6]; + int h = src[7]; + dst[0] = a; + dst[1] = b; + dst[2] = c; + dst[3] = d; + dst[4] = e; + dst[5] = f; + dst[6] = g; + dst[7] = h; + src += 8; + dst += 8; + } while (src < srcend); +} +__attribute__((section(".convcode"))) +void SampleBuffer::midmodify(Sample *data, unsigned int srcsize) { + auto size = srcsize < m_size / 2 ? srcsize : m_size / 2; + size = (size + 15) & (~15); + + m_modified = middata(); + const int *src = reinterpret_cast(data); + const int * const srcend = src + (size / 2); + int *dst = reinterpret_cast(middata()); + do { + int a = src[0]; + int b = src[1]; + int c = src[2]; + int d = src[3]; + int e = src[4]; + int f = src[5]; + int g = src[6]; + int h = src[7]; + dst[0] = a; + dst[1] = b; + dst[2] = c; + dst[3] = d; + dst[4] = e; + dst[5] = f; + dst[6] = g; + dst[7] = h; + src += 8; + dst += 8; + } while (src < srcend); +} + +void SampleBuffer::setModified() { + m_modified = m_buffer; +} + +void SampleBuffer::setMidmodified() { + m_modified = middata(); +} + +void SampleBuffer::setSize(unsigned int size) { + m_size = size < MAX_SAMPLE_BUFFER_SIZE ? size : MAX_SAMPLE_BUFFER_SIZE; +} + +__attribute__((section(".convcode"))) +Sample *SampleBuffer::data() { + return m_buffer; +} +__attribute__((section(".convcode"))) +Sample *SampleBuffer::middata() { + return m_buffer + m_size / 2; +} +uint8_t *SampleBuffer::bytedata() { + return reinterpret_cast(m_buffer); +} + +Sample *SampleBuffer::modified() { + auto m = m_modified; + m_modified = nullptr; + return m; +} +__attribute__((section(".convcode"))) +unsigned int SampleBuffer::size() const { + return m_size; +} +unsigned int SampleBuffer::bytesize() const { + return m_size * sizeof(Sample); +} + diff --git a/firmware/source/samplebuffer.hpp b/firmware/source/samplebuffer.hpp new file mode 100644 index 0000000..d13023a --- /dev/null +++ b/firmware/source/samplebuffer.hpp @@ -0,0 +1,51 @@ +/** + * @file samplebuffer.hpp + * @brief Manages ADC/DAC buffer data. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef SAMPLEBUFFER_HPP_ +#define SAMPLEBUFFER_HPP_ + +#include +#include + +using Sample = uint16_t; + +constexpr unsigned int MAX_SAMPLE_BUFFER_BYTESIZE = sizeof(Sample) * 8192; +constexpr unsigned int MAX_SAMPLE_BUFFER_SIZE = MAX_SAMPLE_BUFFER_BYTESIZE / sizeof(Sample); + +class SampleBuffer +{ +public: + SampleBuffer(Sample *buffer); + + void clear(); + + void modify(Sample *data, unsigned int srcsize); + void midmodify(Sample *data, unsigned int srcsize); + void setModified(); + void setMidmodified(); + Sample *modified(); + + Sample *data(); + Sample *middata(); + uint8_t *bytedata(); + + void setSize(unsigned int size); + unsigned int size() const; + unsigned int bytesize() const; + +private: + Sample *m_buffer = nullptr; + unsigned int m_size = MAX_SAMPLE_BUFFER_SIZE; + Sample *m_modified = nullptr; +}; + +#endif // SAMPLEBUFFER_HPP_ + diff --git a/firmware/source/samples.cpp b/firmware/source/samples.cpp new file mode 100644 index 0000000..cfbf835 --- /dev/null +++ b/firmware/source/samples.cpp @@ -0,0 +1,35 @@ +/** + * @file samples.cpp + * @brief Provides sample buffers for inputs and outputs. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "samples.hpp" + +#include "ch.h" +#include "hal.h" + +#include + +static_assert(sizeof(adcsample_t) == sizeof(uint16_t)); +static_assert(sizeof(dacsample_t) == sizeof(uint16_t)); + +#if defined(TARGET_PLATFORM_H7) +__attribute__((section(".convdata"))) +SampleBuffer Samples::In (reinterpret_cast(0x38000000)); // 16k +__attribute__((section(".convdata"))) +SampleBuffer Samples::Out (reinterpret_cast(0x30004000)); // 16k +SampleBuffer Samples::SigGen (reinterpret_cast(0x30000000)); // 16k +#else +__attribute__((section(".convdata"))) +SampleBuffer Samples::In (reinterpret_cast(0x20008000)); // 16k +__attribute__((section(".convdata"))) +SampleBuffer Samples::Out (reinterpret_cast(0x2000C000)); // 16k +SampleBuffer Samples::Generator (reinterpret_cast(0x20010000)); // 16k +#endif + diff --git a/firmware/source/samples.hpp b/firmware/source/samples.hpp new file mode 100644 index 0000000..6551e25 --- /dev/null +++ b/firmware/source/samples.hpp @@ -0,0 +1,26 @@ +/** + * @file samples.hpp + * @brief Provides sample buffers for inputs and outputs. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_SAMPLES_HPP +#define STMDSP_SAMPLES_HPP + +#include "samplebuffer.hpp" + +class Samples +{ +public: + static SampleBuffer In; + static SampleBuffer Out; + static SampleBuffer Generator; +}; + +#endif // STMDSP_SAMPLES_HPP + diff --git a/firmware/source/sclock.cpp b/firmware/source/sclock.cpp new file mode 100644 index 0000000..6660f95 --- /dev/null +++ b/firmware/source/sclock.cpp @@ -0,0 +1,78 @@ +/** + * @file sclock.cpp + * @brief Manages sampling rate clock speeds. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "sclock.hpp" + +GPTDriver *SClock::m_timer = &GPTD6; +unsigned int SClock::m_div = 1; +unsigned int SClock::m_runcount = 0; + +const GPTConfig SClock::m_timer_config = { +#if defined(TARGET_PLATFORM_H7) + .frequency = 4800000, +#else + .frequency = 36000000, +#endif + .callback = nullptr, + .cr2 = TIM_CR2_MMS_1, /* TRGO */ + .dier = 0 +}; + +const std::array SClock::m_rate_divs = {{ +#if defined(TARGET_PLATFORM_H7) + /* 8k */ 600, + /* 16k */ 300, + /* 20k */ 240, + /* 32k */ 150, + /* 48k */ 100, + /* 96k */ 50 +#else + /* 8k */ 4500, + /* 16k */ 2250, + /* 20k */ 1800, + /* 32k */ 1125, + /* 48k */ 750, + /* 96k */ 375 +#endif +}}; + +void SClock::begin() +{ + gptStart(m_timer, &m_timer_config); +} + +void SClock::start() +{ + if (m_runcount++ == 0) + gptStartContinuous(m_timer, m_div); +} + +void SClock::stop() +{ + if (--m_runcount == 0) + gptStopTimer(m_timer); +} + +void SClock::setRate(SClock::Rate rate) +{ + m_div = m_rate_divs[static_cast(rate)]; +} + +unsigned int SClock::getRate() +{ + for (unsigned int i = 0; i < m_rate_divs.size(); ++i) { + if (m_rate_divs[i] == m_div) + return i; + } + + return static_cast(-1); +} + diff --git a/firmware/source/sclock.hpp b/firmware/source/sclock.hpp new file mode 100644 index 0000000..d5b93df --- /dev/null +++ b/firmware/source/sclock.hpp @@ -0,0 +1,47 @@ +/** + * @file sclock.hpp + * @brief Manages sampling rate clock speeds. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef SCLOCK_HPP_ +#define SCLOCK_HPP_ + +#include "hal.h" + +#include + +class SClock +{ +public: + enum class Rate : unsigned int { + R8K = 0, + R16K, + R20K, + R32K, + R48K, + R96K + }; + + static void begin(); + static void start(); + static void stop(); + + static void setRate(Rate rate); + static unsigned int getRate(); + +private: + static GPTDriver *m_timer; + static unsigned int m_div; + static unsigned int m_runcount; + static const GPTConfig m_timer_config; + static const std::array m_rate_divs; +}; + +#endif // SCLOCK_HPP_ + diff --git a/gui/LICENSE b/gui/LICENSE new file mode 100644 index 0000000..6a34f51 --- /dev/null +++ b/gui/LICENSE @@ -0,0 +1,620 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + diff --git a/gui/Makefile b/gui/Makefile new file mode 100644 index 0000000..0ff9c48 --- /dev/null +++ b/gui/Makefile @@ -0,0 +1,46 @@ +CXX = g++ + +CXXFILES := \ + source/serial/src/serial.cc \ + source/imgui/backends/imgui_impl_sdl2.cpp \ + source/imgui/backends/imgui_impl_opengl2.cpp \ + source/imgui/imgui.cpp \ + source/imgui/imgui_draw.cpp \ + source/imgui/imgui_tables.cpp \ + source/imgui/imgui_widgets.cpp \ + source/ImGuiFileDialog/ImGuiFileDialog.cpp \ + source/ImGuiColorTextEdit/TextEditor.cpp \ + $(wildcard source/stmdsp/*.cpp) \ + $(wildcard source/*.cpp) + +CXXFLAGS := -std=c++20 -O2 \ + -Isource -Isource/imgui -Isource/stmdsp -Isource/serial/include \ + -Isource/ImGuiColorTextEdit -Isource/ImGuiFileDialog \ + $(shell sdl2-config --cflags) \ + -Wall -Wextra -pedantic #-DSTMDSP_DISABLE_FORMULAS + +ifeq ($(OS),Windows_NT) +CXXFILES += source/serial/src/impl/win.cc \ + source/serial/src/impl/list_ports/list_ports_win.cc +CXXFLAGS += -DSTMDSP_WIN32 -Wa,-mbig-obj +LDFLAGS = -mwindows -lSDL2 -lopengl32 -lsetupapi -lole32 +OUTPUT := stmdspgui.exe +else +CXXFILES += source/serial/src/impl/unix.cc \ + source/serial/src/impl/list_ports/list_ports_linux.cc +LDFLAGS = $(shell sdl2-config --libs) -lGL -lpthread +OUTPUT := stmdspgui +endif + +OFILES := $(patsubst %.cc, %.o, $(patsubst %.cpp, %.o, $(CXXFILES))) + +all: $(OUTPUT) + +$(OUTPUT): $(OFILES) + @echo " LD " $(OUTPUT) + @$(CXX) $(OFILES) -o $(OUTPUT) $(LDFLAGS) + +clean: + @echo " CLEAN" + @rm -f $(OFILES) $(OUTPUT) + diff --git a/gui/examples/1_convolve_simple.cpp b/gui/examples/1_convolve_simple.cpp new file mode 100644 index 0000000..95877f1 --- /dev/null +++ b/gui/examples/1_convolve_simple.cpp @@ -0,0 +1,30 @@ +/** + * 1_convolve_simple.cpp + * Written by Clyne Sullivan. + * + * Computes a convolution in the simplest way possible. While the code is brief, it lacks many + * possible optimizations. The convolution's result will not fill the output buffer either, as the + * transient response is not calculated. + */ + +Sample* process_data(Samples samples) +{ + // Define our output buffer. + static Samples buffer; + + // Define our filter + constexpr unsigned int filter_size = 3; + float filter[filter_size] = { + 0.3333, 0.3333, 0.3333 + }; + + // Begin convolving: + // SIZE is the size of the sample buffer. + for (int n = 0; n < SIZE - (filter_size - 1); n++) { + buffer[n] = 0; + for (int k = 0; k < filter_size; k++) + buffer[n] += samples[n + k] * filter[k]; + } + + return buffer; +} diff --git a/gui/examples/2_convolve_overlap_save.cpp b/gui/examples/2_convolve_overlap_save.cpp new file mode 100644 index 0000000..5651f3e --- /dev/null +++ b/gui/examples/2_convolve_overlap_save.cpp @@ -0,0 +1,47 @@ +/** + * 2_convolve_overlap_save.cpp + * Written by Clyne Sullivan. + * + * This convolution examples takes an overlap-save approach, where samples from the previous run + * are saved so that the overall operation is not interrupted (i.e. the observed output will + * transition smoothly between processed "chunks"). + * + * Note that there are still improvements that can be made to the code; for example, notice every + * spot where an integer/float conversion is necessary. Operations like these may slow down the + * computation. + */ + +Sample* process_data(Samples samples) +{ + static Samples buffer; + + constexpr unsigned int filter_size = 3; + float filter[filter_size] = { + 0.3333, 0.3333, 0.3333 + }; + + // Keep a buffer of extra samples for overlap-save + static Sample prev[filter_size]; + + for (int n = 0; n < SIZE; n++) { + buffer[n] = 0; + + for (int k = 0; k < filter_size; k++) { + int i = n - (filter_size - 1) + k; + + // If i is >= 0, access current sample buffer. + // If i is < 0, provide the previous samples from the 'prev' buffer + if (i >= 0) + buffer[n] += samples[i] * filter[k]; + else + buffer[n] += prev[filter_size - 1 + i] * filter[k]; + } + } + + // Save samples for the next convolution run + for (int i = 0; i < filter_size; i++) + prev[i] = samples[SIZE - filter_size + i]; + + return buffer; +} + diff --git a/gui/examples/3_fir.cpp b/gui/examples/3_fir.cpp new file mode 100644 index 0000000..b6d8751 --- /dev/null +++ b/gui/examples/3_fir.cpp @@ -0,0 +1,47 @@ +/** + * 3_fir.cpp + * Written by Clyne Sullivan. + * + * The below code was written for applying FIR filters. While this is still essentially an overlap- + * save convolution, other optimizations have been made to allow for larger filters to be applied + * within the available execution time. Samples are also normalized so that they center around zero. + */ + +Sample* process_data(Samples samples) +{ + static Samples buffer; + + // Define the filter: + constexpr unsigned int filter_size = 3; + static float filter[filter_size] = { + // Put filter values here (note: precision will be truncated for 'float' size). + 0.3333, 0.3333, 0.3333 + }; + + // Do an overlap-save convolution + static Sample prev[filter_size]; + + for (int n = 0; n < SIZE; n++) { + // Using a float variable for accumulation allows for better code optimization + float v = 0; + + for (int k = 0; k < filter_size; k++) { + int i = n - (filter_size - 1) + k; + + auto s = i >= 0 ? samples[i] : prev[filter_size - 1 + i]; + // Sample values are 0 to 4095. Below, the original sample is normalized to a -1.0 to + // 1.0 range for calculation. + v += (s / 2048.f - 1) * filter[k]; + } + + // Return value to sample range of 0-4095. + buffer[n] = (v + 1) * 2048.f; + } + + // Save samples for next convolution + for (int i = 0; i < filter_size; i++) + prev[i] = samples[SIZE - filter_size + i]; + + return buffer; +} + diff --git a/gui/examples/4_fir_pro.cpp b/gui/examples/4_fir_pro.cpp new file mode 100644 index 0000000..1771cd5 --- /dev/null +++ b/gui/examples/4_fir_pro.cpp @@ -0,0 +1,478 @@ +#include +using float32_t = float; + +typedef struct +{ + uint16_t numTaps; /**< number of filter coefficients in the filter. */ + float32_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ + float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ +} arm_fir_instance_f32; + +static void arm_fir_f32(const arm_fir_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); + +Sample* process_data(Samples samples) +{ + // 1. Define our array sizes (Be sure to set Run > Set buffer size... to below value!) + constexpr unsigned int buffer_size = 500; + constexpr unsigned int filter_size = 100; + + // 2. Define our filter and the working arrays + static float filter[filter_size] = { + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f, + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f, + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f, + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f, + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f, + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f, + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f, + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f, + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f, + .01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f,.01f + }; + static float input[buffer_size]; + static float output[buffer_size]; + static float working[buffer_size + filter_size]; + + // 3. Scale 0-4095 interger sample values to +/- 1.0 floats + for (unsigned int i = 0; i < SIZE; i++) + input[i] = (samples[i] - 2048) / 2048.f; + + // 4. Compute the FIR + arm_fir_instance_f32 fir { filter_size, working, filter }; + arm_fir_f32(&fir, input, output, SIZE); + + // 5. Convert float results back to 0-4095 range for output + for (unsigned int i = 0; i < SIZE; i++) + samples[i] = output[i] * 2048.f + 2048; + + return samples; +} + +// Below taken from the CMSIS DSP Library (find it on GitHub) +void arm_fir_f32( + const arm_fir_instance_f32 * S, + float32_t * pSrc, + float32_t * pDst, + uint32_t blockSize) +{ + float32_t *pState = S->pState; /* State pointer */ + float32_t *pCoeffs = S->pCoeffs; /* Coefficient pointer */ + float32_t *pStateCurnt; /* Points to the current sample of the state */ + float32_t *px, *pb; /* Temporary pointers for state and coefficient buffers */ + float32_t acc0, acc1, acc2, acc3, acc4, acc5, acc6, acc7; /* Accumulators */ + float32_t x0, x1, x2, x3, x4, x5, x6, x7, c0; /* Temporary variables to hold state and coefficient values */ + uint32_t numTaps = S->numTaps; /* Number of filter coefficients in the filter */ + uint32_t i, tapCnt, blkCnt; /* Loop counters */ + float32_t p0,p1,p2,p3,p4,p5,p6,p7; /* Temporary product values */ + + /* S->pState points to state array which contains previous frame (numTaps - 1) samples */ + /* pStateCurnt points to the location where the new input data should be written */ + pStateCurnt = &(S->pState[(numTaps - 1u)]); + + /* Apply loop unrolling and compute 8 output values simultaneously. + * The variables acc0 ... acc7 hold output values that are being computed: + * + * acc0 = b[numTaps-1] * x[n-numTaps-1] + b[numTaps-2] * x[n-numTaps-2] + b[numTaps-3] * x[n-numTaps-3] +...+ b[0] * x[0] + * acc1 = b[numTaps-1] * x[n-numTaps] + b[numTaps-2] * x[n-numTaps-1] + b[numTaps-3] * x[n-numTaps-2] +...+ b[0] * x[1] + * acc2 = b[numTaps-1] * x[n-numTaps+1] + b[numTaps-2] * x[n-numTaps] + b[numTaps-3] * x[n-numTaps-1] +...+ b[0] * x[2] + * acc3 = b[numTaps-1] * x[n-numTaps+2] + b[numTaps-2] * x[n-numTaps+1] + b[numTaps-3] * x[n-numTaps] +...+ b[0] * x[3] + */ + blkCnt = blockSize >> 3; + + /* First part of the processing with loop unrolling. Compute 8 outputs at a time. + ** a second loop below computes the remaining 1 to 7 samples. */ + while(blkCnt > 0u) + { + /* Copy four new input samples into the state buffer */ + *pStateCurnt++ = *pSrc++; + *pStateCurnt++ = *pSrc++; + *pStateCurnt++ = *pSrc++; + *pStateCurnt++ = *pSrc++; + + /* Set all accumulators to zero */ + acc0 = 0.0f; + acc1 = 0.0f; + acc2 = 0.0f; + acc3 = 0.0f; + acc4 = 0.0f; + acc5 = 0.0f; + acc6 = 0.0f; + acc7 = 0.0f; + + /* Initialize state pointer */ + px = pState; + + /* Initialize coeff pointer */ + pb = (pCoeffs); + + /* This is separated from the others to avoid + * a call to __aeabi_memmove which would be slower + */ + *pStateCurnt++ = *pSrc++; + *pStateCurnt++ = *pSrc++; + *pStateCurnt++ = *pSrc++; + *pStateCurnt++ = *pSrc++; + + /* Read the first seven samples from the state buffer: x[n-numTaps], x[n-numTaps-1], x[n-numTaps-2] */ + x0 = *px++; + x1 = *px++; + x2 = *px++; + x3 = *px++; + x4 = *px++; + x5 = *px++; + x6 = *px++; + + /* Loop unrolling. Process 8 taps at a time. */ + tapCnt = numTaps >> 3u; + + /* Loop over the number of taps. Unroll by a factor of 8. + ** Repeat until we've computed numTaps-8 coefficients. */ + while(tapCnt > 0u) + { + /* Read the b[numTaps-1] coefficient */ + c0 = *(pb++); + + /* Read x[n-numTaps-3] sample */ + x7 = *(px++); + + /* acc0 += b[numTaps-1] * x[n-numTaps] */ + p0 = x0 * c0; + + /* acc1 += b[numTaps-1] * x[n-numTaps-1] */ + p1 = x1 * c0; + + /* acc2 += b[numTaps-1] * x[n-numTaps-2] */ + p2 = x2 * c0; + + /* acc3 += b[numTaps-1] * x[n-numTaps-3] */ + p3 = x3 * c0; + + /* acc4 += b[numTaps-1] * x[n-numTaps-4] */ + p4 = x4 * c0; + + /* acc1 += b[numTaps-1] * x[n-numTaps-5] */ + p5 = x5 * c0; + + /* acc2 += b[numTaps-1] * x[n-numTaps-6] */ + p6 = x6 * c0; + + /* acc3 += b[numTaps-1] * x[n-numTaps-7] */ + p7 = x7 * c0; + + /* Read the b[numTaps-2] coefficient */ + c0 = *(pb++); + + /* Read x[n-numTaps-4] sample */ + x0 = *(px++); + + acc0 += p0; + acc1 += p1; + acc2 += p2; + acc3 += p3; + acc4 += p4; + acc5 += p5; + acc6 += p6; + acc7 += p7; + + + /* Perform the multiply-accumulate */ + p0 = x1 * c0; + p1 = x2 * c0; + p2 = x3 * c0; + p3 = x4 * c0; + p4 = x5 * c0; + p5 = x6 * c0; + p6 = x7 * c0; + p7 = x0 * c0; + + /* Read the b[numTaps-3] coefficient */ + c0 = *(pb++); + + /* Read x[n-numTaps-5] sample */ + x1 = *(px++); + + acc0 += p0; + acc1 += p1; + acc2 += p2; + acc3 += p3; + acc4 += p4; + acc5 += p5; + acc6 += p6; + acc7 += p7; + + /* Perform the multiply-accumulates */ + p0 = x2 * c0; + p1 = x3 * c0; + p2 = x4 * c0; + p3 = x5 * c0; + p4 = x6 * c0; + p5 = x7 * c0; + p6 = x0 * c0; + p7 = x1 * c0; + + /* Read the b[numTaps-4] coefficient */ + c0 = *(pb++); + + /* Read x[n-numTaps-6] sample */ + x2 = *(px++); + + acc0 += p0; + acc1 += p1; + acc2 += p2; + acc3 += p3; + acc4 += p4; + acc5 += p5; + acc6 += p6; + acc7 += p7; + + /* Perform the multiply-accumulates */ + p0 = x3 * c0; + p1 = x4 * c0; + p2 = x5 * c0; + p3 = x6 * c0; + p4 = x7 * c0; + p5 = x0 * c0; + p6 = x1 * c0; + p7 = x2 * c0; + + /* Read the b[numTaps-4] coefficient */ + c0 = *(pb++); + + /* Read x[n-numTaps-6] sample */ + x3 = *(px++); + + acc0 += p0; + acc1 += p1; + acc2 += p2; + acc3 += p3; + acc4 += p4; + acc5 += p5; + acc6 += p6; + acc7 += p7; + + /* Perform the multiply-accumulates */ + p0 = x4 * c0; + p1 = x5 * c0; + p2 = x6 * c0; + p3 = x7 * c0; + p4 = x0 * c0; + p5 = x1 * c0; + p6 = x2 * c0; + p7 = x3 * c0; + + /* Read the b[numTaps-4] coefficient */ + c0 = *(pb++); + + /* Read x[n-numTaps-6] sample */ + x4 = *(px++); + + acc0 += p0; + acc1 += p1; + acc2 += p2; + acc3 += p3; + acc4 += p4; + acc5 += p5; + acc6 += p6; + acc7 += p7; + + /* Perform the multiply-accumulates */ + p0 = x5 * c0; + p1 = x6 * c0; + p2 = x7 * c0; + p3 = x0 * c0; + p4 = x1 * c0; + p5 = x2 * c0; + p6 = x3 * c0; + p7 = x4 * c0; + + /* Read the b[numTaps-4] coefficient */ + c0 = *(pb++); + + /* Read x[n-numTaps-6] sample */ + x5 = *(px++); + + acc0 += p0; + acc1 += p1; + acc2 += p2; + acc3 += p3; + acc4 += p4; + acc5 += p5; + acc6 += p6; + acc7 += p7; + + /* Perform the multiply-accumulates */ + p0 = x6 * c0; + p1 = x7 * c0; + p2 = x0 * c0; + p3 = x1 * c0; + p4 = x2 * c0; + p5 = x3 * c0; + p6 = x4 * c0; + p7 = x5 * c0; + + /* Read the b[numTaps-4] coefficient */ + c0 = *(pb++); + + /* Read x[n-numTaps-6] sample */ + x6 = *(px++); + + acc0 += p0; + acc1 += p1; + acc2 += p2; + acc3 += p3; + acc4 += p4; + acc5 += p5; + acc6 += p6; + acc7 += p7; + + /* Perform the multiply-accumulates */ + p0 = x7 * c0; + p1 = x0 * c0; + p2 = x1 * c0; + p3 = x2 * c0; + p4 = x3 * c0; + p5 = x4 * c0; + p6 = x5 * c0; + p7 = x6 * c0; + + tapCnt--; + + acc0 += p0; + acc1 += p1; + acc2 += p2; + acc3 += p3; + acc4 += p4; + acc5 += p5; + acc6 += p6; + acc7 += p7; + } + + /* If the filter length is not a multiple of 8, compute the remaining filter taps */ + tapCnt = numTaps % 0x8u; + + while(tapCnt > 0u) + { + /* Read coefficients */ + c0 = *(pb++); + + /* Fetch 1 state variable */ + x7 = *(px++); + + /* Perform the multiply-accumulates */ + p0 = x0 * c0; + p1 = x1 * c0; + p2 = x2 * c0; + p3 = x3 * c0; + p4 = x4 * c0; + p5 = x5 * c0; + p6 = x6 * c0; + p7 = x7 * c0; + + /* Reuse the present sample states for next sample */ + x0 = x1; + x1 = x2; + x2 = x3; + x3 = x4; + x4 = x5; + x5 = x6; + x6 = x7; + + acc0 += p0; + acc1 += p1; + acc2 += p2; + acc3 += p3; + acc4 += p4; + acc5 += p5; + acc6 += p6; + acc7 += p7; + + /* Decrement the loop counter */ + tapCnt--; + } + + /* Advance the state pointer by 8 to process the next group of 8 samples */ + pState = pState + 8; + + /* The results in the 8 accumulators, store in the destination buffer. */ + *pDst++ = acc0; + *pDst++ = acc1; + *pDst++ = acc2; + *pDst++ = acc3; + *pDst++ = acc4; + *pDst++ = acc5; + *pDst++ = acc6; + *pDst++ = acc7; + + blkCnt--; + } + + /* If the blockSize is not a multiple of 8, compute any remaining output samples here. + ** No loop unrolling is used. */ + blkCnt = blockSize % 0x8u; + + while(blkCnt > 0u) + { + /* Copy one sample at a time into state buffer */ + *pStateCurnt++ = *pSrc++; + + /* Set the accumulator to zero */ + acc0 = 0.0f; + + /* Initialize state pointer */ + px = pState; + + /* Initialize Coefficient pointer */ + pb = (pCoeffs); + + i = numTaps; + + /* Perform the multiply-accumulates */ + do + { + acc0 += *px++ * *pb++; + i--; + + } while(i > 0u); + + /* The result is store in the destination buffer. */ + *pDst++ = acc0; + + /* Advance state pointer by 1 for the next sample */ + pState = pState + 1; + + blkCnt--; + } + + /* Processing is complete. + ** Now copy the last numTaps - 1 samples to the start of the state buffer. + ** This prepares the state buffer for the next function call. */ + + /* Points to the start of the state buffer */ + pStateCurnt = S->pState; + + tapCnt = (numTaps - 1u) >> 2u; + + /* copy data */ + while(tapCnt > 0u) + { + *pStateCurnt++ = *pState++; + *pStateCurnt++ = *pState++; + *pStateCurnt++ = *pState++; + *pStateCurnt++ = *pState++; + + /* Decrement the loop counter */ + tapCnt--; + } + + /* Calculate remaining number of copies */ + tapCnt = (numTaps - 1u) % 0x4u; + + /* Copy the remaining q31_t data */ + while(tapCnt > 0u) + { + *pStateCurnt++ = *pState++; + + /* Decrement the loop counter */ + tapCnt--; + } +} diff --git a/gui/examples/5_fir_differentiator.cpp b/gui/examples/5_fir_differentiator.cpp new file mode 100644 index 0000000..1500dee --- /dev/null +++ b/gui/examples/5_fir_differentiator.cpp @@ -0,0 +1,30 @@ +/** + * 5_fir_differentiator.cpp + * Written by Clyne Sullivan. + * + * Does an FIR differentiation on the incoming signal, so that the output is representative of the + * rate of change of the input. + * A scaling factor is applied so that the output's form is more clearly visible. + */ + +Sample* process_data(Samples samples) +{ + constexpr int scaling_factor = 4; + static Samples output; + static Sample prev = 2048; + + // Compute the first output value using the saved sample. + output[0] = 2048 + ((samples[0] - prev) * scaling_factor); + + for (unsigned int i = 1; i < SIZE; i++) { + // Take the rate of change and scale it. + // 2048 is added as the output should be centered in the voltage range. + output[i] = 2048 + ((samples[i] - samples[i - 1]) * scaling_factor); + } + + // Save the last sample for the next iteration. + prev = samples[SIZE - 1]; + + return output; +} + diff --git a/gui/examples/6_iir_test.cpp b/gui/examples/6_iir_test.cpp new file mode 100644 index 0000000..e0b266d --- /dev/null +++ b/gui/examples/6_iir_test.cpp @@ -0,0 +1,23 @@ +/** + * 6_iir_test.cpp + * Written by Clyne Sullivan. + * + * Implements a simple infinite impulse response (IIR) filter using an alpha + * parameter. + * To build upon this example, try setting `alpha` with a parameter knob: + * alpha = param1() / 4095.0 + */ + +Sample* process_data(Samples samples) +{ + constexpr float alpha = 0.7; + + static Sample prev = 2048; + + samples[0] = (1 - alpha) * samples[0] + alpha * prev; + for (unsigned int i = 1; i < SIZE; i++) + samples[i] = (1 - alpha) * samples[i] + alpha * samples[i - 1]; + prev = samples[SIZE - 1]; + + return samples; +} diff --git a/gui/examples/7_iir_echo.cpp b/gui/examples/7_iir_echo.cpp new file mode 100644 index 0000000..75bf56e --- /dev/null +++ b/gui/examples/7_iir_echo.cpp @@ -0,0 +1,30 @@ +/** + * 7_iir_echo.cpp + * Written by Clyne Sullivan. + * + * This filter produces an echo of the given input. There are two parameters: + * alpha controls the feedback gain, and D controls the echo/delay length. + */ + +Sample* process_data(Samples samples) +{ + constexpr float alpha = 0.75; + constexpr unsigned int D = 100; + + static Samples output; + static Sample prev[D]; // prev[0] = output[0 - D] + + // Do calculations with previous output + for (unsigned int i = 0; i < D; i++) + output[i] = samples[i] + alpha * (prev[i] - 2048); + + // Do calculations with current samples + for (unsigned int i = D; i < SIZE; i++) + output[i] = samples[i] + alpha * (output[i - D] - 2048); + + // Save outputs for next computation + for (unsigned int i = 0; i < D; i++) + prev[i] = output[SIZE - (D - i)]; + + return output; +} diff --git a/gui/fonts/LICENSE-2.0.txt b/gui/fonts/LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/gui/fonts/LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/gui/fonts/Roboto-Medium.ttf b/gui/fonts/Roboto-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..39c63d7461796094c0b8889ee8fe2706d344a99a GIT binary patch literal 162588 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 cASb?` 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
  • 2a-ytx-(Y1%*Q`;e(V?9Smc22g?_xG~I&%zq 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≀A#j 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%0AHUW;|^l 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 z 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 literal 0 HcmV?d00001 diff --git a/gui/fonts/RobotoMono-Regular.ttf b/gui/fonts/RobotoMono-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7c4ce36a442d14eeb12444ad707c2afa19422fd8 GIT binary patch literal 86908 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. + */ + +#ifndef CIRCULAR_HPP +#define CIRCULAR_HPP + +#include + +template class Container, typename T> +class CircularBuffer +{ +public: + CircularBuffer(Container& container) : + m_begin(std::begin(container)), + m_end(std::end(container)), + m_current(m_begin) {} + + void put(const T& value) noexcept { + *m_current = value; + if (++m_current == m_end) + m_current = m_begin; + } + + std::size_t size() const noexcept { + return std::distance(m_begin, m_end); + } + + void reset(const T& fill) noexcept { + std::fill(m_begin, m_end, fill); + m_current = m_begin; + } + +private: + Container::iterator m_begin; + Container::iterator m_end; + Container::iterator m_current; +}; + +#endif // CIRCULAR_HPP + diff --git a/gui/source/code.cpp b/gui/source/code.cpp new file mode 100644 index 0000000..f24bb5c --- /dev/null +++ b/gui/source/code.cpp @@ -0,0 +1,172 @@ +/** + * @file code.cpp + * @brief Functionality for compiling and disassembling source code. + * + * Copyright (C) 2022 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "main.hpp" +#include "stmdsp.hpp" +#include "stmdsp_code.hpp" + +#include +#include +#include +#include +#include +#include + +extern std::shared_ptr m_device; + +// Stores the temporary file name currently used for compiling the algorithm. +static std::string tempFileName; + +/** + * Generates a new temporary file name. + * @return A string containing the path and file name. + */ +static std::string newTempFileName(); + +/** + * Executes the given command using system(), collecting the text output in the + * given file. + * @param command The command to be executed. + * @param file The file to write command output to. + * @return True if the command was successful (i.e. returned zero). + */ +static bool codeExecuteCommand(const std::string& command, const std::string& file); + +/** + * Does an in-place replacement of all occurances of "what" with "with". + * @param str The text string to operate on. + * @param what The text to search for. + * @param with The text that will replace occurances of "what". + */ +static void stringReplaceAll(std::string& str, const std::string& what, + const std::string& with); + +std::ifstream compileOpenBinaryFile() +{ + if (!tempFileName.empty()) + return std::ifstream(tempFileName + ".o"); + else + return std::ifstream(); +} + +void compileEditorCode(const std::string& code) +{ + log("Compiling..."); + + if (tempFileName.empty()) { + tempFileName = newTempFileName(); + } else { + std::filesystem::remove(tempFileName + ".o"); + std::filesystem::remove(tempFileName + ".orig.o"); + } + + const auto platform = m_device ? m_device->get_platform() + : stmdsp::platform::L4; + + { + std::ofstream file (tempFileName, std::ios::trunc | std::ios::binary); + + auto file_text = + platform == stmdsp::platform::L4 ? stmdsp::file_header_l4 + : stmdsp::file_header_h7; + const auto buffer_size = m_device ? m_device->get_buffer_size() + : stmdsp::SAMPLES_MAX; + + stringReplaceAll(file_text, "$0", std::to_string(buffer_size)); + + file << file_text << '\n' << code; + } + + const auto scriptFile = tempFileName + +#ifndef STMDSP_WIN32 + ".sh"; +#else + ".bat"; +#endif + + { + std::ofstream makefile (scriptFile, std::ios::binary); + auto make_text = + platform == stmdsp::platform::L4 ? stmdsp::makefile_text_l4 + : stmdsp::makefile_text_h7; + + stringReplaceAll(make_text, "$0", tempFileName); + stringReplaceAll(make_text, "$1", + std::filesystem::current_path().string()); + + makefile << make_text; + } + +#ifndef STMDSP_WIN32 + system((std::string("chmod +x ") + scriptFile).c_str()); +#endif + + const auto makeOutput = scriptFile + ".log"; + const auto makeCommand = scriptFile + " > " + makeOutput + " 2>&1"; + if (codeExecuteCommand(makeCommand, makeOutput)) + log("Compilation succeeded."); + else + log("Compilation failed."); + + std::filesystem::remove(tempFileName); + std::filesystem::remove(scriptFile); +} + +void disassembleCode() +{ + log("Disassembling..."); + + //if (tempFileName.empty()) + // compileEditorCode(); + + const auto output = tempFileName + ".asm.log"; + const auto command = + std::string("arm-none-eabi-objdump -d --no-show-raw-insn ") + + tempFileName + ".orig.o > " + output + " 2>&1"; + + if (codeExecuteCommand(command, output)) + log("Ready."); + else + log("Failed to load disassembly."); +} + +std::string newTempFileName() +{ + const auto path = std::filesystem::temp_directory_path() / "stmdspgui_build"; + return path.string(); +} + +bool codeExecuteCommand(const std::string& command, const std::string& file) +{ + bool success = system(command.c_str()) == 0; + + if (std::ifstream output (file); output.good()) { + std::ostringstream sstr; + sstr << output.rdbuf(); + log(sstr.str().c_str()); + } else { + log("Could not read command output!"); + } + + std::filesystem::remove(file); + + return success; +} + +void stringReplaceAll(std::string& str, const std::string& what, const std::string& with) +{ + std::size_t i; + while ((i = str.find(what)) != std::string::npos) { + str.replace(i, what.size(), with); + i += what.size(); + } +}; + diff --git a/gui/source/code.hpp b/gui/source/code.hpp new file mode 100644 index 0000000..edb46e7 --- /dev/null +++ b/gui/source/code.hpp @@ -0,0 +1,39 @@ +/** + * @file code.hpp + * @brief Functionality for compiling and disassembling source code. + * + * Copyright (C) 2022 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSPGUI_CODE_HPP +#define STMDSPGUI_CODE_HPP + +#include +#include +#include + +/** + * Attempts to open the most recently created binary file. + * @return An opened stream of the file if it exists, an empty stream otherwise. + */ +std::ifstream compileOpenBinaryFile(); + +/** + * Attempts to compile the given C++ algorithm code into a binary. + * Errors are reported to the log view. + * @param code The C++ code for the algorithm (usually from the text editor). + */ +void compileEditorCode(const std::string& code); + +/** + * Disassembles the most recently compiled binary, outputting the results to + * the log view. + */ +void disassembleCode(); + +#endif // STMDSPGUI_CODE_HPP + diff --git a/gui/source/device.cpp b/gui/source/device.cpp new file mode 100644 index 0000000..9c50a0d --- /dev/null +++ b/gui/source/device.cpp @@ -0,0 +1,481 @@ +/** + * @file device.cpp + * @brief Contains code for device-related UI elements and logic. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "stmdsp.hpp" + +#include "circular.hpp" +#include "imgui.h" +#include "wav.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void log(const std::string& str); +extern std::vector deviceGenLoadFormulaEval(const std::string&); +extern std::ifstream compileOpenBinaryFile(); +extern void deviceRenderDisconnect(); + +std::shared_ptr m_device; + +static std::timed_mutex mutexDrawSamples; +static std::timed_mutex mutexDeviceLoad; +static std::ofstream logSamplesFile; +static wav::clip wavOutput; +static std::deque drawSamplesQueue; +static std::deque drawSamplesInputQueue; +static bool drawSamplesInput = false; +static unsigned int drawSamplesBufferSize = 1; + +bool deviceConnect(); + +void deviceSetInputDrawing(bool enabled) +{ + drawSamplesInput = enabled; + if (enabled) { + drawSamplesQueue.clear(); + drawSamplesInputQueue.clear(); + } +} + +static void measureCodeTask(std::shared_ptr device) +{ + std::this_thread::sleep_for(std::chrono::seconds(1)); + + if (device) { + const auto cycles = device->measurement_read(); + log(std::string("Execution time: ") + std::to_string(cycles) + " cycles."); + } +} + +static std::vector tryReceiveChunk( + std::shared_ptr device, + auto readFunc) +{ + for (int tries = 0; tries < 100; ++tries) { + if (!device->is_running()) + break; + + const auto chunk = readFunc(device.get()); + if (!chunk.empty()) + return chunk; + else + std::this_thread::sleep_for(std::chrono::microseconds(20)); + } + + return {}; +} + +static std::chrono::duration getBufferPeriod( + std::shared_ptr device, + const double factor = 0.975) +{ + if (device) { + const double bufferSize = device->get_buffer_size(); + const double sampleRate = device->get_sample_rate(); + return std::chrono::duration(bufferSize / sampleRate * factor); + } else { + return {}; + } +} + +static void drawSamplesTask(std::shared_ptr device) +{ + if (!device) + return; + + // This is the amount of time to wait between device reads. + const auto bufferTime = getBufferPeriod(device, 1); + + // Adds the given chunk of samples to the given queue. + const auto addToQueue = [](auto& queue, const auto& chunk) { + std::scoped_lock lock (mutexDrawSamples); + std::copy(chunk.cbegin(), chunk.cend(), std::back_inserter(queue)); + }; + + std::unique_lock lockDevice (mutexDeviceLoad, std::defer_lock); + + while (device && device->is_running()) { + const auto next = std::chrono::high_resolution_clock::now() + bufferTime; + + if (lockDevice.try_lock_until(next)) { + std::vector chunk, chunk2; + + chunk = tryReceiveChunk(device, + std::mem_fn(&stmdsp::device::continuous_read)); + if (drawSamplesInput) { + chunk2 = tryReceiveChunk(device, + std::mem_fn(&stmdsp::device::continuous_read_input)); + } + + lockDevice.unlock(); + + addToQueue(drawSamplesQueue, chunk); + if (drawSamplesInput) + addToQueue(drawSamplesInputQueue, chunk2); + + if (logSamplesFile.is_open()) { + for (const auto& s : chunk) + logSamplesFile << s << '\n'; + } + } else { + // Device must be busy, back off for a bit. + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + + std::this_thread::sleep_until(next); + } +} + +static void feedSigGenTask(std::shared_ptr device) +{ + if (!device) + return; + + const auto delay = getBufferPeriod(device); + const auto uploadDelay = getBufferPeriod(device, 0.001); + + std::vector wavBuf (device->get_buffer_size() * 2, 2048); + + { + std::scoped_lock lock (mutexDeviceLoad); + device->siggen_upload(wavBuf.data(), wavBuf.size()); + device->siggen_start(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + wavBuf.resize(wavBuf.size() / 2); + std::vector wavIntBuf (wavBuf.size()); + + while (device->is_siggening()) { + const auto next = std::chrono::high_resolution_clock::now() + delay; + + wavOutput.next(wavIntBuf.data(), wavIntBuf.size()); + std::transform(wavIntBuf.cbegin(), wavIntBuf.cend(), + wavBuf.begin(), + [](auto i) { return static_cast(i / 16 + 2048); }); + + { + std::scoped_lock lock (mutexDeviceLoad); + while (!device->siggen_upload(wavBuf.data(), wavBuf.size())) + std::this_thread::sleep_for(uploadDelay); + } + + std::this_thread::sleep_until(next); + } +} + +static void statusTask(std::shared_ptr device) +{ + if (!device) + return; + + while (device->connected()) { + mutexDeviceLoad.lock(); + const auto [status, error] = device->get_status(); + mutexDeviceLoad.unlock(); + + if (error != stmdsp::Error::None) { + switch (error) { + case stmdsp::Error::NotIdle: + log("Error: Device already running..."); + break; + case stmdsp::Error::ConversionAborted: + log("Error: Algorithm unloaded, a fault occurred!"); + break; + case stmdsp::Error::GUIDisconnect: + // Do GUI events for disconnect if device was lost. + deviceConnect(); + deviceRenderDisconnect(); + return; + break; + default: + log("Error: Device had an issue..."); + break; + } + } + + std::this_thread::sleep_for(std::chrono::seconds(1)); + } +} + +void deviceLoadAudioFile(const std::string& file) +{ + wavOutput = wav::clip(file); + if (wavOutput.valid()) + log("Audio file loaded."); + else + log("Error: Bad WAV audio file."); +} + +void deviceLoadLogFile(const std::string& file) +{ + logSamplesFile = std::ofstream(file); + if (logSamplesFile.is_open()) + log("Log file ready."); + else + log("Error: Could not open log file."); +} + +bool deviceGenStartToggle() +{ + if (m_device) { + const bool running = m_device->is_siggening(); + + if (!running) { + if (wavOutput.valid()) { + std::thread(feedSigGenTask, m_device).detach(); + } else { + std::scoped_lock dlock (mutexDeviceLoad); + m_device->siggen_start(); + } + log("Generator started."); + } else { + { + std::scoped_lock dlock (mutexDeviceLoad); + m_device->siggen_stop(); + } + log("Generator stopped."); + } + + return !running; + } + + return false; +} + +void deviceUpdateDrawBufferSize(double timeframe) +{ + drawSamplesBufferSize = std::round( + m_device->get_sample_rate() * timeframe); +} + +void deviceSetSampleRate(unsigned int rate) +{ + do { + m_device->set_sample_rate(rate); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } while (m_device->get_sample_rate() != rate); +} + +bool deviceConnect() +{ + static std::thread statusThread; + + if (!m_device) { + stmdsp::scanner scanner; + if (const auto devices = scanner.scan(); !devices.empty()) { + try { + m_device.reset(new stmdsp::device(devices.front())); + } catch (...) { + log("Failed to connect (check permissions?)."); + m_device.reset(); + } + + if (m_device) { + if (m_device->connected()) { + log("Connected!"); + statusThread = std::thread(statusTask, m_device); + statusThread.detach(); + return true; + } else { + m_device.reset(); + log("Failed to connect."); + } + } + } else { + log("No devices found."); + } + } else { + m_device->disconnect(); + if (statusThread.joinable()) + statusThread.join(); + m_device.reset(); + log("Disconnected."); + } + + return false; +} + +void deviceStart(bool logResults, bool drawSamples) +{ + if (!m_device) { + log("No device connected."); + return; + } + + if (m_device->is_running()) { + { + std::scoped_lock lock (mutexDrawSamples, mutexDeviceLoad); + std::this_thread::sleep_for(std::chrono::microseconds(150)); + m_device->continuous_stop(); + } + if (logSamplesFile.is_open()) { + logSamplesFile.close(); + log("Log file saved and closed."); + } + log("Ready."); + } else { + m_device->continuous_start(); + if (drawSamples || logResults || wavOutput.valid()) + std::thread(drawSamplesTask, m_device).detach(); + + log("Running."); + } +} + +void deviceStartMeasurement() +{ + if (m_device && m_device->is_running()) { + m_device->measurement_start(); + std::thread(measureCodeTask, m_device).detach(); + } +} + +void deviceAlgorithmUpload() +{ + if (!m_device) { + log("No device connected."); + } else if (m_device->is_running()) { + log("Cannot upload algorithm while running."); + } else if (auto algo = compileOpenBinaryFile(); algo.is_open()) { + std::ostringstream sstr; + sstr << algo.rdbuf(); + auto str = sstr.str(); + + m_device->upload_filter(reinterpret_cast(&str[0]), str.size()); + log("Algorithm uploaded."); + } else { + log("Algorithm must be compiled first."); + } +} + +void deviceAlgorithmUnload() +{ + if (!m_device) { + log("No device connected."); + } else if (m_device->is_running()) { + log("Cannot unload algorithm while running."); + } else { + m_device->unload_filter(); + log("Algorithm unloaded."); + } +} + +void deviceGenLoadList(const std::string_view list) +{ + std::vector samples; + + auto it = list.cbegin(); + while (it != list.cend()) { + const auto itend = std::find_if(it, list.cend(), + [](char c) { return !isdigit(c); }); + + unsigned long n; + const auto ec = std::from_chars(it, itend, n).ec; + if (ec != std::errc()) { + log("Error: Bad data in sample list."); + break; + } else if (n > 4095) { + log("Error: Sample data value larger than max of 4095."); + break; + } else { + samples.push_back(n & 4095); + if (samples.size() >= stmdsp::SAMPLES_MAX * 2) { + log("Error: Too many samples for signal generator."); + break; + } + } + + it = std::find_if(itend, list.cend(), isdigit); + } + + if (it == list.cend()) { + // DAC buffer must be of even size + if (samples.size() % 2 != 0) + samples.push_back(samples.back()); + + m_device->siggen_upload(samples.data(), samples.size()); + log("Generator ready."); + } +} + +void deviceGenLoadFormula(const std::string& formula) +{ + auto samples = deviceGenLoadFormulaEval(formula); + + if (!samples.empty()) { + m_device->siggen_upload(samples.data(), samples.size()); + log("Generator ready."); + } else { + log("Error: Bad formula."); + } +} + +std::size_t pullFromQueue( + std::deque& queue, + CircularBuffer& circ) +{ + // We know how big the circular buffer should be to hold enough samples to + // fill the current draw samples view. + // If the given buffer does not match this size, notify the caller. + // TODO this could be done better... drawSamplesBufferSize should be a GUI- + // only thing. + if (circ.size() != drawSamplesBufferSize) + return drawSamplesBufferSize; + + std::scoped_lock lock (mutexDrawSamples); + + // The render code will draw all of the new samples we add to the buffer. + // So, we must provide a certain amount of samples at a time to make the + // render appear smooth. + // The 1.025 factor keeps us on top of the stream; don't want to fall + // behind. + const double FPS = ImGui::GetIO().Framerate; + const auto desiredCount = m_device->get_sample_rate() / FPS; + + // Transfer from the queue to the render buffer. + auto count = std::min(queue.size(), static_cast(desiredCount)); + while (count--) { + circ.put(queue.front()); + queue.pop_front(); + } + + return 0; +} + +/** + * Pulls a render frame's worth of samples from the draw samples queue, adding + * the samples to the given buffer. + */ +std::size_t pullFromDrawQueue( + CircularBuffer& circ) +{ + return pullFromQueue(drawSamplesQueue, circ); +} + +std::size_t pullFromInputDrawQueue( + CircularBuffer& circ) +{ + return pullFromQueue(drawSamplesInputQueue, circ); +} + diff --git a/gui/source/device_formula.cpp b/gui/source/device_formula.cpp new file mode 100644 index 0000000..e21d374 --- /dev/null +++ b/gui/source/device_formula.cpp @@ -0,0 +1,86 @@ +/** + * @file device_formula.cpp + * @brief Function for filling generator buffer using a mathematical formula. + * This is kept in its own file as exprtk.hpp takes forever to compile. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "stmdsp.hpp" + +#include +#include +#include +#include + +#ifndef STMDSP_DISABLE_FORMULAS + +#define exprtk_disable_comments +#define exprtk_disable_break_continue +#define exprtk_disable_sc_andor +#define exprtk_disable_return_statement +#define exprtk_disable_enhanced_features +//#define exprtk_disable_string_capabilities +#define exprtk_disable_superscalar_unroll +#define exprtk_disable_rtl_io_file +#define exprtk_disable_rtl_vecops +//#define exprtk_disable_caseinsensitivity +#include "exprtk.hpp" + +static std::random_device randomDevice; + +std::vector deviceGenLoadFormulaEval(const std::string& formulaString) +{ + double x = 0; + + exprtk::symbol_table symbol_table; + exprtk::function_compositor compositor (symbol_table); + exprtk::expression expression; + exprtk::parser parser; + + symbol_table.add_constants(); + symbol_table.add_variable("x", x); + symbol_table.add_function("random", + [](double l, double h) -> double { + return std::uniform_real_distribution(l, h)(randomDevice); + }); + compositor.add(exprtk::function_compositor::function() + .name("square") + .var("X") + .expression("ceil(sin(pi*X))")); + compositor.add(exprtk::function_compositor::function() + .name("triangle") + .var("X") + .expression("ceil(sin(pi*X))*(X-floor(X))+ceil(-sin(pi*X))*(-X-floor(-X))")); + compositor.add(exprtk::function_compositor::function() + .name("pulse") + .var("L") + .var("X") + .expression("if(X<=L,1,0)")); + expression.register_symbol_table(symbol_table); + parser.compile(formulaString, expression); + + const auto genFun = [&x, &expression] { + const auto s = std::clamp(expression.value(), -1., 1.) * 2048. + 2048.; + ++x; + return static_cast(std::min(s, 4095.)); + }; + + std::vector samples (stmdsp::SAMPLES_MAX); + std::generate(samples.begin(), samples.end(), genFun); + return samples; +} + +#else // no formula support + +std::vector deviceGenLoadFormulaEval(const std::string&) +{ + return {}; +} + +#endif // STMDSP_DISABLE_FORMULAS + diff --git a/gui/source/exprtk.hpp b/gui/source/exprtk.hpp new file mode 100644 index 0000000..bb108c2 --- /dev/null +++ b/gui/source/exprtk.hpp @@ -0,0 +1,40121 @@ +/* + ****************************************************************** + * C++ Mathematical Expression Toolkit Library * + * * + * Author: Arash Partow (1999-2021) * + * URL: http://www.partow.net/programming/exprtk/index.html * + * * + * Copyright notice: * + * Free use of the C++ Mathematical Expression Toolkit Library is * + * permitted under the guidelines and in accordance with the most * + * current version of the MIT License. * + * http://www.opensource.org/licenses/MIT * + * * + * Example expressions: * + * (00) (y + x / y) * (x - y / x) * + * (01) (x^2 / sin(2 * pi / y)) - x / 2 * + * (02) sqrt(1 - (x^2)) * + * (03) 1 - sin(2 * x) + cos(pi / y) * + * (04) a * exp(2 * t) + c * + * (05) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) * + * (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x * + * (07) z := x + sin(2 * pi / y) * + * (08) u := 2 * (pi * z) / (w := x + cos(y / pi)) * + * (09) clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1) * + * (10) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) * + * (11) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1) * + * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] * + * * + ****************************************************************** +*/ + + +#ifndef INCLUDE_EXPRTK_HPP +#define INCLUDE_EXPRTK_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace exprtk +{ + #ifdef exprtk_enable_debugging + #define exprtk_debug(params) printf params + #else + #define exprtk_debug(params) (void)0 + #endif + + #define exprtk_error_location \ + "exprtk.hpp:" + details::to_str(__LINE__) \ + + #if defined(__GNUC__) && (__GNUC__ >= 7) + + #define exprtk_disable_fallthrough_begin \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") \ + + #define exprtk_disable_fallthrough_end \ + _Pragma ("GCC diagnostic pop") \ + + #else + #define exprtk_disable_fallthrough_begin (void)0; + #define exprtk_disable_fallthrough_end (void)0; + #endif + + #if __cplusplus >= 201103L + #define exprtk_override override + #define exprtk_final final + #else + #define exprtk_override + #define exprtk_final + #endif + + namespace details + { + typedef unsigned char uchar_t; + typedef char char_t; + typedef uchar_t* uchar_ptr; + typedef char_t* char_ptr; + typedef uchar_t const* uchar_cptr; + typedef char_t const* char_cptr; + typedef unsigned long long int _uint64_t; + typedef long long int _int64_t; + + inline bool is_whitespace(const char_t c) + { + return (' ' == c) || ('\n' == c) || + ('\r' == c) || ('\t' == c) || + ('\b' == c) || ('\v' == c) || + ('\f' == c) ; + } + + inline bool is_operator_char(const char_t c) + { + return ('+' == c) || ('-' == c) || + ('*' == c) || ('/' == c) || + ('^' == c) || ('<' == c) || + ('>' == c) || ('=' == c) || + (',' == c) || ('!' == c) || + ('(' == c) || (')' == c) || + ('[' == c) || (']' == c) || + ('{' == c) || ('}' == c) || + ('%' == c) || (':' == c) || + ('?' == c) || ('&' == c) || + ('|' == c) || (';' == c) ; + } + + inline bool is_letter(const char_t c) + { + return (('a' <= c) && (c <= 'z')) || + (('A' <= c) && (c <= 'Z')) ; + } + + inline bool is_digit(const char_t c) + { + return ('0' <= c) && (c <= '9'); + } + + inline bool is_letter_or_digit(const char_t c) + { + return is_letter(c) || is_digit(c); + } + + inline bool is_left_bracket(const char_t c) + { + return ('(' == c) || ('[' == c) || ('{' == c); + } + + inline bool is_right_bracket(const char_t c) + { + return (')' == c) || (']' == c) || ('}' == c); + } + + inline bool is_bracket(const char_t c) + { + return is_left_bracket(c) || is_right_bracket(c); + } + + inline bool is_sign(const char_t c) + { + return ('+' == c) || ('-' == c); + } + + inline bool is_invalid(const char_t c) + { + return !is_whitespace (c) && + !is_operator_char(c) && + !is_letter (c) && + !is_digit (c) && + ('.' != c) && + ('_' != c) && + ('$' != c) && + ('~' != c) && + ('\'' != c); + } + + inline bool is_valid_string_char(const char_t c) + { + return std::isprint(static_cast(c)) || + is_whitespace(c); + } + + #ifndef exprtk_disable_caseinsensitivity + inline void case_normalise(std::string& s) + { + for (std::size_t i = 0; i < s.size(); ++i) + { + s[i] = static_cast(std::tolower(s[i])); + } + } + + inline bool imatch(const char_t c1, const char_t c2) + { + return std::tolower(c1) == std::tolower(c2); + } + + inline bool imatch(const std::string& s1, const std::string& s2) + { + if (s1.size() == s2.size()) + { + for (std::size_t i = 0; i < s1.size(); ++i) + { + if (std::tolower(s1[i]) != std::tolower(s2[i])) + { + return false; + } + } + + return true; + } + + return false; + } + + struct ilesscompare + { + inline bool operator() (const std::string& s1, const std::string& s2) const + { + const std::size_t length = std::min(s1.size(),s2.size()); + + for (std::size_t i = 0; i < length; ++i) + { + const char_t c1 = static_cast(std::tolower(s1[i])); + const char_t c2 = static_cast(std::tolower(s2[i])); + + if (c1 > c2) + return false; + else if (c1 < c2) + return true; + } + + return s1.size() < s2.size(); + } + }; + + #else + inline void case_normalise(std::string&) + {} + + inline bool imatch(const char_t c1, const char_t c2) + { + return c1 == c2; + } + + inline bool imatch(const std::string& s1, const std::string& s2) + { + return s1 == s2; + } + + struct ilesscompare + { + inline bool operator() (const std::string& s1, const std::string& s2) const + { + return s1 < s2; + } + }; + #endif + + inline bool is_valid_sf_symbol(const std::string& symbol) + { + // Special function: $f12 or $F34 + return (4 == symbol.size()) && + ('$' == symbol[0]) && + imatch('f',symbol[1]) && + is_digit(symbol[2]) && + is_digit(symbol[3]); + } + + inline const char_t& front(const std::string& s) + { + return s[0]; + } + + inline const char_t& back(const std::string& s) + { + return s[s.size() - 1]; + } + + inline std::string to_str(int i) + { + if (0 == i) + return std::string("0"); + + std::string result; + + if (i < 0) + { + for ( ; i; i /= 10) + { + result += '0' + static_cast(-(i % 10)); + } + + result += '-'; + } + else + { + for ( ; i; i /= 10) + { + result += '0' + static_cast(i % 10); + } + } + + std::reverse(result.begin(), result.end()); + + return result; + } + + inline std::string to_str(std::size_t i) + { + return to_str(static_cast(i)); + } + + inline bool is_hex_digit(const std::string::value_type digit) + { + return (('0' <= digit) && (digit <= '9')) || + (('A' <= digit) && (digit <= 'F')) || + (('a' <= digit) && (digit <= 'f')) ; + } + + inline uchar_t hex_to_bin(uchar_t h) + { + if (('0' <= h) && (h <= '9')) + return (h - '0'); + else + return static_cast(std::toupper(h) - 'A'); + } + + template + inline bool parse_hex(Iterator& itr, Iterator end, + std::string::value_type& result) + { + if ( + (end == (itr )) || + (end == (itr + 1)) || + (end == (itr + 2)) || + (end == (itr + 3)) || + ('0' != *(itr )) || + ('X' != std::toupper(*(itr + 1))) || + (!is_hex_digit(*(itr + 2))) || + (!is_hex_digit(*(itr + 3))) + ) + { + return false; + } + + result = hex_to_bin(static_cast(*(itr + 2))) << 4 | + hex_to_bin(static_cast(*(itr + 3))) ; + + return true; + } + + inline bool cleanup_escapes(std::string& s) + { + typedef std::string::iterator str_itr_t; + + str_itr_t itr1 = s.begin(); + str_itr_t itr2 = s.begin(); + str_itr_t end = s.end (); + + std::size_t removal_count = 0; + + while (end != itr1) + { + if ('\\' == (*itr1)) + { + if (end == ++itr1) + { + return false; + } + else if (parse_hex(itr1, end, *itr2)) + { + itr1+= 4; + itr2+= 1; + removal_count +=4; + } + else if ('a' == (*itr1)) { (*itr2++) = '\a'; ++itr1; ++removal_count; } + else if ('b' == (*itr1)) { (*itr2++) = '\b'; ++itr1; ++removal_count; } + else if ('f' == (*itr1)) { (*itr2++) = '\f'; ++itr1; ++removal_count; } + else if ('n' == (*itr1)) { (*itr2++) = '\n'; ++itr1; ++removal_count; } + else if ('r' == (*itr1)) { (*itr2++) = '\r'; ++itr1; ++removal_count; } + else if ('t' == (*itr1)) { (*itr2++) = '\t'; ++itr1; ++removal_count; } + else if ('v' == (*itr1)) { (*itr2++) = '\v'; ++itr1; ++removal_count; } + else if ('0' == (*itr1)) { (*itr2++) = '\0'; ++itr1; ++removal_count; } + else + { + (*itr2++) = (*itr1++); + ++removal_count; + } + continue; + } + else + (*itr2++) = (*itr1++); + } + + if ((removal_count > s.size()) || (0 == removal_count)) + return false; + + s.resize(s.size() - removal_count); + + return true; + } + + class build_string + { + public: + + build_string(const std::size_t& initial_size = 64) + { + data_.reserve(initial_size); + } + + inline build_string& operator << (const std::string& s) + { + data_ += s; + return (*this); + } + + inline build_string& operator << (char_cptr s) + { + data_ += std::string(s); + return (*this); + } + + inline operator std::string () const + { + return data_; + } + + inline std::string as_string() const + { + return data_; + } + + private: + + std::string data_; + }; + + static const std::string reserved_words[] = + { + "break", "case", "continue", "default", "false", "for", + "if", "else", "ilike", "in", "like", "and", "nand", "nor", + "not", "null", "or", "repeat", "return", "shl", "shr", + "swap", "switch", "true", "until", "var", "while", "xnor", + "xor", "&", "|" + }; + + static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); + + static const std::string reserved_symbols[] = + { + "abs", "acos", "acosh", "and", "asin", "asinh", "atan", + "atanh", "atan2", "avg", "break", "case", "ceil", "clamp", + "continue", "cos", "cosh", "cot", "csc", "default", + "deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", + "expm1", "false", "floor", "for", "frac", "grad2deg", + "hypot", "iclamp", "if", "else", "ilike", "in", "inrange", + "like", "log", "log10", "log2", "logn", "log1p", "mand", + "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", + "not", "not_equal", "null", "or", "pow", "rad2deg", + "repeat", "return", "root", "round", "roundn", "sec", "sgn", + "shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", + "switch", "tan", "tanh", "true", "trunc", "until", "var", + "while", "xnor", "xor", "&", "|" + }; + + static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); + + static const std::string base_function_list[] = + { + "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", + "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", + "csc", "equal", "erf", "erfc", "exp", "expm1", "floor", + "frac", "hypot", "iclamp", "like", "log", "log10", "log2", + "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", + "ncdf", "pow", "root", "round", "roundn", "sec", "sgn", + "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh", + "trunc", "not_equal", "inrange", "deg2grad", "deg2rad", + "rad2deg", "grad2deg" + }; + + static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string); + + static const std::string logic_ops_list[] = + { + "and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|" + }; + + static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string); + + static const std::string cntrl_struct_list[] = + { + "if", "switch", "for", "while", "repeat", "return" + }; + + static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string); + + static const std::string arithmetic_ops_list[] = + { + "+", "-", "*", "/", "%", "^" + }; + + static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string); + + static const std::string assignment_ops_list[] = + { + ":=", "+=", "-=", + "*=", "/=", "%=" + }; + + static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string); + + static const std::string inequality_ops_list[] = + { + "<", "<=", "==", + "=", "!=", "<>", + ">=", ">" + }; + + static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / sizeof(std::string); + + inline bool is_reserved_word(const std::string& symbol) + { + for (std::size_t i = 0; i < reserved_words_size; ++i) + { + if (imatch(symbol, reserved_words[i])) + { + return true; + } + } + + return false; + } + + inline bool is_reserved_symbol(const std::string& symbol) + { + for (std::size_t i = 0; i < reserved_symbols_size; ++i) + { + if (imatch(symbol, reserved_symbols[i])) + { + return true; + } + } + + return false; + } + + inline bool is_base_function(const std::string& function_name) + { + for (std::size_t i = 0; i < base_function_list_size; ++i) + { + if (imatch(function_name, base_function_list[i])) + { + return true; + } + } + + return false; + } + + inline bool is_control_struct(const std::string& cntrl_strct) + { + for (std::size_t i = 0; i < cntrl_struct_list_size; ++i) + { + if (imatch(cntrl_strct, cntrl_struct_list[i])) + { + return true; + } + } + + return false; + } + + inline bool is_logic_opr(const std::string& lgc_opr) + { + for (std::size_t i = 0; i < logic_ops_list_size; ++i) + { + if (imatch(lgc_opr, logic_ops_list[i])) + { + return true; + } + } + + return false; + } + + struct cs_match + { + static inline bool cmp(const char_t c0, const char_t c1) + { + return (c0 == c1); + } + }; + + struct cis_match + { + static inline bool cmp(const char_t c0, const char_t c1) + { + return (std::tolower(c0) == std::tolower(c1)); + } + }; + + template + inline bool match_impl(const Iterator pattern_begin, + const Iterator pattern_end , + const Iterator data_begin , + const Iterator data_end , + const typename std::iterator_traits::value_type& zero_or_more, + const typename std::iterator_traits::value_type& zero_or_one ) + { + const Iterator null_itr(0); + + Iterator d_itr = data_begin; + Iterator p_itr = pattern_begin; + Iterator tb_p_itr = null_itr; + Iterator tb_d_itr = null_itr; + + while (d_itr != data_end) + { + if (zero_or_more == *p_itr) + { + while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr))) + { + ++p_itr; + } + + if (pattern_end == p_itr) + return true; + + const typename std::iterator_traits::value_type c = *(p_itr); + + while ((data_end != d_itr) && !Compare::cmp(c,*d_itr)) + { + ++d_itr; + } + + tb_p_itr = p_itr; + tb_d_itr = d_itr; + + continue; + } + else if (!Compare::cmp(*p_itr, *d_itr) && (zero_or_one != *p_itr)) + { + if (null_itr == tb_d_itr) + return false; + + d_itr = tb_d_itr++; + p_itr = tb_p_itr; + + continue; + } + + ++p_itr; + ++d_itr; + } + + while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr))) + { + ++p_itr; + } + + return (pattern_end == p_itr); + } + + inline bool wc_match(const std::string& wild_card, + const std::string& str) + { + return match_impl( + wild_card.data(), wild_card.data() + wild_card.size(), + str.data(), str.data() + str.size(), + '*', '?'); + } + + inline bool wc_imatch(const std::string& wild_card, + const std::string& str) + { + return match_impl( + wild_card.data(), wild_card.data() + wild_card.size(), + str.data(), str.data() + str.size(), + '*', '?'); + } + + inline bool sequence_match(const std::string& pattern, + const std::string& str, + std::size_t& diff_index, + char_t& diff_value) + { + if (str.empty()) + { + return ("Z" == pattern); + } + else if ('*' == pattern[0]) + return false; + + typedef std::string::const_iterator itr_t; + + itr_t p_itr = pattern.begin(); + itr_t s_itr = str .begin(); + + itr_t p_end = pattern.end(); + itr_t s_end = str .end(); + + while ((s_end != s_itr) && (p_end != p_itr)) + { + if ('*' == (*p_itr)) + { + const char_t target = static_cast(std::toupper(*(p_itr - 1))); + + if ('*' == target) + { + diff_index = static_cast(std::distance(str.begin(),s_itr)); + diff_value = static_cast(std::toupper(*p_itr)); + + return false; + } + else + ++p_itr; + + while (s_itr != s_end) + { + if (target != std::toupper(*s_itr)) + break; + else + ++s_itr; + } + + continue; + } + else if ( + ('?' != *p_itr) && + std::toupper(*p_itr) != std::toupper(*s_itr) + ) + { + diff_index = static_cast(std::distance(str.begin(),s_itr)); + diff_value = static_cast(std::toupper(*p_itr)); + + return false; + } + + ++p_itr; + ++s_itr; + } + + return ( + (s_end == s_itr) && + ( + (p_end == p_itr) || + ('*' == *p_itr) + ) + ); + } + + static const double pow10[] = { + 1.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, + 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, + 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, + 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 + }; + + static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); + + namespace numeric + { + namespace constant + { + static const double e = 2.71828182845904523536028747135266249775724709369996; + static const double pi = 3.14159265358979323846264338327950288419716939937510; + static const double pi_2 = 1.57079632679489661923132169163975144209858469968755; + static const double pi_4 = 0.78539816339744830961566084581987572104929234984378; + static const double pi_180 = 0.01745329251994329576923690768488612713442871888542; + static const double _1_pi = 0.31830988618379067153776752674502872406891929148091; + static const double _2_pi = 0.63661977236758134307553505349005744813783858296183; + static const double _180_pi = 57.29577951308232087679815481410517033240547246656443; + static const double log2 = 0.69314718055994530941723212145817656807550013436026; + static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695; + } + + namespace details + { + struct unknown_type_tag { unknown_type_tag() {} }; + struct real_type_tag { real_type_tag () {} }; + struct complex_type_tag { complex_type_tag() {} }; + struct int_type_tag { int_type_tag () {} }; + + template + struct number_type + { + typedef unknown_type_tag type; + number_type() {} + }; + + #define exprtk_register_real_type_tag(T) \ + template <> struct number_type \ + { typedef real_type_tag type; number_type() {} }; \ + + #define exprtk_register_complex_type_tag(T) \ + template <> struct number_type > \ + { typedef complex_type_tag type; number_type() {} }; \ + + #define exprtk_register_int_type_tag(T) \ + template <> struct number_type \ + { typedef int_type_tag type; number_type() {} }; \ + + exprtk_register_real_type_tag(double ) + exprtk_register_real_type_tag(long double) + exprtk_register_real_type_tag(float ) + + exprtk_register_complex_type_tag(double ) + exprtk_register_complex_type_tag(long double) + exprtk_register_complex_type_tag(float ) + + exprtk_register_int_type_tag(short ) + exprtk_register_int_type_tag(int ) + exprtk_register_int_type_tag(_int64_t ) + exprtk_register_int_type_tag(unsigned short) + exprtk_register_int_type_tag(unsigned int ) + exprtk_register_int_type_tag(_uint64_t ) + + #undef exprtk_register_real_type_tag + #undef exprtk_register_int_type_tag + + template + struct epsilon_type {}; + + #define exprtk_define_epsilon_type(Type, Epsilon) \ + template <> struct epsilon_type \ + { \ + static inline Type value() \ + { \ + const Type epsilon = static_cast(Epsilon); \ + return epsilon; \ + } \ + }; \ + + exprtk_define_epsilon_type(float , 0.000001f) + exprtk_define_epsilon_type(double , 0.0000000001) + exprtk_define_epsilon_type(long double, 0.000000000001) + + #undef exprtk_define_epsilon_type + + template + inline bool is_nan_impl(const T v, real_type_tag) + { + return std::not_equal_to()(v,v); + } + + template + inline int to_int32_impl(const T v, real_type_tag) + { + return static_cast(v); + } + + template + inline _int64_t to_int64_impl(const T v, real_type_tag) + { + return static_cast<_int64_t>(v); + } + + template + inline bool is_true_impl(const T v) + { + return std::not_equal_to()(T(0),v); + } + + template + inline bool is_false_impl(const T v) + { + return std::equal_to()(T(0),v); + } + + template + inline T abs_impl(const T v, real_type_tag) + { + return ((v < T(0)) ? -v : v); + } + + template + inline T min_impl(const T v0, const T v1, real_type_tag) + { + return std::min(v0,v1); + } + + template + inline T max_impl(const T v0, const T v1, real_type_tag) + { + return std::max(v0,v1); + } + + template + inline T equal_impl(const T v0, const T v1, real_type_tag) + { + const T epsilon = epsilon_type::value(); + return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(T(1),std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? T(1) : T(0); + } + + inline float equal_impl(const float v0, const float v1, real_type_tag) + { + const float epsilon = epsilon_type::value(); + return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(1.0f,std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? 1.0f : 0.0f; + } + + template + inline T equal_impl(const T v0, const T v1, int_type_tag) + { + return (v0 == v1) ? 1 : 0; + } + + template + inline T expm1_impl(const T v, real_type_tag) + { + // return std::expm1(v); + if (abs_impl(v,real_type_tag()) < T(0.00001)) + return v + (T(0.5) * v * v); + else + return std::exp(v) - T(1); + } + + template + inline T expm1_impl(const T v, int_type_tag) + { + return T(std::exp(v)) - T(1); + } + + template + inline T nequal_impl(const T v0, const T v1, real_type_tag) + { + typedef real_type_tag rtg; + const T epsilon = epsilon_type::value(); + return (abs_impl(v0 - v1,rtg()) > (std::max(T(1),std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? T(1) : T(0); + } + + inline float nequal_impl(const float v0, const float v1, real_type_tag) + { + typedef real_type_tag rtg; + const float epsilon = epsilon_type::value(); + return (abs_impl(v0 - v1,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f; + } + + template + inline T nequal_impl(const T v0, const T v1, int_type_tag) + { + return (v0 != v1) ? 1 : 0; + } + + template + inline T modulus_impl(const T v0, const T v1, real_type_tag) + { + return std::fmod(v0,v1); + } + + template + inline T modulus_impl(const T v0, const T v1, int_type_tag) + { + return v0 % v1; + } + + template + inline T pow_impl(const T v0, const T v1, real_type_tag) + { + return std::pow(v0,v1); + } + + template + inline T pow_impl(const T v0, const T v1, int_type_tag) + { + return std::pow(static_cast(v0),static_cast(v1)); + } + + template + inline T logn_impl(const T v0, const T v1, real_type_tag) + { + return std::log(v0) / std::log(v1); + } + + template + inline T logn_impl(const T v0, const T v1, int_type_tag) + { + return static_cast(logn_impl(static_cast(v0),static_cast(v1),real_type_tag())); + } + + template + inline T log1p_impl(const T v, real_type_tag) + { + if (v > T(-1)) + { + if (abs_impl(v,real_type_tag()) > T(0.0001)) + { + return std::log(T(1) + v); + } + else + return (T(-0.5) * v + T(1)) * v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T log1p_impl(const T v, int_type_tag) + { + if (v > T(-1)) + { + return std::log(T(1) + v); + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T root_impl(const T v0, const T v1, real_type_tag) + { + if (v1 < T(0)) + return std::numeric_limits::quiet_NaN(); + + const std::size_t n = static_cast(v1); + + if ((v0 < T(0)) && (0 == (n % 2))) + return std::numeric_limits::quiet_NaN(); + + return std::pow(v0, T(1) / n); + } + + template + inline T root_impl(const T v0, const T v1, int_type_tag) + { + return root_impl(static_cast(v0),static_cast(v1),real_type_tag()); + } + + template + inline T round_impl(const T v, real_type_tag) + { + return ((v < T(0)) ? std::ceil(v - T(0.5)) : std::floor(v + T(0.5))); + } + + template + inline T roundn_impl(const T v0, const T v1, real_type_tag) + { + const int index = std::max(0, std::min(pow10_size - 1, static_cast(std::floor(v1)))); + const T p10 = T(pow10[index]); + + if (v0 < T(0)) + return T(std::ceil ((v0 * p10) - T(0.5)) / p10); + else + return T(std::floor((v0 * p10) + T(0.5)) / p10); + } + + template + inline T roundn_impl(const T v0, const T, int_type_tag) + { + return v0; + } + + template + inline T hypot_impl(const T v0, const T v1, real_type_tag) + { + return std::sqrt((v0 * v0) + (v1 * v1)); + } + + template + inline T hypot_impl(const T v0, const T v1, int_type_tag) + { + return static_cast(std::sqrt(static_cast((v0 * v0) + (v1 * v1)))); + } + + template + inline T atan2_impl(const T v0, const T v1, real_type_tag) + { + return std::atan2(v0,v1); + } + + template + inline T atan2_impl(const T, const T, int_type_tag) + { + return 0; + } + + template + inline T shr_impl(const T v0, const T v1, real_type_tag) + { + return v0 * (T(1) / std::pow(T(2),static_cast(static_cast(v1)))); + } + + template + inline T shr_impl(const T v0, const T v1, int_type_tag) + { + return v0 >> v1; + } + + template + inline T shl_impl(const T v0, const T v1, real_type_tag) + { + return v0 * std::pow(T(2),static_cast(static_cast(v1))); + } + + template + inline T shl_impl(const T v0, const T v1, int_type_tag) + { + return v0 << v1; + } + + template + inline T sgn_impl(const T v, real_type_tag) + { + if (v > T(0)) return T(+1); + else if (v < T(0)) return T(-1); + else return T( 0); + } + + template + inline T sgn_impl(const T v, int_type_tag) + { + if (v > T(0)) return T(+1); + else if (v < T(0)) return T(-1); + else return T( 0); + } + + template + inline T and_impl(const T v0, const T v1, real_type_tag) + { + return (is_true_impl(v0) && is_true_impl(v1)) ? T(1) : T(0); + } + + template + inline T and_impl(const T v0, const T v1, int_type_tag) + { + return v0 && v1; + } + + template + inline T nand_impl(const T v0, const T v1, real_type_tag) + { + return (is_false_impl(v0) || is_false_impl(v1)) ? T(1) : T(0); + } + + template + inline T nand_impl(const T v0, const T v1, int_type_tag) + { + return !(v0 && v1); + } + + template + inline T or_impl(const T v0, const T v1, real_type_tag) + { + return (is_true_impl(v0) || is_true_impl(v1)) ? T(1) : T(0); + } + + template + inline T or_impl(const T v0, const T v1, int_type_tag) + { + return (v0 || v1); + } + + template + inline T nor_impl(const T v0, const T v1, real_type_tag) + { + return (is_false_impl(v0) && is_false_impl(v1)) ? T(1) : T(0); + } + + template + inline T nor_impl(const T v0, const T v1, int_type_tag) + { + return !(v0 || v1); + } + + template + inline T xor_impl(const T v0, const T v1, real_type_tag) + { + return (is_false_impl(v0) != is_false_impl(v1)) ? T(1) : T(0); + } + + template + inline T xor_impl(const T v0, const T v1, int_type_tag) + { + return v0 ^ v1; + } + + template + inline T xnor_impl(const T v0, const T v1, real_type_tag) + { + const bool v0_true = is_true_impl(v0); + const bool v1_true = is_true_impl(v1); + + if ((v0_true && v1_true) || (!v0_true && !v1_true)) + return T(1); + else + return T(0); + } + + template + inline T xnor_impl(const T v0, const T v1, int_type_tag) + { + const bool v0_true = is_true_impl(v0); + const bool v1_true = is_true_impl(v1); + + if ((v0_true && v1_true) || (!v0_true && !v1_true)) + return T(1); + else + return T(0); + } + + #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) + #define exprtk_define_erf(TT,impl) \ + inline TT erf_impl(TT v) { return impl(v); } \ + + exprtk_define_erf( float,::erff) + exprtk_define_erf( double,::erf ) + exprtk_define_erf(long double,::erfl) + #undef exprtk_define_erf + #endif + + template + inline T erf_impl(T v, real_type_tag) + { + #if defined(_MSC_VER) && (_MSC_VER < 1900) + // Credits: Abramowitz & Stegun Equations 7.1.25-28 + static const T c[] = { + T( 1.26551223), T(1.00002368), + T( 0.37409196), T(0.09678418), + T(-0.18628806), T(0.27886807), + T(-1.13520398), T(1.48851587), + T(-0.82215223), T(0.17087277) + }; + + const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); + + T result = T(1) - t * std::exp((-v * v) - + c[0] + t * (c[1] + t * + (c[2] + t * (c[3] + t * + (c[4] + t * (c[5] + t * + (c[6] + t * (c[7] + t * + (c[8] + t * (c[9])))))))))); + + return (v >= T(0)) ? result : -result; + #else + return erf_impl(v); + #endif + } + + template + inline T erf_impl(T v, int_type_tag) + { + return erf_impl(static_cast(v),real_type_tag()); + } + + #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) + #define exprtk_define_erfc(TT,impl) \ + inline TT erfc_impl(TT v) { return impl(v); } \ + + exprtk_define_erfc( float,::erfcf) + exprtk_define_erfc( double,::erfc ) + exprtk_define_erfc(long double,::erfcl) + #undef exprtk_define_erfc + #endif + + template + inline T erfc_impl(T v, real_type_tag) + { + #if defined(_MSC_VER) && (_MSC_VER < 1900) + return T(1) - erf_impl(v,real_type_tag()); + #else + return erfc_impl(v); + #endif + } + + template + inline T erfc_impl(T v, int_type_tag) + { + return erfc_impl(static_cast(v),real_type_tag()); + } + + template + inline T ncdf_impl(T v, real_type_tag) + { + T cnd = T(0.5) * (T(1) + erf_impl( + abs_impl(v,real_type_tag()) / + T(numeric::constant::sqrt2),real_type_tag())); + return (v < T(0)) ? (T(1) - cnd) : cnd; + } + + template + inline T ncdf_impl(T v, int_type_tag) + { + return ncdf_impl(static_cast(v),real_type_tag()); + } + + template + inline T sinc_impl(T v, real_type_tag) + { + if (std::abs(v) >= std::numeric_limits::epsilon()) + return(std::sin(v) / v); + else + return T(1); + } + + template + inline T sinc_impl(T v, int_type_tag) + { + return sinc_impl(static_cast(v),real_type_tag()); + } + + template inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } + template inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } + template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } + template inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } + template inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } + template inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); } + template inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } + template inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } + template inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } + template inline T exp_impl(const T v, real_type_tag) { return std::exp (v); } + template inline T floor_impl(const T v, real_type_tag) { return std::floor(v); } + template inline T log_impl(const T v, real_type_tag) { return std::log (v); } + template inline T log10_impl(const T v, real_type_tag) { return std::log10(v); } + template inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); } + template inline T neg_impl(const T v, real_type_tag) { return -v; } + template inline T pos_impl(const T v, real_type_tag) { return +v; } + template inline T sin_impl(const T v, real_type_tag) { return std::sin (v); } + template inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); } + template inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); } + template inline T tan_impl(const T v, real_type_tag) { return std::tan (v); } + template inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); } + template inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); } + template inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); } + template inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); } + template inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } + template inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } + template inline T d2g_impl(const T v, real_type_tag) { return (v * T(20.0/9.0)); } + template inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/20.0)); } + template inline T notl_impl(const T v, real_type_tag) { return (std::not_equal_to()(T(0),v) ? T(0) : T(1)); } + template inline T frac_impl(const T v, real_type_tag) { return (v - static_cast(v)); } + template inline T trunc_impl(const T v, real_type_tag) { return T(static_cast(v)); } + + template inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); } + template inline T const_e_impl (real_type_tag) { return T(numeric::constant::e); } + + template inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); } + template inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } + template inline T log_impl(const T v, int_type_tag) { return std::log (v); } + template inline T log10_impl(const T v, int_type_tag) { return std::log10(v); } + template inline T log2_impl(const T v, int_type_tag) { return std::log(v)/T(numeric::constant::log2); } + template inline T neg_impl(const T v, int_type_tag) { return -v; } + template inline T pos_impl(const T v, int_type_tag) { return +v; } + template inline T ceil_impl(const T v, int_type_tag) { return v; } + template inline T floor_impl(const T v, int_type_tag) { return v; } + template inline T round_impl(const T v, int_type_tag) { return v; } + template inline T notl_impl(const T v, int_type_tag) { return !v; } + template inline T sqrt_impl(const T v, int_type_tag) { return std::sqrt (v); } + template inline T frac_impl(const T , int_type_tag) { return T(0); } + template inline T trunc_impl(const T v, int_type_tag) { return v; } + template inline T acos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T acosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T asin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T asinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T atan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T atanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T cos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T cosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T sin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T sinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T tan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T tanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T cot_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T sec_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + template inline T csc_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } + + template + inline bool is_integer_impl(const T& v, real_type_tag) + { + return std::equal_to()(T(0),std::fmod(v,T(1))); + } + + template + inline bool is_integer_impl(const T&, int_type_tag) + { + return true; + } + } + + template + struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; }; + + template <> struct numeric_info { enum { length = 10, size = 16, bound_length = 9}; }; + template <> struct numeric_info { enum { min_exp = -38, max_exp = +38}; }; + template <> struct numeric_info { enum { min_exp = -308, max_exp = +308}; }; + template <> struct numeric_info { enum { min_exp = -308, max_exp = +308}; }; + + template + inline int to_int32(const T v) + { + const typename details::number_type::type num_type; + return to_int32_impl(v, num_type); + } + + template + inline _int64_t to_int64(const T v) + { + const typename details::number_type::type num_type; + return to_int64_impl(v, num_type); + } + + template + inline bool is_nan(const T v) + { + const typename details::number_type::type num_type; + return is_nan_impl(v, num_type); + } + + template + inline T min(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return min_impl(v0, v1, num_type); + } + + template + inline T max(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return max_impl(v0, v1, num_type); + } + + template + inline T equal(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return equal_impl(v0, v1, num_type); + } + + template + inline T nequal(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return nequal_impl(v0, v1, num_type); + } + + template + inline T modulus(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return modulus_impl(v0, v1, num_type); + } + + template + inline T pow(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return pow_impl(v0, v1, num_type); + } + + template + inline T logn(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return logn_impl(v0, v1, num_type); + } + + template + inline T root(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return root_impl(v0, v1, num_type); + } + + template + inline T roundn(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return roundn_impl(v0, v1, num_type); + } + + template + inline T hypot(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return hypot_impl(v0, v1, num_type); + } + + template + inline T atan2(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return atan2_impl(v0, v1, num_type); + } + + template + inline T shr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return shr_impl(v0, v1, num_type); + } + + template + inline T shl(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return shl_impl(v0, v1, num_type); + } + + template + inline T and_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return and_impl(v0, v1, num_type); + } + + template + inline T nand_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return nand_impl(v0, v1, num_type); + } + + template + inline T or_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return or_impl(v0, v1, num_type); + } + + template + inline T nor_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return nor_impl(v0, v1, num_type); + } + + template + inline T xor_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return xor_impl(v0, v1, num_type); + } + + template + inline T xnor_opr(const T v0, const T v1) + { + const typename details::number_type::type num_type; + return xnor_impl(v0, v1, num_type); + } + + template + inline bool is_integer(const T v) + { + const typename details::number_type::type num_type; + return is_integer_impl(v, num_type); + } + + template + struct fast_exp + { + static inline T result(T v) + { + unsigned int k = N; + T l = T(1); + + while (k) + { + if (k & 1) + { + l *= v; + --k; + } + + v *= v; + k >>= 1; + } + + return l; + } + }; + + template struct fast_exp { static inline T result(const T v) { T v_5 = fast_exp::result(v); return v_5 * v_5; } }; + template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; + template struct fast_exp { static inline T result(const T v) { T v_4 = fast_exp::result(v); return v_4 * v_4; } }; + template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; + template struct fast_exp { static inline T result(const T v) { T v_3 = fast_exp::result(v); return v_3 * v_3; } }; + template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; + template struct fast_exp { static inline T result(const T v) { T v_2 = v * v; return v_2 * v_2; } }; + template struct fast_exp { static inline T result(const T v) { return v * v * v; } }; + template struct fast_exp { static inline T result(const T v) { return v * v; } }; + template struct fast_exp { static inline T result(const T v) { return v; } }; + template struct fast_exp { static inline T result(const T ) { return T(1); } }; + + #define exprtk_define_unary_function(FunctionName) \ + template \ + inline T FunctionName (const T v) \ + { \ + const typename details::number_type::type num_type; \ + return FunctionName##_impl(v,num_type); \ + } \ + + exprtk_define_unary_function(abs ) + exprtk_define_unary_function(acos ) + exprtk_define_unary_function(acosh) + exprtk_define_unary_function(asin ) + exprtk_define_unary_function(asinh) + exprtk_define_unary_function(atan ) + exprtk_define_unary_function(atanh) + exprtk_define_unary_function(ceil ) + exprtk_define_unary_function(cos ) + exprtk_define_unary_function(cosh ) + exprtk_define_unary_function(exp ) + exprtk_define_unary_function(expm1) + exprtk_define_unary_function(floor) + exprtk_define_unary_function(log ) + exprtk_define_unary_function(log10) + exprtk_define_unary_function(log2 ) + exprtk_define_unary_function(log1p) + exprtk_define_unary_function(neg ) + exprtk_define_unary_function(pos ) + exprtk_define_unary_function(round) + exprtk_define_unary_function(sin ) + exprtk_define_unary_function(sinc ) + exprtk_define_unary_function(sinh ) + exprtk_define_unary_function(sqrt ) + exprtk_define_unary_function(tan ) + exprtk_define_unary_function(tanh ) + exprtk_define_unary_function(cot ) + exprtk_define_unary_function(sec ) + exprtk_define_unary_function(csc ) + exprtk_define_unary_function(r2d ) + exprtk_define_unary_function(d2r ) + exprtk_define_unary_function(d2g ) + exprtk_define_unary_function(g2d ) + exprtk_define_unary_function(notl ) + exprtk_define_unary_function(sgn ) + exprtk_define_unary_function(erf ) + exprtk_define_unary_function(erfc ) + exprtk_define_unary_function(ncdf ) + exprtk_define_unary_function(frac ) + exprtk_define_unary_function(trunc) + #undef exprtk_define_unary_function + } + + template + inline T compute_pow10(T d, const int exponent) + { + static const double fract10[] = + { + 0.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010, + 1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020, + 1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030, + 1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040, + 1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050, + 1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060, + 1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070, + 1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080, + 1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090, + 1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100, + 1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110, + 1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120, + 1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130, + 1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140, + 1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150, + 1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160, + 1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170, + 1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, + 1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, + 1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, + 1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, + 1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, + 1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, + 1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, + 1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, + 1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260, + 1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270, + 1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280, + 1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290, + 1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300, + 1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308 + }; + + static const int fract10_size = static_cast(sizeof(fract10) / sizeof(double)); + + const int e = std::abs(exponent); + + if (exponent >= std::numeric_limits::min_exponent10) + { + if (e < fract10_size) + { + if (exponent > 0) + return T(d * fract10[e]); + else + return T(d / fract10[e]); + } + else + return T(d * std::pow(10.0, 10.0 * exponent)); + } + else + { + d /= T(fract10[ -std::numeric_limits::min_exponent10]); + return T(d / fract10[-exponent + std::numeric_limits::min_exponent10]); + } + } + + template + inline bool string_to_type_converter_impl_ref(Iterator& itr, const Iterator end, T& result) + { + if (itr == end) + return false; + + const bool negative = ('-' == (*itr)); + + if (negative || ('+' == (*itr))) + { + if (end == ++itr) + return false; + } + + static const uchar_t zero = static_cast('0'); + + while ((end != itr) && (zero == (*itr))) ++itr; + + bool return_result = true; + unsigned int digit = 0; + const std::size_t length = static_cast(std::distance(itr,end)); + + if (length <= 4) + { + exprtk_disable_fallthrough_begin + switch (length) + { + #ifdef exprtk_use_lut + + #define exprtk_process_digit \ + if ((digit = details::digit_table[(int)*itr++]) < 10) \ + result = result * 10 + (digit); \ + else \ + { \ + return_result = false; \ + break; \ + } \ + + #else + + #define exprtk_process_digit \ + if ((digit = (*itr++ - zero)) < 10) \ + result = result * T(10) + digit; \ + else \ + { \ + return_result = false; \ + break; \ + } \ + + #endif + + case 4 : exprtk_process_digit + case 3 : exprtk_process_digit + case 2 : exprtk_process_digit + case 1 : if ((digit = (*itr - zero))>= 10) { digit = 0; return_result = false; } + + #undef exprtk_process_digit + } + exprtk_disable_fallthrough_end + } + else + return_result = false; + + if (length && return_result) + { + result = result * 10 + static_cast(digit); + ++itr; + } + + result = negative ? -result : result; + return return_result; + } + + template + static inline bool parse_nan(Iterator& itr, const Iterator end, T& t) + { + typedef typename std::iterator_traits::value_type type; + + static const std::size_t nan_length = 3; + + if (std::distance(itr,end) != static_cast(nan_length)) + return false; + + if (static_cast('n') == (*itr)) + { + if ( + (static_cast('a') != *(itr + 1)) || + (static_cast('n') != *(itr + 2)) + ) + { + return false; + } + } + else if ( + (static_cast('A') != *(itr + 1)) || + (static_cast('N') != *(itr + 2)) + ) + { + return false; + } + + t = std::numeric_limits::quiet_NaN(); + + return true; + } + + template + static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, bool negative) + { + static const char_t inf_uc[] = "INFINITY"; + static const char_t inf_lc[] = "infinity"; + static const std::size_t inf_length = 8; + + const std::size_t length = static_cast(std::distance(itr,end)); + + if ((3 != length) && (inf_length != length)) + return false; + + char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; + + while (end != itr) + { + if (*inf_itr == static_cast(*itr)) + { + ++itr; + ++inf_itr; + continue; + } + else + return false; + } + + if (negative) + t = -std::numeric_limits::infinity(); + else + t = std::numeric_limits::infinity(); + + return true; + } + + template + inline bool valid_exponent(const int exponent, numeric::details::real_type_tag) + { + using namespace details::numeric; + return (numeric_info::min_exp <= exponent) && (exponent <= numeric_info::max_exp); + } + + template + inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag) + { + if (end == itr_external) return false; + + Iterator itr = itr_external; + + T d = T(0); + + const bool negative = ('-' == (*itr)); + + if (negative || '+' == (*itr)) + { + if (end == ++itr) + return false; + } + + bool instate = false; + + static const char_t zero = static_cast('0'); + + #define parse_digit_1(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else \ + { break; } \ + if (end == ++itr) break; \ + + #define parse_digit_2(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else { break; } \ + ++itr; \ + + if ('.' != (*itr)) + { + const Iterator curr = itr; + + while ((end != itr) && (zero == (*itr))) ++itr; + + while (end != itr) + { + unsigned int digit; + parse_digit_1(d) + parse_digit_1(d) + parse_digit_2(d) + } + + if (curr != itr) instate = true; + } + + int exponent = 0; + + if (end != itr) + { + if ('.' == (*itr)) + { + const Iterator curr = ++itr; + T tmp_d = T(0); + + while (end != itr) + { + unsigned int digit; + parse_digit_1(tmp_d) + parse_digit_1(tmp_d) + parse_digit_2(tmp_d) + } + + if (curr != itr) + { + instate = true; + + const int frac_exponent = static_cast(-std::distance(curr, itr)); + + if (!valid_exponent(frac_exponent, numeric::details::real_type_tag())) + return false; + + d += compute_pow10(tmp_d, frac_exponent); + } + + #undef parse_digit_1 + #undef parse_digit_2 + } + + if (end != itr) + { + typename std::iterator_traits::value_type c = (*itr); + + if (('e' == c) || ('E' == c)) + { + int exp = 0; + + if (!details::string_to_type_converter_impl_ref(++itr, end, exp)) + { + if (end == itr) + return false; + else + c = (*itr); + } + + exponent += exp; + } + + if (end != itr) + { + if (('f' == c) || ('F' == c) || ('l' == c) || ('L' == c)) + ++itr; + else if ('#' == c) + { + if (end == ++itr) + return false; + else if (('I' <= (*itr)) && ((*itr) <= 'n')) + { + if (('i' == (*itr)) || ('I' == (*itr))) + { + return parse_inf(itr, end, t, negative); + } + else if (('n' == (*itr)) || ('N' == (*itr))) + { + return parse_nan(itr, end, t); + } + else + return false; + } + else + return false; + } + else if (('I' <= (*itr)) && ((*itr) <= 'n')) + { + if (('i' == (*itr)) || ('I' == (*itr))) + { + return parse_inf(itr, end, t, negative); + } + else if (('n' == (*itr)) || ('N' == (*itr))) + { + return parse_nan(itr, end, t); + } + else + return false; + } + else + return false; + } + } + } + + if ((end != itr) || (!instate)) + return false; + else if (!valid_exponent(exponent, numeric::details::real_type_tag())) + return false; + else if (exponent) + d = compute_pow10(d,exponent); + + t = static_cast((negative) ? -d : d); + return true; + } + + template + inline bool string_to_real(const std::string& s, T& t) + { + const typename numeric::details::number_type::type num_type; + + char_cptr begin = s.data(); + char_cptr end = s.data() + s.size(); + + return string_to_real(begin, end, t, num_type); + } + + template + struct functor_t + { + /* + Note: The following definitions for Type, may require tweaking + based on the compiler and target architecture. The benchmark + should provide enough information to make the right choice. + */ + //typedef T Type; + //typedef const T Type; + typedef const T& Type; + typedef T& RefType; + typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3); + typedef T (*tfunc_t)(Type t0, Type t1, Type t2); + typedef T (*bfunc_t)(Type t0, Type t1); + typedef T (*ufunc_t)(Type t0); + }; + + } // namespace details + + struct loop_runtime_check + { + enum loop_types + { + e_invalid = 0, + e_for_loop = 1, + e_while_loop = 2, + e_repeat_until_loop = 4, + e_all_loops = 7 + }; + + enum violation_type + { + e_unknown = 0, + e_iteration_count = 1, + e_timeout = 2 + }; + + loop_types loop_set; + + loop_runtime_check() + : loop_set(e_invalid), + max_loop_iterations(0) + {} + + details::_uint64_t max_loop_iterations; + + struct violation_context + { + loop_types loop; + violation_type violation; + details::_uint64_t iteration_count; + }; + + virtual void handle_runtime_violation(const violation_context&) + { + throw std::runtime_error("ExprTk Loop run-time violation."); + } + + virtual ~loop_runtime_check() {} + }; + + typedef loop_runtime_check* loop_runtime_check_ptr; + + namespace lexer + { + struct token + { + enum token_type + { + e_none = 0, e_error = 1, e_err_symbol = 2, + e_err_number = 3, e_err_string = 4, e_err_sfunc = 5, + e_eof = 6, e_number = 7, e_symbol = 8, + e_string = 9, e_assign = 10, e_addass = 11, + e_subass = 12, e_mulass = 13, e_divass = 14, + e_modass = 15, e_shr = 16, e_shl = 17, + e_lte = 18, e_ne = 19, e_gte = 20, + e_swap = 21, e_lt = '<', e_gt = '>', + e_eq = '=', e_rbracket = ')', e_lbracket = '(', + e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}', + e_lcrlbracket = '{', e_comma = ',', e_add = '+', + e_sub = '-', e_div = '/', e_mul = '*', + e_mod = '%', e_pow = '^', e_colon = ':', + e_ternary = '?' + }; + + token() + : type(e_none), + value(""), + position(std::numeric_limits::max()) + {} + + void clear() + { + type = e_none; + value = ""; + position = std::numeric_limits::max(); + } + + template + inline token& set_operator(const token_type tt, + const Iterator begin, const Iterator end, + const Iterator base_begin = Iterator(0)) + { + type = tt; + value.assign(begin,end); + if (base_begin) + position = static_cast(std::distance(base_begin,begin)); + return (*this); + } + + template + inline token& set_symbol(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) + { + type = e_symbol; + value.assign(begin,end); + if (base_begin) + position = static_cast(std::distance(base_begin,begin)); + return (*this); + } + + template + inline token& set_numeric(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) + { + type = e_number; + value.assign(begin,end); + if (base_begin) + position = static_cast(std::distance(base_begin,begin)); + return (*this); + } + + template + inline token& set_string(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) + { + type = e_string; + value.assign(begin,end); + if (base_begin) + position = static_cast(std::distance(base_begin,begin)); + return (*this); + } + + inline token& set_string(const std::string& s, const std::size_t p) + { + type = e_string; + value = s; + position = p; + return (*this); + } + + template + inline token& set_error(const token_type et, + const Iterator begin, const Iterator end, + const Iterator base_begin = Iterator(0)) + { + if ( + (e_error == et) || + (e_err_symbol == et) || + (e_err_number == et) || + (e_err_string == et) || + (e_err_sfunc == et) + ) + { + type = et; + } + else + type = e_error; + + value.assign(begin,end); + + if (base_begin) + position = static_cast(std::distance(base_begin,begin)); + + return (*this); + } + + static inline std::string to_str(token_type t) + { + switch (t) + { + case e_none : return "NONE"; + case e_error : return "ERROR"; + case e_err_symbol : return "ERROR_SYMBOL"; + case e_err_number : return "ERROR_NUMBER"; + case e_err_string : return "ERROR_STRING"; + case e_eof : return "EOF"; + case e_number : return "NUMBER"; + case e_symbol : return "SYMBOL"; + case e_string : return "STRING"; + case e_assign : return ":="; + case e_addass : return "+="; + case e_subass : return "-="; + case e_mulass : return "*="; + case e_divass : return "/="; + case e_modass : return "%="; + case e_shr : return ">>"; + case e_shl : return "<<"; + case e_lte : return "<="; + case e_ne : return "!="; + case e_gte : return ">="; + case e_lt : return "<"; + case e_gt : return ">"; + case e_eq : return "="; + case e_rbracket : return ")"; + case e_lbracket : return "("; + case e_rsqrbracket : return "]"; + case e_lsqrbracket : return "["; + case e_rcrlbracket : return "}"; + case e_lcrlbracket : return "{"; + case e_comma : return ","; + case e_add : return "+"; + case e_sub : return "-"; + case e_div : return "/"; + case e_mul : return "*"; + case e_mod : return "%"; + case e_pow : return "^"; + case e_colon : return ":"; + case e_ternary : return "?"; + case e_swap : return "<=>"; + default : return "UNKNOWN"; + } + } + + inline bool is_error() const + { + return ( + (e_error == type) || + (e_err_symbol == type) || + (e_err_number == type) || + (e_err_string == type) || + (e_err_sfunc == type) + ); + } + + token_type type; + std::string value; + std::size_t position; + }; + + class generator + { + public: + + typedef token token_t; + typedef std::vector token_list_t; + typedef token_list_t::iterator token_list_itr_t; + typedef details::char_t char_t; + + generator() + : base_itr_(0), + s_itr_ (0), + s_end_ (0) + { + clear(); + } + + inline void clear() + { + base_itr_ = 0; + s_itr_ = 0; + s_end_ = 0; + token_list_.clear(); + token_itr_ = token_list_.end(); + store_token_itr_ = token_list_.end(); + } + + inline bool process(const std::string& str) + { + base_itr_ = str.data(); + s_itr_ = str.data(); + s_end_ = str.data() + str.size(); + + eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_); + token_list_.clear(); + + while (!is_end(s_itr_)) + { + scan_token(); + + if (!token_list_.empty() && token_list_.back().is_error()) + return false; + } + + return true; + } + + inline bool empty() const + { + return token_list_.empty(); + } + + inline std::size_t size() const + { + return token_list_.size(); + } + + inline void begin() + { + token_itr_ = token_list_.begin(); + store_token_itr_ = token_list_.begin(); + } + + inline void store() + { + store_token_itr_ = token_itr_; + } + + inline void restore() + { + token_itr_ = store_token_itr_; + } + + inline token_t& next_token() + { + if (token_list_.end() != token_itr_) + { + return *token_itr_++; + } + else + return eof_token_; + } + + inline token_t& peek_next_token() + { + if (token_list_.end() != token_itr_) + { + return *token_itr_; + } + else + return eof_token_; + } + + inline token_t& operator[](const std::size_t& index) + { + if (index < token_list_.size()) + return token_list_[index]; + else + return eof_token_; + } + + inline token_t operator[](const std::size_t& index) const + { + if (index < token_list_.size()) + return token_list_[index]; + else + return eof_token_; + } + + inline bool finished() const + { + return (token_list_.end() == token_itr_); + } + + inline void insert_front(token_t::token_type tk_type) + { + if ( + !token_list_.empty() && + (token_list_.end() != token_itr_) + ) + { + token_t t = *token_itr_; + + t.type = tk_type; + token_itr_ = token_list_.insert(token_itr_,t); + } + } + + inline std::string substr(const std::size_t& begin, const std::size_t& end) + { + const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; + const details::char_cptr end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_; + + return std::string(begin_itr,end_itr); + } + + inline std::string remaining() const + { + if (finished()) + return ""; + else if (token_list_.begin() != token_itr_) + return std::string(base_itr_ + (token_itr_ - 1)->position, s_end_); + else + return std::string(base_itr_ + token_itr_->position, s_end_); + } + + private: + + inline bool is_end(details::char_cptr itr) + { + return (s_end_ == itr); + } + + #ifndef exprtk_disable_comments + inline bool is_comment_start(details::char_cptr itr) + { + const char_t c0 = *(itr + 0); + const char_t c1 = *(itr + 1); + + if ('#' == c0) + return true; + else if (!is_end(itr + 1)) + { + if (('/' == c0) && ('/' == c1)) return true; + if (('/' == c0) && ('*' == c1)) return true; + } + return false; + } + #else + inline bool is_comment_start(details::char_cptr) + { + return false; + } + #endif + + inline void skip_whitespace() + { + while (!is_end(s_itr_) && details::is_whitespace(*s_itr_)) + { + ++s_itr_; + } + } + + inline void skip_comments() + { + #ifndef exprtk_disable_comments + // The following comment styles are supported: + // 1. // .... \n + // 2. # .... \n + // 3. /* .... */ + struct test + { + static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr) + { + mode = 0; + if ('#' == c0) { mode = 1; incr = 1; } + else if ('/' == c0) + { + if ('/' == c1) { mode = 1; incr = 2; } + else if ('*' == c1) { mode = 2; incr = 2; } + } + return (0 != mode); + } + + static inline bool comment_end(const char_t c0, const char_t c1, int& mode) + { + if ( + ((1 == mode) && ('\n' == c0)) || + ((2 == mode) && ( '*' == c0) && ('/' == c1)) + ) + { + mode = 0; + return true; + } + else + return false; + } + }; + + int mode = 0; + int increment = 0; + + if (is_end(s_itr_)) + return; + else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment)) + return; + + details::char_cptr cmt_start = s_itr_; + + s_itr_ += increment; + + while (!is_end(s_itr_)) + { + if ((1 == mode) && test::comment_end(*s_itr_, 0, mode)) + { + ++s_itr_; + return; + } + + if ((2 == mode)) + { + if (!is_end((s_itr_ + 1)) && test::comment_end(*s_itr_, *(s_itr_ + 1), mode)) + { + s_itr_ += 2; + return; + } + } + + ++s_itr_; + } + + if (2 == mode) + { + token_t t; + t.set_error(token::e_error, cmt_start, cmt_start + mode, base_itr_); + token_list_.push_back(t); + } + #endif + } + + inline void scan_token() + { + if (details::is_whitespace(*s_itr_)) + { + skip_whitespace(); + return; + } + else if (is_comment_start(s_itr_)) + { + skip_comments(); + return; + } + else if (details::is_operator_char(*s_itr_)) + { + scan_operator(); + return; + } + else if (details::is_letter(*s_itr_)) + { + scan_symbol(); + return; + } + else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_))) + { + scan_number(); + return; + } + else if ('$' == (*s_itr_)) + { + scan_special_function(); + return; + } + #ifndef exprtk_disable_string_capabilities + else if ('\'' == (*s_itr_)) + { + scan_string(); + return; + } + #endif + else if ('~' == (*s_itr_)) + { + token_t t; + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); + token_list_.push_back(t); + ++s_itr_; + return; + } + else + { + token_t t; + t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_); + token_list_.push_back(t); + ++s_itr_; + } + } + + inline void scan_operator() + { + token_t t; + + const char_t c0 = s_itr_[0]; + + if (!is_end(s_itr_ + 1)) + { + const char_t c1 = s_itr_[1]; + + if (!is_end(s_itr_ + 2)) + { + const char_t c2 = s_itr_[2]; + + if ((c0 == '<') && (c1 == '=') && (c2 == '>')) + { + t.set_operator(token_t::e_swap, s_itr_, s_itr_ + 3, base_itr_); + token_list_.push_back(t); + s_itr_ += 3; + return; + } + } + + token_t::token_type ttype = token_t::e_none; + + if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; + else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; + else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; + else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne; + else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq; + else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign; + else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl; + else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr; + else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass; + else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass; + else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass; + else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass; + else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass; + + if (token_t::e_none != ttype) + { + t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_); + token_list_.push_back(t); + s_itr_ += 2; + return; + } + } + + if ('<' == c0) + t.set_operator(token_t::e_lt , s_itr_, s_itr_ + 1, base_itr_); + else if ('>' == c0) + t.set_operator(token_t::e_gt , s_itr_, s_itr_ + 1, base_itr_); + else if (';' == c0) + t.set_operator(token_t::e_eof, s_itr_, s_itr_ + 1, base_itr_); + else if ('&' == c0) + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); + else if ('|' == c0) + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); + else + t.set_operator(token_t::token_type(c0), s_itr_, s_itr_ + 1, base_itr_); + + token_list_.push_back(t); + ++s_itr_; + } + + inline void scan_symbol() + { + details::char_cptr initial_itr = s_itr_; + + while (!is_end(s_itr_)) + { + if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_))) + { + if ('.' != (*s_itr_)) + break; + /* + Permit symbols that contain a 'dot' + Allowed : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123 + Disallowed: .abc, abc., abc., abc. + */ + if ( + (s_itr_ != initial_itr) && + !is_end(s_itr_ + 1) && + !details::is_letter_or_digit(*(s_itr_ + 1)) && + ('_' != (*(s_itr_ + 1))) + ) + break; + } + + ++s_itr_; + } + + token_t t; + t.set_symbol(initial_itr,s_itr_,base_itr_); + token_list_.push_back(t); + } + + inline void scan_number() + { + /* + Attempt to match a valid numeric value in one of the following formats: + (01) 123456 + (02) 123456. + (03) 123.456 + (04) 123.456e3 + (05) 123.456E3 + (06) 123.456e+3 + (07) 123.456E+3 + (08) 123.456e-3 + (09) 123.456E-3 + (00) .1234 + (11) .1234e3 + (12) .1234E+3 + (13) .1234e+3 + (14) .1234E-3 + (15) .1234e-3 + */ + + details::char_cptr initial_itr = s_itr_; + bool dot_found = false; + bool e_found = false; + bool post_e_sign_found = false; + bool post_e_digit_found = false; + token_t t; + + while (!is_end(s_itr_)) + { + if ('.' == (*s_itr_)) + { + if (dot_found) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + dot_found = true; + ++s_itr_; + + continue; + } + else if ('e' == std::tolower(*s_itr_)) + { + const char_t& c = *(s_itr_ + 1); + + if (is_end(s_itr_ + 1)) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + else if ( + ('+' != c) && + ('-' != c) && + !details::is_digit(c) + ) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + e_found = true; + ++s_itr_; + + continue; + } + else if (e_found && details::is_sign(*s_itr_) && !post_e_digit_found) + { + if (post_e_sign_found) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + post_e_sign_found = true; + ++s_itr_; + + continue; + } + else if (e_found && details::is_digit(*s_itr_)) + { + post_e_digit_found = true; + ++s_itr_; + + continue; + } + else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_)) + break; + else + ++s_itr_; + } + + t.set_numeric(initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + inline void scan_special_function() + { + details::char_cptr initial_itr = s_itr_; + token_t t; + + // $fdd(x,x,x) = at least 11 chars + if (std::distance(s_itr_,s_end_) < 11) + { + t.set_error( + token::e_err_sfunc, + initial_itr, std::min(initial_itr + 11, s_end_), + base_itr_); + token_list_.push_back(t); + + return; + } + + if ( + !(('$' == *s_itr_) && + (details::imatch ('f',*(s_itr_ + 1))) && + (details::is_digit(*(s_itr_ + 2))) && + (details::is_digit(*(s_itr_ + 3)))) + ) + { + t.set_error( + token::e_err_sfunc, + initial_itr, std::min(initial_itr + 4, s_end_), + base_itr_); + token_list_.push_back(t); + + return; + } + + s_itr_ += 4; // $fdd = 4chars + + t.set_symbol(initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + #ifndef exprtk_disable_string_capabilities + inline void scan_string() + { + details::char_cptr initial_itr = s_itr_ + 1; + token_t t; + + if (std::distance(s_itr_,s_end_) < 2) + { + t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_); + token_list_.push_back(t); + + return; + } + + ++s_itr_; + + bool escaped_found = false; + bool escaped = false; + + while (!is_end(s_itr_)) + { + if (!details::is_valid_string_char(*s_itr_)) + { + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + else if (!escaped && ('\\' == *s_itr_)) + { + escaped_found = true; + escaped = true; + ++s_itr_; + + continue; + } + else if (!escaped) + { + if ('\'' == *s_itr_) + break; + } + else if (escaped) + { + if ( + !is_end(s_itr_) && ('0' == *(s_itr_)) && + ((s_itr_ + 4) <= s_end_) + ) + { + const bool x_seperator = ('X' == std::toupper(*(s_itr_ + 1))); + + const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) && + details::is_hex_digit(*(s_itr_ + 3)) ; + + if (!(x_seperator && both_digits)) + { + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + else + s_itr_ += 3; + } + + escaped = false; + } + + ++s_itr_; + } + + if (is_end(s_itr_)) + { + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + if (!escaped_found) + t.set_string(initial_itr, s_itr_, base_itr_); + else + { + std::string parsed_string(initial_itr,s_itr_); + + if (!details::cleanup_escapes(parsed_string)) + { + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + t.set_string( + parsed_string, + static_cast(std::distance(base_itr_,initial_itr))); + } + + token_list_.push_back(t); + ++s_itr_; + + return; + } + #endif + + private: + + token_list_t token_list_; + token_list_itr_t token_itr_; + token_list_itr_t store_token_itr_; + token_t eof_token_; + details::char_cptr base_itr_; + details::char_cptr s_itr_; + details::char_cptr s_end_; + + friend class token_scanner; + friend class token_modifier; + friend class token_inserter; + friend class token_joiner; + }; + + class helper_interface + { + public: + + virtual void init() { } + virtual void reset() { } + virtual bool result() { return true; } + virtual std::size_t process(generator&) { return 0; } + virtual ~helper_interface() { } + }; + + class token_scanner : public helper_interface + { + public: + + virtual ~token_scanner() + {} + + explicit token_scanner(const std::size_t& stride) + : stride_(stride) + { + if (stride > 4) + { + throw std::invalid_argument("token_scanner() - Invalid stride value"); + } + } + + inline std::size_t process(generator& g) exprtk_override + { + if (g.token_list_.size() >= stride_) + { + for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) + { + token t; + + switch (stride_) + { + case 1 : + { + const token& t0 = g.token_list_[i]; + + if (!operator()(t0)) + { + return i; + } + } + break; + + case 2 : + { + const token& t0 = g.token_list_[i ]; + const token& t1 = g.token_list_[i + 1]; + + if (!operator()(t0, t1)) + { + return i; + } + } + break; + + case 3 : + { + const token& t0 = g.token_list_[i ]; + const token& t1 = g.token_list_[i + 1]; + const token& t2 = g.token_list_[i + 2]; + + if (!operator()(t0, t1, t2)) + { + return i; + } + } + break; + + case 4 : + { + const token& t0 = g.token_list_[i ]; + const token& t1 = g.token_list_[i + 1]; + const token& t2 = g.token_list_[i + 2]; + const token& t3 = g.token_list_[i + 3]; + + if (!operator()(t0, t1, t2, t3)) + { + return i; + } + } + break; + } + } + } + + return (g.token_list_.size() - stride_ + 1); + } + + virtual bool operator() (const token&) + { + return false; + } + + virtual bool operator() (const token&, const token&) + { + return false; + } + + virtual bool operator() (const token&, const token&, const token&) + { + return false; + } + + virtual bool operator() (const token&, const token&, const token&, const token&) + { + return false; + } + + private: + + const std::size_t stride_; + }; + + class token_modifier : public helper_interface + { + public: + + inline std::size_t process(generator& g) exprtk_override + { + std::size_t changes = 0; + + for (std::size_t i = 0; i < g.token_list_.size(); ++i) + { + if (modify(g.token_list_[i])) changes++; + } + + return changes; + } + + virtual bool modify(token& t) = 0; + }; + + class token_inserter : public helper_interface + { + public: + + explicit token_inserter(const std::size_t& stride) + : stride_(stride) + { + if (stride > 5) + { + throw std::invalid_argument("token_inserter() - Invalid stride value"); + } + } + + inline std::size_t process(generator& g) exprtk_override + { + if (g.token_list_.empty()) + return 0; + else if (g.token_list_.size() < stride_) + return 0; + + std::size_t changes = 0; + + typedef std::pair insert_t; + std::vector insert_list; + insert_list.reserve(10000); + + for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) + { + int insert_index = -1; + token t; + + switch (stride_) + { + case 1 : insert_index = insert(g.token_list_[i],t); + break; + + case 2 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], t); + break; + + case 3 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], t); + break; + + case 4 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], t); + break; + + case 5 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], g.token_list_[i + 4], t); + break; + } + + if ((insert_index >= 0) && (insert_index <= (static_cast(stride_) + 1))) + { + insert_list.push_back(insert_t(i, t)); + changes++; + } + } + + if (!insert_list.empty()) + { + generator::token_list_t token_list; + + std::size_t insert_index = 0; + + for (std::size_t i = 0; i < g.token_list_.size(); ++i) + { + token_list.push_back(g.token_list_[i]); + + if ( + (insert_index < insert_list.size()) && + (insert_list[insert_index].first == i) + ) + { + token_list.push_back(insert_list[insert_index].second); + insert_index++; + } + } + + std::swap(g.token_list_,token_list); + } + + return changes; + } + + #define token_inserter_empty_body \ + { \ + return -1; \ + } \ + + inline virtual int insert(const token&, token&) + token_inserter_empty_body + + inline virtual int insert(const token&, const token&, token&) + token_inserter_empty_body + + inline virtual int insert(const token&, const token&, const token&, token&) + token_inserter_empty_body + + inline virtual int insert(const token&, const token&, const token&, const token&, token&) + token_inserter_empty_body + + inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) + token_inserter_empty_body + + #undef token_inserter_empty_body + + private: + + const std::size_t stride_; + }; + + class token_joiner : public helper_interface + { + public: + + explicit token_joiner(const std::size_t& stride) + : stride_(stride) + {} + + inline std::size_t process(generator& g) exprtk_override + { + if (g.token_list_.empty()) + return 0; + + switch (stride_) + { + case 2 : return process_stride_2(g); + case 3 : return process_stride_3(g); + default : return 0; + } + } + + virtual bool join(const token&, const token&, token&) { return false; } + virtual bool join(const token&, const token&, const token&, token&) { return false; } + + private: + + inline std::size_t process_stride_2(generator& g) + { + if (g.token_list_.size() < 2) + return 0; + + std::size_t changes = 0; + + generator::token_list_t token_list; + token_list.reserve(10000); + + for (int i = 0; i < static_cast(g.token_list_.size() - 1); ++i) + { + token t; + + for ( ; ; ) + { + if (!join(g[i], g[i + 1], t)) + { + token_list.push_back(g[i]); + break; + } + + token_list.push_back(t); + + ++changes; + + i+=2; + + if (static_cast(i) >= g.token_list_.size() - 1) + break; + } + } + + token_list.push_back(g.token_list_.back()); + + assert(token_list.size() <= g.token_list_.size()); + + std::swap(token_list, g.token_list_); + + return changes; + } + + inline std::size_t process_stride_3(generator& g) + { + if (g.token_list_.size() < 3) + return 0; + + std::size_t changes = 0; + + generator::token_list_t token_list; + token_list.reserve(10000); + + for (int i = 0; i < static_cast(g.token_list_.size() - 2); ++i) + { + token t; + + for ( ; ; ) + { + if (!join(g[i], g[i + 1], g[i + 2], t)) + { + token_list.push_back(g[i]); + break; + } + + token_list.push_back(t); + + ++changes; + + i+=3; + + if (static_cast(i) >= g.token_list_.size() - 2) + break; + } + } + + token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 2)); + token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 1)); + + assert(token_list.size() <= g.token_list_.size()); + + std::swap(token_list, g.token_list_); + + return changes; + } + + const std::size_t stride_; + }; + + namespace helper + { + + inline void dump(const lexer::generator& generator) + { + for (std::size_t i = 0; i < generator.size(); ++i) + { + const lexer::token& t = generator[i]; + printf("Token[%02d] @ %03d %6s --> '%s'\n", + static_cast(i), + static_cast(t.position), + t.to_str(t.type).c_str(), + t.value.c_str()); + } + } + + class commutative_inserter : public lexer::token_inserter + { + public: + + using lexer::token_inserter::insert; + + commutative_inserter() + : lexer::token_inserter(2) + {} + + inline void ignore_symbol(const std::string& symbol) + { + ignore_set_.insert(symbol); + } + + inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) + { + bool match = false; + new_token.type = lexer::token::e_mul; + new_token.value = "*"; + new_token.position = t1.position; + + if (t0.type == lexer::token::e_symbol) + { + if (ignore_set_.end() != ignore_set_.find(t0.value)) + { + return -1; + } + else if (!t0.value.empty() && ('$' == t0.value[0])) + { + return -1; + } + } + + if (t1.type == lexer::token::e_symbol) + { + if (ignore_set_.end() != ignore_set_.find(t1.value)) + { + return -1; + } + } + if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true; + else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true; + else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true; + else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_number )) match = true; + else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_number )) match = true; + else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number )) match = true; + else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number )) match = true; + else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_symbol )) match = true; + + return (match) ? 1 : -1; + } + + private: + + std::set ignore_set_; + }; + + class operator_joiner : public token_joiner + { + public: + + explicit operator_joiner(const std::size_t& stride) + : token_joiner(stride) + {} + + inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) + { + // ': =' --> ':=' + if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_assign; + t.value = ":="; + t.position = t0.position; + + return true; + } + // '+ =' --> '+=' + else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_addass; + t.value = "+="; + t.position = t0.position; + + return true; + } + // '- =' --> '-=' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_subass; + t.value = "-="; + t.position = t0.position; + + return true; + } + // '* =' --> '*=' + else if ((t0.type == lexer::token::e_mul) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_mulass; + t.value = "*="; + t.position = t0.position; + + return true; + } + // '/ =' --> '/=' + else if ((t0.type == lexer::token::e_div) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_divass; + t.value = "/="; + t.position = t0.position; + + return true; + } + // '% =' --> '%=' + else if ((t0.type == lexer::token::e_mod) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_modass; + t.value = "%="; + t.position = t0.position; + + return true; + } + // '> =' --> '>=' + else if ((t0.type == lexer::token::e_gt) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_gte; + t.value = ">="; + t.position = t0.position; + + return true; + } + // '< =' --> '<=' + else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_lte; + t.value = "<="; + t.position = t0.position; + + return true; + } + // '= =' --> '==' + else if ((t0.type == lexer::token::e_eq) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_eq; + t.value = "=="; + t.position = t0.position; + + return true; + } + // '! =' --> '!=' + else if ((static_cast(t0.type) == '!') && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_ne; + t.value = "!="; + t.position = t0.position; + + return true; + } + // '< >' --> '<>' + else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_gt)) + { + t.type = lexer::token::e_ne; + t.value = "<>"; + t.position = t0.position; + + return true; + } + // '<= >' --> '<=>' + else if ((t0.type == lexer::token::e_lte) && (t1.type == lexer::token::e_gt)) + { + t.type = lexer::token::e_swap; + t.value = "<=>"; + t.position = t0.position; + + return true; + } + // '+ -' --> '-' + else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_sub)) + { + t.type = lexer::token::e_sub; + t.value = "-"; + t.position = t0.position; + + return true; + } + // '- +' --> '-' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_add)) + { + t.type = lexer::token::e_sub; + t.value = "-"; + t.position = t0.position; + + return true; + } + // '- -' --> '+' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub)) + { + /* + Note: May need to reconsider this when wanting to implement + pre/postfix decrement operator + */ + t.type = lexer::token::e_add; + t.value = "+"; + t.position = t0.position; + + return true; + } + else + return false; + } + + inline bool join(const lexer::token& t0, const lexer::token& t1, const lexer::token& t2, lexer::token& t) + { + // '[ * ]' --> '[*]' + if ( + (t0.type == lexer::token::e_lsqrbracket) && + (t1.type == lexer::token::e_mul ) && + (t2.type == lexer::token::e_rsqrbracket) + ) + { + t.type = lexer::token::e_symbol; + t.value = "[*]"; + t.position = t0.position; + + return true; + } + else + return false; + } + }; + + class bracket_checker : public lexer::token_scanner + { + public: + + using lexer::token_scanner::operator(); + + bracket_checker() + : token_scanner(1), + state_(true) + {} + + bool result() + { + if (!stack_.empty()) + { + lexer::token t; + t.value = stack_.top().first; + t.position = stack_.top().second; + error_token_ = t; + state_ = false; + + return false; + } + else + return state_; + } + + lexer::token error_token() + { + return error_token_; + } + + void reset() + { + // Why? because msvc doesn't support swap properly. + stack_ = std::stack >(); + state_ = true; + error_token_.clear(); + } + + bool operator() (const lexer::token& t) + { + if ( + !t.value.empty() && + (lexer::token::e_string != t.type) && + (lexer::token::e_symbol != t.type) && + exprtk::details::is_bracket(t.value[0]) + ) + { + details::char_t c = t.value[0]; + + if (t.type == lexer::token::e_lbracket ) stack_.push(std::make_pair(')',t.position)); + else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); + else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); + else if (exprtk::details::is_right_bracket(c)) + { + if (stack_.empty()) + { + state_ = false; + error_token_ = t; + + return false; + } + else if (c != stack_.top().first) + { + state_ = false; + error_token_ = t; + + return false; + } + else + stack_.pop(); + } + } + + return true; + } + + private: + + bool state_; + std::stack > stack_; + lexer::token error_token_; + }; + + class numeric_checker : public lexer::token_scanner + { + public: + + using lexer::token_scanner::operator(); + + numeric_checker() + : token_scanner (1), + current_index_(0) + {} + + bool result() + { + return error_list_.empty(); + } + + void reset() + { + error_list_.clear(); + current_index_ = 0; + } + + bool operator() (const lexer::token& t) + { + if (token::e_number == t.type) + { + double v; + + if (!exprtk::details::string_to_real(t.value,v)) + { + error_list_.push_back(current_index_); + } + } + + ++current_index_; + + return true; + } + + std::size_t error_count() const + { + return error_list_.size(); + } + + std::size_t error_index(const std::size_t& i) + { + if (i < error_list_.size()) + return error_list_[i]; + else + return std::numeric_limits::max(); + } + + void clear_errors() + { + error_list_.clear(); + } + + private: + + std::size_t current_index_; + std::vector error_list_; + }; + + class symbol_replacer : public lexer::token_modifier + { + private: + + typedef std::map,details::ilesscompare> replace_map_t; + + public: + + bool remove(const std::string& target_symbol) + { + const replace_map_t::iterator itr = replace_map_.find(target_symbol); + + if (replace_map_.end() == itr) + return false; + + replace_map_.erase(itr); + + return true; + } + + bool add_replace(const std::string& target_symbol, + const std::string& replace_symbol, + const lexer::token::token_type token_type = lexer::token::e_symbol) + { + const replace_map_t::iterator itr = replace_map_.find(target_symbol); + + if (replace_map_.end() != itr) + { + return false; + } + + replace_map_[target_symbol] = std::make_pair(replace_symbol,token_type); + + return true; + } + + void clear() + { + replace_map_.clear(); + } + + private: + + bool modify(lexer::token& t) + { + if (lexer::token::e_symbol == t.type) + { + if (replace_map_.empty()) + return false; + + const replace_map_t::iterator itr = replace_map_.find(t.value); + + if (replace_map_.end() != itr) + { + t.value = itr->second.first; + t.type = itr->second.second; + + return true; + } + } + + return false; + } + + replace_map_t replace_map_; + }; + + class sequence_validator : public lexer::token_scanner + { + private: + + typedef std::pair token_pair_t; + typedef std::set set_t; + + public: + + using lexer::token_scanner::operator(); + + sequence_validator() + : lexer::token_scanner(2) + { + add_invalid(lexer::token::e_number, lexer::token::e_number); + add_invalid(lexer::token::e_string, lexer::token::e_string); + add_invalid(lexer::token::e_number, lexer::token::e_string); + add_invalid(lexer::token::e_string, lexer::token::e_number); + + add_invalid_set1(lexer::token::e_assign ); + add_invalid_set1(lexer::token::e_shr ); + add_invalid_set1(lexer::token::e_shl ); + add_invalid_set1(lexer::token::e_lte ); + add_invalid_set1(lexer::token::e_ne ); + add_invalid_set1(lexer::token::e_gte ); + add_invalid_set1(lexer::token::e_lt ); + add_invalid_set1(lexer::token::e_gt ); + add_invalid_set1(lexer::token::e_eq ); + add_invalid_set1(lexer::token::e_comma ); + add_invalid_set1(lexer::token::e_add ); + add_invalid_set1(lexer::token::e_sub ); + add_invalid_set1(lexer::token::e_div ); + add_invalid_set1(lexer::token::e_mul ); + add_invalid_set1(lexer::token::e_mod ); + add_invalid_set1(lexer::token::e_pow ); + add_invalid_set1(lexer::token::e_colon ); + add_invalid_set1(lexer::token::e_ternary); + } + + bool result() + { + return error_list_.empty(); + } + + bool operator() (const lexer::token& t0, const lexer::token& t1) + { + const set_t::value_type p = std::make_pair(t0.type,t1.type); + + if (invalid_bracket_check(t0.type,t1.type)) + { + error_list_.push_back(std::make_pair(t0,t1)); + } + else if (invalid_comb_.find(p) != invalid_comb_.end()) + { + error_list_.push_back(std::make_pair(t0,t1)); + } + + return true; + } + + std::size_t error_count() const + { + return error_list_.size(); + } + + std::pair error(const std::size_t index) + { + if (index < error_list_.size()) + { + return error_list_[index]; + } + else + { + static const lexer::token error_token; + return std::make_pair(error_token,error_token); + } + } + + void clear_errors() + { + error_list_.clear(); + } + + private: + + void add_invalid(lexer::token::token_type base, lexer::token::token_type t) + { + invalid_comb_.insert(std::make_pair(base,t)); + } + + void add_invalid_set1(lexer::token::token_type t) + { + add_invalid(t, lexer::token::e_assign); + add_invalid(t, lexer::token::e_shr ); + add_invalid(t, lexer::token::e_shl ); + add_invalid(t, lexer::token::e_lte ); + add_invalid(t, lexer::token::e_ne ); + add_invalid(t, lexer::token::e_gte ); + add_invalid(t, lexer::token::e_lt ); + add_invalid(t, lexer::token::e_gt ); + add_invalid(t, lexer::token::e_eq ); + add_invalid(t, lexer::token::e_comma ); + add_invalid(t, lexer::token::e_div ); + add_invalid(t, lexer::token::e_mul ); + add_invalid(t, lexer::token::e_mod ); + add_invalid(t, lexer::token::e_pow ); + add_invalid(t, lexer::token::e_colon ); + } + + bool invalid_bracket_check(lexer::token::token_type base, lexer::token::token_type t) + { + if (details::is_right_bracket(static_cast(base))) + { + switch (t) + { + case lexer::token::e_assign : return (']' != base); + case lexer::token::e_string : return (')' != base); + default : return false; + } + } + else if (details::is_left_bracket(static_cast(base))) + { + if (details::is_right_bracket(static_cast(t))) + return false; + else if (details::is_left_bracket(static_cast(t))) + return false; + else + { + switch (t) + { + case lexer::token::e_number : return false; + case lexer::token::e_symbol : return false; + case lexer::token::e_string : return false; + case lexer::token::e_add : return false; + case lexer::token::e_sub : return false; + case lexer::token::e_colon : return false; + case lexer::token::e_ternary : return false; + default : return true ; + } + } + } + else if (details::is_right_bracket(static_cast(t))) + { + switch (base) + { + case lexer::token::e_number : return false; + case lexer::token::e_symbol : return false; + case lexer::token::e_string : return false; + case lexer::token::e_eof : return false; + case lexer::token::e_colon : return false; + case lexer::token::e_ternary : return false; + default : return true ; + } + } + else if (details::is_left_bracket(static_cast(t))) + { + switch (base) + { + case lexer::token::e_rbracket : return true; + case lexer::token::e_rsqrbracket : return true; + case lexer::token::e_rcrlbracket : return true; + default : return false; + } + } + + return false; + } + + set_t invalid_comb_; + std::vector > error_list_; + }; + + class sequence_validator_3tokens : public lexer::token_scanner + { + private: + + typedef lexer::token::token_type token_t; + typedef std::pair > token_triplet_t; + typedef std::set set_t; + + public: + + using lexer::token_scanner::operator(); + + sequence_validator_3tokens() + : lexer::token_scanner(3) + { + add_invalid(lexer::token::e_number , lexer::token::e_number , lexer::token::e_number); + add_invalid(lexer::token::e_string , lexer::token::e_string , lexer::token::e_string); + add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma ); + + add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow ); + + add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); + } + + bool result() + { + return error_list_.empty(); + } + + bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) + { + const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type)); + + if (invalid_comb_.find(p) != invalid_comb_.end()) + { + error_list_.push_back(std::make_pair(t0,t1)); + } + + return true; + } + + std::size_t error_count() const + { + return error_list_.size(); + } + + std::pair error(const std::size_t index) + { + if (index < error_list_.size()) + { + return error_list_[index]; + } + else + { + static const lexer::token error_token; + return std::make_pair(error_token,error_token); + } + } + + void clear_errors() + { + error_list_.clear(); + } + + private: + + void add_invalid(token_t t0, token_t t1, token_t t2) + { + invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2))); + } + + set_t invalid_comb_; + std::vector > error_list_; + }; + + struct helper_assembly + { + inline bool register_scanner(lexer::token_scanner* scanner) + { + if (token_scanner_list.end() != std::find(token_scanner_list.begin(), + token_scanner_list.end (), + scanner)) + { + return false; + } + + token_scanner_list.push_back(scanner); + + return true; + } + + inline bool register_modifier(lexer::token_modifier* modifier) + { + if (token_modifier_list.end() != std::find(token_modifier_list.begin(), + token_modifier_list.end (), + modifier)) + { + return false; + } + + token_modifier_list.push_back(modifier); + + return true; + } + + inline bool register_joiner(lexer::token_joiner* joiner) + { + if (token_joiner_list.end() != std::find(token_joiner_list.begin(), + token_joiner_list.end (), + joiner)) + { + return false; + } + + token_joiner_list.push_back(joiner); + + return true; + } + + inline bool register_inserter(lexer::token_inserter* inserter) + { + if (token_inserter_list.end() != std::find(token_inserter_list.begin(), + token_inserter_list.end (), + inserter)) + { + return false; + } + + token_inserter_list.push_back(inserter); + + return true; + } + + inline bool run_modifiers(lexer::generator& g) + { + error_token_modifier = reinterpret_cast(0); + + for (std::size_t i = 0; i < token_modifier_list.size(); ++i) + { + lexer::token_modifier& modifier = (*token_modifier_list[i]); + + modifier.reset(); + modifier.process(g); + + if (!modifier.result()) + { + error_token_modifier = token_modifier_list[i]; + + return false; + } + } + + return true; + } + + inline bool run_joiners(lexer::generator& g) + { + error_token_joiner = reinterpret_cast(0); + + for (std::size_t i = 0; i < token_joiner_list.size(); ++i) + { + lexer::token_joiner& joiner = (*token_joiner_list[i]); + + joiner.reset(); + joiner.process(g); + + if (!joiner.result()) + { + error_token_joiner = token_joiner_list[i]; + + return false; + } + } + + return true; + } + + inline bool run_inserters(lexer::generator& g) + { + error_token_inserter = reinterpret_cast(0); + + for (std::size_t i = 0; i < token_inserter_list.size(); ++i) + { + lexer::token_inserter& inserter = (*token_inserter_list[i]); + + inserter.reset(); + inserter.process(g); + + if (!inserter.result()) + { + error_token_inserter = token_inserter_list[i]; + + return false; + } + } + + return true; + } + + inline bool run_scanners(lexer::generator& g) + { + error_token_scanner = reinterpret_cast(0); + + for (std::size_t i = 0; i < token_scanner_list.size(); ++i) + { + lexer::token_scanner& scanner = (*token_scanner_list[i]); + + scanner.reset(); + scanner.process(g); + + if (!scanner.result()) + { + error_token_scanner = token_scanner_list[i]; + + return false; + } + } + + return true; + } + + std::vector token_scanner_list; + std::vector token_modifier_list; + std::vector token_joiner_list; + std::vector token_inserter_list; + + lexer::token_scanner* error_token_scanner; + lexer::token_modifier* error_token_modifier; + lexer::token_joiner* error_token_joiner; + lexer::token_inserter* error_token_inserter; + }; + } + + class parser_helper + { + public: + + typedef token token_t; + typedef generator generator_t; + + inline bool init(const std::string& str) + { + if (!lexer_.process(str)) + { + return false; + } + + lexer_.begin(); + + next_token(); + + return true; + } + + inline generator_t& lexer() + { + return lexer_; + } + + inline const generator_t& lexer() const + { + return lexer_; + } + + inline void store_token() + { + lexer_.store(); + store_current_token_ = current_token_; + } + + inline void restore_token() + { + lexer_.restore(); + current_token_ = store_current_token_; + } + + inline void next_token() + { + current_token_ = lexer_.next_token(); + } + + inline const token_t& current_token() const + { + return current_token_; + } + + enum token_advance_mode + { + e_hold = 0, + e_advance = 1 + }; + + inline void advance_token(const token_advance_mode mode) + { + if (e_advance == mode) + { + next_token(); + } + } + + inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance) + { + if (current_token().type != ttype) + { + return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is(const token_t::token_type& ttype, + const std::string& value, + const token_advance_mode mode = e_advance) + { + if ( + (current_token().type != ttype) || + !exprtk::details::imatch(value,current_token().value) + ) + { + return false; + } + + advance_token(mode); + + return true; + } + + inline bool peek_token_is(const token_t::token_type& ttype) + { + return (lexer_.peek_next_token().type == ttype); + } + + inline bool peek_token_is(const std::string& s) + { + return (exprtk::details::imatch(lexer_.peek_next_token().value,s)); + } + + private: + + generator_t lexer_; + token_t current_token_; + token_t store_current_token_; + }; + } + + template + class vector_view + { + public: + + typedef T* data_ptr_t; + + vector_view(data_ptr_t data, const std::size_t& size) + : size_(size), + data_(data), + data_ref_(0) + {} + + vector_view(const vector_view& vv) + : size_(vv.size_), + data_(vv.data_), + data_ref_(0) + {} + + inline void rebase(data_ptr_t data) + { + data_ = data; + + if (!data_ref_.empty()) + { + for (std::size_t i = 0; i < data_ref_.size(); ++i) + { + (*data_ref_[i]) = data; + } + } + } + + inline data_ptr_t data() const + { + return data_; + } + + inline std::size_t size() const + { + return size_; + } + + inline const T& operator[](const std::size_t index) const + { + return data_[index]; + } + + inline T& operator[](const std::size_t index) + { + return data_[index]; + } + + void set_ref(data_ptr_t* data_ref) + { + data_ref_.push_back(data_ref); + } + + private: + + const std::size_t size_; + data_ptr_t data_; + std::vector data_ref_; + }; + + template + inline vector_view make_vector_view(T* data, + const std::size_t size, const std::size_t offset = 0) + { + return vector_view(data + offset, size); + } + + template + inline vector_view make_vector_view(std::vector& v, + const std::size_t size, const std::size_t offset = 0) + { + return vector_view(v.data() + offset, size); + } + + template class results_context; + + template + struct type_store + { + enum store_type + { + e_unknown, + e_scalar , + e_vector , + e_string + }; + + type_store() + : data(0), + size(0), + type(e_unknown) + {} + + union + { + void* data; + T* vec_data; + }; + + std::size_t size; + store_type type; + + class parameter_list + { + public: + + explicit parameter_list(std::vector& pl) + : parameter_list_(pl) + {} + + inline bool empty() const + { + return parameter_list_.empty(); + } + + inline std::size_t size() const + { + return parameter_list_.size(); + } + + inline type_store& operator[](const std::size_t& index) + { + return parameter_list_[index]; + } + + inline const type_store& operator[](const std::size_t& index) const + { + return parameter_list_[index]; + } + + inline type_store& front() + { + return parameter_list_[0]; + } + + inline const type_store& front() const + { + return parameter_list_[0]; + } + + inline type_store& back() + { + return parameter_list_.back(); + } + + inline const type_store& back() const + { + return parameter_list_.back(); + } + + private: + + std::vector& parameter_list_; + + friend class results_context; + }; + + template + struct type_view + { + typedef type_store type_store_t; + typedef ViewType value_t; + + explicit type_view(type_store_t& ts) + : ts_(ts), + data_(reinterpret_cast(ts_.data)) + {} + + explicit type_view(const type_store_t& ts) + : ts_(const_cast(ts)), + data_(reinterpret_cast(ts_.data)) + {} + + inline std::size_t size() const + { + return ts_.size; + } + + inline value_t& operator[](const std::size_t& i) + { + return data_[i]; + } + + inline const value_t& operator[](const std::size_t& i) const + { + return data_[i]; + } + + inline const value_t* begin() const { return data_; } + inline value_t* begin() { return data_; } + + inline const value_t* end() const + { + return static_cast(data_ + ts_.size); + } + + inline value_t* end() + { + return static_cast(data_ + ts_.size); + } + + type_store_t& ts_; + value_t* data_; + }; + + typedef type_view vector_view; + typedef type_view string_view; + + struct scalar_view + { + typedef type_store type_store_t; + typedef T value_t; + + explicit scalar_view(type_store_t& ts) + : v_(*reinterpret_cast(ts.data)) + {} + + explicit scalar_view(const type_store_t& ts) + : v_(*reinterpret_cast(const_cast(ts).data)) + {} + + inline value_t& operator() () + { + return v_; + } + + inline const value_t& operator() () const + { + return v_; + } + + template + inline bool to_int(IntType& i) const + { + if (!exprtk::details::numeric::is_integer(v_)) + return false; + + i = static_cast(v_); + + return true; + } + + template + inline bool to_uint(UIntType& u) const + { + if (v_ < T(0)) + return false; + else if (!exprtk::details::numeric::is_integer(v_)) + return false; + + u = static_cast(v_); + + return true; + } + + T& v_; + }; + }; + + template + inline std::string to_str(const StringView& view) + { + return std::string(view.begin(),view.size()); + } + + #ifndef exprtk_disable_return_statement + namespace details + { + template class return_node; + template class return_envelope_node; + } + #endif + + template + class results_context + { + public: + + typedef type_store type_store_t; + + results_context() + : results_available_(false) + {} + + inline std::size_t count() const + { + if (results_available_) + return parameter_list_.size(); + else + return 0; + } + + inline type_store_t& operator[](const std::size_t& index) + { + return parameter_list_[index]; + } + + inline const type_store_t& operator[](const std::size_t& index) const + { + return parameter_list_[index]; + } + + private: + + inline void clear() + { + results_available_ = false; + } + + typedef std::vector ts_list_t; + typedef typename type_store_t::parameter_list parameter_list_t; + + inline void assign(const parameter_list_t& pl) + { + parameter_list_ = pl.parameter_list_; + results_available_ = true; + } + + bool results_available_; + ts_list_t parameter_list_; + + #ifndef exprtk_disable_return_statement + friend class details::return_node; + friend class details::return_envelope_node; + #endif + }; + + namespace details + { + enum operator_type + { + e_default , e_null , e_add , e_sub , + e_mul , e_div , e_mod , e_pow , + e_atan2 , e_min , e_max , e_avg , + e_sum , e_prod , e_lt , e_lte , + e_eq , e_equal , e_ne , e_nequal , + e_gte , e_gt , e_and , e_nand , + e_or , e_nor , e_xor , e_xnor , + e_mand , e_mor , e_scand , e_scor , + e_shr , e_shl , e_abs , e_acos , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_logn , + e_neg , e_pos , e_round , e_roundn , + e_root , e_sqrt , e_sin , e_sinc , + e_sinh , e_sec , e_csc , e_tan , + e_tanh , e_cot , e_clamp , e_iclamp , + e_inrange , e_sgn , e_r2d , e_d2r , + e_d2g , e_g2d , e_hypot , e_notl , + e_erf , e_erfc , e_ncdf , e_frac , + e_trunc , e_assign , e_addass , e_subass , + e_mulass , e_divass , e_modass , e_in , + e_like , e_ilike , e_multi , e_smulti , + e_swap , + + // Do not add new functions/operators after this point. + e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, + e_sf04 = 1004, e_sf05 = 1005, e_sf06 = 1006, e_sf07 = 1007, + e_sf08 = 1008, e_sf09 = 1009, e_sf10 = 1010, e_sf11 = 1011, + e_sf12 = 1012, e_sf13 = 1013, e_sf14 = 1014, e_sf15 = 1015, + e_sf16 = 1016, e_sf17 = 1017, e_sf18 = 1018, e_sf19 = 1019, + e_sf20 = 1020, e_sf21 = 1021, e_sf22 = 1022, e_sf23 = 1023, + e_sf24 = 1024, e_sf25 = 1025, e_sf26 = 1026, e_sf27 = 1027, + e_sf28 = 1028, e_sf29 = 1029, e_sf30 = 1030, e_sf31 = 1031, + e_sf32 = 1032, e_sf33 = 1033, e_sf34 = 1034, e_sf35 = 1035, + e_sf36 = 1036, e_sf37 = 1037, e_sf38 = 1038, e_sf39 = 1039, + e_sf40 = 1040, e_sf41 = 1041, e_sf42 = 1042, e_sf43 = 1043, + e_sf44 = 1044, e_sf45 = 1045, e_sf46 = 1046, e_sf47 = 1047, + e_sf48 = 1048, e_sf49 = 1049, e_sf50 = 1050, e_sf51 = 1051, + e_sf52 = 1052, e_sf53 = 1053, e_sf54 = 1054, e_sf55 = 1055, + e_sf56 = 1056, e_sf57 = 1057, e_sf58 = 1058, e_sf59 = 1059, + e_sf60 = 1060, e_sf61 = 1061, e_sf62 = 1062, e_sf63 = 1063, + e_sf64 = 1064, e_sf65 = 1065, e_sf66 = 1066, e_sf67 = 1067, + e_sf68 = 1068, e_sf69 = 1069, e_sf70 = 1070, e_sf71 = 1071, + e_sf72 = 1072, e_sf73 = 1073, e_sf74 = 1074, e_sf75 = 1075, + e_sf76 = 1076, e_sf77 = 1077, e_sf78 = 1078, e_sf79 = 1079, + e_sf80 = 1080, e_sf81 = 1081, e_sf82 = 1082, e_sf83 = 1083, + e_sf84 = 1084, e_sf85 = 1085, e_sf86 = 1086, e_sf87 = 1087, + e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091, + e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095, + e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099, + e_sffinal = 1100, + e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003, + e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007, + e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011, + e_sf4ext12 = 2012, e_sf4ext13 = 2013, e_sf4ext14 = 2014, e_sf4ext15 = 2015, + e_sf4ext16 = 2016, e_sf4ext17 = 2017, e_sf4ext18 = 2018, e_sf4ext19 = 2019, + e_sf4ext20 = 2020, e_sf4ext21 = 2021, e_sf4ext22 = 2022, e_sf4ext23 = 2023, + e_sf4ext24 = 2024, e_sf4ext25 = 2025, e_sf4ext26 = 2026, e_sf4ext27 = 2027, + e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031, + e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035, + e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, + e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043, + e_sf4ext44 = 2044, e_sf4ext45 = 2045, e_sf4ext46 = 2046, e_sf4ext47 = 2047, + e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051, + e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055, + e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059, + e_sf4ext60 = 2060, e_sf4ext61 = 2061 + }; + + inline std::string to_str(const operator_type opr) + { + switch (opr) + { + case e_add : return "+" ; + case e_sub : return "-" ; + case e_mul : return "*" ; + case e_div : return "/" ; + case e_mod : return "%" ; + case e_pow : return "^" ; + case e_assign : return ":=" ; + case e_addass : return "+=" ; + case e_subass : return "-=" ; + case e_mulass : return "*=" ; + case e_divass : return "/=" ; + case e_modass : return "%=" ; + case e_lt : return "<" ; + case e_lte : return "<=" ; + case e_eq : return "==" ; + case e_equal : return "=" ; + case e_ne : return "!=" ; + case e_nequal : return "<>" ; + case e_gte : return ">=" ; + case e_gt : return ">" ; + case e_and : return "and" ; + case e_or : return "or" ; + case e_xor : return "xor" ; + case e_nand : return "nand"; + case e_nor : return "nor" ; + case e_xnor : return "xnor"; + default : return "N/A" ; + } + } + + struct base_operation_t + { + base_operation_t(const operator_type t, const unsigned int& np) + : type(t), + num_params(np) + {} + + operator_type type; + unsigned int num_params; + }; + + namespace loop_unroll + { + #ifndef exprtk_disable_superscalar_unroll + const unsigned int global_loop_batch_size = 16; + #else + const unsigned int global_loop_batch_size = 4; + #endif + + struct details + { + explicit details(const std::size_t& vsize, + const unsigned int loop_batch_size = global_loop_batch_size) + : batch_size(loop_batch_size ), + remainder (vsize % batch_size), + upper_bound(static_cast(vsize - (remainder ? loop_batch_size : 0))) + {} + + unsigned int batch_size; + int remainder; + int upper_bound; + }; + } + + #ifdef exprtk_enable_debugging + inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) + { + if (size) + exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); + else + exprtk_debug(("%s - addr: %p size: %d\n", + s.c_str(), + ptr, + static_cast(size))); + } + #else + inline void dump_ptr(const std::string&, const void*) {} + inline void dump_ptr(const std::string&, const void*, const std::size_t) {} + #endif + + template + class vec_data_store + { + public: + + typedef vec_data_store type; + typedef T* data_t; + + private: + + struct control_block + { + control_block() + : ref_count(1), + size (0), + data (0), + destruct (true) + {} + + explicit control_block(const std::size_t& dsize) + : ref_count(1 ), + size (dsize), + data (0 ), + destruct (true ) + { create_data(); } + + control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) + : ref_count(1 ), + size (dsize ), + data (dptr ), + destruct (dstrct) + {} + + ~control_block() + { + if (data && destruct && (0 == ref_count)) + { + dump_ptr("~control_block() data",data); + delete[] data; + data = reinterpret_cast(0); + } + } + + static inline control_block* create(const std::size_t& dsize, data_t data_ptr = data_t(0), bool dstrct = false) + { + if (dsize) + { + if (0 == data_ptr) + return (new control_block(dsize)); + else + return (new control_block(dsize, data_ptr, dstrct)); + } + else + return (new control_block); + } + + static inline void destroy(control_block*& cntrl_blck) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + delete cntrl_blck; + } + + cntrl_blck = 0; + } + } + + std::size_t ref_count; + std::size_t size; + data_t data; + bool destruct; + + private: + + control_block(const control_block&); + control_block& operator=(const control_block&); + + inline void create_data() + { + destruct = true; + data = new T[size]; + std::fill_n(data, size, T(0)); + dump_ptr("control_block::create_data() - data",data,size); + } + }; + + public: + + vec_data_store() + : control_block_(control_block::create(0)) + {} + + explicit vec_data_store(const std::size_t& size) + : control_block_(control_block::create(size,reinterpret_cast(0),true)) + {} + + vec_data_store(const std::size_t& size, data_t data, bool dstrct = false) + : control_block_(control_block::create(size, data, dstrct)) + {} + + vec_data_store(const type& vds) + { + control_block_ = vds.control_block_; + control_block_->ref_count++; + } + + ~vec_data_store() + { + control_block::destroy(control_block_); + } + + type& operator=(const type& vds) + { + if (this != &vds) + { + std::size_t final_size = min_size(control_block_, vds.control_block_); + + vds.control_block_->size = final_size; + control_block_->size = final_size; + + if (control_block_->destruct || (0 == control_block_->data)) + { + control_block::destroy(control_block_); + + control_block_ = vds.control_block_; + control_block_->ref_count++; + } + } + + return (*this); + } + + inline data_t data() + { + return control_block_->data; + } + + inline data_t data() const + { + return control_block_->data; + } + + inline std::size_t size() + { + return control_block_->size; + } + + inline std::size_t size() const + { + return control_block_->size; + } + + inline data_t& ref() + { + return control_block_->data; + } + + inline void dump() const + { + #ifdef exprtk_enable_debugging + exprtk_debug(("size: %d\taddress:%p\tdestruct:%c\n", + size(), + data(), + (control_block_->destruct ? 'T' : 'F'))); + + for (std::size_t i = 0; i < size(); ++i) + { + if (5 == i) + exprtk_debug(("\n")); + + exprtk_debug(("%15.10f ",data()[i])); + } + exprtk_debug(("\n")); + #endif + } + + static inline void match_sizes(type& vds0, type& vds1) + { + const std::size_t size = min_size(vds0.control_block_,vds1.control_block_); + vds0.control_block_->size = size; + vds1.control_block_->size = size; + } + + private: + + static inline std::size_t min_size(control_block* cb0, control_block* cb1) + { + const std::size_t size0 = cb0->size; + const std::size_t size1 = cb1->size; + + if (size0 && size1) + return std::min(size0,size1); + else + return (size0) ? size0 : size1; + } + + control_block* control_block_; + }; + + namespace numeric + { + namespace details + { + template + inline T process_impl(const operator_type operation, const T arg) + { + switch (operation) + { + case e_abs : return numeric::abs (arg); + case e_acos : return numeric::acos (arg); + case e_acosh : return numeric::acosh(arg); + case e_asin : return numeric::asin (arg); + case e_asinh : return numeric::asinh(arg); + case e_atan : return numeric::atan (arg); + case e_atanh : return numeric::atanh(arg); + case e_ceil : return numeric::ceil (arg); + case e_cos : return numeric::cos (arg); + case e_cosh : return numeric::cosh (arg); + case e_exp : return numeric::exp (arg); + case e_expm1 : return numeric::expm1(arg); + case e_floor : return numeric::floor(arg); + case e_log : return numeric::log (arg); + case e_log10 : return numeric::log10(arg); + case e_log2 : return numeric::log2 (arg); + case e_log1p : return numeric::log1p(arg); + case e_neg : return numeric::neg (arg); + case e_pos : return numeric::pos (arg); + case e_round : return numeric::round(arg); + case e_sin : return numeric::sin (arg); + case e_sinc : return numeric::sinc (arg); + case e_sinh : return numeric::sinh (arg); + case e_sqrt : return numeric::sqrt (arg); + case e_tan : return numeric::tan (arg); + case e_tanh : return numeric::tanh (arg); + case e_cot : return numeric::cot (arg); + case e_sec : return numeric::sec (arg); + case e_csc : return numeric::csc (arg); + case e_r2d : return numeric::r2d (arg); + case e_d2r : return numeric::d2r (arg); + case e_d2g : return numeric::d2g (arg); + case e_g2d : return numeric::g2d (arg); + case e_notl : return numeric::notl (arg); + case e_sgn : return numeric::sgn (arg); + case e_erf : return numeric::erf (arg); + case e_erfc : return numeric::erfc (arg); + case e_ncdf : return numeric::ncdf (arg); + case e_frac : return numeric::frac (arg); + case e_trunc : return numeric::trunc(arg); + + default : exprtk_debug(("numeric::details::process_impl - Invalid unary operation.\n")); + return std::numeric_limits::quiet_NaN(); + } + } + + template + inline T process_impl(const operator_type operation, const T arg0, const T arg1) + { + switch (operation) + { + case e_add : return (arg0 + arg1); + case e_sub : return (arg0 - arg1); + case e_mul : return (arg0 * arg1); + case e_div : return (arg0 / arg1); + case e_mod : return modulus(arg0,arg1); + case e_pow : return pow(arg0,arg1); + case e_atan2 : return atan2(arg0,arg1); + case e_min : return std::min(arg0,arg1); + case e_max : return std::max(arg0,arg1); + case e_logn : return logn(arg0,arg1); + case e_lt : return (arg0 < arg1) ? T(1) : T(0); + case e_lte : return (arg0 <= arg1) ? T(1) : T(0); + case e_eq : return std::equal_to()(arg0,arg1) ? T(1) : T(0); + case e_ne : return std::not_equal_to()(arg0,arg1) ? T(1) : T(0); + case e_gte : return (arg0 >= arg1) ? T(1) : T(0); + case e_gt : return (arg0 > arg1) ? T(1) : T(0); + case e_and : return and_opr (arg0,arg1); + case e_nand : return nand_opr(arg0,arg1); + case e_or : return or_opr (arg0,arg1); + case e_nor : return nor_opr (arg0,arg1); + case e_xor : return xor_opr (arg0,arg1); + case e_xnor : return xnor_opr(arg0,arg1); + case e_root : return root (arg0,arg1); + case e_roundn : return roundn (arg0,arg1); + case e_equal : return equal (arg0,arg1); + case e_nequal : return nequal (arg0,arg1); + case e_hypot : return hypot (arg0,arg1); + case e_shr : return shr (arg0,arg1); + case e_shl : return shl (arg0,arg1); + + default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); + return std::numeric_limits::quiet_NaN(); + } + } + + template + inline T process_impl(const operator_type operation, const T arg0, const T arg1, int_type_tag) + { + switch (operation) + { + case e_add : return (arg0 + arg1); + case e_sub : return (arg0 - arg1); + case e_mul : return (arg0 * arg1); + case e_div : return (arg0 / arg1); + case e_mod : return arg0 % arg1; + case e_pow : return pow(arg0,arg1); + case e_min : return std::min(arg0,arg1); + case e_max : return std::max(arg0,arg1); + case e_logn : return logn(arg0,arg1); + case e_lt : return (arg0 < arg1) ? T(1) : T(0); + case e_lte : return (arg0 <= arg1) ? T(1) : T(0); + case e_eq : return (arg0 == arg1) ? T(1) : T(0); + case e_ne : return (arg0 != arg1) ? T(1) : T(0); + case e_gte : return (arg0 >= arg1) ? T(1) : T(0); + case e_gt : return (arg0 > arg1) ? T(1) : T(0); + case e_and : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(1) : T(0); + case e_nand : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(0) : T(1); + case e_or : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(1) : T(0); + case e_nor : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(0) : T(1); + case e_xor : return arg0 ^ arg1; + case e_xnor : return !(arg0 ^ arg1); + case e_root : return root(arg0,arg1); + case e_equal : return arg0 == arg1; + case e_nequal : return arg0 != arg1; + case e_hypot : return hypot(arg0,arg1); + case e_shr : return arg0 >> arg1; + case e_shl : return arg0 << arg1; + + default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); + return std::numeric_limits::quiet_NaN(); + } + } + } + + template + inline T process(const operator_type operation, const T arg) + { + return exprtk::details::numeric::details::process_impl(operation,arg); + } + + template + inline T process(const operator_type operation, const T arg0, const T arg1) + { + return exprtk::details::numeric::details::process_impl(operation, arg0, arg1); + } + } + + template + struct node_collector_interface + { + typedef Node* node_ptr_t; + typedef Node** node_pp_t; + typedef std::vector noderef_list_t; + + virtual ~node_collector_interface() {} + + virtual void collect_nodes(noderef_list_t&) {} + }; + + template + struct node_depth_base; + + template + class expression_node : public node_collector_interface >, + public node_depth_base > + { + public: + + enum node_type + { + e_none , e_null , e_constant , e_unary , + e_binary , e_binary_ext , e_trinary , e_quaternary , + e_vararg , e_conditional , e_while , e_repeat , + e_for , e_switch , e_mswitch , e_return , + e_retenv , e_variable , e_stringvar , e_stringconst , + e_stringvarrng , e_cstringvarrng , e_strgenrange , e_strconcat , + e_stringvarsize , e_strswap , e_stringsize , e_stringvararg , + e_function , e_vafunction , e_genfunction , e_strfunction , + e_strcondition , e_strccondition , e_add , e_sub , + e_mul , e_div , e_mod , e_pow , + e_lt , e_lte , e_gt , e_gte , + e_eq , e_ne , e_and , e_nand , + e_or , e_nor , e_xor , e_xnor , + e_in , e_like , e_ilike , e_inranges , + e_ipow , e_ipowinv , e_abs , e_acos , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_neg , + e_pos , e_round , e_sin , e_sinc , + e_sinh , e_sqrt , e_tan , e_tanh , + e_cot , e_sec , e_csc , e_r2d , + e_d2r , e_d2g , e_g2d , e_notl , + e_sgn , e_erf , e_erfc , e_ncdf , + e_frac , e_trunc , e_uvouv , e_vov , + e_cov , e_voc , e_vob , e_bov , + e_cob , e_boc , e_vovov , e_vovoc , + e_vocov , e_covov , e_covoc , e_vovovov , + e_vovovoc , e_vovocov , e_vocovov , e_covovov , + e_covocov , e_vocovoc , e_covovoc , e_vococov , + e_sf3ext , e_sf4ext , e_nulleq , e_strass , + e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , + e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , + e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , + e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , + e_valvecarith , e_vecunaryop , e_break , e_continue , + e_swap + }; + + typedef T value_type; + typedef expression_node* expression_ptr; + typedef node_collector_interface > nci_t; + typedef typename nci_t::noderef_list_t noderef_list_t; + typedef node_depth_base > ndb_t; + + virtual ~expression_node() + {} + + inline virtual T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + inline virtual expression_node* branch(const std::size_t& index = 0) const + { + return reinterpret_cast(index * 0); + } + + inline virtual node_type type() const + { + return e_none; + } + }; + + template + inline bool is_generally_string_node(const expression_node* node); + + inline bool is_true(const double v) + { + return std::not_equal_to()(0.0,v); + } + + inline bool is_true(const long double v) + { + return std::not_equal_to()(0.0L,v); + } + + inline bool is_true(const float v) + { + return std::not_equal_to()(0.0f,v); + } + + template + inline bool is_true(const std::complex& v) + { + return std::not_equal_to >()(std::complex(0),v); + } + + template + inline bool is_true(const expression_node* node) + { + return std::not_equal_to()(T(0),node->value()); + } + + template + inline bool is_true(const std::pair*,bool>& node) + { + return std::not_equal_to()(T(0),node.first->value()); + } + + template + inline bool is_false(const expression_node* node) + { + return std::equal_to()(T(0),node->value()); + } + + template + inline bool is_false(const std::pair*,bool>& node) + { + return std::equal_to()(T(0),node.first->value()); + } + + template + inline bool is_unary_node(const expression_node* node) + { + return node && (details::expression_node::e_unary == node->type()); + } + + template + inline bool is_neg_unary_node(const expression_node* node) + { + return node && (details::expression_node::e_neg == node->type()); + } + + template + inline bool is_binary_node(const expression_node* node) + { + return node && (details::expression_node::e_binary == node->type()); + } + + template + inline bool is_variable_node(const expression_node* node) + { + return node && (details::expression_node::e_variable == node->type()); + } + + template + inline bool is_ivariable_node(const expression_node* node) + { + return node && + ( + details::expression_node::e_variable == node->type() || + details::expression_node::e_vecelem == node->type() || + details::expression_node::e_rbvecelem == node->type() || + details::expression_node::e_rbveccelem == node->type() + ); + } + + template + inline bool is_vector_elem_node(const expression_node* node) + { + return node && (details::expression_node::e_vecelem == node->type()); + } + + template + inline bool is_rebasevector_elem_node(const expression_node* node) + { + return node && (details::expression_node::e_rbvecelem == node->type()); + } + + template + inline bool is_rebasevector_celem_node(const expression_node* node) + { + return node && (details::expression_node::e_rbveccelem == node->type()); + } + + template + inline bool is_vector_node(const expression_node* node) + { + return node && (details::expression_node::e_vector == node->type()); + } + + template + inline bool is_ivector_node(const expression_node* node) + { + if (node) + { + switch (node->type()) + { + case details::expression_node::e_vector : + case details::expression_node::e_vecvalass : + case details::expression_node::e_vecvecass : + case details::expression_node::e_vecopvalass : + case details::expression_node::e_vecopvecass : + case details::expression_node::e_vecvecswap : + case details::expression_node::e_vecvecarith : + case details::expression_node::e_vecvalarith : + case details::expression_node::e_valvecarith : + case details::expression_node::e_vecunaryop : return true; + default : return false; + } + } + else + return false; + } + + template + inline bool is_constant_node(const expression_node* node) + { + return node && (details::expression_node::e_constant == node->type()); + } + + template + inline bool is_null_node(const expression_node* node) + { + return node && (details::expression_node::e_null == node->type()); + } + + template + inline bool is_break_node(const expression_node* node) + { + return node && (details::expression_node::e_break == node->type()); + } + + template + inline bool is_continue_node(const expression_node* node) + { + return node && (details::expression_node::e_continue == node->type()); + } + + template + inline bool is_swap_node(const expression_node* node) + { + return node && (details::expression_node::e_swap == node->type()); + } + + template + inline bool is_function(const expression_node* node) + { + return node && (details::expression_node::e_function == node->type()); + } + + template + inline bool is_return_node(const expression_node* node) + { + return node && (details::expression_node::e_return == node->type()); + } + + template class unary_node; + + template + inline bool is_negate_node(const expression_node* node) + { + if (node && is_unary_node(node)) + { + return (details::e_neg == static_cast*>(node)->operation()); + } + else + return false; + } + + template + inline bool branch_deletable(expression_node* node) + { + return (0 != node) && + !is_variable_node(node) && + !is_string_node (node) ; + } + + template + inline bool all_nodes_valid(expression_node* (&b)[N]) + { + for (std::size_t i = 0; i < N; ++i) + { + if (0 == b[i]) return false; + } + + return true; + } + + template class Sequence> + inline bool all_nodes_valid(const Sequence*,Allocator>& b) + { + for (std::size_t i = 0; i < b.size(); ++i) + { + if (0 == b[i]) return false; + } + + return true; + } + + template + inline bool all_nodes_variables(expression_node* (&b)[N]) + { + for (std::size_t i = 0; i < N; ++i) + { + if (0 == b[i]) + return false; + else if (!is_variable_node(b[i])) + return false; + } + + return true; + } + + template class Sequence> + inline bool all_nodes_variables(Sequence*,Allocator>& b) + { + for (std::size_t i = 0; i < b.size(); ++i) + { + if (0 == b[i]) + return false; + else if (!is_variable_node(b[i])) + return false; + } + + return true; + } + + template + class node_collection_destructor + { + public: + + typedef node_collector_interface nci_t; + + typedef typename nci_t::node_ptr_t node_ptr_t; + typedef typename nci_t::node_pp_t node_pp_t; + typedef typename nci_t::noderef_list_t noderef_list_t; + + static void delete_nodes(node_ptr_t& root) + { + std::vector node_delete_list; + node_delete_list.reserve(1000); + + collect_nodes(root, node_delete_list); + + for (std::size_t i = 0; i < node_delete_list.size(); ++i) + { + node_ptr_t& node = *node_delete_list[i]; + exprtk_debug(("ncd::delete_nodes() - deleting: %p\n", static_cast(node))); + delete node; + node = reinterpret_cast(0); + } + } + + private: + + static void collect_nodes(node_ptr_t& root, noderef_list_t& node_delete_list) + { + std::deque node_list; + node_list.push_back(root); + node_delete_list.push_back(&root); + + noderef_list_t child_node_delete_list; + child_node_delete_list.reserve(1000); + + while (!node_list.empty()) + { + node_list.front()->collect_nodes(child_node_delete_list); + + if (!child_node_delete_list.empty()) + { + for (std::size_t i = 0; i < child_node_delete_list.size(); ++i) + { + node_pp_t& node = child_node_delete_list[i]; + + if (0 == (*node)) + { + exprtk_debug(("ncd::collect_nodes() - null node encountered.\n")); + } + + node_list.push_back(*node); + } + + node_delete_list.insert( + node_delete_list.end(), + child_node_delete_list.begin(), child_node_delete_list.end()); + + child_node_delete_list.clear(); + } + + node_list.pop_front(); + } + + std::reverse(node_delete_list.begin(), node_delete_list.end()); + } + }; + + template + inline void free_all_nodes(NodeAllocator& node_allocator, expression_node* (&b)[N]) + { + for (std::size_t i = 0; i < N; ++i) + { + free_node(node_allocator,b[i]); + } + } + + template class Sequence> + inline void free_all_nodes(NodeAllocator& node_allocator, Sequence*,Allocator>& b) + { + for (std::size_t i = 0; i < b.size(); ++i) + { + free_node(node_allocator,b[i]); + } + + b.clear(); + } + + template + inline void free_node(NodeAllocator&, expression_node*& node) + { + if ((0 == node) || is_variable_node(node) || is_string_node(node)) + { + return; + } + + node_collection_destructor > + ::delete_nodes(node); + } + + template + inline void destroy_node(expression_node*& node) + { + if (0 != node) + { + node_collection_destructor > + ::delete_nodes(node); + } + } + + template + struct node_depth_base + { + typedef Node* node_ptr_t; + typedef std::pair nb_pair_t; + + node_depth_base() + : depth_set(false), + depth(0) + {} + + virtual ~node_depth_base() {} + + virtual std::size_t node_depth() const { return 1; } + + std::size_t compute_node_depth(const Node* const& node) const + { + if (!depth_set) + { + depth = 1 + (node ? node->node_depth() : 0); + depth_set = true; + } + + return depth; + } + + std::size_t compute_node_depth(const nb_pair_t& branch) const + { + if (!depth_set) + { + depth = 1 + (branch.first ? branch.first->node_depth() : 0); + depth_set = true; + } + + return depth; + } + + template + std::size_t compute_node_depth(const nb_pair_t (&branch)[N]) const + { + if (!depth_set) + { + depth = 0; + for (std::size_t i = 0; i < N; ++i) + { + if (branch[i].first) + { + depth = std::max(depth,branch[i].first->node_depth()); + } + } + depth += 1; + depth_set = true; + } + + return depth; + } + + template + std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1) const + { + if (!depth_set) + { + depth = 1 + std::max(compute_node_depth(n0), compute_node_depth(n1)); + depth_set = true; + } + + return depth; + } + + template + std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, + const BranchType& n2) const + { + if (!depth_set) + { + depth = 1 + std::max( + std::max(compute_node_depth(n0), compute_node_depth(n1)), + compute_node_depth(n2)); + depth_set = true; + } + + return depth; + } + + template + std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, + const BranchType& n2, const BranchType& n3) const + { + if (!depth_set) + { + depth = 1 + std::max( + std::max(compute_node_depth(n0), compute_node_depth(n1)), + std::max(compute_node_depth(n2), compute_node_depth(n3))); + depth_set = true; + } + + return depth; + } + + template class Sequence> + std::size_t compute_node_depth(const Sequence& branch_list) const + { + if (!depth_set) + { + for (std::size_t i = 0; i < branch_list.size(); ++i) + { + if (branch_list[i]) + { + depth = std::max(depth, compute_node_depth(branch_list[i])); + } + } + depth_set = true; + } + + return depth; + } + + template class Sequence> + std::size_t compute_node_depth(const Sequence& branch_list) const + { + if (!depth_set) + { + for (std::size_t i = 0; i < branch_list.size(); ++i) + { + if (branch_list[i].first) + { + depth = std::max(depth, compute_node_depth(branch_list[i].first)); + } + } + depth_set = true; + } + + return depth; + } + + mutable bool depth_set; + mutable std::size_t depth; + + template + void collect(node_ptr_t const& node, + const bool deletable, + NodeSequence& delete_node_list) const + { + if ((0 != node) && deletable) + { + delete_node_list.push_back(const_cast(&node)); + } + } + + template + void collect(const nb_pair_t& branch, + NodeSequence& delete_node_list) const + { + collect(branch.first, branch.second, delete_node_list); + } + + template + void collect(Node*& node, + NodeSequence& delete_node_list) const + { + collect(node, branch_deletable(node), delete_node_list); + } + + template + void collect(const nb_pair_t(&branch)[N], + NodeSequence& delete_node_list) const + { + for (std::size_t i = 0; i < N; ++i) + { + collect(branch[i].first, branch[i].second, delete_node_list); + } + } + + template class Sequence, + typename NodeSequence> + void collect(const Sequence& branch, + NodeSequence& delete_node_list) const + { + for (std::size_t i = 0; i < branch.size(); ++i) + { + collect(branch[i].first, branch[i].second, delete_node_list); + } + } + + template class Sequence, + typename NodeSequence> + void collect(const Sequence& branch_list, + NodeSequence& delete_node_list) const + { + for (std::size_t i = 0; i < branch_list.size(); ++i) + { + collect(branch_list[i], branch_deletable(branch_list[i]), delete_node_list); + } + } + + template class Sequence, + typename NodeSequence> + void collect(const Sequence& branch_list, + const Sequence& branch_deletable_list, + NodeSequence& delete_node_list) const + { + for (std::size_t i = 0; i < branch_list.size(); ++i) + { + collect(branch_list[i], branch_deletable_list[i], delete_node_list); + } + } + }; + + template + class vector_holder + { + private: + + typedef Type value_type; + typedef value_type* value_ptr; + typedef const value_ptr const_value_ptr; + + class vector_holder_base + { + public: + + virtual ~vector_holder_base() {} + + inline value_ptr operator[](const std::size_t& index) const + { + return value_at(index); + } + + inline std::size_t size() const + { + return vector_size(); + } + + inline value_ptr data() const + { + return value_at(0); + } + + virtual inline bool rebaseable() const + { + return false; + } + + virtual void set_ref(value_ptr*) {} + + protected: + + virtual value_ptr value_at(const std::size_t&) const = 0; + virtual std::size_t vector_size() const = 0; + }; + + class array_vector_impl : public vector_holder_base + { + public: + + array_vector_impl(const Type* vec, const std::size_t& vec_size) + : vec_(vec), + size_(vec_size) + {} + + protected: + + value_ptr value_at(const std::size_t& index) const + { + if (index < size_) + return const_cast(vec_ + index); + else + return const_value_ptr(0); + } + + std::size_t vector_size() const + { + return size_; + } + + private: + + array_vector_impl operator=(const array_vector_impl&); + + const Type* vec_; + const std::size_t size_; + }; + + template class Sequence> + class sequence_vector_impl : public vector_holder_base + { + public: + + typedef Sequence sequence_t; + + sequence_vector_impl(sequence_t& seq) + : sequence_(seq) + {} + + protected: + + value_ptr value_at(const std::size_t& index) const + { + return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0); + } + + std::size_t vector_size() const + { + return sequence_.size(); + } + + private: + + sequence_vector_impl operator=(const sequence_vector_impl&); + + sequence_t& sequence_; + }; + + class vector_view_impl : public vector_holder_base + { + public: + + typedef exprtk::vector_view vector_view_t; + + vector_view_impl(vector_view_t& vec_view) + : vec_view_(vec_view) + {} + + void set_ref(value_ptr* ref) + { + vec_view_.set_ref(ref); + } + + virtual inline bool rebaseable() const + { + return true; + } + + protected: + + value_ptr value_at(const std::size_t& index) const + { + return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0); + } + + std::size_t vector_size() const + { + return vec_view_.size(); + } + + private: + + vector_view_impl operator=(const vector_view_impl&); + + vector_view_t& vec_view_; + }; + + public: + + typedef typename details::vec_data_store vds_t; + + vector_holder(Type* vec, const std::size_t& vec_size) + : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) + {} + + vector_holder(const vds_t& vds) + : vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size())) + {} + + template + vector_holder(std::vector& vec) + : vector_holder_base_(new(buffer)sequence_vector_impl(vec)) + {} + + vector_holder(exprtk::vector_view& vec) + : vector_holder_base_(new(buffer)vector_view_impl(vec)) + {} + + inline value_ptr operator[](const std::size_t& index) const + { + return (*vector_holder_base_)[index]; + } + + inline std::size_t size() const + { + return vector_holder_base_->size(); + } + + inline value_ptr data() const + { + return vector_holder_base_->data(); + } + + void set_ref(value_ptr* ref) + { + vector_holder_base_->set_ref(ref); + } + + bool rebaseable() const + { + return vector_holder_base_->rebaseable(); + } + + private: + + mutable vector_holder_base* vector_holder_base_; + uchar_t buffer[64]; + }; + + template + class null_node exprtk_final : public expression_node + { + public: + + inline T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_null; + } + }; + + template + inline void construct_branch_pair(std::pair*,bool> (&branch)[N], + expression_node* b, + const std::size_t& index) + { + if (b && (index < N)) + { + branch[index] = std::make_pair(b,branch_deletable(b)); + } + } + + template + inline void construct_branch_pair(std::pair*,bool>& branch, expression_node* b) + { + if (b) + { + branch = std::make_pair(b,branch_deletable(b)); + } + } + + template + inline void init_branches(std::pair*,bool> (&branch)[N], + expression_node* b0, + expression_node* b1 = reinterpret_cast*>(0), + expression_node* b2 = reinterpret_cast*>(0), + expression_node* b3 = reinterpret_cast*>(0), + expression_node* b4 = reinterpret_cast*>(0), + expression_node* b5 = reinterpret_cast*>(0), + expression_node* b6 = reinterpret_cast*>(0), + expression_node* b7 = reinterpret_cast*>(0), + expression_node* b8 = reinterpret_cast*>(0), + expression_node* b9 = reinterpret_cast*>(0)) + { + construct_branch_pair(branch, b0, 0); + construct_branch_pair(branch, b1, 1); + construct_branch_pair(branch, b2, 2); + construct_branch_pair(branch, b3, 3); + construct_branch_pair(branch, b4, 4); + construct_branch_pair(branch, b5, 5); + construct_branch_pair(branch, b6, 6); + construct_branch_pair(branch, b7, 7); + construct_branch_pair(branch, b8, 8); + construct_branch_pair(branch, b9, 9); + } + + template + class null_eq_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + explicit null_eq_node(expression_ptr branch, const bool equality = true) + : equality_(equality) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + assert(branch_.first); + + const T v = branch_.first->value(); + const bool result = details::numeric::is_nan(v); + + if (result) + return (equality_) ? T(1) : T(0); + else + return (equality_) ? T(0) : T(1); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_nulleq; + } + + inline operator_type operation() const + { + return details::e_eq; + } + + inline expression_node* branch(const std::size_t&) const + { + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bool equality_; + branch_t branch_; + }; + + template + class literal_node exprtk_final : public expression_node + { + public: + + explicit literal_node(const T& v) + : value_(v) + {} + + inline T value() const + { + return value_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_constant; + } + + inline expression_node* branch(const std::size_t&) const + { + return reinterpret_cast*>(0); + } + + private: + + literal_node(literal_node&) {} + literal_node& operator=(literal_node&) { return (*this); } + + const T value_; + }; + + template + struct range_pack; + + template + struct range_data_type; + + template + class range_interface + { + public: + + typedef range_pack range_t; + + virtual ~range_interface() + {} + + virtual range_t& range_ref() = 0; + + virtual const range_t& range_ref() const = 0; + }; + + #ifndef exprtk_disable_string_capabilities + template + class string_base_node + { + public: + + typedef range_data_type range_data_type_t; + + virtual ~string_base_node() + {} + + virtual std::string str () const = 0; + + virtual char_cptr base() const = 0; + + virtual std::size_t size() const = 0; + }; + + template + class string_literal_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef range_pack range_t; + + explicit string_literal_node(const std::string& v) + : value_(v) + { + rp_.n0_c = std::make_pair(true,0); + rp_.n1_c = std::make_pair(true,v.size() - 1); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + inline T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringconst; + } + + inline expression_node* branch(const std::size_t&) const + { + return reinterpret_cast*>(0); + } + + std::string str() const + { + return value_; + } + + char_cptr base() const + { + return value_.data(); + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return rp_; + } + + const range_t& range_ref() const + { + return rp_; + } + + private: + + string_literal_node(const string_literal_node&); + string_literal_node& operator=(const string_literal_node&); + + const std::string value_; + range_t rp_; + }; + #endif + + template + class unary_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + unary_node(const operator_type& opr, expression_ptr branch) + : operation_(opr) + { + construct_branch_pair(branch_,branch); + } + + inline T value() const + { + assert(branch_.first); + + const T arg = branch_.first->value(); + + return numeric::process(operation_,arg); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_unary; + } + + inline operator_type operation() const + { + return operation_; + } + + inline expression_node* branch(const std::size_t&) const + { + return branch_.first; + } + + inline void release() + { + branch_.second = false; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_final + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + protected: + + operator_type operation_; + branch_t branch_; + }; + + template + class binary_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + binary_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : operation_(opr) + { + init_branches<2>(branch_, branch0, branch1); + } + + inline T value() const + { + assert(branch_[0].first); + assert(branch_[1].first); + + const T arg0 = branch_[0].first->value(); + const T arg1 = branch_[1].first->value(); + + return numeric::process(operation_,arg0,arg1); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_binary; + } + + inline operator_type operation() + { + return operation_; + } + + inline expression_node* branch(const std::size_t& index = 0) const + { + if (0 == index) + return branch_[0].first; + else if (1 == index) + return branch_[1].first; + else + return reinterpret_cast(0); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_final + { + return expression_node::ndb_t::template compute_node_depth<2>(branch_); + } + + protected: + + operator_type operation_; + branch_t branch_[2]; + }; + + template + class binary_ext_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + binary_ext_node(expression_ptr branch0, expression_ptr branch1) + { + init_branches<2>(branch_, branch0, branch1); + } + + inline T value() const + { + assert(branch_[0].first); + assert(branch_[1].first); + + const T arg0 = branch_[0].first->value(); + const T arg1 = branch_[1].first->value(); + + return Operation::process(arg0,arg1); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_binary_ext; + } + + inline operator_type operation() + { + return Operation::operation(); + } + + inline expression_node* branch(const std::size_t& index = 0) const + { + if (0 == index) + return branch_[0].first; + else if (1 == index) + return branch_[1].first; + else + return reinterpret_cast(0); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::template compute_node_depth<2>(branch_); + } + + protected: + + branch_t branch_[2]; + }; + + template + class trinary_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + trinary_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1, + expression_ptr branch2) + : operation_(opr) + { + init_branches<3>(branch_, branch0, branch1, branch2); + } + + inline T value() const + { + assert(branch_[0].first); + assert(branch_[1].first); + assert(branch_[2].first); + + const T arg0 = branch_[0].first->value(); + const T arg1 = branch_[1].first->value(); + const T arg2 = branch_[2].first->value(); + + switch (operation_) + { + case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1)); + + case e_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1); + + case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) + return arg1; + else + return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); + + default : exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); + return std::numeric_limits::quiet_NaN(); + } + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_trinary; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_final + { + return expression_node::ndb_t::template compute_node_depth<3>(branch_); + } + + protected: + + operator_type operation_; + branch_t branch_[3]; + }; + + template + class quaternary_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + quaternary_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1, + expression_ptr branch2, + expression_ptr branch3) + : operation_(opr) + { + init_branches<4>(branch_, branch0, branch1, branch2, branch3); + } + + inline T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_quaternary; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_final + { + return expression_node::ndb_t::template compute_node_depth<4>(branch_); + } + + protected: + + operator_type operation_; + branch_t branch_[4]; + }; + + template + class conditional_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + conditional_node(expression_ptr condition, + expression_ptr consequent, + expression_ptr alternative) + { + construct_branch_pair(condition_ , condition ); + construct_branch_pair(consequent_ , consequent ); + construct_branch_pair(alternative_, alternative); + } + + inline T value() const + { + assert(condition_ .first); + assert(consequent_ .first); + assert(alternative_.first); + + if (is_true(condition_)) + return consequent_.first->value(); + else + return alternative_.first->value(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_conditional; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(consequent_ , node_delete_list); + expression_node::ndb_t::collect(alternative_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth + (condition_, consequent_, alternative_); + } + + private: + + branch_t condition_; + branch_t consequent_; + branch_t alternative_; + }; + + template + class cons_conditional_node exprtk_final : public expression_node + { + public: + + // Consequent only conditional statement node + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + cons_conditional_node(expression_ptr condition, + expression_ptr consequent) + { + construct_branch_pair(condition_ , condition ); + construct_branch_pair(consequent_, consequent); + } + + inline T value() const + { + assert(condition_ .first); + assert(consequent_.first); + + if (is_true(condition_)) + return consequent_.first->value(); + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_conditional; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(consequent_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t:: + compute_node_depth(condition_, consequent_); + } + + private: + + branch_t condition_; + branch_t consequent_; + }; + + #ifndef exprtk_disable_break_continue + template + class break_exception + { + public: + + explicit break_exception(const T& v) + : value(v) + {} + + T value; + }; + + class continue_exception + {}; + + template + class break_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + break_node(expression_ptr ret = expression_ptr(0)) + { + construct_branch_pair(return_, ret); + } + + inline T value() const + { + throw break_exception(return_.first ? return_.first->value() : std::numeric_limits::quiet_NaN()); + #ifndef _MSC_VER + return std::numeric_limits::quiet_NaN(); + #endif + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_break; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(return_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(return_); + } + + private: + + branch_t return_; + }; + + template + class continue_node exprtk_final : public expression_node + { + public: + + inline T value() const + { + throw continue_exception(); + #ifndef _MSC_VER + return std::numeric_limits::quiet_NaN(); + #endif + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_break; + } + }; + #endif + + #ifdef exprtk_enable_runtime_checks + struct loop_runtime_checker + { + loop_runtime_checker(loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0), + loop_runtime_check::loop_types lp_typ = loop_runtime_check::e_invalid) + : iteration_count_(0), + loop_runtime_check_(loop_rt_chk), + loop_type(lp_typ) + {} + + inline void reset(const _uint64_t initial_value = 0) const + { + iteration_count_ = initial_value; + } + + inline bool check() const + { + if ( + (0 == loop_runtime_check_) || + (++iteration_count_ <= loop_runtime_check_->max_loop_iterations) + ) + { + return true; + } + + loop_runtime_check::violation_context ctxt; + ctxt.loop = loop_type; + ctxt.violation = loop_runtime_check::e_iteration_count; + + loop_runtime_check_->handle_runtime_violation(ctxt); + + return false; + } + + mutable _uint64_t iteration_count_; + mutable loop_runtime_check_ptr loop_runtime_check_; + loop_runtime_check::loop_types loop_type; + }; + #else + struct loop_runtime_checker + { + loop_runtime_checker(loop_runtime_check_ptr, loop_runtime_check::loop_types) + {} + + inline void reset(const _uint64_t = 0) const + {} + + inline bool check() const + { + return true; + } + }; + #endif + + template + class while_loop_node exprtk_final + : public expression_node, + public loop_runtime_checker + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + while_loop_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk,loop_runtime_check::e_while_loop) + { + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); + } + + inline T value() const + { + assert(condition_.first); + assert(loop_body_.first); + + T result = T(0); + + loop_runtime_checker::reset(); + + while (is_true(condition_) && loop_runtime_checker::check()) + { + result = loop_body_.first->value(); + } + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_while; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + + private: + + branch_t condition_; + branch_t loop_body_; + }; + + template + class repeat_until_loop_node exprtk_final + : public expression_node, + public loop_runtime_checker + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + repeat_until_loop_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) + { + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); + } + + inline T value() const + { + assert(condition_.first); + assert(loop_body_.first); + + T result = T(0); + + loop_runtime_checker::reset(1); + + do + { + result = loop_body_.first->value(); + } + while (is_false(condition_.first) && loop_runtime_checker::check()); + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_repeat; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + + private: + + branch_t condition_; + branch_t loop_body_; + }; + + template + class for_loop_node exprtk_final + : public expression_node, + public loop_runtime_checker + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + for_loop_node(expression_ptr initialiser, + expression_ptr condition, + expression_ptr incrementor, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) + { + construct_branch_pair(initialiser_, initialiser); + construct_branch_pair(condition_ , condition ); + construct_branch_pair(incrementor_, incrementor); + construct_branch_pair(loop_body_ , loop_body ); + } + + inline T value() const + { + assert(condition_.first); + assert(loop_body_.first); + + T result = T(0); + + loop_runtime_checker::reset(); + + if (initialiser_.first) + initialiser_.first->value(); + + if (incrementor_.first) + { + while (is_true(condition_) && loop_runtime_checker::check()) + { + result = loop_body_.first->value(); + incrementor_.first->value(); + } + } + else + { + while (is_true(condition_) && loop_runtime_checker::check()) + { + result = loop_body_.first->value(); + } + } + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_for; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(initialiser_ , node_delete_list); + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(incrementor_ , node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth + (initialiser_, condition_, incrementor_, loop_body_); + } + + private: + + branch_t initialiser_; + branch_t condition_ ; + branch_t incrementor_; + branch_t loop_body_ ; + }; + + #ifndef exprtk_disable_break_continue + template + class while_loop_bc_node exprtk_final + : public expression_node, + public loop_runtime_checker + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + while_loop_bc_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) + { + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); + } + + inline T value() const + { + assert(condition_.first); + assert(loop_body_.first); + + T result = T(0); + + loop_runtime_checker::reset(); + + while (is_true(condition_) && loop_runtime_checker::check()) + { + try + { + result = loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_while; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + + private: + + branch_t condition_; + branch_t loop_body_; + }; + + template + class repeat_until_loop_bc_node exprtk_final + : public expression_node, + public loop_runtime_checker + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + repeat_until_loop_bc_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) + { + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); + } + + inline T value() const + { + assert(condition_.first); + assert(loop_body_.first); + + T result = T(0); + + loop_runtime_checker::reset(); + + do + { + try + { + result = loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + while (is_false(condition_.first) && loop_runtime_checker::check()); + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_repeat; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + + private: + + branch_t condition_; + branch_t loop_body_; + }; + + template + class for_loop_bc_node exprtk_final + : public expression_node, + public loop_runtime_checker + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + for_loop_bc_node(expression_ptr initialiser, + expression_ptr condition, + expression_ptr incrementor, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) + { + construct_branch_pair(initialiser_, initialiser); + construct_branch_pair(condition_ , condition ); + construct_branch_pair(incrementor_, incrementor); + construct_branch_pair(loop_body_ , loop_body ); + } + + inline T value() const + { + assert(condition_.first); + assert(loop_body_.first); + + T result = T(0); + + loop_runtime_checker::reset(); + + if (initialiser_.first) + initialiser_.first->value(); + + if (incrementor_.first) + { + while (is_true(condition_) && loop_runtime_checker::check()) + { + try + { + result = loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + + incrementor_.first->value(); + } + } + else + { + while (is_true(condition_) && loop_runtime_checker::check()) + { + try + { + result = loop_body_.first->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } + } + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_for; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(initialiser_ , node_delete_list); + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(incrementor_ , node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth + (initialiser_, condition_, incrementor_, loop_body_); + } + + private: + + branch_t initialiser_; + branch_t condition_ ; + branch_t incrementor_; + branch_t loop_body_ ; + }; + #endif + + template + class switch_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + template class Sequence> + explicit switch_node(const Sequence& arg_list) + { + if (1 != (arg_list.size() & 1)) + return; + + arg_list_.resize(arg_list.size()); + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (arg_list[i]) + { + construct_branch_pair(arg_list_[i], arg_list[i]); + } + else + { + arg_list_.clear(); + return; + } + } + } + + inline T value() const + { + if (!arg_list_.empty()) + { + const std::size_t upper_bound = (arg_list_.size() - 1); + + for (std::size_t i = 0; i < upper_bound; i += 2) + { + expression_ptr condition = arg_list_[i ].first; + expression_ptr consequent = arg_list_[i + 1].first; + + if (is_true(condition)) + { + return consequent->value(); + } + } + + return arg_list_[upper_bound].first->value(); + } + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_final + { + return expression_node::e_switch; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_final + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + + protected: + + std::vector arg_list_; + }; + + template + class switch_n_node exprtk_final : public switch_node + { + public: + + typedef expression_node* expression_ptr; + + template class Sequence> + explicit switch_n_node(const Sequence& arg_list) + : switch_node(arg_list) + {} + + inline T value() const + { + return Switch_N::process(switch_node::arg_list_); + } + }; + + template + class multi_switch_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + template class Sequence> + explicit multi_switch_node(const Sequence& arg_list) + { + if (0 != (arg_list.size() & 1)) + return; + + arg_list_.resize(arg_list.size()); + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (arg_list[i]) + { + construct_branch_pair(arg_list_[i], arg_list[i]); + } + else + { + arg_list_.clear(); + return; + } + } + } + + inline T value() const + { + T result = T(0); + + if (arg_list_.empty()) + { + return std::numeric_limits::quiet_NaN(); + } + + const std::size_t upper_bound = (arg_list_.size() - 1); + + for (std::size_t i = 0; i < upper_bound; i += 2) + { + expression_ptr condition = arg_list_[i ].first; + expression_ptr consequent = arg_list_[i + 1].first; + + if (is_true(condition)) + { + result = consequent->value(); + } + } + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_mswitch; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } + + std::size_t node_depth() const exprtk_final + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + + private: + + std::vector arg_list_; + }; + + template + class ivariable + { + public: + + virtual ~ivariable() + {} + + virtual T& ref() = 0; + virtual const T& ref() const = 0; + }; + + template + class variable_node exprtk_final + : public expression_node, + public ivariable + { + public: + + static T null_value; + + explicit variable_node() + : value_(&null_value) + {} + + explicit variable_node(T& v) + : value_(&v) + {} + + inline bool operator <(const variable_node& v) const + { + return this < (&v); + } + + inline T value() const + { + return (*value_); + } + + inline T& ref() + { + return (*value_); + } + + inline const T& ref() const + { + return (*value_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_variable; + } + + private: + + T* value_; + }; + + template + T variable_node::null_value = T(std::numeric_limits::quiet_NaN()); + + template + struct range_pack + { + typedef expression_node* expression_node_ptr; + typedef std::pair cached_range_t; + + range_pack() + : n0_e (std::make_pair(false,expression_node_ptr(0))), + n1_e (std::make_pair(false,expression_node_ptr(0))), + n0_c (std::make_pair(false,0)), + n1_c (std::make_pair(false,0)), + cache(std::make_pair(0,0)) + {} + + void clear() + { + n0_e = std::make_pair(false,expression_node_ptr(0)); + n1_e = std::make_pair(false,expression_node_ptr(0)); + n0_c = std::make_pair(false,0); + n1_c = std::make_pair(false,0); + cache = std::make_pair(0,0); + } + + void free() + { + if (n0_e.first && n0_e.second) + { + n0_e.first = false; + + if ( + !is_variable_node(n0_e.second) && + !is_string_node (n0_e.second) + ) + { + destroy_node(n0_e.second); + } + } + + if (n1_e.first && n1_e.second) + { + n1_e.first = false; + + if ( + !is_variable_node(n1_e.second) && + !is_string_node (n1_e.second) + ) + { + destroy_node(n1_e.second); + } + } + } + + bool const_range() const + { + return ( n0_c.first && n1_c.first) && + (!n0_e.first && !n1_e.first); + } + + bool var_range() const + { + return ( n0_e.first && n1_e.first) && + (!n0_c.first && !n1_c.first); + } + + bool operator() (std::size_t& r0, std::size_t& r1, + const std::size_t& size = std::numeric_limits::max()) const + { + if (n0_c.first) + r0 = n0_c.second; + else if (n0_e.first) + { + r0 = static_cast(details::numeric::to_int64(n0_e.second->value())); + } + else + return false; + + if (n1_c.first) + r1 = n1_c.second; + else if (n1_e.first) + { + r1 = static_cast(details::numeric::to_int64(n1_e.second->value())); + } + else + return false; + + if ( + (std::numeric_limits::max() != size) && + (std::numeric_limits::max() == r1 ) + ) + { + r1 = size - 1; + } + + cache.first = r0; + cache.second = r1; + + #ifndef exprtk_enable_runtime_checks + return (r0 <= r1); + #else + return range_runtime_check(r0, r1, size); + #endif + } + + inline std::size_t const_size() const + { + return (n1_c.second - n0_c.second + 1); + } + + inline std::size_t cache_size() const + { + return (cache.second - cache.first + 1); + } + + std::pair n0_e; + std::pair n1_e; + std::pair n0_c; + std::pair n1_c; + mutable cached_range_t cache; + + #ifdef exprtk_enable_runtime_checks + bool range_runtime_check(const std::size_t r0, + const std::size_t r1, + const std::size_t size) const + { + if (r0 >= size) + { + throw std::runtime_error("range error: (r0 < 0) || (r0 >= size)"); + return false; + } + + if (r1 >= size) + { + throw std::runtime_error("range error: (r1 < 0) || (r1 >= size)"); + return false; + } + + return (r0 <= r1); + } + #endif + }; + + template + class string_base_node; + + template + struct range_data_type + { + typedef range_pack range_t; + typedef string_base_node* strbase_ptr_t; + + range_data_type() + : range(0), + data (0), + size (0), + type_size(0), + str_node (0) + {} + + range_t* range; + void* data; + std::size_t size; + std::size_t type_size; + strbase_ptr_t str_node; + }; + + template class vector_node; + + template + class vector_interface + { + public: + + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + virtual ~vector_interface() + {} + + virtual std::size_t size () const = 0; + + virtual vector_node_ptr vec() const = 0; + + virtual vector_node_ptr vec() = 0; + + virtual vds_t& vds () = 0; + + virtual const vds_t& vds () const = 0; + + virtual bool side_effect () const { return false; } + }; + + template + class vector_node exprtk_final + : public expression_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + explicit vector_node(vector_holder_t* vh) + : vector_holder_(vh), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + } + + vector_node(const vds_t& vds, vector_holder_t* vh) + : vector_holder_(vh), + vds_(vds) + {} + + inline T value() const + { + return vds().data()[0]; + } + + vector_node_ptr vec() const + { + return const_cast(this); + } + + vector_node_ptr vec() + { + return this; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vector; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + private: + + vector_holder_t* vector_holder_; + vds_t vds_; + }; + + template + class vector_elem_node exprtk_final + : public expression_node, + public ivariable + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; + + vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) + : vec_holder_(vec_holder), + vector_base_((*vec_holder)[0]) + { + construct_branch_pair(index_, index); + } + + inline T value() const + { + return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline T& ref() + { + return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline const T& ref() const + { + return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vec_holder_); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(index_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(index_); + } + + private: + + vector_holder_ptr vec_holder_; + T* vector_base_; + branch_t index_; + }; + + template + class rebasevector_elem_node exprtk_final + : public expression_node, + public ivariable + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store vds_t; + typedef std::pair branch_t; + + rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) + : vector_holder_(vec_holder), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + construct_branch_pair(index_, index); + } + + inline T value() const + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline T& ref() + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline const T& ref() const + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_rbvecelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(index_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(index_); + } + + private: + + vector_holder_ptr vector_holder_; + vds_t vds_; + branch_t index_; + }; + + template + class rebasevector_celem_node exprtk_final + : public expression_node, + public ivariable + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store vds_t; + + rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder) + : index_(index), + vector_holder_(vec_holder), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + } + + inline T value() const + { + return *(vds_.data() + index_); + } + + inline T& ref() + { + return *(vds_.data() + index_); + } + + inline const T& ref() const + { + return *(vds_.data() + index_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_rbveccelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + private: + + const std::size_t index_; + vector_holder_ptr vector_holder_; + vds_t vds_; + }; + + template + class vector_assignment_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_assignment_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list, + const bool single_value_initialse) + : vector_base_(vector_base), + initialiser_list_(initialiser_list), + size_(size), + single_value_initialse_(single_value_initialse) + {} + + inline T value() const + { + if (single_value_initialse_) + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = initialiser_list_[0]->value(); + } + } + else + { + std::size_t il_size = initialiser_list_.size(); + + for (std::size_t i = 0; i < il_size; ++i) + { + *(vector_base_ + i) = initialiser_list_[i]->value(); + } + + if (il_size < size_) + { + for (std::size_t i = il_size; i < size_; ++i) + { + *(vector_base_ + i) = T(0); + } + } + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecdefass; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + + private: + + vector_assignment_node& operator=(const vector_assignment_node&); + + mutable T* vector_base_; + std::vector initialiser_list_; + const std::size_t size_; + const bool single_value_initialse_; + }; + + template + class swap_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef variable_node* variable_node_ptr; + + swap_node(variable_node_ptr var0, variable_node_ptr var1) + : var0_(var0), + var1_(var1) + {} + + inline T value() const + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_swap; + } + + private: + + variable_node_ptr var0_; + variable_node_ptr var1_; + }; + + template + class swap_generic_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + typedef ivariable* ivariable_ptr; + + swap_generic_node(expression_ptr var0, expression_ptr var1) + : binary_node(details::e_swap, var0, var1), + var0_(dynamic_cast(var0)), + var1_(dynamic_cast(var1)) + {} + + inline T value() const + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_swap; + } + + private: + + ivariable_ptr var0_; + ivariable_ptr var1_; + }; + + template + class swap_vecvec_node exprtk_final + : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + swap_vecvec_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node(details::e_swap, branch0, branch1), + vec0_node_ptr_(0), + vec1_node_ptr_(0), + vec_size_ (0), + initialised_ (false) + { + if (is_ivector_node(binary_node::branch_[0].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + { + vec0_node_ptr_ = vi->vec(); + vds() = vi->vds(); + } + } + + if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + } + } + + if (vec0_node_ptr_ && vec1_node_ptr_) + { + vec_size_ = std::min(vec0_node_ptr_->vds().size(), + vec1_node_ptr_->vds().size()); + + initialised_ = true; + } + } + + inline T value() const + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + if (initialised_) + { + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + for (std::size_t i = 0; i < vec_size_; ++i) + { + std::swap(vec0[i],vec1[i]); + } + + return vec1_node_ptr_->value(); + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() + { + return vec0_node_ptr_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecvecswap; + } + + std::size_t size() const + { + return vec_size_; + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + std::size_t vec_size_; + bool initialised_; + vds_t vds_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class stringvar_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef range_pack range_t; + + static std::string null_value; + + explicit stringvar_node() + : value_(&null_value) + {} + + explicit stringvar_node(std::string& v) + : value_(&v) + { + rp_.n0_c = std::make_pair(true,0); + rp_.n1_c = std::make_pair(true,v.size() - 1); + rp_.cache.first = rp_.n0_c.second; + rp_.cache.second = rp_.n1_c.second; + } + + inline bool operator <(const stringvar_node& v) const + { + return this < (&v); + } + + inline T value() const + { + rp_.n1_c.second = (*value_).size() - 1; + rp_.cache.second = rp_.n1_c.second; + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return ref(); + } + + char_cptr base() const + { + return &(*value_)[0]; + } + + std::size_t size() const + { + return ref().size(); + } + + std::string& ref() + { + return (*value_); + } + + const std::string& ref() const + { + return (*value_); + } + + range_t& range_ref() + { + return rp_; + } + + const range_t& range_ref() const + { + return rp_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringvar; + } + + private: + + std::string* value_; + mutable range_t rp_; + }; + + template + std::string stringvar_node::null_value = std::string(""); + + template + class string_range_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef range_pack range_t; + + static std::string null_value; + + explicit string_range_node(std::string& v, const range_t& rp) + : value_(&v), + rp_(rp) + {} + + virtual ~string_range_node() + { + rp_.free(); + } + + inline bool operator <(const string_range_node& v) const + { + return this < (&v); + } + + inline T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + inline std::string str() const + { + return (*value_); + } + + char_cptr base() const + { + return &(*value_)[0]; + } + + std::size_t size() const + { + return ref().size(); + } + + inline range_t range() const + { + return rp_; + } + + inline virtual std::string& ref() + { + return (*value_); + } + + inline virtual const std::string& ref() const + { + return (*value_); + } + + inline range_t& range_ref() + { + return rp_; + } + + inline const range_t& range_ref() const + { + return rp_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringvarrng; + } + + private: + + std::string* value_; + range_t rp_; + }; + + template + std::string string_range_node::null_value = std::string(""); + + template + class const_string_range_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef range_pack range_t; + + explicit const_string_range_node(const std::string& v, const range_t& rp) + : value_(v), + rp_(rp) + {} + + ~const_string_range_node() + { + rp_.free(); + } + + inline T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return value_; + } + + char_cptr base() const + { + return value_.data(); + } + + std::size_t size() const + { + return value_.size(); + } + + range_t range() const + { + return rp_; + } + + range_t& range_ref() + { + return rp_; + } + + const range_t& range_ref() const + { + return rp_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_cstringvarrng; + } + + private: + + const_string_range_node& operator=(const const_string_range_node&); + + const std::string value_; + range_t rp_; + }; + + template + class generic_string_range_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef std::pair branch_t; + + + generic_string_range_node(expression_ptr str_branch, const range_t& brange) + : initialised_(false), + str_base_ptr_ (0), + str_range_ptr_(0), + base_range_(brange) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + construct_branch_pair(branch_, str_branch); + + if (is_generally_string_node(branch_.first)) + { + str_base_ptr_ = dynamic_cast(branch_.first); + + if (0 == str_base_ptr_) + return; + + str_range_ptr_ = dynamic_cast(branch_.first); + + if (0 == str_range_ptr_) + return; + } + + initialised_ = (str_base_ptr_ && str_range_ptr_); + } + + ~generic_string_range_node() + { + base_range_.free(); + } + + inline T value() const + { + if (initialised_) + { + assert(branch_.first); + + branch_.first->value(); + + std::size_t str_r0 = 0; + std::size_t str_r1 = 0; + + std::size_t r0 = 0; + std::size_t r1 = 0; + + const range_t& range = str_range_ptr_->range_ref(); + + const std::size_t base_str_size = str_base_ptr_->size(); + + if ( + range (str_r0, str_r1, base_str_size) && + base_range_( r0, r1, base_str_size - str_r0) + ) + { + const std::size_t size = (r1 - r0) + 1; + + range_.n1_c.second = size - 1; + range_.cache.second = range_.n1_c.second; + + value_.assign(str_base_ptr_->base() + str_r0 + r0, size); + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return value_; + } + + char_cptr base() const + { + return &value_[0]; + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strgenrange; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bool initialised_; + branch_t branch_; + str_base_ptr str_base_ptr_; + irange_ptr str_range_ptr_; + mutable range_t base_range_; + mutable range_t range_; + mutable std::string value_; + }; + + template + class string_concat_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + string_concat_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + initialised_(false), + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_range_ptr_(0), + str1_range_ptr_(0) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_range_ptr_) + return; + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + str1_range_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_range_ptr_) + return; + } + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + std::size_t str0_r0 = 0; + std::size_t str0_r1 = 0; + + std::size_t str1_r0 = 0; + std::size_t str1_r1 = 0; + + const range_t& range0 = str0_range_ptr_->range_ref(); + const range_t& range1 = str1_range_ptr_->range_ref(); + + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size0 = (str0_r1 - str0_r0) + 1; + const std::size_t size1 = (str1_r1 - str1_r0) + 1; + + value_.assign(str0_base_ptr_->base() + str0_r0, size0); + value_.append(str1_base_ptr_->base() + str1_r0, size1); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return value_; + } + + char_cptr base() const + { + return &value_[0]; + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strconcat; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + irange_ptr str0_range_ptr_; + irange_ptr str1_range_ptr_; + mutable range_t range_; + mutable std::string value_; + }; + + template + class swap_string_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + swap_string_node(expression_ptr branch0, expression_ptr branch1) + : binary_node(details::e_swap, branch0, branch1), + initialised_(false), + str0_node_ptr_(0), + str1_node_ptr_(0) + { + if (is_string_node(binary_node::branch_[0].first)) + { + str0_node_ptr_ = static_cast(binary_node::branch_[0].first); + } + + if (is_string_node(binary_node::branch_[1].first)) + { + str1_node_ptr_ = static_cast(binary_node::branch_[1].first); + } + + initialised_ = (str0_node_ptr_ && str1_node_ptr_); + } + + inline T value() const + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return str0_node_ptr_->str(); + } + + char_cptr base() const + { + return str0_node_ptr_->base(); + } + + std::size_t size() const + { + return str0_node_ptr_->size(); + } + + range_t& range_ref() + { + return str0_node_ptr_->range_ref(); + } + + const range_t& range_ref() const + { + return str0_node_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strswap; + } + + private: + + bool initialised_; + strvar_node_ptr str0_node_ptr_; + strvar_node_ptr str1_node_ptr_; + }; + + template + class swap_genstrings_node exprtk_final : public binary_node + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + swap_genstrings_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node(details::e_default, branch0, branch1), + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_range_ptr_(0), + str1_range_ptr_(0), + initialised_(false) + { + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + + if (0 == range) + return; + + str0_range_ptr_ = &(range->range_ref()); + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + + if (0 == range) + return; + + str1_range_ptr_ = &(range->range_ref()); + } + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + std::size_t str0_r0 = 0; + std::size_t str0_r1 = 0; + + std::size_t str1_r0 = 0; + std::size_t str1_r1 = 0; + + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); + + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size0 = range0.cache_size(); + const std::size_t size1 = range1.cache_size(); + const std::size_t max_size = std::min(size0,size1); + + char_ptr s0 = const_cast(str0_base_ptr_->base() + str0_r0); + char_ptr s1 = const_cast(str1_base_ptr_->base() + str1_r0); + + loop_unroll::details lud(max_size); + char_cptr upper_bound = s0 + lud.upper_bound; + + while (s0 < upper_bound) + { + #define exprtk_loop(N) \ + std::swap(s0[N], s1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + s0 += lud.batch_size; + s1 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { std::swap(s0[i], s1[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + } + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strswap; + } + + private: + + swap_genstrings_node(swap_genstrings_node&); + swap_genstrings_node& operator=(swap_genstrings_node&); + + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + range_ptr str0_range_ptr_; + range_ptr str1_range_ptr_; + bool initialised_; + }; + + template + class stringvar_size_node exprtk_final : public expression_node + { + public: + + static std::string null_value; + + explicit stringvar_size_node() + : value_(&null_value) + {} + + explicit stringvar_size_node(std::string& v) + : value_(&v) + {} + + inline T value() const + { + return T((*value_).size()); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringvarsize; + } + + private: + + std::string* value_; + }; + + template + std::string stringvar_size_node::null_value = std::string(""); + + template + class string_size_node exprtk_final : public expression_node + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef std::pair branch_t; + + + explicit string_size_node(expression_ptr branch) + : str_base_ptr_(0) + { + construct_branch_pair(branch_, branch); + + if (is_generally_string_node(branch_.first)) + { + str_base_ptr_ = dynamic_cast(branch_.first); + + if (0 == str_base_ptr_) + return; + } + } + + inline T value() const + { + T result = std::numeric_limits::quiet_NaN(); + + if (str_base_ptr_) + { + branch_.first->value(); + result = T(str_base_ptr_->size()); + } + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringsize; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + branch_t branch_; + str_base_ptr str_base_ptr_; + }; + + struct asn_assignment + { + static inline void execute(std::string& s, char_cptr data, const std::size_t size) + { s.assign(data,size); } + }; + + struct asn_addassignment + { + static inline void execute(std::string& s, char_cptr data, const std::size_t size) + { s.append(data,size); } + }; + + template + class assignment_string_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + assignment_string_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + initialised_(false), + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_node_ptr_ (0), + str1_range_ptr_(0) + { + if (is_string_node(binary_node::branch_[0].first)) + { + str0_node_ptr_ = static_cast(binary_node::branch_[0].first); + + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + + if (0 == range) + return; + + str1_range_ptr_ = &(range->range_ref()); + } + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_node_ptr_ && + str1_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[1].first->value(); + + std::size_t r0 = 0; + std::size_t r1 = 0; + + const range_t& range = (*str1_range_ptr_); + + if (range(r0, r1, str1_base_ptr_->size())) + { + AssignmentProcess::execute(str0_node_ptr_->ref(), + str1_base_ptr_->base() + r0, + (r1 - r0) + 1); + + binary_node::branch_[0].first->value(); + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return str0_node_ptr_->str(); + } + + char_cptr base() const + { + return str0_node_ptr_->base(); + } + + std::size_t size() const + { + return str0_node_ptr_->size(); + } + + range_t& range_ref() + { + return str0_node_ptr_->range_ref(); + } + + const range_t& range_ref() const + { + return str0_node_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strass; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + strvar_node_ptr str0_node_ptr_; + range_ptr str1_range_ptr_; + }; + + template + class assignment_string_range_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_range_node* str_rng_node_ptr; + typedef string_base_node * str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + assignment_string_range_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + initialised_(false), + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_rng_node_ptr_ (0), + str0_range_ptr_ (0), + str1_range_ptr_ (0) + { + if (is_string_range_node(binary_node::branch_[0].first)) + { + str0_rng_node_ptr_ = static_cast(binary_node::branch_[0].first); + + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + + if (0 == range) + return; + + str0_range_ptr_ = &(range->range_ref()); + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + + if (0 == range) + return; + + str1_range_ptr_ = &(range->range_ref()); + } + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_rng_node_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + std::size_t s0_r0 = 0; + std::size_t s0_r1 = 0; + + std::size_t s1_r0 = 0; + std::size_t s1_r1 = 0; + + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); + + if ( + range0(s0_r0, s0_r1, str0_base_ptr_->size()) && + range1(s1_r0, s1_r1, str1_base_ptr_->size()) + ) + { + const std::size_t size = std::min((s0_r1 - s0_r0), (s1_r1 - s1_r0)) + 1; + + std::copy(str1_base_ptr_->base() + s1_r0, + str1_base_ptr_->base() + s1_r0 + size, + const_cast(base() + s0_r0)); + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return str0_base_ptr_->str(); + } + + char_cptr base() const + { + return str0_base_ptr_->base(); + } + + std::size_t size() const + { + return str0_base_ptr_->size(); + } + + range_t& range_ref() + { + return str0_rng_node_ptr_->range_ref(); + } + + const range_t& range_ref() const + { + return str0_rng_node_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strass; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + str_rng_node_ptr str0_rng_node_ptr_; + range_ptr str0_range_ptr_; + range_ptr str1_range_ptr_; + }; + + template + class conditional_string_node exprtk_final + : public trinary_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + conditional_string_node(expression_ptr condition, + expression_ptr consequent, + expression_ptr alternative) + : trinary_node(details::e_default,consequent,alternative,condition), + initialised_(false), + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_range_ptr_(0), + str1_range_ptr_(0), + condition_ (condition), + consequent_ (consequent), + alternative_(alternative) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(trinary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(trinary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(trinary_node::branch_[0].first); + + if (0 == str0_range_ptr_) + return; + } + + if (is_generally_string_node(trinary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(trinary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + str1_range_ptr_ = dynamic_cast(trinary_node::branch_[1].first); + + if (0 == str1_range_ptr_) + return; + } + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + + } + + inline T value() const + { + if (initialised_) + { + assert(condition_ ); + assert(consequent_ ); + assert(alternative_); + + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (is_true(condition_)) + { + consequent_->value(); + + const range_t& range = str0_range_ptr_->range_ref(); + + if (range(r0, r1, str0_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str0_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(1); + } + } + else + { + alternative_->value(); + + const range_t& range = str1_range_ptr_->range_ref(); + + if (range(r0, r1, str1_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str1_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(0); + } + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return value_; + } + + char_cptr base() const + { + return &value_[0]; + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strcondition; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + irange_ptr str0_range_ptr_; + irange_ptr str1_range_ptr_; + mutable range_t range_; + mutable std::string value_; + + expression_ptr condition_; + expression_ptr consequent_; + expression_ptr alternative_; + }; + + template + class cons_conditional_str_node exprtk_final + : public binary_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + cons_conditional_str_node(expression_ptr condition, + expression_ptr consequent) + : binary_node(details::e_default, consequent, condition), + initialised_(false), + str0_base_ptr_ (0), + str0_range_ptr_(0), + condition_ (condition), + consequent_(consequent) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_range_ptr_) + return; + } + + initialised_ = str0_base_ptr_ && str0_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) + { + assert(condition_ ); + assert(consequent_); + + if (is_true(condition_)) + { + consequent_->value(); + + const range_t& range = str0_range_ptr_->range_ref(); + + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (range(r0, r1, str0_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str0_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(1); + } + } + } + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return value_; + } + + char_cptr base() const + { + return &value_[0]; + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strccondition; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + irange_ptr str0_range_ptr_; + mutable range_t range_; + mutable std::string value_; + + expression_ptr condition_; + expression_ptr consequent_; + }; + + template + class str_vararg_node exprtk_final + : public expression_node , + public string_base_node, + public range_interface + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef std::pair branch_t; + + template class Sequence> + explicit str_vararg_node(const Sequence& arg_list) + : initialised_(false), + str_base_ptr_ (0), + str_range_ptr_(0) + { + construct_branch_pair(final_node_, const_cast(arg_list.back())); + + if (0 == final_node_.first) + return; + else if (!is_generally_string_node(final_node_.first)) + return; + + str_base_ptr_ = dynamic_cast(final_node_.first); + + if (0 == str_base_ptr_) + return; + + str_range_ptr_ = dynamic_cast(final_node_.first); + + if (0 == str_range_ptr_) + return; + + initialised_ = str_base_ptr_ && str_range_ptr_; + + if (arg_list.size() > 1) + { + const std::size_t arg_list_size = arg_list.size() - 1; + + arg_list_.resize(arg_list_size); + + for (std::size_t i = 0; i < arg_list_size; ++i) + { + if (arg_list[i]) + { + construct_branch_pair(arg_list_[i], arg_list[i]); + } + else + { + arg_list_.clear(); + return; + } + } + } + } + + inline T value() const + { + if (!arg_list_.empty()) + { + VarArgFunction::process(arg_list_); + } + + final_node_.first->value(); + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return str_base_ptr_->str(); + } + + char_cptr base() const + { + return str_base_ptr_->base(); + } + + std::size_t size() const + { + return str_base_ptr_->size(); + } + + range_t& range_ref() + { + return str_range_ptr_->range_ref(); + } + + const range_t& range_ref() const + { + return str_range_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringvararg; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(final_node_ , node_delete_list); + expression_node::ndb_t::collect(arg_list_ , node_delete_list); + } + + std::size_t node_depth() const + { + return std::max( + expression_node::ndb_t::compute_node_depth(final_node_), + expression_node::ndb_t::compute_node_depth(arg_list_ )); + } + + private: + + bool initialised_; + branch_t final_node_; + str_base_ptr str_base_ptr_; + irange_ptr str_range_ptr_; + std::vector arg_list_; + }; + #endif + + template + inline T axn(const T a, const T x) + { + // a*x^n + return a * exprtk::details::numeric::fast_exp::result(x); + } + + template + inline T axnb(const T a, const T x, const T b) + { + // a*x^n+b + return a * exprtk::details::numeric::fast_exp::result(x) + b; + } + + template + struct sf_base + { + typedef typename details::functor_t::Type Type; + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; + }; + + #define define_sfop3(NN,OP0,OP1) \ + template \ + struct sf##NN##_op : public sf_base \ + { \ + typedef typename sf_base::Type const Type; \ + static inline T process(Type x, Type y, Type z) \ + { \ + return (OP0); \ + } \ + static inline std::string id() \ + { \ + return (OP1); \ + } \ + }; \ + + define_sfop3(00,(x + y) / z ,"(t+t)/t") + define_sfop3(01,(x + y) * z ,"(t+t)*t") + define_sfop3(02,(x + y) - z ,"(t+t)-t") + define_sfop3(03,(x + y) + z ,"(t+t)+t") + define_sfop3(04,(x - y) + z ,"(t-t)+t") + define_sfop3(05,(x - y) / z ,"(t-t)/t") + define_sfop3(06,(x - y) * z ,"(t-t)*t") + define_sfop3(07,(x * y) + z ,"(t*t)+t") + define_sfop3(08,(x * y) - z ,"(t*t)-t") + define_sfop3(09,(x * y) / z ,"(t*t)/t") + define_sfop3(10,(x * y) * z ,"(t*t)*t") + define_sfop3(11,(x / y) + z ,"(t/t)+t") + define_sfop3(12,(x / y) - z ,"(t/t)-t") + define_sfop3(13,(x / y) / z ,"(t/t)/t") + define_sfop3(14,(x / y) * z ,"(t/t)*t") + define_sfop3(15,x / (y + z) ,"t/(t+t)") + define_sfop3(16,x / (y - z) ,"t/(t-t)") + define_sfop3(17,x / (y * z) ,"t/(t*t)") + define_sfop3(18,x / (y / z) ,"t/(t/t)") + define_sfop3(19,x * (y + z) ,"t*(t+t)") + define_sfop3(20,x * (y - z) ,"t*(t-t)") + define_sfop3(21,x * (y * z) ,"t*(t*t)") + define_sfop3(22,x * (y / z) ,"t*(t/t)") + define_sfop3(23,x - (y + z) ,"t-(t+t)") + define_sfop3(24,x - (y - z) ,"t-(t-t)") + define_sfop3(25,x - (y / z) ,"t-(t/t)") + define_sfop3(26,x - (y * z) ,"t-(t*t)") + define_sfop3(27,x + (y * z) ,"t+(t*t)") + define_sfop3(28,x + (y / z) ,"t+(t/t)") + define_sfop3(29,x + (y + z) ,"t+(t+t)") + define_sfop3(30,x + (y - z) ,"t+(t-t)") + define_sfop3(31,(axnb(x,y,z))," ") + define_sfop3(32,(axnb(x,y,z))," ") + define_sfop3(33,(axnb(x,y,z))," ") + define_sfop3(34,(axnb(x,y,z))," ") + define_sfop3(35,(axnb(x,y,z))," ") + define_sfop3(36,(axnb(x,y,z))," ") + define_sfop3(37,(axnb(x,y,z))," ") + define_sfop3(38,(axnb(x,y,z))," ") + define_sfop3(39,x * numeric::log(y) + z,"") + define_sfop3(40,x * numeric::log(y) - z,"") + define_sfop3(41,x * numeric::log10(y) + z,"") + define_sfop3(42,x * numeric::log10(y) - z,"") + define_sfop3(43,x * numeric::sin(y) + z ,"") + define_sfop3(44,x * numeric::sin(y) - z ,"") + define_sfop3(45,x * numeric::cos(y) + z ,"") + define_sfop3(46,x * numeric::cos(y) - z ,"") + define_sfop3(47,details::is_true(x) ? y : z,"") + + #define define_sfop4(NN,OP0,OP1) \ + template \ + struct sf##NN##_op : public sf_base \ + { \ + typedef typename sf_base::Type const Type; \ + static inline T process(Type x, Type y, Type z, Type w) \ + { \ + return (OP0); \ + } \ + static inline std::string id() \ + { \ + return (OP1); \ + } \ + }; \ + + define_sfop4(48,(x + ((y + z) / w)),"t+((t+t)/t)") + define_sfop4(49,(x + ((y + z) * w)),"t+((t+t)*t)") + define_sfop4(50,(x + ((y - z) / w)),"t+((t-t)/t)") + define_sfop4(51,(x + ((y - z) * w)),"t+((t-t)*t)") + define_sfop4(52,(x + ((y * z) / w)),"t+((t*t)/t)") + define_sfop4(53,(x + ((y * z) * w)),"t+((t*t)*t)") + define_sfop4(54,(x + ((y / z) + w)),"t+((t/t)+t)") + define_sfop4(55,(x + ((y / z) / w)),"t+((t/t)/t)") + define_sfop4(56,(x + ((y / z) * w)),"t+((t/t)*t)") + define_sfop4(57,(x - ((y + z) / w)),"t-((t+t)/t)") + define_sfop4(58,(x - ((y + z) * w)),"t-((t+t)*t)") + define_sfop4(59,(x - ((y - z) / w)),"t-((t-t)/t)") + define_sfop4(60,(x - ((y - z) * w)),"t-((t-t)*t)") + define_sfop4(61,(x - ((y * z) / w)),"t-((t*t)/t)") + define_sfop4(62,(x - ((y * z) * w)),"t-((t*t)*t)") + define_sfop4(63,(x - ((y / z) / w)),"t-((t/t)/t)") + define_sfop4(64,(x - ((y / z) * w)),"t-((t/t)*t)") + define_sfop4(65,(((x + y) * z) - w),"((t+t)*t)-t") + define_sfop4(66,(((x - y) * z) - w),"((t-t)*t)-t") + define_sfop4(67,(((x * y) * z) - w),"((t*t)*t)-t") + define_sfop4(68,(((x / y) * z) - w),"((t/t)*t)-t") + define_sfop4(69,(((x + y) / z) - w),"((t+t)/t)-t") + define_sfop4(70,(((x - y) / z) - w),"((t-t)/t)-t") + define_sfop4(71,(((x * y) / z) - w),"((t*t)/t)-t") + define_sfop4(72,(((x / y) / z) - w),"((t/t)/t)-t") + define_sfop4(73,((x * y) + (z * w)),"(t*t)+(t*t)") + define_sfop4(74,((x * y) - (z * w)),"(t*t)-(t*t)") + define_sfop4(75,((x * y) + (z / w)),"(t*t)+(t/t)") + define_sfop4(76,((x * y) - (z / w)),"(t*t)-(t/t)") + define_sfop4(77,((x / y) + (z / w)),"(t/t)+(t/t)") + define_sfop4(78,((x / y) - (z / w)),"(t/t)-(t/t)") + define_sfop4(79,((x / y) - (z * w)),"(t/t)-(t*t)") + define_sfop4(80,(x / (y + (z * w))),"t/(t+(t*t))") + define_sfop4(81,(x / (y - (z * w))),"t/(t-(t*t))") + define_sfop4(82,(x * (y + (z * w))),"t*(t+(t*t))") + define_sfop4(83,(x * (y - (z * w))),"t*(t-(t*t))") + + define_sfop4(84,(axn(x,y) + axn(z,w)),"") + define_sfop4(85,(axn(x,y) + axn(z,w)),"") + define_sfop4(86,(axn(x,y) + axn(z,w)),"") + define_sfop4(87,(axn(x,y) + axn(z,w)),"") + define_sfop4(88,(axn(x,y) + axn(z,w)),"") + define_sfop4(89,(axn(x,y) + axn(z,w)),"") + define_sfop4(90,(axn(x,y) + axn(z,w)),"") + define_sfop4(91,(axn(x,y) + axn(z,w)),"") + define_sfop4(92,((details::is_true(x) && details::is_true(y)) ? z : w),"") + define_sfop4(93,((details::is_true(x) || details::is_true(y)) ? z : w),"") + define_sfop4(94,((x < y) ? z : w),"") + define_sfop4(95,((x <= y) ? z : w),"") + define_sfop4(96,((x > y) ? z : w),"") + define_sfop4(97,((x >= y) ? z : w),"") + define_sfop4(98,(details::is_true(numeric::equal(x,y)) ? z : w),"") + define_sfop4(99,(x * numeric::sin(y) + z * numeric::cos(w)),"") + + define_sfop4(ext00,((x + y) - (z * w)),"(t+t)-(t*t)") + define_sfop4(ext01,((x + y) - (z / w)),"(t+t)-(t/t)") + define_sfop4(ext02,((x + y) + (z * w)),"(t+t)+(t*t)") + define_sfop4(ext03,((x + y) + (z / w)),"(t+t)+(t/t)") + define_sfop4(ext04,((x - y) + (z * w)),"(t-t)+(t*t)") + define_sfop4(ext05,((x - y) + (z / w)),"(t-t)+(t/t)") + define_sfop4(ext06,((x - y) - (z * w)),"(t-t)-(t*t)") + define_sfop4(ext07,((x - y) - (z / w)),"(t-t)-(t/t)") + define_sfop4(ext08,((x + y) - (z - w)),"(t+t)-(t-t)") + define_sfop4(ext09,((x + y) + (z - w)),"(t+t)+(t-t)") + define_sfop4(ext10,((x + y) + (z + w)),"(t+t)+(t+t)") + define_sfop4(ext11,((x + y) * (z - w)),"(t+t)*(t-t)") + define_sfop4(ext12,((x + y) / (z - w)),"(t+t)/(t-t)") + define_sfop4(ext13,((x - y) - (z + w)),"(t-t)-(t+t)") + define_sfop4(ext14,((x - y) + (z + w)),"(t-t)+(t+t)") + define_sfop4(ext15,((x - y) * (z + w)),"(t-t)*(t+t)") + define_sfop4(ext16,((x - y) / (z + w)),"(t-t)/(t+t)") + define_sfop4(ext17,((x * y) - (z + w)),"(t*t)-(t+t)") + define_sfop4(ext18,((x / y) - (z + w)),"(t/t)-(t+t)") + define_sfop4(ext19,((x * y) + (z + w)),"(t*t)+(t+t)") + define_sfop4(ext20,((x / y) + (z + w)),"(t/t)+(t+t)") + define_sfop4(ext21,((x * y) + (z - w)),"(t*t)+(t-t)") + define_sfop4(ext22,((x / y) + (z - w)),"(t/t)+(t-t)") + define_sfop4(ext23,((x * y) - (z - w)),"(t*t)-(t-t)") + define_sfop4(ext24,((x / y) - (z - w)),"(t/t)-(t-t)") + define_sfop4(ext25,((x + y) * (z * w)),"(t+t)*(t*t)") + define_sfop4(ext26,((x + y) * (z / w)),"(t+t)*(t/t)") + define_sfop4(ext27,((x + y) / (z * w)),"(t+t)/(t*t)") + define_sfop4(ext28,((x + y) / (z / w)),"(t+t)/(t/t)") + define_sfop4(ext29,((x - y) / (z * w)),"(t-t)/(t*t)") + define_sfop4(ext30,((x - y) / (z / w)),"(t-t)/(t/t)") + define_sfop4(ext31,((x - y) * (z * w)),"(t-t)*(t*t)") + define_sfop4(ext32,((x - y) * (z / w)),"(t-t)*(t/t)") + define_sfop4(ext33,((x * y) * (z + w)),"(t*t)*(t+t)") + define_sfop4(ext34,((x / y) * (z + w)),"(t/t)*(t+t)") + define_sfop4(ext35,((x * y) / (z + w)),"(t*t)/(t+t)") + define_sfop4(ext36,((x / y) / (z + w)),"(t/t)/(t+t)") + define_sfop4(ext37,((x * y) / (z - w)),"(t*t)/(t-t)") + define_sfop4(ext38,((x / y) / (z - w)),"(t/t)/(t-t)") + define_sfop4(ext39,((x * y) * (z - w)),"(t*t)*(t-t)") + define_sfop4(ext40,((x * y) / (z * w)),"(t*t)/(t*t)") + define_sfop4(ext41,((x / y) * (z / w)),"(t/t)*(t/t)") + define_sfop4(ext42,((x / y) * (z - w)),"(t/t)*(t-t)") + define_sfop4(ext43,((x * y) * (z * w)),"(t*t)*(t*t)") + define_sfop4(ext44,(x + (y * (z / w))),"t+(t*(t/t))") + define_sfop4(ext45,(x - (y * (z / w))),"t-(t*(t/t))") + define_sfop4(ext46,(x + (y / (z * w))),"t+(t/(t*t))") + define_sfop4(ext47,(x - (y / (z * w))),"t-(t/(t*t))") + define_sfop4(ext48,(((x - y) - z) * w),"((t-t)-t)*t") + define_sfop4(ext49,(((x - y) - z) / w),"((t-t)-t)/t") + define_sfop4(ext50,(((x - y) + z) * w),"((t-t)+t)*t") + define_sfop4(ext51,(((x - y) + z) / w),"((t-t)+t)/t") + define_sfop4(ext52,((x + (y - z)) * w),"(t+(t-t))*t") + define_sfop4(ext53,((x + (y - z)) / w),"(t+(t-t))/t") + define_sfop4(ext54,((x + y) / (z + w)),"(t+t)/(t+t)") + define_sfop4(ext55,((x - y) / (z - w)),"(t-t)/(t-t)") + define_sfop4(ext56,((x + y) * (z + w)),"(t+t)*(t+t)") + define_sfop4(ext57,((x - y) * (z - w)),"(t-t)*(t-t)") + define_sfop4(ext58,((x - y) + (z - w)),"(t-t)+(t-t)") + define_sfop4(ext59,((x - y) - (z - w)),"(t-t)-(t-t)") + define_sfop4(ext60,((x / y) + (z * w)),"(t/t)+(t*t)") + define_sfop4(ext61,(((x * y) * z) / w),"((t*t)*t)/t") + + #undef define_sfop3 + #undef define_sfop4 + + template + class sf3_node exprtk_final : public trinary_node + { + public: + + typedef expression_node* expression_ptr; + + sf3_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1, + expression_ptr branch2) + : trinary_node(opr, branch0, branch1, branch2) + {} + + inline T value() const + { + assert(trinary_node::branch_[0].first); + assert(trinary_node::branch_[1].first); + assert(trinary_node::branch_[2].first); + + const T x = trinary_node::branch_[0].first->value(); + const T y = trinary_node::branch_[1].first->value(); + const T z = trinary_node::branch_[2].first->value(); + + return SpecialFunction::process(x, y, z); + } + }; + + template + class sf4_node exprtk_final : public quaternary_node + { + public: + + typedef expression_node* expression_ptr; + + sf4_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1, + expression_ptr branch2, + expression_ptr branch3) + : quaternary_node(opr, branch0, branch1, branch2, branch3) + {} + + inline T value() const + { + assert(quaternary_node::branch_[0].first); + assert(quaternary_node::branch_[1].first); + assert(quaternary_node::branch_[2].first); + assert(quaternary_node::branch_[3].first); + + const T x = quaternary_node::branch_[0].first->value(); + const T y = quaternary_node::branch_[1].first->value(); + const T z = quaternary_node::branch_[2].first->value(); + const T w = quaternary_node::branch_[3].first->value(); + + return SpecialFunction::process(x, y, z, w); + } + }; + + template + class sf3_var_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + sf3_var_node(const T& v0, const T& v1, const T& v2) + : v0_(v0), + v1_(v1), + v2_(v2) + {} + + inline T value() const + { + return SpecialFunction::process(v0_, v1_, v2_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_trinary; + } + + private: + + sf3_var_node(sf3_var_node&); + sf3_var_node& operator=(sf3_var_node&); + + const T& v0_; + const T& v1_; + const T& v2_; + }; + + template + class sf4_var_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3) + : v0_(v0), + v1_(v1), + v2_(v2), + v3_(v3) + {} + + inline T value() const + { + return SpecialFunction::process(v0_, v1_, v2_, v3_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_trinary; + } + + private: + + sf4_var_node(sf4_var_node&); + sf4_var_node& operator=(sf4_var_node&); + + const T& v0_; + const T& v1_; + const T& v2_; + const T& v3_; + }; + + template + class vararg_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + template class Sequence> + explicit vararg_node(const Sequence& arg_list) + { + arg_list_.resize(arg_list.size()); + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (arg_list[i]) + { + construct_branch_pair(arg_list_[i],arg_list[i]); + } + else + { + arg_list_.clear(); + return; + } + } + } + + inline T value() const + { + return VarArgFunction::process(arg_list_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vararg; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + + private: + + std::vector arg_list_; + }; + + template + class vararg_varnode exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + template class Sequence> + explicit vararg_varnode(const Sequence& arg_list) + { + arg_list_.resize(arg_list.size()); + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (arg_list[i] && is_variable_node(arg_list[i])) + { + variable_node* var_node_ptr = static_cast*>(arg_list[i]); + arg_list_[i] = (&var_node_ptr->ref()); + } + else + { + arg_list_.clear(); + return; + } + } + } + + inline T value() const + { + if (!arg_list_.empty()) + return VarArgFunction::process(arg_list_); + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vararg; + } + + private: + + std::vector arg_list_; + }; + + template + class vectorize_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + explicit vectorize_node(const expression_ptr v) + : ivec_ptr_(0) + { + construct_branch_pair(v_, v); + + if (is_ivector_node(v_.first)) + { + ivec_ptr_ = dynamic_cast*>(v_.first); + } + else + ivec_ptr_ = 0; + } + + inline T value() const + { + if (ivec_ptr_) + { + assert(v_.first); + + v_.first->value(); + + return VecFunction::process(ivec_ptr_); + } + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecfunc; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(v_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(v_); + } + + private: + + vector_interface* ivec_ptr_; + branch_t v_; + }; + + template + class assignment_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + var_node_ptr_(0) + { + if (is_variable_node(binary_node::branch_[0].first)) + { + var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const + { + if (var_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& result = var_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + variable_node* var_node_ptr_; + }; + + template + class assignment_vec_elem_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_vec_elem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec_node_ptr_(0) + { + if (is_vector_elem_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const + { + if (vec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& result = vec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_elem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const + { + if (rbvec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& result = rbvec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_celem_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_celem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + rbvec_node_ptr_(0) + { + if (is_rebasevector_celem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const + { + if (rbvec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& result = rbvec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_celem_node* rbvec_node_ptr_; + }; + + template + class assignment_vec_node exprtk_final + : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec_node_ptr_(0) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec_node_ptr_->vds(); + } + } + + inline T value() const + { + if (vec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + const T v = binary_node::branch_[1].first->value(); + + T* vec = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + vec[N] = v; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; + } + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : *vec++ = v; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return vec_node_ptr_->value(); + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return vec_node_ptr_; + } + + vector_node_ptr vec() + { + return vec_node_ptr_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecvalass; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node* vec_node_ptr_; + vds_t vds_; + }; + + template + class assignment_vecvec_node exprtk_final + : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vecvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec0_node_ptr_(0), + vec1_node_ptr_(0), + initialised_(false), + src_is_ivec_(false) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec0_node_ptr_->vds(); + } + + if (is_vector_node(binary_node::branch_[1].first)) + { + vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); + } + else if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + + if (!vi->side_effect()) + { + vi->vds() = vds(); + src_is_ivec_ = true; + } + else + vds_t::match_sizes(vds(),vi->vds()); + } + } + + initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + } + + inline T value() const + { + if (initialised_) + { + assert(binary_node::branch_[1].first); + + binary_node::branch_[1].first->value(); + + if (src_is_ivec_) + return vec0_node_ptr_->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec0[N] = vec1[N]; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : *vec0++ = *vec1++; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return vec0_node_ptr_->value(); + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() + { + return vec0_node_ptr_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecvecass; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + bool initialised_; + bool src_is_ivec_; + vds_t vds_; + }; + + template + class assignment_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + var_node_ptr_(0) + { + if (is_variable_node(binary_node::branch_[0].first)) + { + var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const + { + if (var_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& v = var_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + variable_node* var_node_ptr_; + }; + + template + class assignment_vec_elem_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_vec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec_node_ptr_(0) + { + if (is_vector_elem_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const + { + if (vec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& v = vec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const + { + if (rbvec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_celem_op_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_celem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + rbvec_node_ptr_(0) + { + if (is_rebasevector_celem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const + { + if (rbvec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_celem_node* rbvec_node_ptr_; + }; + + template + class assignment_vec_op_node exprtk_final + : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vec_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec_node_ptr_(0) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec_node_ptr_->vds(); + } + } + + inline T value() const + { + if (vec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + const T v = binary_node::branch_[1].first->value(); + + T* vec = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + Operation::assign(vec[N],v); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; + } + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : Operation::assign(*vec++,v); \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + + #undef exprtk_loop + #undef case_stmt + + return vec_node_ptr_->value(); + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return vec_node_ptr_; + } + + vector_node_ptr vec() + { + return vec_node_ptr_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecopvalass; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + bool side_effect() const + { + return true; + } + + private: + + vector_node* vec_node_ptr_; + vds_t vds_; + }; + + template + class assignment_vecvec_op_node exprtk_final + : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vecvec_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec0_node_ptr_(0), + vec1_node_ptr_(0), + initialised_(false) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec0_node_ptr_->vds(); + } + + if (is_vector_node(binary_node::branch_[1].first)) + { + vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vec1_node_ptr_->vds() = vds(); + } + else if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + vec1_node_ptr_->vds() = vds(); + } + else + vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); + } + + initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + } + + inline T value() const + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec0[N] = Operation::process(vec0[N], vec1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec0[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return vec0_node_ptr_->value(); + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() + { + return vec0_node_ptr_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecopvecass; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + bool side_effect() const + { + return true; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + bool initialised_; + vds_t vds_; + }; + + template + class vec_binop_vecvec_node exprtk_final + : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + vec_binop_vecvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec0_node_ptr_(0), + vec1_node_ptr_(0), + temp_ (0), + temp_vec_node_(0), + initialised_(false) + { + bool v0_is_ivec = false; + bool v1_is_ivec = false; + + if (is_vector_node(binary_node::branch_[0].first)) + { + vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); + } + else if (is_ivector_node(binary_node::branch_[0].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + { + vec0_node_ptr_ = vi->vec(); + v0_is_ivec = true; + } + } + + if (is_vector_node(binary_node::branch_[1].first)) + { + vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); + } + else if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + v1_is_ivec = true; + } + } + + if (vec0_node_ptr_ && vec1_node_ptr_) + { + vector_holder& vec0 = vec0_node_ptr_->vec_holder(); + vector_holder& vec1 = vec1_node_ptr_->vec_holder(); + + if (v0_is_ivec && (vec0.size() <= vec1.size())) + vds_ = vds_t(vec0_node_ptr_->vds()); + else if (v1_is_ivec && (vec1.size() <= vec0.size())) + vds_ = vds_t(vec1_node_ptr_->vds()); + else + vds_ = vds_t(std::min(vec0.size(),vec1.size())); + + temp_ = new vector_holder(vds().data(),vds().size()); + temp_vec_node_ = new vector_node (vds(),temp_); + + initialised_ = true; + } + } + + ~vec_binop_vecvec_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const + { + if (initialised_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + const T* vec0 = vec0_node_ptr_->vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); + T* vec2 = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec2 + lud.upper_bound; + + while (vec2 < upper_bound) + { + #define exprtk_loop(N) \ + vec2[N] = Operation::process(vec0[N], vec1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + vec2 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return temp_vec_node_; + } + + vector_node_ptr vec() + { + return temp_vec_node_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecvecarith; + } + + std::size_t size() const + { + return vds_.size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node_ptr vec0_node_ptr_; + vector_node_ptr vec1_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + bool initialised_; + vds_t vds_; + }; + + template + class vec_binop_vecval_node exprtk_final + : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + vec_binop_vecval_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec0_node_ptr_(0), + temp_ (0), + temp_vec_node_(0) + { + bool v0_is_ivec = false; + + if (is_vector_node(binary_node::branch_[0].first)) + { + vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); + } + else if (is_ivector_node(binary_node::branch_[0].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + { + vec0_node_ptr_ = vi->vec(); + v0_is_ivec = true; + } + } + + if (vec0_node_ptr_) + { + if (v0_is_ivec) + vds() = vec0_node_ptr_->vds(); + else + vds() = vds_t(vec0_node_ptr_->size()); + + temp_ = new vector_holder(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); + } + } + + ~vec_binop_vecval_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const + { + if (vec0_node_ptr_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + binary_node::branch_[0].first->value(); + const T v = binary_node::branch_[1].first->value(); + + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N], v); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return temp_vec_node_; + } + + vector_node_ptr vec() + { + return temp_vec_node_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecvalarith; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node_ptr vec0_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + vds_t vds_; + }; + + template + class vec_binop_valvec_node exprtk_final + : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + vec_binop_valvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec1_node_ptr_(0), + temp_ (0), + temp_vec_node_(0) + { + bool v1_is_ivec = false; + + if (is_vector_node(binary_node::branch_[1].first)) + { + vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); + } + else if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + v1_is_ivec = true; + } + } + + if (vec1_node_ptr_) + { + if (v1_is_ivec) + vds() = vec1_node_ptr_->vds(); + else + vds() = vds_t(vec1_node_ptr_->size()); + + temp_ = new vector_holder(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); + } + } + + ~vec_binop_valvec_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const + { + if (vec1_node_ptr_) + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + const T v = binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + T* vec0 = vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec0[N] = Operation::process(v, vec1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return temp_vec_node_; + } + + vector_node_ptr vec() + { + return temp_vec_node_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecvalarith; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node_ptr vec1_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + vds_t vds_; + }; + + template + class unary_vector_node exprtk_final + : public unary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + unary_vector_node(const operator_type& opr, expression_ptr branch0) + : unary_node(opr, branch0), + vec0_node_ptr_(0), + temp_ (0), + temp_vec_node_(0) + { + bool vec0_is_ivec = false; + + if (is_vector_node(unary_node::branch_.first)) + { + vec0_node_ptr_ = static_cast(unary_node::branch_.first); + } + else if (is_ivector_node(unary_node::branch_.first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(unary_node::branch_.first))) + { + vec0_node_ptr_ = vi->vec(); + vec0_is_ivec = true; + } + } + + if (vec0_node_ptr_) + { + if (vec0_is_ivec) + vds_ = vec0_node_ptr_->vds(); + else + vds_ = vds_t(vec0_node_ptr_->size()); + + temp_ = new vector_holder(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); + } + } + + ~unary_vector_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const + { + assert(unary_node::branch_.first); + + unary_node::branch_.first->value(); + + if (vec0_node_ptr_) + { + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return temp_vec_node_; + } + + vector_node_ptr vec() + { + return temp_vec_node_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecunaryop; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node_ptr vec0_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + vds_t vds_; + }; + + template + class scand_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + scand_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + {} + + inline T value() const + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + return ( + std::not_equal_to() + (T(0),binary_node::branch_[0].first->value()) && + std::not_equal_to() + (T(0),binary_node::branch_[1].first->value()) + ) ? T(1) : T(0); + } + }; + + template + class scor_node exprtk_final : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + scor_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1) + {} + + inline T value() const + { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + return ( + std::not_equal_to() + (T(0),binary_node::branch_[0].first->value()) || + std::not_equal_to() + (T(0),binary_node::branch_[1].first->value()) + ) ? T(1) : T(0); + } + }; + + template + class function_N_node exprtk_final : public expression_node + { + public: + + // Function of N paramters. + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef IFunction ifunction; + + explicit function_N_node(ifunction* func) + : function_((N == func->param_count) ? func : reinterpret_cast(0)), + parameter_count_(func->param_count) + {} + + template + bool init_branches(expression_ptr (&b)[NumBranches]) + { + // Needed for incompetent and broken msvc compiler versions + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + if (N != NumBranches) + return false; + else + { + for (std::size_t i = 0; i < NumBranches; ++i) + { + if (b[i]) + branch_[i] = std::make_pair(b[i],branch_deletable(b[i])); + else + return false; + } + return true; + } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + } + + inline bool operator <(const function_N_node& fn) const + { + return this < (&fn); + } + + inline T value() const + { + // Needed for incompetent and broken msvc compiler versions + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + if ((0 == function_) || (0 == N)) + return std::numeric_limits::quiet_NaN(); + else + { + T v[N]; + evaluate_branches::execute(v,branch_); + return invoke::execute(*function_,v); + } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_function; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::template compute_node_depth(branch_); + } + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[BranchCount], const branch_t (&b)[BranchCount]) + { + for (std::size_t i = 0; i < BranchCount; ++i) + { + v[i] = b[i].first->value(); + } + } + }; + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[5], const branch_t (&b)[5]) + { + v[0] = b[0].first->value(); + v[1] = b[1].first->value(); + v[2] = b[2].first->value(); + v[3] = b[3].first->value(); + v[4] = b[4].first->value(); + } + }; + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[4], const branch_t (&b)[4]) + { + v[0] = b[0].first->value(); + v[1] = b[1].first->value(); + v[2] = b[2].first->value(); + v[3] = b[3].first->value(); + } + }; + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[3], const branch_t (&b)[3]) + { + v[0] = b[0].first->value(); + v[1] = b[1].first->value(); + v[2] = b[2].first->value(); + } + }; + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[2], const branch_t (&b)[2]) + { + v[0] = b[0].first->value(); + v[1] = b[1].first->value(); + } + }; + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[1], const branch_t (&b)[1]) + { + v[0] = b[0].first->value(); + } + }; + + template + struct invoke { static inline T execute(ifunction&, branch_t (&)[ParamCount]) { return std::numeric_limits::quiet_NaN(); } }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[20]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18],v[19]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[19]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[18]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[17]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[16]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[15]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[14]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[13]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[12]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[11]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[10]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[9]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[8]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[7]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[6]) + { return f(v[0],v[1],v[2],v[3],v[4],v[5]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[5]) + { return f(v[0],v[1],v[2],v[3],v[4]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[4]) + { return f(v[0],v[1],v[2],v[3]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[3]) + { return f(v[0],v[1],v[2]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[2]) + { return f(v[0],v[1]); } + }; + + template + struct invoke + { + static inline T_ execute(ifunction& f, T_ (&v)[1]) + { return f(v[0]); } + }; + + private: + + ifunction* function_; + std::size_t parameter_count_; + branch_t branch_[N]; + }; + + template + class function_N_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef IFunction ifunction; + + explicit function_N_node(ifunction* func) + : function_((0 == func->param_count) ? func : reinterpret_cast(0)) + {} + + inline bool operator <(const function_N_node& fn) const + { + return this < (&fn); + } + + inline T value() const + { + if (function_) + return (*function_)(); + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_function; + } + + private: + + ifunction* function_; + }; + + template + class vararg_function_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vararg_function_node(VarArgFunction* func, + const std::vector& arg_list) + : function_(func), + arg_list_(arg_list) + { + value_list_.resize(arg_list.size(),std::numeric_limits::quiet_NaN()); + } + + inline bool operator <(const vararg_function_node& fn) const + { + return this < (&fn); + } + + inline T value() const + { + if (function_) + { + populate_value_list(); + return (*function_)(value_list_); + } + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vafunction; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + for (std::size_t i = 0; i < arg_list_.size(); ++i) + { + if (arg_list_[i] && !details::is_variable_node(arg_list_[i])) + { + node_delete_list.push_back(&arg_list_[i]); + } + } + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + + private: + + inline void populate_value_list() const + { + for (std::size_t i = 0; i < arg_list_.size(); ++i) + { + value_list_[i] = arg_list_[i]->value(); + } + } + + VarArgFunction* function_; + std::vector arg_list_; + mutable std::vector value_list_; + }; + + template + class generic_function_node : public expression_node + { + public: + + typedef type_store type_store_t; + typedef expression_node* expression_ptr; + typedef variable_node variable_node_t; + typedef vector_node vector_node_t; + typedef variable_node_t* variable_node_ptr_t; + typedef vector_node_t* vector_node_ptr_t; + typedef range_interface range_interface_t; + typedef range_data_type range_data_type_t; + typedef range_pack range_t; + typedef std::pair branch_t; + typedef std::pair void_t; + typedef std::vector tmp_vs_t; + typedef std::vector typestore_list_t; + typedef std::vector range_list_t; + + explicit generic_function_node(const std::vector& arg_list, + GenericFunction* func = reinterpret_cast(0)) + : function_(func), + arg_list_(arg_list) + {} + + virtual ~generic_function_node() + {} + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const exprtk_final + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + virtual bool init_branches() + { + expr_as_vec1_store_.resize(arg_list_.size(),T(0) ); + typestore_list_ .resize(arg_list_.size(),type_store_t() ); + range_list_ .resize(arg_list_.size(),range_data_type_t()); + branch_ .resize(arg_list_.size(),branch_t(reinterpret_cast(0),false)); + + for (std::size_t i = 0; i < arg_list_.size(); ++i) + { + type_store_t& ts = typestore_list_[i]; + + if (0 == arg_list_[i]) + return false; + else if (is_ivector_node(arg_list_[i])) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 == (vi = dynamic_cast*>(arg_list_[i]))) + return false; + + ts.size = vi->size(); + ts.data = vi->vds().data(); + ts.type = type_store_t::e_vector; + vi->vec()->vec_holder().set_ref(&ts.vec_data); + } + #ifndef exprtk_disable_string_capabilities + else if (is_generally_string_node(arg_list_[i])) + { + string_base_node* sbn = reinterpret_cast*>(0); + + if (0 == (sbn = dynamic_cast*>(arg_list_[i]))) + return false; + + ts.size = sbn->size(); + ts.data = reinterpret_cast(const_cast(sbn->base())); + ts.type = type_store_t::e_string; + + range_list_[i].data = ts.data; + range_list_[i].size = ts.size; + range_list_[i].type_size = sizeof(char); + range_list_[i].str_node = sbn; + + range_interface_t* ri = reinterpret_cast(0); + + if (0 == (ri = dynamic_cast(arg_list_[i]))) + return false; + + const range_t& rp = ri->range_ref(); + + if ( + rp.const_range() && + is_const_string_range_node(arg_list_[i]) + ) + { + ts.size = rp.const_size(); + ts.data = static_cast(ts.data) + rp.n0_c.second; + range_list_[i].range = reinterpret_cast(0); + } + else + range_list_[i].range = &(ri->range_ref()); + } + #endif + else if (is_variable_node(arg_list_[i])) + { + variable_node_ptr_t var = variable_node_ptr_t(0); + + if (0 == (var = dynamic_cast(arg_list_[i]))) + return false; + + ts.size = 1; + ts.data = &var->ref(); + ts.type = type_store_t::e_scalar; + } + else + { + ts.size = 1; + ts.data = reinterpret_cast(&expr_as_vec1_store_[i]); + ts.type = type_store_t::e_scalar; + } + + branch_[i] = std::make_pair(arg_list_[i],branch_deletable(arg_list_[i])); + } + + return true; + } + + inline bool operator <(const generic_function_node& fn) const + { + return this < (&fn); + } + + inline T value() const + { + if (function_) + { + if (populate_value_list()) + { + typedef typename GenericFunction::parameter_list_t parameter_list_t; + + return (*function_)(parameter_list_t(typestore_list_)); + } + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_genfunction; + } + + protected: + + inline virtual bool populate_value_list() const + { + for (std::size_t i = 0; i < branch_.size(); ++i) + { + expr_as_vec1_store_[i] = branch_[i].first->value(); + } + + for (std::size_t i = 0; i < branch_.size(); ++i) + { + range_data_type_t& rdt = range_list_[i]; + + if (rdt.range) + { + const range_t& rp = (*rdt.range); + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (rp(r0, r1, rdt.size)) + { + type_store_t& ts = typestore_list_[i]; + + ts.size = rp.cache_size(); + #ifndef exprtk_disable_string_capabilities + if (ts.type == type_store_t::e_string) + ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; + else + #endif + ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); + } + else + return false; + } + } + + return true; + } + + GenericFunction* function_; + mutable typestore_list_t typestore_list_; + + private: + + std::vector arg_list_; + std::vector branch_; + mutable tmp_vs_t expr_as_vec1_store_; + mutable range_list_t range_list_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class string_function_node : public generic_function_node, + public string_base_node, + public range_interface + { + public: + + typedef generic_function_node gen_function_t; + typedef range_pack range_t; + + string_function_node(StringFunction* func, + const std::vector& arg_list) + : gen_function_t(arg_list,func) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + } + + inline bool operator <(const string_function_node& fn) const + { + return this < (&fn); + } + + inline T value() const + { + if (gen_function_t::function_) + { + if (gen_function_t::populate_value_list()) + { + typedef typename StringFunction::parameter_list_t parameter_list_t; + + const T result = (*gen_function_t::function_) + ( + ret_string_, + parameter_list_t(gen_function_t::typestore_list_) + ); + + range_.n1_c.second = ret_string_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return result; + } + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strfunction; + } + + std::string str() const + { + return ret_string_; + } + + char_cptr base() const + { + return &ret_string_[0]; + } + + std::size_t size() const + { + return ret_string_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; + } + + protected: + + mutable range_t range_; + mutable std::string ret_string_; + }; + #endif + + template + class multimode_genfunction_node : public generic_function_node + { + public: + + typedef generic_function_node gen_function_t; + typedef range_pack range_t; + + multimode_genfunction_node(GenericFunction* func, + const std::size_t& param_seq_index, + const std::vector& arg_list) + : gen_function_t(arg_list,func), + param_seq_index_(param_seq_index) + {} + + inline T value() const + { + if (gen_function_t::function_) + { + if (gen_function_t::populate_value_list()) + { + typedef typename GenericFunction::parameter_list_t parameter_list_t; + + return (*gen_function_t::function_) + ( + param_seq_index_, + parameter_list_t(gen_function_t::typestore_list_) + ); + } + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const exprtk_final + { + return expression_node::e_genfunction; + } + + private: + + std::size_t param_seq_index_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class multimode_strfunction_node exprtk_final : public string_function_node + { + public: + + typedef string_function_node str_function_t; + typedef range_pack range_t; + + multimode_strfunction_node(StringFunction* func, + const std::size_t& param_seq_index, + const std::vector& arg_list) + : str_function_t(func,arg_list), + param_seq_index_(param_seq_index) + {} + + inline T value() const + { + if (str_function_t::function_) + { + if (str_function_t::populate_value_list()) + { + typedef typename StringFunction::parameter_list_t parameter_list_t; + + const T result = (*str_function_t::function_) + ( + param_seq_index_, + str_function_t::ret_string_, + parameter_list_t(str_function_t::typestore_list_) + ); + + str_function_t::range_.n1_c.second = str_function_t::ret_string_.size() - 1; + str_function_t::range_.cache.second = str_function_t::range_.n1_c.second; + + return result; + } + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strfunction; + } + + private: + + const std::size_t param_seq_index_; + }; + #endif + + class return_exception + {}; + + template + class null_igenfunc + { + public: + + virtual ~null_igenfunc() + {} + + typedef type_store generic_type; + typedef typename generic_type::parameter_list parameter_list_t; + + inline virtual T operator() (parameter_list_t) + { + return std::numeric_limits::quiet_NaN(); + } + }; + + #ifndef exprtk_disable_return_statement + template + class return_node exprtk_final : public generic_function_node > + { + public: + + typedef null_igenfunc igeneric_function_t; + typedef igeneric_function_t* igeneric_function_ptr; + typedef generic_function_node gen_function_t; + typedef results_context results_context_t; + + return_node(const std::vector& arg_list, + results_context_t& rc) + : gen_function_t (arg_list), + results_context_(&rc) + {} + + inline T value() const + { + if ( + (0 != results_context_) && + gen_function_t::populate_value_list() + ) + { + typedef typename type_store::parameter_list parameter_list_t; + + results_context_-> + assign(parameter_list_t(gen_function_t::typestore_list_)); + + throw return_exception(); + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_return; + } + + private: + + results_context_t* results_context_; + }; + + template + class return_envelope_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef results_context results_context_t; + typedef std::pair branch_t; + + return_envelope_node(expression_ptr body, results_context_t& rc) + : results_context_(&rc ), + return_invoked_ (false) + { + construct_branch_pair(body_, body); + } + + inline T value() const + { + assert(body_.first); + + try + { + return_invoked_ = false; + results_context_->clear(); + + return body_.first->value(); + } + catch(const return_exception&) + { + return_invoked_ = true; + return std::numeric_limits::quiet_NaN(); + } + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_retenv; + } + + inline bool* retinvk_ptr() + { + return &return_invoked_; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(body_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(body_); + } + + private: + + results_context_t* results_context_; + mutable bool return_invoked_; + branch_t body_; + }; + #endif + + #define exprtk_define_unary_op(OpName) \ + template \ + struct OpName##_op \ + { \ + typedef typename functor_t::Type Type; \ + typedef typename expression_node::node_type node_t; \ + \ + static inline T process(Type v) \ + { \ + return numeric:: OpName (v); \ + } \ + \ + static inline node_t type() \ + { \ + return expression_node::e_##OpName; \ + } \ + \ + static inline details::operator_type operation() \ + { \ + return details::e_##OpName; \ + } \ + }; \ + + exprtk_define_unary_op(abs ) + exprtk_define_unary_op(acos ) + exprtk_define_unary_op(acosh) + exprtk_define_unary_op(asin ) + exprtk_define_unary_op(asinh) + exprtk_define_unary_op(atan ) + exprtk_define_unary_op(atanh) + exprtk_define_unary_op(ceil ) + exprtk_define_unary_op(cos ) + exprtk_define_unary_op(cosh ) + exprtk_define_unary_op(cot ) + exprtk_define_unary_op(csc ) + exprtk_define_unary_op(d2g ) + exprtk_define_unary_op(d2r ) + exprtk_define_unary_op(erf ) + exprtk_define_unary_op(erfc ) + exprtk_define_unary_op(exp ) + exprtk_define_unary_op(expm1) + exprtk_define_unary_op(floor) + exprtk_define_unary_op(frac ) + exprtk_define_unary_op(g2d ) + exprtk_define_unary_op(log ) + exprtk_define_unary_op(log10) + exprtk_define_unary_op(log2 ) + exprtk_define_unary_op(log1p) + exprtk_define_unary_op(ncdf ) + exprtk_define_unary_op(neg ) + exprtk_define_unary_op(notl ) + exprtk_define_unary_op(pos ) + exprtk_define_unary_op(r2d ) + exprtk_define_unary_op(round) + exprtk_define_unary_op(sec ) + exprtk_define_unary_op(sgn ) + exprtk_define_unary_op(sin ) + exprtk_define_unary_op(sinc ) + exprtk_define_unary_op(sinh ) + exprtk_define_unary_op(sqrt ) + exprtk_define_unary_op(tan ) + exprtk_define_unary_op(tanh ) + exprtk_define_unary_op(trunc) + #undef exprtk_define_unary_op + + template + struct opr_base + { + typedef typename details::functor_t::Type Type; + typedef typename details::functor_t::RefType RefType; + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; + }; + + template + struct add_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + + static inline T process(Type t1, Type t2) { return t1 + t2; } + static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; } + static inline void assign(RefType t1, Type t2) { t1 += t2; } + static inline typename expression_node::node_type type() { return expression_node::e_add; } + static inline details::operator_type operation() { return details::e_add; } + }; + + template + struct mul_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + + static inline T process(Type t1, Type t2) { return t1 * t2; } + static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; } + static inline void assign(RefType t1, Type t2) { t1 *= t2; } + static inline typename expression_node::node_type type() { return expression_node::e_mul; } + static inline details::operator_type operation() { return details::e_mul; } + }; + + template + struct sub_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + + static inline T process(Type t1, Type t2) { return t1 - t2; } + static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; } + static inline void assign(RefType t1, Type t2) { t1 -= t2; } + static inline typename expression_node::node_type type() { return expression_node::e_sub; } + static inline details::operator_type operation() { return details::e_sub; } + }; + + template + struct div_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + + static inline T process(Type t1, Type t2) { return t1 / t2; } + static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; } + static inline void assign(RefType t1, Type t2) { t1 /= t2; } + static inline typename expression_node::node_type type() { return expression_node::e_div; } + static inline details::operator_type operation() { return details::e_div; } + }; + + template + struct mod_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + + static inline T process(Type t1, Type t2) { return numeric::modulus(t1,t2); } + static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_mod; } + static inline details::operator_type operation() { return details::e_mod; } + }; + + template + struct pow_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + + static inline T process(Type t1, Type t2) { return numeric::pow(t1,t2); } + static inline void assign(RefType t1, Type t2) { t1 = numeric::pow(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_pow; } + static inline details::operator_type operation() { return details::e_pow; } + }; + + template + struct lt_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return ((t1 < t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_lt; } + static inline details::operator_type operation() { return details::e_lt; } + }; + + template + struct lte_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return ((t1 <= t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_lte; } + static inline details::operator_type operation() { return details::e_lte; } + }; + + template + struct gt_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return ((t1 > t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_gt; } + static inline details::operator_type operation() { return details::e_gt; } + }; + + template + struct gte_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return ((t1 >= t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_gte; } + static inline details::operator_type operation() { return details::e_gte; } + }; + + template + struct eq_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (std::equal_to()(t1,t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_eq; } + static inline details::operator_type operation() { return details::e_eq; } + }; + + template + struct equal_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return numeric::equal(t1,t2); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_eq; } + static inline details::operator_type operation() { return details::e_equal; } + }; + + template + struct ne_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return (std::not_equal_to()(t1,t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_ne; } + static inline details::operator_type operation() { return details::e_ne; } + }; + + template + struct and_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); } + static inline typename expression_node::node_type type() { return expression_node::e_and; } + static inline details::operator_type operation() { return details::e_and; } + }; + + template + struct nand_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); } + static inline typename expression_node::node_type type() { return expression_node::e_nand; } + static inline details::operator_type operation() { return details::e_nand; } + }; + + template + struct or_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); } + static inline typename expression_node::node_type type() { return expression_node::e_or; } + static inline details::operator_type operation() { return details::e_or; } + }; + + template + struct nor_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_nor; } + }; + + template + struct xor_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return numeric::xor_opr(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_xor; } + }; + + template + struct xnor_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(Type t1, Type t2) { return numeric::xnor_opr(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_xnor; } + }; + + template + struct in_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } + static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_in; } + static inline details::operator_type operation() { return details::e_in; } + }; + + template + struct like_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } + static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_like; } + static inline details::operator_type operation() { return details::e_like; } + }; + + template + struct ilike_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } + static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_ilike; } + static inline details::operator_type operation() { return details::e_ilike; } + }; + + template + struct inrange_op : public opr_base + { + typedef typename opr_base::Type Type; + + static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } + static inline T process(const std::string& t0, const std::string& t1, const std::string& t2) + { + return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); + } + static inline typename expression_node::node_type type() { return expression_node::e_inranges; } + static inline details::operator_type operation() { return details::e_inrange; } + }; + + template + inline T value(details::expression_node* n) + { + return n->value(); + } + + template + inline T value(std::pair*,bool> n) + { + return n.first->value(); + } + + template + inline T value(const T* t) + { + return (*t); + } + + template + inline T value(const T& t) + { + return t; + } + + template + struct vararg_add_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& arg_list) + { + switch (arg_list.size()) + { + case 0 : return T(0); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + default : + { + T result = T(0); + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + result += value(arg_list[i]); + } + + return result; + } + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return value(arg_list[0]) + value(arg_list[1]); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) ; + } + + template + static inline T process_4(const Sequence& arg_list) + { + return value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) + value(arg_list[3]) ; + } + + template + static inline T process_5(const Sequence& arg_list) + { + return value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) + value(arg_list[3]) + + value(arg_list[4]) ; + } + }; + + template + struct vararg_mul_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& arg_list) + { + switch (arg_list.size()) + { + case 0 : return T(0); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + default : + { + T result = T(value(arg_list[0])); + + for (std::size_t i = 1; i < arg_list.size(); ++i) + { + result *= value(arg_list[i]); + } + + return result; + } + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return value(arg_list[0]) * value(arg_list[1]); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return value(arg_list[0]) * value(arg_list[1]) * + value(arg_list[2]) ; + } + + template + static inline T process_4(const Sequence& arg_list) + { + return value(arg_list[0]) * value(arg_list[1]) * + value(arg_list[2]) * value(arg_list[3]) ; + } + + template + static inline T process_5(const Sequence& arg_list) + { + return value(arg_list[0]) * value(arg_list[1]) * + value(arg_list[2]) * value(arg_list[3]) * + value(arg_list[4]) ; + } + }; + + template + struct vararg_avg_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& arg_list) + { + switch (arg_list.size()) + { + case 0 : return T(0); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + default : return vararg_add_op::process(arg_list) / arg_list.size(); + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return (value(arg_list[0]) + value(arg_list[1])) / T(2); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return (value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2])) / T(3); + } + + template + static inline T process_4(const Sequence& arg_list) + { + return (value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) + value(arg_list[3])) / T(4); + } + + template + static inline T process_5(const Sequence& arg_list) + { + return (value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) + value(arg_list[3]) + + value(arg_list[4])) / T(5); + } + }; + + template + struct vararg_min_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& arg_list) + { + switch (arg_list.size()) + { + case 0 : return T(0); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + default : + { + T result = T(value(arg_list[0])); + + for (std::size_t i = 1; i < arg_list.size(); ++i) + { + const T v = value(arg_list[i]); + + if (v < result) + result = v; + } + + return result; + } + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return std::min(value(arg_list[0]),value(arg_list[1])); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return std::min(std::min(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); + } + + template + static inline T process_4(const Sequence& arg_list) + { + return std::min( + std::min(value(arg_list[0]), value(arg_list[1])), + std::min(value(arg_list[2]), value(arg_list[3]))); + } + + template + static inline T process_5(const Sequence& arg_list) + { + return std::min( + std::min(std::min(value(arg_list[0]), value(arg_list[1])), + std::min(value(arg_list[2]), value(arg_list[3]))), + value(arg_list[4])); + } + }; + + template + struct vararg_max_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& arg_list) + { + switch (arg_list.size()) + { + case 0 : return T(0); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + default : + { + T result = T(value(arg_list[0])); + + for (std::size_t i = 1; i < arg_list.size(); ++i) + { + const T v = value(arg_list[i]); + + if (v > result) + result = v; + } + + return result; + } + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return std::max(value(arg_list[0]),value(arg_list[1])); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return std::max(std::max(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); + } + + template + static inline T process_4(const Sequence& arg_list) + { + return std::max( + std::max(value(arg_list[0]), value(arg_list[1])), + std::max(value(arg_list[2]), value(arg_list[3]))); + } + + template + static inline T process_5(const Sequence& arg_list) + { + return std::max( + std::max(std::max(value(arg_list[0]), value(arg_list[1])), + std::max(value(arg_list[2]), value(arg_list[3]))), + value(arg_list[4])); + } + }; + + template + struct vararg_mand_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& arg_list) + { + switch (arg_list.size()) + { + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + default : + { + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (std::equal_to()(T(0), value(arg_list[i]))) + return T(0); + } + + return T(1); + } + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return std::not_equal_to() + (T(0), value(arg_list[0])) ? T(1) : T(0); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) + ) ? T(1) : T(0); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) && + std::not_equal_to()(T(0), value(arg_list[2])) + ) ? T(1) : T(0); + } + + template + static inline T process_4(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) && + std::not_equal_to()(T(0), value(arg_list[2])) && + std::not_equal_to()(T(0), value(arg_list[3])) + ) ? T(1) : T(0); + } + + template + static inline T process_5(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) && + std::not_equal_to()(T(0), value(arg_list[2])) && + std::not_equal_to()(T(0), value(arg_list[3])) && + std::not_equal_to()(T(0), value(arg_list[4])) + ) ? T(1) : T(0); + } + }; + + template + struct vararg_mor_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& arg_list) + { + switch (arg_list.size()) + { + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + default : + { + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (std::not_equal_to()(T(0), value(arg_list[i]))) + return T(1); + } + + return T(0); + } + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return std::not_equal_to() + (T(0), value(arg_list[0])) ? T(1) : T(0); + } + + template + static inline T process_2(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) + ) ? T(1) : T(0); + } + + template + static inline T process_3(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) || + std::not_equal_to()(T(0), value(arg_list[2])) + ) ? T(1) : T(0); + } + + template + static inline T process_4(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) || + std::not_equal_to()(T(0), value(arg_list[2])) || + std::not_equal_to()(T(0), value(arg_list[3])) + ) ? T(1) : T(0); + } + + template + static inline T process_5(const Sequence& arg_list) + { + return ( + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) || + std::not_equal_to()(T(0), value(arg_list[2])) || + std::not_equal_to()(T(0), value(arg_list[3])) || + std::not_equal_to()(T(0), value(arg_list[4])) + ) ? T(1) : T(0); + } + }; + + template + struct vararg_multi_op : public opr_base + { + typedef typename opr_base::Type Type; + + template class Sequence> + static inline T process(const Sequence& arg_list) + { + switch (arg_list.size()) + { + case 0 : return std::numeric_limits::quiet_NaN(); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + case 6 : return process_6(arg_list); + case 7 : return process_7(arg_list); + case 8 : return process_8(arg_list); + default : + { + for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) + { + value(arg_list[i]); + } + + return value(arg_list.back()); + } + } + } + + template + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + value(arg_list[0]); + return value(arg_list[1]); + } + + template + static inline T process_3(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + return value(arg_list[2]); + } + + template + static inline T process_4(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + return value(arg_list[3]); + } + + template + static inline T process_5(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + return value(arg_list[4]); + } + + template + static inline T process_6(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + value(arg_list[4]); + return value(arg_list[5]); + } + + template + static inline T process_7(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + value(arg_list[4]); + value(arg_list[5]); + return value(arg_list[6]); + } + + template + static inline T process_8(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + value(arg_list[4]); + value(arg_list[5]); + value(arg_list[6]); + return value(arg_list[7]); + } + }; + + template + struct vec_add_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); + + loop_unroll::details lud(vec_size); + + if (vec_size <= static_cast(lud.batch_size)) + { + T result = T(0); + int i = 0; + + exprtk_disable_fallthrough_begin + switch (vec_size) + { + #define case_stmt(N) \ + case N : result += vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(16) case_stmt(15) + case_stmt(14) case_stmt(13) + case_stmt(12) case_stmt(11) + case_stmt(10) case_stmt( 9) + case_stmt( 8) case_stmt( 7) + case_stmt( 6) case_stmt( 5) + #endif + case_stmt( 4) case_stmt( 3) + case_stmt( 2) case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef case_stmt + + return result; + } + + T r[] = { + T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0) + }; + + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + r[N] += vec[N]; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : r[0] += vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return (r[ 0] + r[ 1] + r[ 2] + r[ 3]) + #ifndef exprtk_disable_superscalar_unroll + + (r[ 4] + r[ 5] + r[ 6] + r[ 7]) + + (r[ 8] + r[ 9] + r[10] + r[11]) + + (r[12] + r[13] + r[14] + r[15]) + #endif + ; + } + }; + + template + struct vec_mul_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); + + loop_unroll::details lud(vec_size); + + if (vec_size <= static_cast(lud.batch_size)) + { + T result = T(1); + int i = 0; + + exprtk_disable_fallthrough_begin + switch (vec_size) + { + #define case_stmt(N) \ + case N : result *= vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(16) case_stmt(15) + case_stmt(14) case_stmt(13) + case_stmt(12) case_stmt(11) + case_stmt(10) case_stmt( 9) + case_stmt( 8) case_stmt( 7) + case_stmt( 6) case_stmt( 5) + #endif + case_stmt( 4) case_stmt( 3) + case_stmt( 2) case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef case_stmt + + return result; + } + + T r[] = { + T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1), + T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1) + }; + + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + r[N] *= vec[N]; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : r[0] *= vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return (r[ 0] * r[ 1] * r[ 2] * r[ 3]) + #ifndef exprtk_disable_superscalar_unroll + + (r[ 4] * r[ 5] * r[ 6] * r[ 7]) + + (r[ 8] * r[ 9] * r[10] * r[11]) + + (r[12] * r[13] * r[14] * r[15]) + #endif + ; + } + }; + + template + struct vec_avg_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const std::size_t vec_size = v->vec()->vds().size(); + + return vec_add_op::process(v) / vec_size; + } + }; + + template + struct vec_min_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); + + T result = vec[0]; + + for (std::size_t i = 1; i < vec_size; ++i) + { + const T v_i = vec[i]; + + if (v_i < result) + result = v_i; + } + + return result; + } + }; + + template + struct vec_max_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); + + T result = vec[0]; + + for (std::size_t i = 1; i < vec_size; ++i) + { + const T v_i = vec[i]; + + if (v_i > result) + result = v_i; + } + + return result; + } + }; + + template + class vov_base_node : public expression_node + { + public: + + virtual ~vov_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T& v0() const = 0; + + virtual const T& v1() const = 0; + }; + + template + class cov_base_node : public expression_node + { + public: + + virtual ~cov_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual const T& v() const = 0; + }; + + template + class voc_base_node : public expression_node + { + public: + + virtual ~voc_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual const T& v() const = 0; + }; + + template + class vob_base_node : public expression_node + { + public: + + virtual ~vob_base_node() + {} + + virtual const T& v() const = 0; + }; + + template + class bov_base_node : public expression_node + { + public: + + virtual ~bov_base_node() + {} + + virtual const T& v() const = 0; + }; + + template + class cob_base_node : public expression_node + { + public: + + virtual ~cob_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual void set_c(const T) = 0; + + virtual expression_node* move_branch(const std::size_t& index) = 0; + }; + + template + class boc_base_node : public expression_node + { + public: + + virtual ~boc_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual void set_c(const T) = 0; + + virtual expression_node* move_branch(const std::size_t& index) = 0; + }; + + template + class uv_base_node : public expression_node + { + public: + + virtual ~uv_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T& v() const = 0; + }; + + template + class sos_base_node : public expression_node + { + public: + + virtual ~sos_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + + template + class sosos_base_node : public expression_node + { + public: + + virtual ~sosos_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + + template + class T0oT1oT2_base_node : public expression_node + { + public: + + virtual ~T0oT1oT2_base_node() + {} + + virtual std::string type_id() const = 0; + }; + + template + class T0oT1oT2oT3_base_node : public expression_node + { + public: + + virtual ~T0oT1oT2oT3_base_node() + {} + + virtual std::string type_id() const = 0; + }; + + template + class unary_variable_node exprtk_final : public uv_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + explicit unary_variable_node(const T& var) + : v_(var) + {} + + inline T value() const + { + return Operation::process(v_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline const T& v() const + { + return v_; + } + + private: + + unary_variable_node(unary_variable_node&); + unary_variable_node& operator=(unary_variable_node&); + + const T& v_; + }; + + template + class uvouv_node exprtk_final : public expression_node + { + public: + + // UOpr1(v0) Op UOpr2(v1) + + typedef expression_node* expression_ptr; + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + typedef typename functor_t::ufunc_t ufunc_t; + + explicit uvouv_node(const T& var0,const T& var1, + ufunc_t uf0, ufunc_t uf1, bfunc_t bf) + : v0_(var0), + v1_(var1), + u0_(uf0 ), + u1_(uf1 ), + f_ (bf ) + {} + + inline T value() const + { + return f_(u0_(v0_),u1_(v1_)); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_uvouv; + } + + inline operator_type operation() const + { + return details::e_default; + } + + inline const T& v0() + { + return v0_; + } + + inline const T& v1() + { + return v1_; + } + + inline ufunc_t u0() + { + return u0_; + } + + inline ufunc_t u1() + { + return u1_; + } + + inline ufunc_t f() + { + return f_; + } + + private: + + uvouv_node(uvouv_node&); + uvouv_node& operator=(uvouv_node&); + + const T& v0_; + const T& v1_; + const ufunc_t u0_; + const ufunc_t u1_; + const bfunc_t f_; + }; + + template + class unary_branch_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef Operation operation_t; + + explicit unary_branch_node(expression_ptr branch) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + return Operation::process(branch_.first->value()); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline expression_node* branch(const std::size_t&) const + { + return branch_.first; + } + + inline void release() + { + branch_.second = false; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + unary_branch_node(unary_branch_node&); + unary_branch_node& operator=(unary_branch_node&); + + branch_t branch_; + }; + + template struct is_const { enum {result = 0}; }; + template struct is_const { enum {result = 1}; }; + template struct is_const_ref { enum {result = 0}; }; + template struct is_const_ref { enum {result = 1}; }; + template struct is_ref { enum {result = 0}; }; + template struct is_ref { enum {result = 1}; }; + template struct is_ref { enum {result = 0}; }; + + template + struct param_to_str { static std::string result() { static const std::string r("v"); return r; } }; + + template <> + struct param_to_str<0> { static std::string result() { static const std::string r("c"); return r; } }; + + #define exprtk_crtype(Type) \ + param_to_str::result>::result() \ + + template + struct T0oT1oT2process + { + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + + struct mode0 + { + static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) + { + // (T0 o0 T1) o1 T2 + return bf1(bf0(t0,t1),t2); + } + + template + static inline std::string id() + { + static const std::string result = "(" + exprtk_crtype(T0) + "o" + + exprtk_crtype(T1) + ")o(" + + exprtk_crtype(T2) + ")" ; + return result; + } + }; + + struct mode1 + { + static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) + { + // T0 o0 (T1 o1 T2) + return bf0(t0,bf1(t1,t2)); + } + + template + static inline std::string id() + { + static const std::string result = "(" + exprtk_crtype(T0) + ")o(" + + exprtk_crtype(T1) + "o" + + exprtk_crtype(T2) + ")" ; + return result; + } + }; + }; + + template + struct T0oT1oT20T3process + { + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + + struct mode0 + { + static inline T process(const T& t0, const T& t1, + const T& t2, const T& t3, + const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) + { + // (T0 o0 T1) o1 (T2 o2 T3) + return bf1(bf0(t0,t1),bf2(t2,t3)); + } + + template + static inline std::string id() + { + static const std::string result = "(" + exprtk_crtype(T0) + "o" + + exprtk_crtype(T1) + ")o" + + "(" + exprtk_crtype(T2) + "o" + + exprtk_crtype(T3) + ")" ; + return result; + } + }; + + struct mode1 + { + static inline T process(const T& t0, const T& t1, + const T& t2, const T& t3, + const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) + { + // (T0 o0 (T1 o1 (T2 o2 T3)) + return bf0(t0,bf1(t1,bf2(t2,t3))); + } + template + static inline std::string id() + { + static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + + exprtk_crtype(T1) + ")o(" + + exprtk_crtype(T2) + "o" + + exprtk_crtype(T3) + "))" ; + return result; + } + }; + + struct mode2 + { + static inline T process(const T& t0, const T& t1, + const T& t2, const T& t3, + const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) + { + // (T0 o0 ((T1 o1 T2) o2 T3) + return bf0(t0,bf2(bf1(t1,t2),t3)); + } + + template + static inline std::string id() + { + static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + + exprtk_crtype(T1) + "o" + + exprtk_crtype(T2) + ")o(" + + exprtk_crtype(T3) + "))" ; + return result; + } + }; + + struct mode3 + { + static inline T process(const T& t0, const T& t1, + const T& t2, const T& t3, + const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) + { + // (((T0 o0 T1) o1 T2) o2 T3) + return bf2(bf1(bf0(t0,t1),t2),t3); + } + + template + static inline std::string id() + { + static const std::string result = "((" + exprtk_crtype(T0) + "o" + + exprtk_crtype(T1) + ")o(" + + exprtk_crtype(T2) + "))o(" + + exprtk_crtype(T3) + ")"; + return result; + } + }; + + struct mode4 + { + static inline T process(const T& t0, const T& t1, + const T& t2, const T& t3, + const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) + { + // ((T0 o0 (T1 o1 T2)) o2 T3 + return bf2(bf0(t0,bf1(t1,t2)),t3); + } + + template + static inline std::string id() + { + static const std::string result = "((" + exprtk_crtype(T0) + ")o(" + + exprtk_crtype(T1) + "o" + + exprtk_crtype(T2) + "))o(" + + exprtk_crtype(T3) + ")" ; + return result; + } + }; + }; + + #undef exprtk_crtype + + template + struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; + template + const typename expression_node::node_type nodetype_T0oT1::result = expression_node::e_none; + + #define synthesis_node_type_define(T0_,T1_,v_) \ + template \ + struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; \ + template \ + const typename expression_node::node_type nodetype_T0oT1::result = expression_node:: v_; \ + + synthesis_node_type_define(const T0&, const T1&, e_vov) + synthesis_node_type_define(const T0&, const T1 , e_voc) + synthesis_node_type_define(const T0 , const T1&, e_cov) + synthesis_node_type_define( T0&, T1&, e_none) + synthesis_node_type_define(const T0 , const T1 , e_none) + synthesis_node_type_define( T0&, const T1 , e_none) + synthesis_node_type_define(const T0 , T1&, e_none) + synthesis_node_type_define(const T0&, T1&, e_none) + synthesis_node_type_define( T0&, const T1&, e_none) + #undef synthesis_node_type_define + + template + struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; + template + const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node::e_none; + + #define synthesis_node_type_define(T0_,T1_,T2_,v_) \ + template \ + struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; \ + template \ + const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node:: v_; \ + + synthesis_node_type_define(const T0&, const T1&, const T2&, e_vovov) + synthesis_node_type_define(const T0&, const T1&, const T2 , e_vovoc) + synthesis_node_type_define(const T0&, const T1 , const T2&, e_vocov) + synthesis_node_type_define(const T0 , const T1&, const T2&, e_covov) + synthesis_node_type_define(const T0 , const T1&, const T2 , e_covoc) + synthesis_node_type_define(const T0 , const T1 , const T2 , e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2&, e_none ) + synthesis_node_type_define(const T0&, const T1 , const T2 , e_none ) + synthesis_node_type_define( T0&, T1&, T2&, e_none ) + #undef synthesis_node_type_define + + template + struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; + template + const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node::e_none; + + #define synthesis_node_type_define(T0_,T1_,T2_,T3_,v_) \ + template \ + struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; \ + template \ + const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node:: v_; \ + + synthesis_node_type_define(const T0&, const T1&, const T2&, const T3&, e_vovovov) + synthesis_node_type_define(const T0&, const T1&, const T2&, const T3 , e_vovovoc) + synthesis_node_type_define(const T0&, const T1&, const T2 , const T3&, e_vovocov) + synthesis_node_type_define(const T0&, const T1 , const T2&, const T3&, e_vocovov) + synthesis_node_type_define(const T0 , const T1&, const T2&, const T3&, e_covovov) + synthesis_node_type_define(const T0 , const T1&, const T2 , const T3&, e_covocov) + synthesis_node_type_define(const T0&, const T1 , const T2&, const T3 , e_vocovoc) + synthesis_node_type_define(const T0 , const T1&, const T2&, const T3 , e_covovoc) + synthesis_node_type_define(const T0&, const T1 , const T2 , const T3&, e_vococov) + synthesis_node_type_define(const T0 , const T1 , const T2 , const T3 , e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2 , const T3&, e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2&, const T3 , e_none ) + synthesis_node_type_define(const T0 , const T1&, const T2 , const T3 , e_none ) + synthesis_node_type_define(const T0&, const T1 , const T2 , const T3 , e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2&, const T3&, e_none ) + synthesis_node_type_define(const T0&, const T1&, const T2 , const T3 , e_none ) + #undef synthesis_node_type_define + + template + class T0oT1 exprtk_final : public expression_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + typedef T value_type; + typedef T0oT1 node_type; + + T0oT1(T0 p0, T1 p1, const bfunc_t p2) + : t0_(p0), + t1_(p1), + f_ (p2) + {} + + inline typename expression_node::node_type type() const + { + static const typename expression_node::node_type result = nodetype_T0oT1::result; + return result; + } + + inline operator_type operation() const + { + return e_default; + } + + inline T value() const + { + return f_(t0_,t1_); + } + + inline T0 t0() const + { + return t0_; + } + + inline T1 t1() const + { + return t1_; + } + + inline bfunc_t f() const + { + return f_; + } + + template + static inline expression_node* allocate(Allocator& allocator, + T0 p0, T1 p1, + bfunc_t p2) + { + return allocator + .template allocate_type + (p0, p1, p2); + } + + private: + + T0oT1(T0oT1&) {} + T0oT1& operator=(T0oT1&) { return (*this); } + + T0 t0_; + T1 t1_; + const bfunc_t f_; + }; + + template + class T0oT1oT2 exprtk_final : public T0oT1oT2_base_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + typedef T value_type; + typedef T0oT1oT2 node_type; + typedef ProcessMode process_mode_t; + + T0oT1oT2(T0 p0, T1 p1, T2 p2, const bfunc_t p3, const bfunc_t p4) + : t0_(p0), + t1_(p1), + t2_(p2), + f0_(p3), + f1_(p4) + {} + + inline typename expression_node::node_type type() const + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; + return result; + } + + inline operator_type operation() const + { + return e_default; + } + + inline T value() const + { + return ProcessMode::process(t0_, t1_, t2_, f0_, f1_); + } + + inline T0 t0() const + { + return t0_; + } + + inline T1 t1() const + { + return t1_; + } + + inline T2 t2() const + { + return t2_; + } + + bfunc_t f0() const + { + return f0_; + } + + bfunc_t f1() const + { + return f1_; + } + + std::string type_id() const + { + return id(); + } + + static inline std::string id() + { + return process_mode_t::template id(); + } + + template + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4) + { + return allocator + .template allocate_type + (p0, p1, p2, p3, p4); + } + + private: + + T0oT1oT2(node_type&) {} + node_type& operator=(node_type&) { return (*this); } + + T0 t0_; + T1 t1_; + T2 t2_; + const bfunc_t f0_; + const bfunc_t f1_; + }; + + template + class T0oT1oT2oT3 exprtk_final : public T0oT1oT2oT3_base_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::bfunc_t bfunc_t; + typedef T value_type; + typedef T0_ T0; + typedef T1_ T1; + typedef T2_ T2; + typedef T3_ T3; + typedef T0oT1oT2oT3 node_type; + typedef ProcessMode process_mode_t; + + T0oT1oT2oT3(T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6) + : t0_(p0), + t1_(p1), + t2_(p2), + t3_(p3), + f0_(p4), + f1_(p5), + f2_(p6) + {} + + inline T value() const + { + return ProcessMode::process(t0_, t1_, t2_, t3_, f0_, f1_, f2_); + } + + inline T0 t0() const + { + return t0_; + } + + inline T1 t1() const + { + return t1_; + } + + inline T2 t2() const + { + return t2_; + } + + inline T3 t3() const + { + return t3_; + } + + inline bfunc_t f0() const + { + return f0_; + } + + inline bfunc_t f1() const + { + return f1_; + } + + inline bfunc_t f2() const + { + return f2_; + } + + inline std::string type_id() const + { + return id(); + } + + static inline std::string id() + { + return process_mode_t::template id(); + } + + template + static inline expression_node* allocate(Allocator& allocator, + T0 p0, T1 p1, T2 p2, T3 p3, + bfunc_t p4, bfunc_t p5, bfunc_t p6) + { + return allocator + .template allocate_type + (p0, p1, p2, p3, p4, p5, p6); + } + + private: + + T0oT1oT2oT3(node_type&) {} + node_type& operator=(node_type&) { return (*this); } + + T0 t0_; + T1 t1_; + T2 t2_; + T3 t3_; + const bfunc_t f0_; + const bfunc_t f1_; + const bfunc_t f2_; + }; + + template + class T0oT1oT2_sf3 exprtk_final : public T0oT1oT2_base_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::tfunc_t tfunc_t; + typedef T value_type; + typedef T0oT1oT2_sf3 node_type; + + T0oT1oT2_sf3(T0 p0, T1 p1, T2 p2, const tfunc_t p3) + : t0_(p0), + t1_(p1), + t2_(p2), + f_ (p3) + {} + + inline typename expression_node::node_type type() const + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; + return result; + } + + inline operator_type operation() const + { + return e_default; + } + + inline T value() const + { + return f_(t0_, t1_, t2_); + } + + inline T0 t0() const + { + return t0_; + } + + inline T1 t1() const + { + return t1_; + } + + inline T2 t2() const + { + return t2_; + } + + tfunc_t f() const + { + return f_; + } + + std::string type_id() const + { + return id(); + } + + static inline std::string id() + { + return "sf3"; + } + + template + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3) + { + return allocator + .template allocate_type + (p0, p1, p2, p3); + } + + private: + + T0oT1oT2_sf3(node_type&) {} + node_type& operator=(node_type&) { return (*this); } + + T0 t0_; + T1 t1_; + T2 t2_; + const tfunc_t f_; + }; + + template + class sf3ext_type_node : public T0oT1oT2_base_node + { + public: + + virtual ~sf3ext_type_node() + {} + + virtual T0 t0() const = 0; + + virtual T1 t1() const = 0; + + virtual T2 t2() const = 0; + }; + + template + class T0oT1oT2_sf3ext exprtk_final : public sf3ext_type_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::tfunc_t tfunc_t; + typedef T value_type; + typedef T0oT1oT2_sf3ext node_type; + + T0oT1oT2_sf3ext(T0 p0, T1 p1, T2 p2) + : t0_(p0), + t1_(p1), + t2_(p2) + {} + + inline typename expression_node::node_type type() const + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; + return result; + } + + inline operator_type operation() const + { + return e_default; + } + + inline T value() const + { + return SF3Operation::process(t0_, t1_, t2_); + } + + T0 t0() const + { + return t0_; + } + + T1 t1() const + { + return t1_; + } + + T2 t2() const + { + return t2_; + } + + std::string type_id() const + { + return id(); + } + + static inline std::string id() + { + return SF3Operation::id(); + } + + template + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2) + { + return allocator + .template allocate_type + (p0, p1, p2); + } + + private: + + T0oT1oT2_sf3ext(node_type&) {} + node_type& operator=(node_type&) { return (*this); } + + T0 t0_; + T1 t1_; + T2 t2_; + }; + + template + inline bool is_sf3ext_node(const expression_node* n) + { + switch (n->type()) + { + case expression_node::e_vovov : return true; + case expression_node::e_vovoc : return true; + case expression_node::e_vocov : return true; + case expression_node::e_covov : return true; + case expression_node::e_covoc : return true; + default : return false; + } + } + + template + class T0oT1oT2oT3_sf4 exprtk_final : public T0oT1oT2_base_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t qfunc_t; + typedef T value_type; + typedef T0oT1oT2oT3_sf4 node_type; + + T0oT1oT2oT3_sf4(T0 p0, T1 p1, T2 p2, T3 p3, const qfunc_t p4) + : t0_(p0), + t1_(p1), + t2_(p2), + t3_(p3), + f_ (p4) + {} + + inline typename expression_node::node_type type() const + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; + return result; + } + + inline operator_type operation() const + { + return e_default; + } + + inline T value() const + { + return f_(t0_, t1_, t2_, t3_); + } + + inline T0 t0() const + { + return t0_; + } + + inline T1 t1() const + { + return t1_; + } + + inline T2 t2() const + { + return t2_; + } + + inline T3 t3() const + { + return t3_; + } + + qfunc_t f() const + { + return f_; + } + + std::string type_id() const + { + return id(); + } + + static inline std::string id() + { + return "sf4"; + } + + template + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4) + { + return allocator + .template allocate_type + (p0, p1, p2, p3, p4); + } + + private: + + T0oT1oT2oT3_sf4(node_type&) {} + node_type& operator=(node_type&) { return (*this); } + + T0 t0_; + T1 t1_; + T2 t2_; + T3 t3_; + const qfunc_t f_; + }; + + template + class T0oT1oT2oT3_sf4ext exprtk_final : public T0oT1oT2oT3_base_node + { + public: + + typedef typename details::functor_t functor_t; + typedef typename functor_t::tfunc_t tfunc_t; + typedef T value_type; + typedef T0oT1oT2oT3_sf4ext node_type; + + T0oT1oT2oT3_sf4ext(T0 p0, T1 p1, T2 p2, T3 p3) + : t0_(p0), + t1_(p1), + t2_(p2), + t3_(p3) + {} + + inline typename expression_node::node_type type() const + { + static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; + return result; + } + + inline operator_type operation() const + { + return e_default; + } + + inline T value() const + { + return SF4Operation::process(t0_, t1_, t2_, t3_); + } + + inline T0 t0() const + { + return t0_; + } + + inline T1 t1() const + { + return t1_; + } + + inline T2 t2() const + { + return t2_; + } + + inline T3 t3() const + { + return t3_; + } + + std::string type_id() const + { + return id(); + } + + static inline std::string id() + { + return SF4Operation::id(); + } + + template + static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3) + { + return allocator + .template allocate_type + (p0, p1, p2, p3); + } + + private: + + T0oT1oT2oT3_sf4ext(node_type&) {} + node_type& operator=(node_type&) { return (*this); } + + T0 t0_; + T1 t1_; + T2 t2_; + T3 t3_; + }; + + template + inline bool is_sf4ext_node(const expression_node* n) + { + switch (n->type()) + { + case expression_node::e_vovovov : return true; + case expression_node::e_vovovoc : return true; + case expression_node::e_vovocov : return true; + case expression_node::e_vocovov : return true; + case expression_node::e_covovov : return true; + case expression_node::e_covocov : return true; + case expression_node::e_vocovoc : return true; + case expression_node::e_covovoc : return true; + case expression_node::e_vococov : return true; + default : return false; + } + } + + template + struct T0oT1_define + { + typedef details::T0oT1 type0; + }; + + template + struct T0oT1oT2_define + { + typedef details::T0oT1oT2::mode0> type0; + typedef details::T0oT1oT2::mode1> type1; + typedef details::T0oT1oT2_sf3 sf3_type; + typedef details::sf3ext_type_node sf3_type_node; + }; + + template + struct T0oT1oT2oT3_define + { + typedef details::T0oT1oT2oT3::mode0> type0; + typedef details::T0oT1oT2oT3::mode1> type1; + typedef details::T0oT1oT2oT3::mode2> type2; + typedef details::T0oT1oT2oT3::mode3> type3; + typedef details::T0oT1oT2oT3::mode4> type4; + typedef details::T0oT1oT2oT3_sf4 sf4_type; + }; + + template + class vov_node exprtk_final : public vov_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // variable op variable node + explicit vov_node(const T& var0, const T& var1) + : v0_(var0), + v1_(var1) + {} + + inline T value() const + { + return Operation::process(v0_,v1_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline const T& v0() const + { + return v0_; + } + + inline const T& v1() const + { + return v1_; + } + + protected: + + const T& v0_; + const T& v1_; + + private: + + vov_node(vov_node&); + vov_node& operator=(vov_node&); + }; + + template + class cov_node exprtk_final : public cov_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // constant op variable node + explicit cov_node(const T& const_var, const T& var) + : c_(const_var), + v_(var) + {} + + inline T value() const + { + return Operation::process(c_,v_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline const T c() const + { + return c_; + } + + inline const T& v() const + { + return v_; + } + + protected: + + const T c_; + const T& v_; + + private: + + cov_node(const cov_node&); + cov_node& operator=(const cov_node&); + }; + + template + class voc_node exprtk_final : public voc_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // variable op constant node + explicit voc_node(const T& var, const T& const_var) + : v_(var), + c_(const_var) + {} + + inline T value() const + { + return Operation::process(v_,c_); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline const T c() const + { + return c_; + } + + inline const T& v() const + { + return v_; + } + + protected: + + const T& v_; + const T c_; + + private: + + voc_node(const voc_node&); + voc_node& operator=(const voc_node&); + }; + + template + class vob_node exprtk_final : public vob_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef Operation operation_t; + + // variable op constant node + explicit vob_node(const T& var, const expression_ptr branch) + : v_(var) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + assert(branch_.first); + return Operation::process(v_,branch_.first->value()); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline const T& v() const + { + return v_; + } + + inline expression_node* branch(const std::size_t&) const + { + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + vob_node(const vob_node&); + vob_node& operator=(const vob_node&); + + const T& v_; + branch_t branch_; + }; + + template + class bov_node exprtk_final : public bov_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef Operation operation_t; + + // variable op constant node + explicit bov_node(const expression_ptr branch, const T& var) + : v_(var) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + assert(branch_.first); + return Operation::process(branch_.first->value(),v_); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline const T& v() const + { + return v_; + } + + inline expression_node* branch(const std::size_t&) const + { + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bov_node(const bov_node&); + bov_node& operator=(const bov_node&); + + const T& v_; + branch_t branch_; + }; + + template + class cob_node exprtk_final : public cob_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef Operation operation_t; + + // variable op constant node + explicit cob_node(const T const_var, const expression_ptr branch) + : c_(const_var) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + assert(branch_.first); + return Operation::process(c_,branch_.first->value()); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline const T c() const + { + return c_; + } + + inline void set_c(const T new_c) + { + (*const_cast(&c_)) = new_c; + } + + inline expression_node* branch(const std::size_t&) const + { + return branch_.first; + } + + inline expression_node* move_branch(const std::size_t&) + { + branch_.second = false; + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + cob_node(const cob_node&); + cob_node& operator=(const cob_node&); + + const T c_; + branch_t branch_; + }; + + template + class boc_node exprtk_final : public boc_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef Operation operation_t; + + // variable op constant node + explicit boc_node(const expression_ptr branch, const T const_var) + : c_(const_var) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + assert(branch_.first); + return Operation::process(branch_.first->value(),c_); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline const T c() const + { + return c_; + } + + inline void set_c(const T new_c) + { + (*const_cast(&c_)) = new_c; + } + + inline expression_node* branch(const std::size_t&) const + { + return branch_.first; + } + + inline expression_node* move_branch(const std::size_t&) + { + branch_.second = false; + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + boc_node(const boc_node&); + boc_node& operator=(const boc_node&); + + const T c_; + branch_t branch_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class sos_node exprtk_final : public sos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // string op string node + explicit sos_node(SType0 p0, SType1 p1) + : s0_(p0), + s1_(p1) + {} + + inline T value() const + { + return Operation::process(s0_,s1_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + protected: + + SType0 s0_; + SType1 s1_; + + private: + + sos_node(sos_node&); + sos_node& operator=(sos_node&); + }; + + template + class str_xrox_node exprtk_final : public sos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // string-range op string node + explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0) + : s0_ (p0 ), + s1_ (p1 ), + rp0_(rp0) + {} + + ~str_xrox_node() + { + rp0_.free(); + } + + inline T value() const + { + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (rp0_(r0, r1, s0_.size())) + return Operation::process(s0_.substr(r0, (r1 - r0) + 1), s1_); + else + return T(0); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + protected: + + SType0 s0_; + SType1 s1_; + RangePack rp0_; + + private: + + str_xrox_node(str_xrox_node&); + str_xrox_node& operator=(str_xrox_node&); + }; + + template + class str_xoxr_node exprtk_final : public sos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // string op string range node + explicit str_xoxr_node(SType0 p0, SType1 p1, RangePack rp1) + : s0_ (p0 ), + s1_ (p1 ), + rp1_(rp1) + {} + + ~str_xoxr_node() + { + rp1_.free(); + } + + inline T value() const + { + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (rp1_(r0, r1, s1_.size())) + return Operation::process(s0_, s1_.substr(r0, (r1 - r0) + 1)); + else + return T(0); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + protected: + + SType0 s0_; + SType1 s1_; + RangePack rp1_; + + private: + + str_xoxr_node(str_xoxr_node&); + str_xoxr_node& operator=(str_xoxr_node&); + }; + + template + class str_xroxr_node exprtk_final : public sos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // string-range op string-range node + explicit str_xroxr_node(SType0 p0, SType1 p1, RangePack rp0, RangePack rp1) + : s0_ (p0 ), + s1_ (p1 ), + rp0_(rp0), + rp1_(rp1) + {} + + ~str_xroxr_node() + { + rp0_.free(); + rp1_.free(); + } + + inline T value() const + { + std::size_t r0_0 = 0; + std::size_t r0_1 = 0; + std::size_t r1_0 = 0; + std::size_t r1_1 = 0; + + if ( + rp0_(r0_0, r1_0, s0_.size()) && + rp1_(r0_1, r1_1, s1_.size()) + ) + { + return Operation::process( + s0_.substr(r0_0, (r1_0 - r0_0) + 1), + s1_.substr(r0_1, (r1_1 - r0_1) + 1) + ); + } + else + return T(0); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + protected: + + SType0 s0_; + SType1 s1_; + RangePack rp0_; + RangePack rp1_; + + private: + + str_xroxr_node(str_xroxr_node&); + str_xroxr_node& operator=(str_xroxr_node&); + }; + + template + class str_sogens_node exprtk_final : public binary_node + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + str_sogens_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_range_ptr_(0), + str1_range_ptr_(0) + { + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + + if (0 == range) + return; + + str0_range_ptr_ = &(range->range_ref()); + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + + if (0 == range) + return; + + str1_range_ptr_ = &(range->range_ref()); + } + } + + inline T value() const + { + if ( + str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ + ) + { + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + std::size_t str0_r0 = 0; + std::size_t str0_r1 = 0; + + std::size_t str1_r0 = 0; + std::size_t str1_r1 = 0; + + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); + + if ( + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) + ) + { + return Operation::process( + str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0) + 1), + str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0) + 1) + ); + } + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + private: + + str_sogens_node(str_sogens_node&); + str_sogens_node& operator=(str_sogens_node&); + + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + range_ptr str0_range_ptr_; + range_ptr str1_range_ptr_; + }; + + template + class sosos_node exprtk_final : public sosos_base_node + { + public: + + typedef expression_node* expression_ptr; + typedef Operation operation_t; + + // variable op variable node + explicit sosos_node(SType0 p0, SType1 p1, SType2 p2) + : s0_(p0), + s1_(p1), + s2_(p2) + {} + + inline T value() const + { + return Operation::process(s0_,s1_,s2_); + } + + inline typename expression_node::node_type type() const + { + return Operation::type(); + } + + inline operator_type operation() const + { + return Operation::operation(); + } + + inline std::string& s0() + { + return s0_; + } + + inline std::string& s1() + { + return s1_; + } + + inline std::string& s2() + { + return s2_; + } + + protected: + + SType0 s0_; + SType1 s1_; + SType2 s2_; + + private: + + sosos_node(sosos_node&); + sosos_node& operator=(sosos_node&); + }; + #endif + + template + class ipow_node exprtk_final: public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef PowOp operation_t; + + explicit ipow_node(const T& v) + : v_(v) + {} + + inline T value() const + { + return PowOp::result(v_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_ipow; + } + + private: + + ipow_node(const ipow_node&); + ipow_node& operator=(const ipow_node&); + + const T& v_; + }; + + template + class bipow_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipow_node(expression_ptr branch) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + assert(branch_.first); + return PowOp::result(branch_.first->value()); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_ipow; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bipow_node(const bipow_node&); + bipow_node& operator=(const bipow_node&); + + branch_t branch_; + }; + + template + class ipowinv_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef PowOp operation_t; + + explicit ipowinv_node(const T& v) + : v_(v) + {} + + inline T value() const + { + return (T(1) / PowOp::result(v_)); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_ipowinv; + } + + private: + + ipowinv_node(const ipowinv_node&); + ipowinv_node& operator=(const ipowinv_node&); + + const T& v_; + }; + + template + class bipowninv_node exprtk_final : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipowninv_node(expression_ptr branch) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + assert(branch_.first); + return (T(1) / PowOp::result(branch_.first->value())); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_ipowinv; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + + private: + + bipowninv_node(const bipowninv_node&); + bipowninv_node& operator=(const bipowninv_node&); + + branch_t branch_; + }; + + template + inline bool is_vov_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_cov_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_voc_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_cob_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_boc_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_t0ot1ot2_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_t0ot1ot2ot3_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_uv_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_string_node(const expression_node* node) + { + return node && (expression_node::e_stringvar == node->type()); + } + + template + inline bool is_string_range_node(const expression_node* node) + { + return node && (expression_node::e_stringvarrng == node->type()); + } + + template + inline bool is_const_string_node(const expression_node* node) + { + return node && (expression_node::e_stringconst == node->type()); + } + + template + inline bool is_const_string_range_node(const expression_node* node) + { + return node && (expression_node::e_cstringvarrng == node->type()); + } + + template + inline bool is_string_assignment_node(const expression_node* node) + { + return node && (expression_node::e_strass == node->type()); + } + + template + inline bool is_string_concat_node(const expression_node* node) + { + return node && (expression_node::e_strconcat == node->type()); + } + + template + inline bool is_string_function_node(const expression_node* node) + { + return node && (expression_node::e_strfunction == node->type()); + } + + template + inline bool is_string_condition_node(const expression_node* node) + { + return node && (expression_node::e_strcondition == node->type()); + } + + template + inline bool is_string_ccondition_node(const expression_node* node) + { + return node && (expression_node::e_strccondition == node->type()); + } + + template + inline bool is_string_vararg_node(const expression_node* node) + { + return node && (expression_node::e_stringvararg == node->type()); + } + + template + inline bool is_genricstring_range_node(const expression_node* node) + { + return node && (expression_node::e_strgenrange == node->type()); + } + + template + inline bool is_generally_string_node(const expression_node* node) + { + if (node) + { + switch (node->type()) + { + case expression_node::e_stringvar : + case expression_node::e_stringconst : + case expression_node::e_stringvarrng : + case expression_node::e_cstringvarrng : + case expression_node::e_strgenrange : + case expression_node::e_strass : + case expression_node::e_strconcat : + case expression_node::e_strfunction : + case expression_node::e_strcondition : + case expression_node::e_strccondition : + case expression_node::e_stringvararg : return true; + default : return false; + } + } + + return false; + } + + class node_allocator + { + public: + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[1]) + { + expression_node* result = + allocate(operation, branch[0]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[2]) + { + expression_node* result = + allocate(operation, branch[0], branch[1]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[3]) + { + expression_node* result = + allocate(operation, branch[0], branch[1], branch[2]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[4]) + { + expression_node* result = + allocate(operation, branch[0], branch[1], branch[2], branch[3]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[5]) + { + expression_node* result = + allocate(operation, branch[0],branch[1], branch[2], branch[3], branch[4]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[6]) + { + expression_node* result = + allocate(operation, branch[0], branch[1], branch[2], branch[3], branch[4], branch[5]); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate() const + { + return (new node_type()); + } + + template class Sequence> + inline expression_node* allocate(const Sequence& seq) const + { + expression_node* + result = (new node_type(seq)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(T1& t1) const + { + expression_node* + result = (new node_type(t1)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_c(const T1& t1) const + { + expression_node* + result = (new node_type(t1)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_cr(const T1& t1, T2& t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rc(T1& t1, const T2& t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rr(T1& t1, T2& t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_tt(T1 t1, T2 t2) const + { + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_ttt(T1 t1, T2 t2, T3 t3) const + { + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_tttt(T1 t1, T2 t2, T3 t3, T4 t4) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rrr(T1& t1, T2& t2, T3& t3) const + { + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rrrr(T1& t1, T2& t2, T3& t3, T4& t4) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_rrrrr(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3) const + { + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6, + const T7& t7) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6, + const T7& t7, const T8& t8) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6, + const T7& t7, const T8& t8, + const T9& t9) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate(const T1& t1, const T2& t2, + const T3& t3, const T4& t4, + const T5& t5, const T6& t6, + const T7& t7, const T8& t8, + const T9& t9, const T10& t10) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3) const + { + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4, + T5 t5) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4, + T5 t5, T6 t6) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6)); + result->node_depth(); + return result; + } + + template + inline expression_node* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4, + T5 t5, T6 t6, + T7 t7) const + { + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); + result->node_depth(); + return result; + } + + template + void inline free(expression_node*& e) const + { + exprtk_debug(("node_allocator::free() - deleting expression_node " + "type: %03d addr: %p\n", + static_cast(e->type()), + reinterpret_cast(e))); + delete e; + e = 0; + } + }; + + inline void load_operations_map(std::multimap& m) + { + #define register_op(Symbol,Type,Args) \ + m.insert(std::make_pair(std::string(Symbol),details::base_operation_t(Type,Args))); \ + + register_op( "abs", e_abs , 1) + register_op( "acos", e_acos , 1) + register_op( "acosh", e_acosh , 1) + register_op( "asin", e_asin , 1) + register_op( "asinh", e_asinh , 1) + register_op( "atan", e_atan , 1) + register_op( "atanh", e_atanh , 1) + register_op( "ceil", e_ceil , 1) + register_op( "cos", e_cos , 1) + register_op( "cosh", e_cosh , 1) + register_op( "exp", e_exp , 1) + register_op( "expm1", e_expm1 , 1) + register_op( "floor", e_floor , 1) + register_op( "log", e_log , 1) + register_op( "log10", e_log10 , 1) + register_op( "log2", e_log2 , 1) + register_op( "log1p", e_log1p , 1) + register_op( "round", e_round , 1) + register_op( "sin", e_sin , 1) + register_op( "sinc", e_sinc , 1) + register_op( "sinh", e_sinh , 1) + register_op( "sec", e_sec , 1) + register_op( "csc", e_csc , 1) + register_op( "sqrt", e_sqrt , 1) + register_op( "tan", e_tan , 1) + register_op( "tanh", e_tanh , 1) + register_op( "cot", e_cot , 1) + register_op( "rad2deg", e_r2d , 1) + register_op( "deg2rad", e_d2r , 1) + register_op( "deg2grad", e_d2g , 1) + register_op( "grad2deg", e_g2d , 1) + register_op( "sgn", e_sgn , 1) + register_op( "not", e_notl , 1) + register_op( "erf", e_erf , 1) + register_op( "erfc", e_erfc , 1) + register_op( "ncdf", e_ncdf , 1) + register_op( "frac", e_frac , 1) + register_op( "trunc", e_trunc , 1) + register_op( "atan2", e_atan2 , 2) + register_op( "mod", e_mod , 2) + register_op( "logn", e_logn , 2) + register_op( "pow", e_pow , 2) + register_op( "root", e_root , 2) + register_op( "roundn", e_roundn , 2) + register_op( "equal", e_equal , 2) + register_op("not_equal", e_nequal , 2) + register_op( "hypot", e_hypot , 2) + register_op( "shr", e_shr , 2) + register_op( "shl", e_shl , 2) + register_op( "clamp", e_clamp , 3) + register_op( "iclamp", e_iclamp , 3) + register_op( "inrange", e_inrange , 3) + #undef register_op + } + + } // namespace details + + class function_traits + { + public: + + function_traits() + : allow_zero_parameters_(false), + has_side_effects_(true), + min_num_args_(0), + max_num_args_(std::numeric_limits::max()) + {} + + inline bool& allow_zero_parameters() + { + return allow_zero_parameters_; + } + + inline bool& has_side_effects() + { + return has_side_effects_; + } + + std::size_t& min_num_args() + { + return min_num_args_; + } + + std::size_t& max_num_args() + { + return max_num_args_; + } + + private: + + bool allow_zero_parameters_; + bool has_side_effects_; + std::size_t min_num_args_; + std::size_t max_num_args_; + }; + + template + void enable_zero_parameters(FunctionType& func) + { + func.allow_zero_parameters() = true; + + if (0 != func.min_num_args()) + { + func.min_num_args() = 0; + } + } + + template + void disable_zero_parameters(FunctionType& func) + { + func.allow_zero_parameters() = false; + } + + template + void enable_has_side_effects(FunctionType& func) + { + func.has_side_effects() = true; + } + + template + void disable_has_side_effects(FunctionType& func) + { + func.has_side_effects() = false; + } + + template + void set_min_num_args(FunctionType& func, const std::size_t& num_args) + { + func.min_num_args() = num_args; + + if ((0 != func.min_num_args()) && func.allow_zero_parameters()) + func.allow_zero_parameters() = false; + } + + template + void set_max_num_args(FunctionType& func, const std::size_t& num_args) + { + func.max_num_args() = num_args; + } + + template + class ifunction : public function_traits + { + public: + + explicit ifunction(const std::size_t& pc) + : param_count(pc) + {} + + virtual ~ifunction() + {} + + #define empty_method_body(N) \ + { \ + exprtk_debug(("ifunction::operator() - Operator(" #N ") has not been overridden\n")); \ + return std::numeric_limits::quiet_NaN(); \ + } \ + + inline virtual T operator() () + empty_method_body(0) + + inline virtual T operator() (const T&) + empty_method_body(1) + + inline virtual T operator() (const T&,const T&) + empty_method_body(2) + + inline virtual T operator() (const T&, const T&, const T&) + empty_method_body(3) + + inline virtual T operator() (const T&, const T&, const T&, const T&) + empty_method_body(4) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&) + empty_method_body(5) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(6) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(7) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(8) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(9) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(10) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&) + empty_method_body(11) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&) + empty_method_body(12) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&) + empty_method_body(13) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&) + empty_method_body(14) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&) + empty_method_body(15) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(16) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(17) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(18) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(19) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body(20) + + #undef empty_method_body + + std::size_t param_count; + }; + + template + class ivararg_function : public function_traits + { + public: + + virtual ~ivararg_function() + {} + + inline virtual T operator() (const std::vector&) + { + exprtk_debug(("ivararg_function::operator() - Operator has not been overridden\n")); + return std::numeric_limits::quiet_NaN(); + } + }; + + template + class igeneric_function : public function_traits + { + public: + + enum return_type + { + e_rtrn_scalar = 0, + e_rtrn_string = 1, + e_rtrn_overload = 2 + }; + + typedef T type; + typedef type_store generic_type; + typedef typename generic_type::parameter_list parameter_list_t; + + igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) + : parameter_sequence(param_seq), + rtrn_type(rtr_type) + {} + + virtual ~igeneric_function() + {} + + #define igeneric_function_empty_body(N) \ + { \ + exprtk_debug(("igeneric_function::operator() - Operator(" #N ") has not been overridden\n")); \ + return std::numeric_limits::quiet_NaN(); \ + } \ + + // f(i_0,i_1,....,i_N) --> Scalar + inline virtual T operator() (parameter_list_t) + igeneric_function_empty_body(1) + + // f(i_0,i_1,....,i_N) --> String + inline virtual T operator() (std::string&, parameter_list_t) + igeneric_function_empty_body(2) + + // f(psi,i_0,i_1,....,i_N) --> Scalar + inline virtual T operator() (const std::size_t&, parameter_list_t) + igeneric_function_empty_body(3) + + // f(psi,i_0,i_1,....,i_N) --> String + inline virtual T operator() (const std::size_t&, std::string&, parameter_list_t) + igeneric_function_empty_body(4) + + std::string parameter_sequence; + return_type rtrn_type; + }; + + template class parser; + template class expression_helper; + + template + class symbol_table + { + public: + + typedef T (*ff00_functor)(); + typedef T (*ff01_functor)(T); + typedef T (*ff02_functor)(T, T); + typedef T (*ff03_functor)(T, T, T); + typedef T (*ff04_functor)(T, T, T, T); + typedef T (*ff05_functor)(T, T, T, T, T); + typedef T (*ff06_functor)(T, T, T, T, T, T); + typedef T (*ff07_functor)(T, T, T, T, T, T, T); + typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); + typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); + typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); + typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); + + protected: + + struct freefunc00 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc00(ff00_functor ff) : exprtk::ifunction(0), f(ff) {} + inline T operator() () + { return f(); } + ff00_functor f; + }; + + struct freefunc01 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc01(ff01_functor ff) : exprtk::ifunction(1), f(ff) {} + inline T operator() (const T& v0) + { return f(v0); } + ff01_functor f; + }; + + struct freefunc02 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc02(ff02_functor ff) : exprtk::ifunction(2), f(ff) {} + inline T operator() (const T& v0, const T& v1) + { return f(v0, v1); } + ff02_functor f; + }; + + struct freefunc03 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc03(ff03_functor ff) : exprtk::ifunction(3), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2) + { return f(v0, v1, v2); } + ff03_functor f; + }; + + struct freefunc04 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc04(ff04_functor ff) : exprtk::ifunction(4), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) + { return f(v0, v1, v2, v3); } + ff04_functor f; + }; + + struct freefunc05 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc05(ff05_functor ff) : exprtk::ifunction(5), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) + { return f(v0, v1, v2, v3, v4); } + ff05_functor f; + }; + + struct freefunc06 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc06(ff06_functor ff) : exprtk::ifunction(6), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + { return f(v0, v1, v2, v3, v4, v5); } + ff06_functor f; + }; + + struct freefunc07 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc07(ff07_functor ff) : exprtk::ifunction(7), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6) + { return f(v0, v1, v2, v3, v4, v5, v6); } + ff07_functor f; + }; + + struct freefunc08 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc08(ff08_functor ff) : exprtk::ifunction(8), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7) + { return f(v0, v1, v2, v3, v4, v5, v6, v7); } + ff08_functor f; + }; + + struct freefunc09 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc09(ff09_functor ff) : exprtk::ifunction(9), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8) + { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8); } + ff09_functor f; + }; + + struct freefunc10 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc10(ff10_functor ff) : exprtk::ifunction(10), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) + { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); } + ff10_functor f; + }; + + struct freefunc11 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc11(ff11_functor ff) : exprtk::ifunction(11), f(ff) {} + inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) + { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } + ff11_functor f; + }; + + struct freefunc12 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc12(ff12_functor ff) : exprtk::ifunction(12), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11); } + ff12_functor f; + }; + + struct freefunc13 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc13(ff13_functor ff) : exprtk::ifunction(13), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12); } + ff13_functor f; + }; + + struct freefunc14 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc14(ff14_functor ff) : exprtk::ifunction(14), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12, const T& v13) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13); } + ff14_functor f; + }; + + struct freefunc15 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc15(ff15_functor ff) : exprtk::ifunction(15), f(ff) {} + inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14); } + ff15_functor f; + }; + + template + struct type_store + { + typedef details::expression_node* expression_ptr; + typedef typename details::variable_node variable_node_t; + typedef ifunction ifunction_t; + typedef ivararg_function ivararg_function_t; + typedef igeneric_function igeneric_function_t; + typedef details::vector_holder vector_t; + #ifndef exprtk_disable_string_capabilities + typedef typename details::stringvar_node stringvar_node_t; + #endif + + typedef Type type_t; + typedef type_t* type_ptr; + typedef std::pair type_pair_t; + typedef std::map type_map_t; + typedef typename type_map_t::iterator tm_itr_t; + typedef typename type_map_t::const_iterator tm_const_itr_t; + + enum { lut_size = 256 }; + + type_map_t map; + std::size_t size; + + type_store() + : size(0) + {} + + struct deleter + { + #define exprtk_define_process(Type) \ + static inline void process(std::pair& n) \ + { \ + delete n.second; \ + } \ + + exprtk_define_process(variable_node_t ) + exprtk_define_process(vector_t ) + #ifndef exprtk_disable_string_capabilities + exprtk_define_process(stringvar_node_t) + #endif + + #undef exprtk_define_process + + template + static inline void process(std::pair&) + {} + }; + + inline bool symbol_exists(const std::string& symbol_name) const + { + if (symbol_name.empty()) + return false; + else if (map.end() != map.find(symbol_name)) + return true; + else + return false; + } + + template + inline std::string entity_name(const PtrType& ptr) const + { + if (map.empty()) + return std::string(); + + tm_const_itr_t itr = map.begin(); + + while (map.end() != itr) + { + if (itr->second.second == ptr) + { + return itr->first; + } + else + ++itr; + } + + return std::string(); + } + + inline bool is_constant(const std::string& symbol_name) const + { + if (symbol_name.empty()) + return false; + else + { + const tm_const_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + return false; + else + return (*itr).second.first; + } + } + + template + inline bool add_impl(const std::string& symbol_name, RType t, const bool is_const) + { + if (symbol_name.size() > 1) + { + for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) + { + if (details::imatch(symbol_name, details::reserved_symbols[i])) + { + return false; + } + } + } + + const tm_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + { + map[symbol_name] = Tie::make(t,is_const); + ++size; + } + + return true; + } + + struct tie_array + { + static inline std::pair make(std::pair v, const bool is_const = false) + { + return std::make_pair(is_const, new vector_t(v.first, v.second)); + } + }; + + struct tie_stdvec + { + template + static inline std::pair make(std::vector& v, const bool is_const = false) + { + return std::make_pair(is_const, new vector_t(v)); + } + }; + + struct tie_vecview + { + static inline std::pair make(exprtk::vector_view& v, const bool is_const = false) + { + return std::make_pair(is_const, new vector_t(v)); + } + }; + + struct tie_stddeq + { + template + static inline std::pair make(std::deque& v, const bool is_const = false) + { + return std::make_pair(is_const, new vector_t(v)); + } + }; + + template + inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false) + { + return add_impl > + (symbol_name, std::make_pair(v,v_size), is_const); + } + + inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_const = false) + { + return add_impl > + (symbol_name, std::make_pair(v,v_size), is_const); + } + + template + inline bool add(const std::string& symbol_name, std::vector& v, const bool is_const = false) + { + return add_impl&> + (symbol_name, v, is_const); + } + + inline bool add(const std::string& symbol_name, exprtk::vector_view& v, const bool is_const = false) + { + return add_impl&> + (symbol_name, v, is_const); + } + + template + inline bool add(const std::string& symbol_name, std::deque& v, const bool is_const = false) + { + return add_impl&> + (symbol_name, v, is_const); + } + + inline bool add(const std::string& symbol_name, RawType& t, const bool is_const = false) + { + struct tie + { + static inline std::pair make(T& t,const bool is_const = false) + { + return std::make_pair(is_const, new variable_node_t(t)); + } + + #ifndef exprtk_disable_string_capabilities + static inline std::pair make(std::string& t,const bool is_const = false) + { + return std::make_pair(is_const, new stringvar_node_t(t)); + } + #endif + + static inline std::pair make(function_t& t, const bool is_constant = false) + { + return std::make_pair(is_constant,&t); + } + + static inline std::pair make(vararg_function_t& t, const bool is_const = false) + { + return std::make_pair(is_const,&t); + } + + static inline std::pair make(generic_function_t& t, const bool is_constant = false) + { + return std::make_pair(is_constant,&t); + } + }; + + const tm_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + { + map[symbol_name] = tie::make(t,is_const); + ++size; + } + + return true; + } + + inline type_ptr get(const std::string& symbol_name) const + { + const tm_const_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + return reinterpret_cast(0); + else + return itr->second.second; + } + + template + struct ptr_match + { + static inline bool test(const PtrType, const void*) + { + return false; + } + }; + + template + struct ptr_match + { + static inline bool test(const variable_node_t* p, const void* ptr) + { + exprtk_debug(("ptr_match::test() - %p <--> %p\n",(void*)(&(p->ref())),ptr)); + return (&(p->ref()) == ptr); + } + }; + + inline type_ptr get_from_varptr(const void* ptr) const + { + tm_const_itr_t itr = map.begin(); + + while (map.end() != itr) + { + type_ptr ret_ptr = itr->second.second; + + if (ptr_match::test(ret_ptr,ptr)) + { + return ret_ptr; + } + + ++itr; + } + + return type_ptr(0); + } + + inline bool remove(const std::string& symbol_name, const bool delete_node = true) + { + const tm_itr_t itr = map.find(symbol_name); + + if (map.end() != itr) + { + if (delete_node) + { + deleter::process((*itr).second); + } + + map.erase(itr); + --size; + + return true; + } + else + return false; + } + + inline RawType& type_ref(const std::string& symbol_name) + { + struct init_type + { + static inline double set(double) { return (0.0); } + static inline double set(long double) { return (0.0); } + static inline float set(float) { return (0.0f); } + static inline std::string set(std::string) { return std::string(""); } + }; + + static RawType null_type = init_type::set(RawType()); + + const tm_const_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + return null_type; + else + return itr->second.second->ref(); + } + + inline void clear(const bool delete_node = true) + { + if (!map.empty()) + { + if (delete_node) + { + tm_itr_t itr = map.begin(); + tm_itr_t end = map.end (); + + while (end != itr) + { + deleter::process((*itr).second); + ++itr; + } + } + + map.clear(); + } + + size = 0; + } + + template class Sequence> + inline std::size_t get_list(Sequence,Allocator>& list) const + { + std::size_t count = 0; + + if (!map.empty()) + { + tm_const_itr_t itr = map.begin(); + tm_const_itr_t end = map.end (); + + while (end != itr) + { + list.push_back(std::make_pair((*itr).first,itr->second.second->ref())); + ++itr; + ++count; + } + } + + return count; + } + + template class Sequence> + inline std::size_t get_list(Sequence& vlist) const + { + std::size_t count = 0; + + if (!map.empty()) + { + tm_const_itr_t itr = map.begin(); + tm_const_itr_t end = map.end (); + + while (end != itr) + { + vlist.push_back((*itr).first); + ++itr; + ++count; + } + } + + return count; + } + }; + + typedef details::expression_node* expression_ptr; + typedef typename details::variable_node variable_t; + typedef typename details::vector_holder vector_holder_t; + typedef variable_t* variable_ptr; + #ifndef exprtk_disable_string_capabilities + typedef typename details::stringvar_node stringvar_t; + typedef stringvar_t* stringvar_ptr; + #endif + typedef ifunction function_t; + typedef ivararg_function vararg_function_t; + typedef igeneric_function generic_function_t; + typedef function_t* function_ptr; + typedef vararg_function_t* vararg_function_ptr; + typedef generic_function_t* generic_function_ptr; + + static const std::size_t lut_size = 256; + + // Symbol Table Holder + struct control_block + { + struct st_data + { + type_store variable_store; + type_store function_store; + type_store vararg_function_store; + type_store generic_function_store; + type_store string_function_store; + type_store overload_function_store; + type_store vector_store; + #ifndef exprtk_disable_string_capabilities + type_store stringvar_store; + #endif + + st_data() + { + for (std::size_t i = 0; i < details::reserved_words_size; ++i) + { + reserved_symbol_table_.insert(details::reserved_words[i]); + } + + for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) + { + reserved_symbol_table_.insert(details::reserved_symbols[i]); + } + } + + ~st_data() + { + for (std::size_t i = 0; i < free_function_list_.size(); ++i) + { + delete free_function_list_[i]; + } + } + + inline bool is_reserved_symbol(const std::string& symbol) const + { + return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); + } + + static inline st_data* create() + { + return (new st_data); + } + + static inline void destroy(st_data*& sd) + { + delete sd; + sd = reinterpret_cast(0); + } + + std::list local_symbol_list_; + std::list local_stringvar_list_; + std::set reserved_symbol_table_; + std::vector*> free_function_list_; + }; + + control_block() + : ref_count(1), + data_(st_data::create()) + {} + + explicit control_block(st_data* data) + : ref_count(1), + data_(data) + {} + + ~control_block() + { + if (data_ && (0 == ref_count)) + { + st_data::destroy(data_); + } + } + + static inline control_block* create() + { + return (new control_block); + } + + template + static inline void destroy(control_block*& cntrl_blck, SymTab* sym_tab) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + if (sym_tab) + sym_tab->clear(); + + delete cntrl_blck; + } + + cntrl_blck = 0; + } + } + + std::size_t ref_count; + st_data* data_; + }; + + public: + + symbol_table() + : control_block_(control_block::create()) + { + clear(); + } + + ~symbol_table() + { + control_block::destroy(control_block_,this); + } + + symbol_table(const symbol_table& st) + { + control_block_ = st.control_block_; + control_block_->ref_count++; + } + + inline symbol_table& operator=(const symbol_table& st) + { + if (this != &st) + { + control_block::destroy(control_block_,reinterpret_cast*>(0)); + + control_block_ = st.control_block_; + control_block_->ref_count++; + } + + return (*this); + } + + inline bool operator==(const symbol_table& st) const + { + return (this == &st) || (control_block_ == st.control_block_); + } + + inline void clear_variables(const bool delete_node = true) + { + local_data().variable_store.clear(delete_node); + } + + inline void clear_functions() + { + local_data().function_store.clear(); + } + + inline void clear_strings() + { + #ifndef exprtk_disable_string_capabilities + local_data().stringvar_store.clear(); + #endif + } + + inline void clear_vectors() + { + local_data().vector_store.clear(); + } + + inline void clear_local_constants() + { + local_data().local_symbol_list_.clear(); + } + + inline void clear() + { + if (!valid()) return; + clear_variables (); + clear_functions (); + clear_strings (); + clear_vectors (); + clear_local_constants(); + } + + inline std::size_t variable_count() const + { + if (valid()) + return local_data().variable_store.size; + else + return 0; + } + + #ifndef exprtk_disable_string_capabilities + inline std::size_t stringvar_count() const + { + if (valid()) + return local_data().stringvar_store.size; + else + return 0; + } + #endif + + inline std::size_t function_count() const + { + if (valid()) + return local_data().function_store.size; + else + return 0; + } + + inline std::size_t vector_count() const + { + if (valid()) + return local_data().vector_store.size; + else + return 0; + } + + inline variable_ptr get_variable(const std::string& variable_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(variable_name)) + return reinterpret_cast(0); + else + return local_data().variable_store.get(variable_name); + } + + inline variable_ptr get_variable(const T& var_ref) const + { + if (!valid()) + return reinterpret_cast(0); + else + return local_data().variable_store.get_from_varptr( + reinterpret_cast(&var_ref)); + } + + #ifndef exprtk_disable_string_capabilities + inline stringvar_ptr get_stringvar(const std::string& string_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(string_name)) + return reinterpret_cast(0); + else + return local_data().stringvar_store.get(string_name); + } + #endif + + inline function_ptr get_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast(0); + else + return local_data().function_store.get(function_name); + } + + inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(vararg_function_name)) + return reinterpret_cast(0); + else + return local_data().vararg_function_store.get(vararg_function_name); + } + + inline generic_function_ptr get_generic_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast(0); + else + return local_data().generic_function_store.get(function_name); + } + + inline generic_function_ptr get_string_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast(0); + else + return local_data().string_function_store.get(function_name); + } + + inline generic_function_ptr get_overload_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast(0); + else + return local_data().overload_function_store.get(function_name); + } + + typedef vector_holder_t* vector_holder_ptr; + + inline vector_holder_ptr get_vector(const std::string& vector_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(vector_name)) + return reinterpret_cast(0); + else + return local_data().vector_store.get(vector_name); + } + + inline T& variable_ref(const std::string& symbol_name) + { + static T null_var = T(0); + if (!valid()) + return null_var; + else if (!valid_symbol(symbol_name)) + return null_var; + else + return local_data().variable_store.type_ref(symbol_name); + } + + #ifndef exprtk_disable_string_capabilities + inline std::string& stringvar_ref(const std::string& symbol_name) + { + static std::string null_stringvar; + if (!valid()) + return null_stringvar; + else if (!valid_symbol(symbol_name)) + return null_stringvar; + else + return local_data().stringvar_store.type_ref(symbol_name); + } + #endif + + inline bool is_constant_node(const std::string& symbol_name) const + { + if (!valid()) + return false; + else if (!valid_symbol(symbol_name)) + return false; + else + return local_data().variable_store.is_constant(symbol_name); + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_constant_string(const std::string& symbol_name) const + { + if (!valid()) + return false; + else if (!valid_symbol(symbol_name)) + return false; + else if (!local_data().stringvar_store.symbol_exists(symbol_name)) + return false; + else + return local_data().stringvar_store.is_constant(symbol_name); + } + #endif + + inline bool create_variable(const std::string& variable_name, const T& value = T(0)) + { + if (!valid()) + return false; + else if (!valid_symbol(variable_name)) + return false; + else if (symbol_exists(variable_name)) + return false; + + local_data().local_symbol_list_.push_back(value); + T& t = local_data().local_symbol_list_.back(); + + return add_variable(variable_name,t); + } + + #ifndef exprtk_disable_string_capabilities + inline bool create_stringvar(const std::string& stringvar_name, const std::string& value = std::string("")) + { + if (!valid()) + return false; + else if (!valid_symbol(stringvar_name)) + return false; + else if (symbol_exists(stringvar_name)) + return false; + + local_data().local_stringvar_list_.push_back(value); + std::string& s = local_data().local_stringvar_list_.back(); + + return add_stringvar(stringvar_name,s); + } + #endif + + inline bool add_variable(const std::string& variable_name, T& t, const bool is_constant = false) + { + if (!valid()) + return false; + else if (!valid_symbol(variable_name)) + return false; + else if (symbol_exists(variable_name)) + return false; + else + return local_data().variable_store.add(variable_name, t, is_constant); + } + + inline bool add_constant(const std::string& constant_name, const T& value) + { + if (!valid()) + return false; + else if (!valid_symbol(constant_name)) + return false; + else if (symbol_exists(constant_name)) + return false; + + local_data().local_symbol_list_.push_back(value); + T& t = local_data().local_symbol_list_.back(); + + return add_variable(constant_name, t, true); + } + + #ifndef exprtk_disable_string_capabilities + inline bool add_stringvar(const std::string& stringvar_name, std::string& s, const bool is_constant = false) + { + if (!valid()) + return false; + else if (!valid_symbol(stringvar_name)) + return false; + else if (symbol_exists(stringvar_name)) + return false; + else + return local_data().stringvar_store.add(stringvar_name, s, is_constant); + } + #endif + + inline bool add_function(const std::string& function_name, function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name)) + return false; + else if (symbol_exists(function_name)) + return false; + else + return local_data().function_store.add(function_name,function); + } + + inline bool add_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) + { + if (!valid()) + return false; + else if (!valid_symbol(vararg_function_name)) + return false; + else if (symbol_exists(vararg_function_name)) + return false; + else + return local_data().vararg_function_store.add(vararg_function_name,vararg_function); + } + + inline bool add_function(const std::string& function_name, generic_function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name)) + return false; + else if (symbol_exists(function_name)) + return false; + else + { + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().generic_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_string : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().string_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_overload : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? + local_data().overload_function_store.add(function_name,function) : false; + } + } + + return false; + } + + #define exprtk_define_freefunction(NN) \ + inline bool add_function(const std::string& function_name, ff##NN##_functor function) \ + { \ + if (!valid()) \ + { return false; } \ + if (!valid_symbol(function_name)) \ + { return false; } \ + if (symbol_exists(function_name)) \ + { return false; } \ + \ + exprtk::ifunction* ifunc = new freefunc##NN(function); \ + \ + local_data().free_function_list_.push_back(ifunc); \ + \ + return add_function(function_name,(*local_data().free_function_list_.back())); \ + } \ + + exprtk_define_freefunction(00) exprtk_define_freefunction(01) + exprtk_define_freefunction(02) exprtk_define_freefunction(03) + exprtk_define_freefunction(04) exprtk_define_freefunction(05) + exprtk_define_freefunction(06) exprtk_define_freefunction(07) + exprtk_define_freefunction(08) exprtk_define_freefunction(09) + exprtk_define_freefunction(10) exprtk_define_freefunction(11) + exprtk_define_freefunction(12) exprtk_define_freefunction(13) + exprtk_define_freefunction(14) exprtk_define_freefunction(15) + + #undef exprtk_define_freefunction + + inline bool add_reserved_function(const std::string& function_name, function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name,false)) + return false; + else if (symbol_exists(function_name,false)) + return false; + else + return local_data().function_store.add(function_name,function); + } + + inline bool add_reserved_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) + { + if (!valid()) + return false; + else if (!valid_symbol(vararg_function_name,false)) + return false; + else if (symbol_exists(vararg_function_name,false)) + return false; + else + return local_data().vararg_function_store.add(vararg_function_name,vararg_function); + } + + inline bool add_reserved_function(const std::string& function_name, generic_function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name,false)) + return false; + else if (symbol_exists(function_name,false)) + return false; + else + { + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().generic_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_string : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().string_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_overload : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? + local_data().overload_function_store.add(function_name,function) : false; + } + } + + return false; + } + + template + inline bool add_vector(const std::string& vector_name, T (&v)[N]) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else + return local_data().vector_store.add(vector_name,v); + } + + inline bool add_vector(const std::string& vector_name, T* v, const std::size_t& v_size) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else if (0 == v_size) + return false; + else + return local_data().vector_store.add(vector_name, v, v_size); + } + + template + inline bool add_vector(const std::string& vector_name, std::vector& v) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else if (0 == v.size()) + return false; + else + return local_data().vector_store.add(vector_name,v); + } + + inline bool add_vector(const std::string& vector_name, exprtk::vector_view& v) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else if (0 == v.size()) + return false; + else + return local_data().vector_store.add(vector_name,v); + } + + inline bool remove_variable(const std::string& variable_name, const bool delete_node = true) + { + if (!valid()) + return false; + else + return local_data().variable_store.remove(variable_name, delete_node); + } + + #ifndef exprtk_disable_string_capabilities + inline bool remove_stringvar(const std::string& string_name) + { + if (!valid()) + return false; + else + return local_data().stringvar_store.remove(string_name); + } + #endif + + inline bool remove_function(const std::string& function_name) + { + if (!valid()) + return false; + else + return local_data().function_store.remove(function_name); + } + + inline bool remove_vararg_function(const std::string& vararg_function_name) + { + if (!valid()) + return false; + else + return local_data().vararg_function_store.remove(vararg_function_name); + } + + inline bool remove_vector(const std::string& vector_name) + { + if (!valid()) + return false; + else + return local_data().vector_store.remove(vector_name); + } + + inline bool add_constants() + { + return add_pi () && + add_epsilon () && + add_infinity() ; + } + + inline bool add_pi() + { + const typename details::numeric::details::number_type::type num_type; + static const T local_pi = details::numeric::details::const_pi_impl(num_type); + return add_constant("pi",local_pi); + } + + inline bool add_epsilon() + { + static const T local_epsilon = details::numeric::details::epsilon_type::value(); + return add_constant("epsilon",local_epsilon); + } + + inline bool add_infinity() + { + static const T local_infinity = std::numeric_limits::infinity(); + return add_constant("inf",local_infinity); + } + + template + inline bool add_package(Package& package) + { + return package.register_package(*this); + } + + template class Sequence> + inline std::size_t get_variable_list(Sequence,Allocator>& vlist) const + { + if (!valid()) + return 0; + else + return local_data().variable_store.get_list(vlist); + } + + template class Sequence> + inline std::size_t get_variable_list(Sequence& vlist) const + { + if (!valid()) + return 0; + else + return local_data().variable_store.get_list(vlist); + } + + #ifndef exprtk_disable_string_capabilities + template class Sequence> + inline std::size_t get_stringvar_list(Sequence,Allocator>& svlist) const + { + if (!valid()) + return 0; + else + return local_data().stringvar_store.get_list(svlist); + } + + template class Sequence> + inline std::size_t get_stringvar_list(Sequence& svlist) const + { + if (!valid()) + return 0; + else + return local_data().stringvar_store.get_list(svlist); + } + #endif + + template class Sequence> + inline std::size_t get_vector_list(Sequence& vlist) const + { + if (!valid()) + return 0; + else + return local_data().vector_store.get_list(vlist); + } + + inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const + { + /* + Function will return true if symbol_name exists as either a + reserved symbol, variable, stringvar, vector or function name + in any of the type stores. + */ + if (!valid()) + return false; + else if (local_data().variable_store.symbol_exists(symbol_name)) + return true; + #ifndef exprtk_disable_string_capabilities + else if (local_data().stringvar_store.symbol_exists(symbol_name)) + return true; + #endif + else if (local_data().vector_store.symbol_exists(symbol_name)) + return true; + else if (local_data().function_store.symbol_exists(symbol_name)) + return true; + else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) + return true; + else + return false; + } + + inline bool is_variable(const std::string& variable_name) const + { + if (!valid()) + return false; + else + return local_data().variable_store.symbol_exists(variable_name); + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_stringvar(const std::string& stringvar_name) const + { + if (!valid()) + return false; + else + return local_data().stringvar_store.symbol_exists(stringvar_name); + } + + inline bool is_conststr_stringvar(const std::string& symbol_name) const + { + if (!valid()) + return false; + else if (!valid_symbol(symbol_name)) + return false; + else if (!local_data().stringvar_store.symbol_exists(symbol_name)) + return false; + + return ( + local_data().stringvar_store.symbol_exists(symbol_name) || + local_data().stringvar_store.is_constant (symbol_name) + ); + } + #endif + + inline bool is_function(const std::string& function_name) const + { + if (!valid()) + return false; + else + return local_data().function_store.symbol_exists(function_name); + } + + inline bool is_vararg_function(const std::string& vararg_function_name) const + { + if (!valid()) + return false; + else + return local_data().vararg_function_store.symbol_exists(vararg_function_name); + } + + inline bool is_vector(const std::string& vector_name) const + { + if (!valid()) + return false; + else + return local_data().vector_store.symbol_exists(vector_name); + } + + inline std::string get_variable_name(const expression_ptr& ptr) const + { + return local_data().variable_store.entity_name(ptr); + } + + inline std::string get_vector_name(const vector_holder_ptr& ptr) const + { + return local_data().vector_store.entity_name(ptr); + } + + #ifndef exprtk_disable_string_capabilities + inline std::string get_stringvar_name(const expression_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + + inline std::string get_conststr_stringvar_name(const expression_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + #endif + + inline bool valid() const + { + // Symbol table sanity check. + return control_block_ && control_block_->data_; + } + + inline void load_from(const symbol_table& st) + { + { + std::vector name_list; + + st.local_data().function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::ifunction& ifunc = *st.get_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } + + { + std::vector name_list; + + st.local_data().vararg_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::ivararg_function& ivafunc = *st.get_vararg_function(name_list[i]); + add_function(name_list[i],ivafunc); + } + } + } + + { + std::vector name_list; + + st.local_data().generic_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::igeneric_function& ifunc = *st.get_generic_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } + + { + std::vector name_list; + + st.local_data().string_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::igeneric_function& ifunc = *st.get_string_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } + + { + std::vector name_list; + + st.local_data().overload_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::igeneric_function& ifunc = *st.get_overload_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } + } + + private: + + inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const + { + if (symbol.empty()) + return false; + else if (!details::is_letter(symbol[0])) + return false; + else if (symbol.size() > 1) + { + for (std::size_t i = 1; i < symbol.size(); ++i) + { + if ( + !details::is_letter_or_digit(symbol[i]) && + ('_' != symbol[i]) + ) + { + if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) + continue; + else + return false; + } + } + } + + return (check_reserved_symb) ? (!local_data().is_reserved_symbol(symbol)) : true; + } + + inline bool valid_function(const std::string& symbol) const + { + if (symbol.empty()) + return false; + else if (!details::is_letter(symbol[0])) + return false; + else if (symbol.size() > 1) + { + for (std::size_t i = 1; i < symbol.size(); ++i) + { + if ( + !details::is_letter_or_digit(symbol[i]) && + ('_' != symbol[i]) + ) + { + if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) + continue; + else + return false; + } + } + } + + return true; + } + + typedef typename control_block::st_data local_data_t; + + inline local_data_t& local_data() + { + return *(control_block_->data_); + } + + inline const local_data_t& local_data() const + { + return *(control_block_->data_); + } + + control_block* control_block_; + + friend class parser; + }; + + template + class function_compositor; + + template + class expression + { + private: + + typedef details::expression_node* expression_ptr; + typedef details::vector_holder* vector_holder_ptr; + typedef std::vector > symtab_list_t; + + struct control_block + { + enum data_type + { + e_unknown , + e_expr , + e_vecholder, + e_data , + e_vecdata , + e_string + }; + + struct data_pack + { + data_pack() + : pointer(0), + type(e_unknown), + size(0) + {} + + data_pack(void* ptr, const data_type dt, const std::size_t sz = 0) + : pointer(ptr), + type(dt), + size(sz) + {} + + void* pointer; + data_type type; + std::size_t size; + }; + + typedef std::vector local_data_list_t; + typedef results_context results_context_t; + + control_block() + : ref_count(0), + expr (0), + results (0), + retinv_null(false), + return_invoked(&retinv_null) + {} + + explicit control_block(expression_ptr e) + : ref_count(1), + expr (e), + results (0), + retinv_null(false), + return_invoked(&retinv_null) + {} + + ~control_block() + { + if (expr && details::branch_deletable(expr)) + { + destroy_node(expr); + } + + if (!local_data_list.empty()) + { + for (std::size_t i = 0; i < local_data_list.size(); ++i) + { + switch (local_data_list[i].type) + { + case e_expr : delete reinterpret_cast(local_data_list[i].pointer); + break; + + case e_vecholder : delete reinterpret_cast(local_data_list[i].pointer); + break; + + case e_data : delete reinterpret_cast(local_data_list[i].pointer); + break; + + case e_vecdata : delete [] reinterpret_cast(local_data_list[i].pointer); + break; + + case e_string : delete reinterpret_cast(local_data_list[i].pointer); + break; + + default : break; + } + } + } + + if (results) + { + delete results; + } + } + + static inline control_block* create(expression_ptr e) + { + return new control_block(e); + } + + static inline void destroy(control_block*& cntrl_blck) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + delete cntrl_blck; + } + + cntrl_blck = 0; + } + } + + std::size_t ref_count; + expression_ptr expr; + local_data_list_t local_data_list; + results_context_t* results; + bool retinv_null; + bool* return_invoked; + + friend class function_compositor; + }; + + public: + + expression() + : control_block_(0) + { + set_expression(new details::null_node()); + } + + expression(const expression& e) + : control_block_ (e.control_block_ ), + symbol_table_list_(e.symbol_table_list_) + { + control_block_->ref_count++; + } + + explicit expression(const symbol_table& symbol_table) + : control_block_(0) + { + set_expression(new details::null_node()); + symbol_table_list_.push_back(symbol_table); + } + + inline expression& operator=(const expression& e) + { + if (this != &e) + { + if (control_block_) + { + if ( + (0 != control_block_->ref_count) && + (0 == --control_block_->ref_count) + ) + { + delete control_block_; + } + + control_block_ = 0; + } + + control_block_ = e.control_block_; + control_block_->ref_count++; + symbol_table_list_ = e.symbol_table_list_; + } + + return *this; + } + + inline bool operator==(const expression& e) const + { + return (this == &e); + } + + inline bool operator!() const + { + return ( + (0 == control_block_ ) || + (0 == control_block_->expr) + ); + } + + inline expression& release() + { + control_block::destroy(control_block_); + + return (*this); + } + + ~expression() + { + control_block::destroy(control_block_); + } + + inline T value() const + { + assert(control_block_ ); + assert(control_block_->expr); + + return control_block_->expr->value(); + } + + inline T operator() () const + { + return value(); + } + + inline operator T() const + { + return value(); + } + + inline operator bool() const + { + return details::is_true(value()); + } + + inline void register_symbol_table(symbol_table& st) + { + symbol_table_list_.push_back(st); + } + + inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const + { + return symbol_table_list_[index]; + } + + inline symbol_table& get_symbol_table(const std::size_t& index = 0) + { + return symbol_table_list_[index]; + } + + typedef results_context results_context_t; + + inline const results_context_t& results() const + { + if (control_block_->results) + return (*control_block_->results); + else + { + static const results_context_t null_results; + return null_results; + } + } + + inline bool return_invoked() const + { + return (*control_block_->return_invoked); + } + + private: + + inline symtab_list_t get_symbol_table_list() const + { + return symbol_table_list_; + } + + inline void set_expression(const expression_ptr expr) + { + if (expr) + { + if (control_block_) + { + if (0 == --control_block_->ref_count) + { + delete control_block_; + } + } + + control_block_ = control_block::create(expr); + } + } + + inline void register_local_var(expression_ptr expr) + { + if (expr) + { + if (control_block_) + { + control_block_-> + local_data_list.push_back( + typename expression::control_block:: + data_pack(reinterpret_cast(expr), + control_block::e_expr)); + } + } + } + + inline void register_local_var(vector_holder_ptr vec_holder) + { + if (vec_holder) + { + if (control_block_) + { + control_block_-> + local_data_list.push_back( + typename expression::control_block:: + data_pack(reinterpret_cast(vec_holder), + control_block::e_vecholder)); + } + } + } + + inline void register_local_data(void* data, const std::size_t& size = 0, const std::size_t data_mode = 0) + { + if (data) + { + if (control_block_) + { + typename control_block::data_type dt = control_block::e_data; + + switch (data_mode) + { + case 0 : dt = control_block::e_data; break; + case 1 : dt = control_block::e_vecdata; break; + case 2 : dt = control_block::e_string; break; + } + + control_block_-> + local_data_list.push_back( + typename expression::control_block:: + data_pack(reinterpret_cast(data), dt, size)); + } + } + } + + inline const typename control_block::local_data_list_t& local_data_list() + { + if (control_block_) + { + return control_block_->local_data_list; + } + else + { + static typename control_block::local_data_list_t null_local_data_list; + return null_local_data_list; + } + } + + inline void register_return_results(results_context_t* rc) + { + if (control_block_ && rc) + { + control_block_->results = rc; + } + } + + inline void set_retinvk(bool* retinvk_ptr) + { + if (control_block_) + { + control_block_->return_invoked = retinvk_ptr; + } + } + + control_block* control_block_; + symtab_list_t symbol_table_list_; + + friend class parser; + friend class expression_helper; + friend class function_compositor; + }; + + template + class expression_helper + { + public: + + static inline bool is_constant(const expression& expr) + { + return details::is_constant_node(expr.control_block_->expr); + } + + static inline bool is_variable(const expression& expr) + { + return details::is_variable_node(expr.control_block_->expr); + } + + static inline bool is_unary(const expression& expr) + { + return details::is_unary_node(expr.control_block_->expr); + } + + static inline bool is_binary(const expression& expr) + { + return details::is_binary_node(expr.control_block_->expr); + } + + static inline bool is_function(const expression& expr) + { + return details::is_function(expr.control_block_->expr); + } + + static inline bool is_null(const expression& expr) + { + return details::is_null_node(expr.control_block_->expr); + } + }; + + template + inline bool is_valid(const expression& expr) + { + return !expression_helper::is_null(expr); + } + + namespace parser_error + { + enum error_mode + { + e_unknown = 0, + e_syntax = 1, + e_token = 2, + e_numeric = 4, + e_symtab = 5, + e_lexer = 6, + e_helper = 7, + e_parser = 8 + }; + + struct type + { + type() + : mode(parser_error::e_unknown), + line_no (0), + column_no(0) + {} + + lexer::token token; + error_mode mode; + std::string diagnostic; + std::string src_location; + std::string error_line; + std::size_t line_no; + std::size_t column_no; + }; + + inline type make_error(const error_mode mode, + const std::string& diagnostic = "", + const std::string& src_location = "") + { + type t; + t.mode = mode; + t.token.type = lexer::token::e_error; + t.diagnostic = diagnostic; + t.src_location = src_location; + exprtk_debug(("%s\n",diagnostic .c_str())); + return t; + } + + inline type make_error(const error_mode mode, + const lexer::token& tk, + const std::string& diagnostic = "", + const std::string& src_location = "") + { + type t; + t.mode = mode; + t.token = tk; + t.diagnostic = diagnostic; + t.src_location = src_location; + exprtk_debug(("%s\n",diagnostic .c_str())); + return t; + } + + inline std::string to_str(error_mode mode) + { + switch (mode) + { + case e_unknown : return std::string("Unknown Error"); + case e_syntax : return std::string("Syntax Error" ); + case e_token : return std::string("Token Error" ); + case e_numeric : return std::string("Numeric Error"); + case e_symtab : return std::string("Symbol Error" ); + case e_lexer : return std::string("Lexer Error" ); + case e_helper : return std::string("Helper Error" ); + case e_parser : return std::string("Parser Error" ); + default : return std::string("Unknown Error"); + } + } + + inline bool update_error(type& error, const std::string& expression) + { + if ( + expression.empty() || + (error.token.position > expression.size()) || + (std::numeric_limits::max() == error.token.position) + ) + { + return false; + } + + std::size_t error_line_start = 0; + + for (std::size_t i = error.token.position; i > 0; --i) + { + const details::char_t c = expression[i]; + + if (('\n' == c) || ('\r' == c)) + { + error_line_start = i + 1; + break; + } + } + + std::size_t next_nl_position = std::min(expression.size(), + expression.find_first_of('\n',error.token.position + 1)); + + error.column_no = error.token.position - error_line_start; + error.error_line = expression.substr(error_line_start, + next_nl_position - error_line_start); + + error.line_no = 0; + + for (std::size_t i = 0; i < next_nl_position; ++i) + { + if ('\n' == expression[i]) + ++error.line_no; + } + + return true; + } + + inline void dump_error(const type& error) + { + printf("Position: %02d Type: [%s] Msg: %s\n", + static_cast(error.token.position), + exprtk::parser_error::to_str(error.mode).c_str(), + error.diagnostic.c_str()); + } + } + + namespace details + { + template + inline void disable_type_checking(Parser& p) + { + p.state_.type_check_enabled = false; + } + } + + template + class parser : public lexer::parser_helper + { + private: + + enum precedence_level + { + e_level00, e_level01, e_level02, e_level03, e_level04, + e_level05, e_level06, e_level07, e_level08, e_level09, + e_level10, e_level11, e_level12, e_level13, e_level14 + }; + + typedef const T& cref_t; + typedef const T const_t; + typedef ifunction F; + typedef ivararg_function VAF; + typedef igeneric_function GF; + typedef ifunction ifunction_t; + typedef ivararg_function ivararg_function_t; + typedef igeneric_function igeneric_function_t; + typedef details::expression_node expression_node_t; + typedef details::literal_node literal_node_t; + typedef details::unary_node unary_node_t; + typedef details::binary_node binary_node_t; + typedef details::trinary_node trinary_node_t; + typedef details::quaternary_node quaternary_node_t; + typedef details::conditional_node conditional_node_t; + typedef details::cons_conditional_node cons_conditional_node_t; + typedef details::while_loop_node while_loop_node_t; + typedef details::repeat_until_loop_node repeat_until_loop_node_t; + typedef details::for_loop_node for_loop_node_t; + #ifndef exprtk_disable_break_continue + typedef details::while_loop_bc_node while_loop_bc_node_t; + typedef details::repeat_until_loop_bc_node repeat_until_loop_bc_node_t; + typedef details::for_loop_bc_node for_loop_bc_node_t; + #endif + typedef details::switch_node switch_node_t; + typedef details::variable_node variable_node_t; + typedef details::vector_elem_node vector_elem_node_t; + typedef details::rebasevector_elem_node rebasevector_elem_node_t; + typedef details::rebasevector_celem_node rebasevector_celem_node_t; + typedef details::vector_node vector_node_t; + typedef details::range_pack range_t; + #ifndef exprtk_disable_string_capabilities + typedef details::stringvar_node stringvar_node_t; + typedef details::string_literal_node string_literal_node_t; + typedef details::string_range_node string_range_node_t; + typedef details::const_string_range_node const_string_range_node_t; + typedef details::generic_string_range_node generic_string_range_node_t; + typedef details::string_concat_node string_concat_node_t; + typedef details::assignment_string_node assignment_string_node_t; + typedef details::assignment_string_range_node assignment_string_range_node_t; + typedef details::conditional_string_node conditional_string_node_t; + typedef details::cons_conditional_str_node cons_conditional_str_node_t; + #endif + typedef details::assignment_node assignment_node_t; + typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; + typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; + typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; + typedef details::assignment_vec_node assignment_vec_node_t; + typedef details::assignment_vecvec_node assignment_vecvec_node_t; + typedef details::scand_node scand_node_t; + typedef details::scor_node scor_node_t; + typedef lexer::token token_t; + typedef expression_node_t* expression_node_ptr; + typedef expression expression_t; + typedef symbol_table symbol_table_t; + typedef typename expression::symtab_list_t symbol_table_list_t; + typedef details::vector_holder* vector_holder_ptr; + + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; + + typedef details::operator_type operator_t; + + typedef std::map unary_op_map_t; + typedef std::map binary_op_map_t; + typedef std::map trinary_op_map_t; + + typedef std::map > sf3_map_t; + typedef std::map > sf4_map_t; + + typedef std::map inv_binary_op_map_t; + typedef std::multimap base_ops_map_t; + typedef std::set disabled_func_set_t; + + typedef details::T0oT1_define vov_t; + typedef details::T0oT1_define cov_t; + typedef details::T0oT1_define voc_t; + + typedef details::T0oT1oT2_define vovov_t; + typedef details::T0oT1oT2_define vovoc_t; + typedef details::T0oT1oT2_define vocov_t; + typedef details::T0oT1oT2_define covov_t; + typedef details::T0oT1oT2_define covoc_t; + typedef details::T0oT1oT2_define cocov_t; + typedef details::T0oT1oT2_define vococ_t; + + typedef details::T0oT1oT2oT3_define vovovov_t; + typedef details::T0oT1oT2oT3_define vovovoc_t; + typedef details::T0oT1oT2oT3_define vovocov_t; + typedef details::T0oT1oT2oT3_define vocovov_t; + typedef details::T0oT1oT2oT3_define covovov_t; + + typedef details::T0oT1oT2oT3_define covocov_t; + typedef details::T0oT1oT2oT3_define vocovoc_t; + typedef details::T0oT1oT2oT3_define covovoc_t; + typedef details::T0oT1oT2oT3_define vococov_t; + + typedef results_context results_context_t; + + typedef parser_helper prsrhlpr_t; + + struct scope_element + { + enum element_type + { + e_none , + e_variable, + e_vector , + e_vecelem , + e_string + }; + + typedef details::vector_holder vector_holder_t; + typedef variable_node_t* variable_node_ptr; + typedef vector_holder_t* vector_holder_ptr; + typedef expression_node_t* expression_node_ptr; + #ifndef exprtk_disable_string_capabilities + typedef stringvar_node_t* stringvar_node_ptr; + #endif + + scope_element() + : name("???"), + size (std::numeric_limits::max()), + index(std::numeric_limits::max()), + depth(std::numeric_limits::max()), + ref_count(0), + ip_index (0), + type (e_none), + active(false), + data (0), + var_node (0), + vec_node (0) + #ifndef exprtk_disable_string_capabilities + ,str_node(0) + #endif + {} + + bool operator < (const scope_element& se) const + { + if (ip_index < se.ip_index) + return true; + else if (ip_index > se.ip_index) + return false; + else if (depth < se.depth) + return true; + else if (depth > se.depth) + return false; + else if (index < se.index) + return true; + else if (index > se.index) + return false; + else + return (name < se.name); + } + + void clear() + { + name = "???"; + size = std::numeric_limits::max(); + index = std::numeric_limits::max(); + depth = std::numeric_limits::max(); + type = e_none; + active = false; + ref_count = 0; + ip_index = 0; + data = 0; + var_node = 0; + vec_node = 0; + #ifndef exprtk_disable_string_capabilities + str_node = 0; + #endif + } + + std::string name; + std::size_t size; + std::size_t index; + std::size_t depth; + std::size_t ref_count; + std::size_t ip_index; + element_type type; + bool active; + void* data; + expression_node_ptr var_node; + vector_holder_ptr vec_node; + #ifndef exprtk_disable_string_capabilities + stringvar_node_ptr str_node; + #endif + }; + + class scope_element_manager + { + public: + + typedef expression_node_t* expression_node_ptr; + typedef variable_node_t* variable_node_ptr; + typedef parser parser_t; + + explicit scope_element_manager(parser& p) + : parser_(p), + input_param_cnt_(0) + {} + + inline std::size_t size() const + { + return element_.size(); + } + + inline bool empty() const + { + return element_.empty(); + } + + inline scope_element& get_element(const std::size_t& index) + { + if (index < element_.size()) + return element_[index]; + else + return null_element_; + } + + inline scope_element& get_element(const std::string& var_name, + const std::size_t index = std::numeric_limits::max()) + { + const std::size_t current_depth = parser_.state_.scope_depth; + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.depth > current_depth) + continue; + else if ( + details::imatch(se.name, var_name) && + (se.index == index) + ) + return se; + } + + return null_element_; + } + + inline scope_element& get_active_element(const std::string& var_name, + const std::size_t index = std::numeric_limits::max()) + { + const std::size_t current_depth = parser_.state_.scope_depth; + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.depth > current_depth) + continue; + else if ( + details::imatch(se.name, var_name) && + (se.index == index) && + (se.active) + ) + return se; + } + + return null_element_; + } + + inline bool add_element(const scope_element& se) + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& cse = element_[i]; + + if ( + details::imatch(cse.name, se.name) && + (cse.depth <= se.depth) && + (cse.index == se.index) && + (cse.size == se.size ) && + (cse.type == se.type ) && + (cse.active) + ) + return false; + } + + element_.push_back(se); + std::sort(element_.begin(),element_.end()); + + return true; + } + + inline void deactivate(const std::size_t& scope_depth) + { + exprtk_debug(("deactivate() - Scope depth: %d\n", + static_cast(parser_.state_.scope_depth))); + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.active && (se.depth >= scope_depth)) + { + exprtk_debug(("deactivate() - element[%02d] '%s'\n", + static_cast(i), + se.name.c_str())); + + se.active = false; + } + } + } + + inline void free_element(scope_element& se) + { + exprtk_debug(("free_element() - se[%s]\n", se.name.c_str())); + + switch (se.type) + { + case scope_element::e_variable : delete reinterpret_cast(se.data); + delete se.var_node; + break; + + case scope_element::e_vector : delete[] reinterpret_cast(se.data); + delete se.vec_node; + break; + + case scope_element::e_vecelem : delete se.var_node; + break; + + #ifndef exprtk_disable_string_capabilities + case scope_element::e_string : delete reinterpret_cast(se.data); + delete se.str_node; + break; + #endif + + default : return; + } + + se.clear(); + } + + inline void cleanup() + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + free_element(element_[i]); + } + + element_.clear(); + + input_param_cnt_ = 0; + } + + inline std::size_t next_ip_index() + { + return ++input_param_cnt_; + } + + inline expression_node_ptr get_variable(const T& v) + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if ( + se.active && + se.var_node && + details::is_variable_node(se.var_node) + ) + { + variable_node_ptr vn = reinterpret_cast(se.var_node); + + if (&(vn->ref()) == (&v)) + { + return se.var_node; + } + } + } + + return expression_node_ptr(0); + } + + private: + + scope_element_manager& operator=(const scope_element_manager&); + + parser_t& parser_; + std::vector element_; + scope_element null_element_; + std::size_t input_param_cnt_; + }; + + class scope_handler + { + public: + + typedef parser parser_t; + + explicit scope_handler(parser& p) + : parser_(p) + { + parser_.state_.scope_depth++; + #ifdef exprtk_enable_debugging + const std::string depth(2 * parser_.state_.scope_depth,'-'); + exprtk_debug(("%s> Scope Depth: %02d\n", + depth.c_str(), + static_cast(parser_.state_.scope_depth))); + #endif + } + + ~scope_handler() + { + parser_.sem_.deactivate(parser_.state_.scope_depth); + parser_.state_.scope_depth--; + #ifdef exprtk_enable_debugging + const std::string depth(2 * parser_.state_.scope_depth,'-'); + exprtk_debug(("<%s Scope Depth: %02d\n", + depth.c_str(), + static_cast(parser_.state_.scope_depth))); + #endif + } + + private: + + scope_handler& operator=(const scope_handler&); + + parser_t& parser_; + }; + + class stack_limit_handler + { + public: + + typedef parser parser_t; + + explicit stack_limit_handler(parser& p) + : parser_(p), + limit_exceeded_(false) + { + if (++parser_.state_.stack_depth > parser_.settings_.max_stack_depth_) + { + limit_exceeded_ = true; + parser_.set_error( + make_error(parser_error::e_parser, + "ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + + " exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), + exprtk_error_location)); + } + } + + ~stack_limit_handler() + { + parser_.state_.stack_depth--; + } + + bool operator!() + { + return limit_exceeded_; + } + + private: + + stack_limit_handler& operator=(const stack_limit_handler&); + + parser_t& parser_; + bool limit_exceeded_; + }; + + struct symtab_store + { + symbol_table_list_t symtab_list_; + + typedef typename symbol_table_t::local_data_t local_data_t; + typedef typename symbol_table_t::variable_ptr variable_ptr; + typedef typename symbol_table_t::function_ptr function_ptr; + #ifndef exprtk_disable_string_capabilities + typedef typename symbol_table_t::stringvar_ptr stringvar_ptr; + #endif + typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; + typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; + typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; + + inline bool empty() const + { + return symtab_list_.empty(); + } + + inline void clear() + { + symtab_list_.clear(); + } + + inline bool valid() const + { + if (!empty()) + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (symtab_list_[i].valid()) + return true; + } + } + + return false; + } + + inline bool valid_symbol(const std::string& symbol) const + { + if (!symtab_list_.empty()) + return symtab_list_[0].valid_symbol(symbol); + else + return false; + } + + inline bool valid_function_name(const std::string& symbol) const + { + if (!symtab_list_.empty()) + return symtab_list_[0].valid_function(symbol); + else + return false; + } + + inline variable_ptr get_variable(const std::string& variable_name) const + { + if (!valid_symbol(variable_name)) + return reinterpret_cast(0); + + variable_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .variable_store.get(variable_name); + + if (result) break; + } + + return result; + } + + inline variable_ptr get_variable(const T& var_ref) const + { + variable_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i).variable_store + .get_from_varptr(reinterpret_cast(&var_ref)); + + if (result) break; + } + + return result; + } + + #ifndef exprtk_disable_string_capabilities + inline stringvar_ptr get_stringvar(const std::string& string_name) const + { + if (!valid_symbol(string_name)) + return reinterpret_cast(0); + + stringvar_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .stringvar_store.get(string_name); + + if (result) break; + } + + return result; + } + #endif + + inline function_ptr get_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const + { + if (!valid_function_name(vararg_function_name)) + return reinterpret_cast(0); + + vararg_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .vararg_function_store.get(vararg_function_name); + + if (result) break; + } + + return result; + } + + inline generic_function_ptr get_generic_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + generic_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .generic_function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline generic_function_ptr get_string_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + generic_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).string_function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline generic_function_ptr get_overload_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + generic_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).overload_function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline vector_holder_ptr get_vector(const std::string& vector_name) const + { + if (!valid_symbol(vector_name)) + return reinterpret_cast(0); + + vector_holder_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).vector_store.get(vector_name); + + if (result) break; + } + + return result; + } + + inline bool is_constant_node(const std::string& symbol_name) const + { + if (!valid_symbol(symbol_name)) + return false; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (local_data(i).variable_store.is_constant(symbol_name)) + return true; + } + + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_constant_string(const std::string& symbol_name) const + { + if (!valid_symbol(symbol_name)) + return false; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (!local_data(i).stringvar_store.symbol_exists(symbol_name)) + continue; + else if (local_data(i).stringvar_store.is_constant(symbol_name)) + return true; + } + + return false; + } + #endif + + inline bool symbol_exists(const std::string& symbol) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (symtab_list_[i].symbol_exists(symbol)) + return true; + } + + return false; + } + + inline bool is_variable(const std::string& variable_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().variable_store + .symbol_exists(variable_name) + ) + return true; + } + + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_stringvar(const std::string& stringvar_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().stringvar_store + .symbol_exists(stringvar_name) + ) + return true; + } + + return false; + } + + inline bool is_conststr_stringvar(const std::string& symbol_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().stringvar_store + .symbol_exists(symbol_name) + ) + { + return ( + local_data(i).stringvar_store.symbol_exists(symbol_name) || + local_data(i).stringvar_store.is_constant (symbol_name) + ); + + } + } + + return false; + } + #endif + + inline bool is_function(const std::string& function_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vararg_function_store + .symbol_exists(function_name) + ) + return true; + } + + return false; + } + + inline bool is_vararg_function(const std::string& vararg_function_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vararg_function_store + .symbol_exists(vararg_function_name) + ) + return true; + } + + return false; + } + + inline bool is_vector(const std::string& vector_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vector_store + .symbol_exists(vector_name) + ) + return true; + } + + return false; + } + + inline std::string get_variable_name(const expression_node_ptr& ptr) const + { + return local_data().variable_store.entity_name(ptr); + } + + inline std::string get_vector_name(const vector_holder_ptr& ptr) const + { + return local_data().vector_store.entity_name(ptr); + } + + #ifndef exprtk_disable_string_capabilities + inline std::string get_stringvar_name(const expression_node_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + + inline std::string get_conststr_stringvar_name(const expression_node_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + #endif + + inline local_data_t& local_data(const std::size_t& index = 0) + { + return symtab_list_[index].local_data(); + } + + inline const local_data_t& local_data(const std::size_t& index = 0) const + { + return symtab_list_[index].local_data(); + } + + inline symbol_table_t& get_symbol_table(const std::size_t& index = 0) + { + return symtab_list_[index]; + } + }; + + struct parser_state + { + parser_state() + : type_check_enabled(true) + { + reset(); + } + + void reset() + { + parsing_return_stmt = false; + parsing_break_stmt = false; + return_stmt_present = false; + side_effect_present = false; + scope_depth = 0; + stack_depth = 0; + parsing_loop_stmt_count = 0; + } + + #ifndef exprtk_enable_debugging + void activate_side_effect(const std::string&) + #else + void activate_side_effect(const std::string& source) + #endif + { + if (!side_effect_present) + { + side_effect_present = true; + + exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); + } + } + + bool parsing_return_stmt; + bool parsing_break_stmt; + bool return_stmt_present; + bool side_effect_present; + bool type_check_enabled; + std::size_t scope_depth; + std::size_t stack_depth; + std::size_t parsing_loop_stmt_count; + }; + + public: + + struct unknown_symbol_resolver + { + + enum usr_symbol_type + { + e_usr_unknown_type = 0, + e_usr_variable_type = 1, + e_usr_constant_type = 2 + }; + + enum usr_mode + { + e_usrmode_default = 0, + e_usrmode_extended = 1 + }; + + usr_mode mode; + + unknown_symbol_resolver(const usr_mode m = e_usrmode_default) + : mode(m) + {} + + virtual ~unknown_symbol_resolver() + {} + + virtual bool process(const std::string& /*unknown_symbol*/, + usr_symbol_type& st, + T& default_value, + std::string& error_message) + { + if (e_usrmode_default != mode) + return false; + + st = e_usr_variable_type; + default_value = T(0); + error_message.clear(); + + return true; + } + + virtual bool process(const std::string& /* unknown_symbol */, + symbol_table_t& /* symbol_table */, + std::string& /* error_message */) + { + return false; + } + }; + + enum collect_type + { + e_ct_none = 0, + e_ct_variables = 1, + e_ct_functions = 2, + e_ct_assignments = 4 + }; + + enum symbol_type + { + e_st_unknown = 0, + e_st_variable = 1, + e_st_vector = 2, + e_st_vecelem = 3, + e_st_string = 4, + e_st_function = 5, + e_st_local_variable = 6, + e_st_local_vector = 7, + e_st_local_string = 8 + }; + + class dependent_entity_collector + { + public: + + typedef std::pair symbol_t; + typedef std::vector symbol_list_t; + + dependent_entity_collector(const std::size_t options = e_ct_none) + : options_(options), + collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ), + collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ), + collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments), + return_present_ (false), + final_stmt_return_(false) + {} + + template class Sequence> + inline std::size_t symbols(Sequence& symbols_list) + { + if (!collect_variables_ && !collect_functions_) + return 0; + else if (symbol_name_list_.empty()) + return 0; + + for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) + { + details::case_normalise(symbol_name_list_[i].first); + } + + std::sort(symbol_name_list_.begin(),symbol_name_list_.end()); + + std::unique_copy(symbol_name_list_.begin(), + symbol_name_list_.end (), + std::back_inserter(symbols_list)); + + return symbols_list.size(); + } + + template class Sequence> + inline std::size_t assignment_symbols(Sequence& assignment_list) + { + if (!collect_assignments_) + return 0; + else if (assignment_name_list_.empty()) + return 0; + + for (std::size_t i = 0; i < assignment_name_list_.size(); ++i) + { + details::case_normalise(assignment_name_list_[i].first); + } + + std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); + + std::unique_copy(assignment_name_list_.begin(), + assignment_name_list_.end (), + std::back_inserter(assignment_list)); + + return assignment_list.size(); + } + + void clear() + { + symbol_name_list_ .clear(); + assignment_name_list_.clear(); + retparam_list_ .clear(); + return_present_ = false; + final_stmt_return_ = false; + } + + bool& collect_variables() + { + return collect_variables_; + } + + bool& collect_functions() + { + return collect_functions_; + } + + bool& collect_assignments() + { + return collect_assignments_; + } + + bool return_present() const + { + return return_present_; + } + + bool final_stmt_return() const + { + return final_stmt_return_; + } + + typedef std::vector retparam_list_t; + + retparam_list_t return_param_type_list() const + { + return retparam_list_; + } + + private: + + inline void add_symbol(const std::string& symbol, const symbol_type st) + { + switch (st) + { + case e_st_variable : + case e_st_vector : + case e_st_string : + case e_st_local_variable : + case e_st_local_vector : + case e_st_local_string : if (collect_variables_) + symbol_name_list_ + .push_back(std::make_pair(symbol, st)); + break; + + case e_st_function : if (collect_functions_) + symbol_name_list_ + .push_back(std::make_pair(symbol, st)); + break; + + default : return; + } + } + + inline void add_assignment(const std::string& symbol, const symbol_type st) + { + switch (st) + { + case e_st_variable : + case e_st_vector : + case e_st_string : if (collect_assignments_) + assignment_name_list_ + .push_back(std::make_pair(symbol, st)); + break; + + default : return; + } + } + + std::size_t options_; + bool collect_variables_; + bool collect_functions_; + bool collect_assignments_; + bool return_present_; + bool final_stmt_return_; + symbol_list_t symbol_name_list_; + symbol_list_t assignment_name_list_; + retparam_list_t retparam_list_; + + friend class parser; + }; + + class settings_store + { + private: + + typedef std::set disabled_entity_set_t; + typedef disabled_entity_set_t::iterator des_itr_t; + + public: + + enum settings_compilation_options + { + e_unknown = 0, + e_replacer = 1, + e_joiner = 2, + e_numeric_check = 4, + e_bracket_check = 8, + e_sequence_check = 16, + e_commutative_check = 32, + e_strength_reduction = 64, + e_disable_vardef = 128, + e_collect_vars = 256, + e_collect_funcs = 512, + e_collect_assings = 1024, + e_disable_usr_on_rsrvd = 2048, + e_disable_zero_return = 4096 + }; + + enum settings_base_funcs + { + e_bf_unknown = 0, + e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , + e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , + e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , + e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , + e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , + e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , + e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , + e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , + e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , + e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , + e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , + e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , + e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , + e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad, + e_bf_rad2deg , e_bf_grad2deg + }; + + enum settings_control_structs + { + e_ctrl_unknown = 0, + e_ctrl_ifelse, + e_ctrl_switch, + e_ctrl_for_loop, + e_ctrl_while_loop, + e_ctrl_repeat_loop, + e_ctrl_return + }; + + enum settings_logic_opr + { + e_logic_unknown = 0, + e_logic_and, e_logic_nand, e_logic_nor, + e_logic_not, e_logic_or, e_logic_xnor, + e_logic_xor, e_logic_scand, e_logic_scor + }; + + enum settings_arithmetic_opr + { + e_arith_unknown = 0, + e_arith_add, e_arith_sub, e_arith_mul, + e_arith_div, e_arith_mod, e_arith_pow + }; + + enum settings_assignment_opr + { + e_assign_unknown = 0, + e_assign_assign, e_assign_addass, e_assign_subass, + e_assign_mulass, e_assign_divass, e_assign_modass + }; + + enum settings_inequality_opr + { + e_ineq_unknown = 0, + e_ineq_lt, e_ineq_lte, e_ineq_eq, + e_ineq_equal, e_ineq_ne, e_ineq_nequal, + e_ineq_gte, e_ineq_gt + }; + + static const std::size_t compile_all_opts = e_replacer + + e_joiner + + e_numeric_check + + e_bracket_check + + e_sequence_check + + e_commutative_check + + e_strength_reduction; + + settings_store(const std::size_t compile_options = compile_all_opts) + : max_stack_depth_(400), + max_node_depth_(10000) + { + load_compile_options(compile_options); + } + + settings_store& enable_all_base_functions() + { + disabled_func_set_.clear(); + return (*this); + } + + settings_store& enable_all_control_structures() + { + disabled_ctrl_set_.clear(); + return (*this); + } + + settings_store& enable_all_logic_ops() + { + disabled_logic_set_.clear(); + return (*this); + } + + settings_store& enable_all_arithmetic_ops() + { + disabled_arithmetic_set_.clear(); + return (*this); + } + + settings_store& enable_all_assignment_ops() + { + disabled_assignment_set_.clear(); + return (*this); + } + + settings_store& enable_all_inequality_ops() + { + disabled_inequality_set_.clear(); + return (*this); + } + + settings_store& enable_local_vardef() + { + disable_vardef_ = false; + return (*this); + } + + settings_store& disable_all_base_functions() + { + std::copy(details::base_function_list, + details::base_function_list + details::base_function_list_size, + std::insert_iterator + (disabled_func_set_, disabled_func_set_.begin())); + return (*this); + } + + settings_store& disable_all_control_structures() + { + std::copy(details::cntrl_struct_list, + details::cntrl_struct_list + details::cntrl_struct_list_size, + std::insert_iterator + (disabled_ctrl_set_, disabled_ctrl_set_.begin())); + return (*this); + } + + settings_store& disable_all_logic_ops() + { + std::copy(details::logic_ops_list, + details::logic_ops_list + details::logic_ops_list_size, + std::insert_iterator + (disabled_logic_set_, disabled_logic_set_.begin())); + return (*this); + } + + settings_store& disable_all_arithmetic_ops() + { + std::copy(details::arithmetic_ops_list, + details::arithmetic_ops_list + details::arithmetic_ops_list_size, + std::insert_iterator + (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); + return (*this); + } + + settings_store& disable_all_assignment_ops() + { + std::copy(details::assignment_ops_list, + details::assignment_ops_list + details::assignment_ops_list_size, + std::insert_iterator + (disabled_assignment_set_, disabled_assignment_set_.begin())); + return (*this); + } + + settings_store& disable_all_inequality_ops() + { + std::copy(details::inequality_ops_list, + details::inequality_ops_list + details::inequality_ops_list_size, + std::insert_iterator + (disabled_inequality_set_, disabled_inequality_set_.begin())); + return (*this); + } + + settings_store& disable_local_vardef() + { + disable_vardef_ = true; + return (*this); + } + + bool replacer_enabled () const { return enable_replacer_; } + bool commutative_check_enabled () const { return enable_commutative_check_; } + bool joiner_enabled () const { return enable_joiner_; } + bool numeric_check_enabled () const { return enable_numeric_check_; } + bool bracket_check_enabled () const { return enable_bracket_check_; } + bool sequence_check_enabled () const { return enable_sequence_check_; } + bool strength_reduction_enabled () const { return enable_strength_reduction_; } + bool collect_variables_enabled () const { return enable_collect_vars_; } + bool collect_functions_enabled () const { return enable_collect_funcs_; } + bool collect_assignments_enabled() const { return enable_collect_assings_; } + bool vardef_disabled () const { return disable_vardef_; } + bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } + bool zero_return_disabled () const { return disable_zero_return_; } + + bool function_enabled(const std::string& function_name) const + { + if (disabled_func_set_.empty()) + return true; + else + return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); + } + + bool control_struct_enabled(const std::string& control_struct) const + { + if (disabled_ctrl_set_.empty()) + return true; + else + return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); + } + + bool logic_enabled(const std::string& logic_operation) const + { + if (disabled_logic_set_.empty()) + return true; + else + return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); + } + + bool arithmetic_enabled(const details::operator_type& arithmetic_operation) const + { + if (disabled_logic_set_.empty()) + return true; + else + return disabled_arithmetic_set_.end() == disabled_arithmetic_set_ + .find(arith_opr_to_string(arithmetic_operation)); + } + + bool assignment_enabled(const details::operator_type& assignment) const + { + if (disabled_assignment_set_.empty()) + return true; + else + return disabled_assignment_set_.end() == disabled_assignment_set_ + .find(assign_opr_to_string(assignment)); + } + + bool inequality_enabled(const details::operator_type& inequality) const + { + if (disabled_inequality_set_.empty()) + return true; + else + return disabled_inequality_set_.end() == disabled_inequality_set_ + .find(inequality_opr_to_string(inequality)); + } + + bool function_disabled(const std::string& function_name) const + { + if (disabled_func_set_.empty()) + return false; + else + return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); + } + + bool control_struct_disabled(const std::string& control_struct) const + { + if (disabled_ctrl_set_.empty()) + return false; + else + return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); + } + + bool logic_disabled(const std::string& logic_operation) const + { + if (disabled_logic_set_.empty()) + return false; + else + return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); + } + + bool assignment_disabled(const details::operator_type assignment_operation) const + { + if (disabled_assignment_set_.empty()) + return false; + else + return disabled_assignment_set_.end() != disabled_assignment_set_ + .find(assign_opr_to_string(assignment_operation)); + } + + bool logic_disabled(const details::operator_type logic_operation) const + { + if (disabled_logic_set_.empty()) + return false; + else + return disabled_logic_set_.end() != disabled_logic_set_ + .find(logic_opr_to_string(logic_operation)); + } + + bool arithmetic_disabled(const details::operator_type arithmetic_operation) const + { + if (disabled_arithmetic_set_.empty()) + return false; + else + return disabled_arithmetic_set_.end() != disabled_arithmetic_set_ + .find(arith_opr_to_string(arithmetic_operation)); + } + + bool inequality_disabled(const details::operator_type& inequality) const + { + if (disabled_inequality_set_.empty()) + return false; + else + return disabled_inequality_set_.end() != disabled_inequality_set_ + .find(inequality_opr_to_string(inequality)); + } + + settings_store& disable_base_function(settings_base_funcs bf) + { + if ( + (e_bf_unknown != bf) && + (static_cast(bf) < (details::base_function_list_size + 1)) + ) + { + disabled_func_set_.insert(details::base_function_list[bf - 1]); + } + + return (*this); + } + + settings_store& disable_control_structure(settings_control_structs ctrl_struct) + { + if ( + (e_ctrl_unknown != ctrl_struct) && + (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) + ) + { + disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); + } + + return (*this); + } + + settings_store& disable_logic_operation(settings_logic_opr logic) + { + if ( + (e_logic_unknown != logic) && + (static_cast(logic) < (details::logic_ops_list_size + 1)) + ) + { + disabled_logic_set_.insert(details::logic_ops_list[logic - 1]); + } + + return (*this); + } + + settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) + { + if ( + (e_arith_unknown != arithmetic) && + (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) + ) + { + disabled_arithmetic_set_.insert(details::arithmetic_ops_list[arithmetic - 1]); + } + + return (*this); + } + + settings_store& disable_assignment_operation(settings_assignment_opr assignment) + { + if ( + (e_assign_unknown != assignment) && + (static_cast(assignment) < (details::assignment_ops_list_size + 1)) + ) + { + disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); + } + + return (*this); + } + + settings_store& disable_inequality_operation(settings_inequality_opr inequality) + { + if ( + (e_ineq_unknown != inequality) && + (static_cast(inequality) < (details::inequality_ops_list_size + 1)) + ) + { + disabled_inequality_set_.insert(details::inequality_ops_list[inequality - 1]); + } + + return (*this); + } + + settings_store& enable_base_function(settings_base_funcs bf) + { + if ( + (e_bf_unknown != bf) && + (static_cast(bf) < (details::base_function_list_size + 1)) + ) + { + const des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); + + if (disabled_func_set_.end() != itr) + { + disabled_func_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_control_structure(settings_control_structs ctrl_struct) + { + if ( + (e_ctrl_unknown != ctrl_struct) && + (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) + ) + { + const des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); + + if (disabled_ctrl_set_.end() != itr) + { + disabled_ctrl_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_logic_operation(settings_logic_opr logic) + { + if ( + (e_logic_unknown != logic) && + (static_cast(logic) < (details::logic_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); + + if (disabled_logic_set_.end() != itr) + { + disabled_logic_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) + { + if ( + (e_arith_unknown != arithmetic) && + (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); + + if (disabled_arithmetic_set_.end() != itr) + { + disabled_arithmetic_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_assignment_operation(settings_assignment_opr assignment) + { + if ( + (e_assign_unknown != assignment) && + (static_cast(assignment) < (details::assignment_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); + + if (disabled_assignment_set_.end() != itr) + { + disabled_assignment_set_.erase(itr); + } + } + + return (*this); + } + + settings_store& enable_inequality_operation(settings_inequality_opr inequality) + { + if ( + (e_ineq_unknown != inequality) && + (static_cast(inequality) < (details::inequality_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); + + if (disabled_inequality_set_.end() != itr) + { + disabled_inequality_set_.erase(itr); + } + } + + return (*this); + } + + void set_max_stack_depth(const std::size_t mx_stack_depth) + { + max_stack_depth_ = mx_stack_depth; + } + + void set_max_node_depth(const std::size_t max_node_depth) + { + max_node_depth_ = max_node_depth; + } + + private: + + void load_compile_options(const std::size_t compile_options) + { + enable_replacer_ = (compile_options & e_replacer ) == e_replacer; + enable_joiner_ = (compile_options & e_joiner ) == e_joiner; + enable_numeric_check_ = (compile_options & e_numeric_check ) == e_numeric_check; + enable_bracket_check_ = (compile_options & e_bracket_check ) == e_bracket_check; + enable_sequence_check_ = (compile_options & e_sequence_check ) == e_sequence_check; + enable_commutative_check_ = (compile_options & e_commutative_check ) == e_commutative_check; + enable_strength_reduction_ = (compile_options & e_strength_reduction ) == e_strength_reduction; + enable_collect_vars_ = (compile_options & e_collect_vars ) == e_collect_vars; + enable_collect_funcs_ = (compile_options & e_collect_funcs ) == e_collect_funcs; + enable_collect_assings_ = (compile_options & e_collect_assings ) == e_collect_assings; + disable_vardef_ = (compile_options & e_disable_vardef ) == e_disable_vardef; + disable_rsrvd_sym_usr_ = (compile_options & e_disable_usr_on_rsrvd) == e_disable_usr_on_rsrvd; + disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; + } + + std::string assign_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_assign : return ":="; + case details::e_addass : return "+="; + case details::e_subass : return "-="; + case details::e_mulass : return "*="; + case details::e_divass : return "/="; + case details::e_modass : return "%="; + default : return ""; + } + } + + std::string arith_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_add : return "+"; + case details::e_sub : return "-"; + case details::e_mul : return "*"; + case details::e_div : return "/"; + case details::e_mod : return "%"; + default : return ""; + } + } + + std::string inequality_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_lt : return "<"; + case details::e_lte : return "<="; + case details::e_eq : return "=="; + case details::e_equal : return "="; + case details::e_ne : return "!="; + case details::e_nequal: return "<>"; + case details::e_gte : return ">="; + case details::e_gt : return ">"; + default : return ""; + } + } + + std::string logic_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_and : return "and" ; + case details::e_or : return "or" ; + case details::e_xor : return "xor" ; + case details::e_nand : return "nand"; + case details::e_nor : return "nor" ; + case details::e_xnor : return "xnor"; + case details::e_notl : return "not" ; + default : return "" ; + } + } + + bool enable_replacer_; + bool enable_joiner_; + bool enable_numeric_check_; + bool enable_bracket_check_; + bool enable_sequence_check_; + bool enable_commutative_check_; + bool enable_strength_reduction_; + bool enable_collect_vars_; + bool enable_collect_funcs_; + bool enable_collect_assings_; + bool disable_vardef_; + bool disable_rsrvd_sym_usr_; + bool disable_zero_return_; + + disabled_entity_set_t disabled_func_set_ ; + disabled_entity_set_t disabled_ctrl_set_ ; + disabled_entity_set_t disabled_logic_set_; + disabled_entity_set_t disabled_arithmetic_set_; + disabled_entity_set_t disabled_assignment_set_; + disabled_entity_set_t disabled_inequality_set_; + + std::size_t max_stack_depth_; + std::size_t max_node_depth_; + + friend class parser; + }; + + typedef settings_store settings_t; + + parser(const settings_t& settings = settings_t()) + : settings_(settings), + resolve_unknown_symbol_(false), + results_context_(0), + unknown_symbol_resolver_(reinterpret_cast(0)), + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning (disable:4355) + #endif + sem_(*this), + #ifdef _MSC_VER + #pragma warning(pop) + #endif + operator_joiner_2_(2), + operator_joiner_3_(3), + loop_runtime_check_(0) + { + init_precompilation(); + + load_operations_map (base_ops_map_ ); + load_unary_operations_map (unary_op_map_ ); + load_binary_operations_map (binary_op_map_ ); + load_inv_binary_operations_map(inv_binary_op_map_); + load_sf3_map (sf3_map_ ); + load_sf4_map (sf4_map_ ); + + expression_generator_.init_synthesize_map(); + expression_generator_.set_parser(*this); + expression_generator_.set_uom(unary_op_map_); + expression_generator_.set_bom(binary_op_map_); + expression_generator_.set_ibom(inv_binary_op_map_); + expression_generator_.set_sf3m(sf3_map_); + expression_generator_.set_sf4m(sf4_map_); + expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); + } + + ~parser() + {} + + inline void init_precompilation() + { + if (settings_.collect_variables_enabled()) + dec_.collect_variables() = true; + + if (settings_.collect_functions_enabled()) + dec_.collect_functions() = true; + + if (settings_.collect_assignments_enabled()) + dec_.collect_assignments() = true; + + if (settings_.replacer_enabled()) + { + symbol_replacer_.clear(); + symbol_replacer_.add_replace("true" , "1", lexer::token::e_number); + symbol_replacer_.add_replace("false", "0", lexer::token::e_number); + helper_assembly_.token_modifier_list.clear(); + helper_assembly_.register_modifier(&symbol_replacer_); + } + + if (settings_.commutative_check_enabled()) + { + for (std::size_t i = 0; i < details::reserved_words_size; ++i) + { + commutative_inserter_.ignore_symbol(details::reserved_words[i]); + } + + helper_assembly_.token_inserter_list.clear(); + helper_assembly_.register_inserter(&commutative_inserter_); + } + + if (settings_.joiner_enabled()) + { + helper_assembly_.token_joiner_list.clear(); + helper_assembly_.register_joiner(&operator_joiner_2_); + helper_assembly_.register_joiner(&operator_joiner_3_); + } + + if ( + settings_.numeric_check_enabled () || + settings_.bracket_check_enabled () || + settings_.sequence_check_enabled() + ) + { + helper_assembly_.token_scanner_list.clear(); + + if (settings_.numeric_check_enabled()) + { + helper_assembly_.register_scanner(&numeric_checker_); + } + + if (settings_.bracket_check_enabled()) + { + helper_assembly_.register_scanner(&bracket_checker_); + } + + if (settings_.sequence_check_enabled()) + { + helper_assembly_.register_scanner(&sequence_validator_ ); + helper_assembly_.register_scanner(&sequence_validator_3tkns_); + } + } + } + + inline bool compile(const std::string& expression_string, expression& expr) + { + state_ .reset(); + error_list_ .clear(); + brkcnt_list_ .clear(); + synthesis_error_.clear(); + sem_ .cleanup(); + + return_cleanup(); + + expression_generator_.set_allocator(node_allocator_); + + if (expression_string.empty()) + { + set_error( + make_error(parser_error::e_syntax, + "ERR001 - Empty expression!", + exprtk_error_location)); + + return false; + } + + if (!init(expression_string)) + { + process_lexer_errors(); + return false; + } + + if (lexer().empty()) + { + set_error( + make_error(parser_error::e_syntax, + "ERR002 - Empty expression!", + exprtk_error_location)); + + return false; + } + + if (!run_assemblies()) + { + return false; + } + + symtab_store_.symtab_list_ = expr.get_symbol_table_list(); + dec_.clear(); + + lexer().begin(); + + next_token(); + + expression_node_ptr e = parse_corpus(); + + if ((0 != e) && (token_t::e_eof == current_token().type)) + { + bool* retinvk_ptr = 0; + + if (state_.return_stmt_present) + { + dec_.return_present_ = true; + + e = expression_generator_ + .return_envelope(e, results_context_, retinvk_ptr); + } + + expr.set_expression(e); + expr.set_retinvk(retinvk_ptr); + + register_local_vars(expr); + register_return_results(expr); + + return !(!expr); + } + else + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR003 - Invalid expression encountered", + exprtk_error_location)); + } + + if ((0 != e) && branch_deletable(e)) + { + destroy_node(e); + } + + dec_.clear (); + sem_.cleanup (); + return_cleanup(); + + return false; + } + } + + inline expression_t compile(const std::string& expression_string, symbol_table_t& symtab) + { + expression_t expression; + + expression.register_symbol_table(symtab); + + compile(expression_string,expression); + + return expression; + } + + void process_lexer_errors() + { + for (std::size_t i = 0; i < lexer().size(); ++i) + { + if (lexer()[i].is_error()) + { + std::string diagnostic = "ERR004 - "; + + switch (lexer()[i].type) + { + case lexer::token::e_error : diagnostic += "General token error"; + break; + + case lexer::token::e_err_symbol : diagnostic += "Symbol error"; + break; + + case lexer::token::e_err_number : diagnostic += "Invalid numeric token"; + break; + + case lexer::token::e_err_string : diagnostic += "Invalid string token"; + break; + + case lexer::token::e_err_sfunc : diagnostic += "Invalid special function token"; + break; + + default : diagnostic += "Unknown compiler error"; + } + + set_error( + make_error(parser_error::e_lexer, + lexer()[i], + diagnostic + ": " + lexer()[i].value, + exprtk_error_location)); + } + } + } + + inline bool run_assemblies() + { + if (settings_.commutative_check_enabled()) + { + helper_assembly_.run_inserters(lexer()); + } + + if (settings_.joiner_enabled()) + { + helper_assembly_.run_joiners(lexer()); + } + + if (settings_.replacer_enabled()) + { + helper_assembly_.run_modifiers(lexer()); + } + + if ( + settings_.numeric_check_enabled () || + settings_.bracket_check_enabled () || + settings_.sequence_check_enabled() + ) + { + if (!helper_assembly_.run_scanners(lexer())) + { + if (helper_assembly_.error_token_scanner) + { + lexer::helper::bracket_checker* bracket_checker_ptr = 0; + lexer::helper::numeric_checker* numeric_checker_ptr = 0; + lexer::helper::sequence_validator* sequence_validator_ptr = 0; + lexer::helper::sequence_validator_3tokens* sequence_validator3_ptr = 0; + + if (0 != (bracket_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + set_error( + make_error(parser_error::e_token, + bracket_checker_ptr->error_token(), + "ERR005 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", + exprtk_error_location)); + } + else if (0 != (numeric_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) + { + lexer::token error_token = lexer()[numeric_checker_ptr->error_index(i)]; + + set_error( + make_error(parser_error::e_token, + error_token, + "ERR006 - Invalid numeric token: '" + error_token.value + "'", + exprtk_error_location)); + } + + if (numeric_checker_ptr->error_count()) + { + numeric_checker_ptr->clear_errors(); + } + } + else if (0 != (sequence_validator_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + for (std::size_t i = 0; i < sequence_validator_ptr->error_count(); ++i) + { + std::pair error_token = sequence_validator_ptr->error(i); + + set_error( + make_error(parser_error::e_token, + error_token.first, + "ERR007 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); + } + + if (sequence_validator_ptr->error_count()) + { + sequence_validator_ptr->clear_errors(); + } + } + else if (0 != (sequence_validator3_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + for (std::size_t i = 0; i < sequence_validator3_ptr->error_count(); ++i) + { + std::pair error_token = sequence_validator3_ptr->error(i); + + set_error( + make_error(parser_error::e_token, + error_token.first, + "ERR008 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); + } + + if (sequence_validator3_ptr->error_count()) + { + sequence_validator3_ptr->clear_errors(); + } + } + } + + return false; + } + } + + return true; + } + + inline settings_store& settings() + { + return settings_; + } + + inline parser_error::type get_error(const std::size_t& index) const + { + if (index < error_list_.size()) + return error_list_[index]; + else + throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); + } + + inline std::string error() const + { + if (!error_list_.empty()) + { + return error_list_[0].diagnostic; + } + else + return std::string("No Error"); + } + + inline std::size_t error_count() const + { + return error_list_.size(); + } + + inline dependent_entity_collector& dec() + { + return dec_; + } + + inline bool replace_symbol(const std::string& old_symbol, const std::string& new_symbol) + { + if (!settings_.replacer_enabled()) + return false; + else if (details::is_reserved_word(old_symbol)) + return false; + else + return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol); + } + + inline bool remove_replace_symbol(const std::string& symbol) + { + if (!settings_.replacer_enabled()) + return false; + else if (details::is_reserved_word(symbol)) + return false; + else + return symbol_replacer_.remove(symbol); + } + + inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast(0)) + { + resolve_unknown_symbol_ = true; + + if (usr) + unknown_symbol_resolver_ = usr; + else + unknown_symbol_resolver_ = &default_usr_; + } + + inline void enable_unknown_symbol_resolver(unknown_symbol_resolver& usr) + { + enable_unknown_symbol_resolver(&usr); + } + + inline void disable_unknown_symbol_resolver() + { + resolve_unknown_symbol_ = false; + unknown_symbol_resolver_ = &default_usr_; + } + + inline void register_loop_runtime_check(loop_runtime_check& lrtchk) + { + loop_runtime_check_ = &lrtchk; + } + + inline void clear_loop_runtime_check() + { + loop_runtime_check_ = loop_runtime_check_ptr(0); + } + + private: + + inline bool valid_base_operation(const std::string& symbol) const + { + const std::size_t length = symbol.size(); + + if ( + (length < 3) || // Shortest base op symbol length + (length > 9) // Longest base op symbol length + ) + return false; + else + return settings_.function_enabled(symbol) && + (base_ops_map_.end() != base_ops_map_.find(symbol)); + } + + inline bool valid_vararg_operation(const std::string& symbol) const + { + static const std::string s_sum = "sum" ; + static const std::string s_mul = "mul" ; + static const std::string s_avg = "avg" ; + static const std::string s_min = "min" ; + static const std::string s_max = "max" ; + static const std::string s_mand = "mand"; + static const std::string s_mor = "mor" ; + static const std::string s_multi = "~" ; + static const std::string s_mswitch = "[*]" ; + + return + ( + details::imatch(symbol,s_sum ) || + details::imatch(symbol,s_mul ) || + details::imatch(symbol,s_avg ) || + details::imatch(symbol,s_min ) || + details::imatch(symbol,s_max ) || + details::imatch(symbol,s_mand ) || + details::imatch(symbol,s_mor ) || + details::imatch(symbol,s_multi ) || + details::imatch(symbol,s_mswitch) + ) && + settings_.function_enabled(symbol); + } + + bool is_invalid_logic_operation(const details::operator_type operation) const + { + return settings_.logic_disabled(operation); + } + + bool is_invalid_arithmetic_operation(const details::operator_type operation) const + { + return settings_.arithmetic_disabled(operation); + } + + bool is_invalid_assignment_operation(const details::operator_type operation) const + { + return settings_.assignment_disabled(operation); + } + + bool is_invalid_inequality_operation(const details::operator_type operation) const + { + return settings_.inequality_disabled(operation); + } + + #ifdef exprtk_enable_debugging + inline void next_token() + { + const std::string ct_str = current_token().value; + const std::size_t ct_pos = current_token().position; + parser_helper::next_token(); + const std::string depth(2 * state_.scope_depth,' '); + exprtk_debug(("%s" + "prev[%s | %04d] --> curr[%s | %04d] stack_level: %3d\n", + depth.c_str(), + ct_str.c_str(), + static_cast(ct_pos), + current_token().value.c_str(), + static_cast(current_token().position), + static_cast(state_.stack_depth))); + } + #endif + + inline expression_node_ptr parse_corpus() + { + std::vector arg_list; + std::vector side_effect_list; + + scoped_vec_delete sdd((*this),arg_list); + + lexer::token begin_token; + lexer::token end_token; + + for ( ; ; ) + { + state_.side_effect_present = false; + + begin_token = current_token(); + + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR009 - Invalid expression encountered", + exprtk_error_location)); + } + + return error_node(); + } + else + { + arg_list.push_back(arg); + + side_effect_list.push_back(state_.side_effect_present); + + end_token = current_token(); + + const std::string sub_expr = construct_subexpr(begin_token, end_token); + + exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", + static_cast(arg_list.size() - 1), + sub_expr.c_str())); + + exprtk_debug(("parse_corpus(%02d) - Side effect present: %s\n", + static_cast(arg_list.size() - 1), + state_.side_effect_present ? "true" : "false")); + + exprtk_debug(("-------------------------------------------------\n")); + } + + if (lexer().finished()) + break; + else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + if (lexer().finished()) + break; + else + next_token(); + } + } + + if ( + !arg_list.empty() && + is_return_node(arg_list.back()) + ) + { + dec_.final_stmt_return_ = true; + } + + const expression_node_ptr result = simplify(arg_list,side_effect_list); + + sdd.delete_ptr = (0 == result); + + return result; + } + + std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) + { + std::string result = lexer().substr(begin_token.position,end_token.position); + + for (std::size_t i = 0; i < result.size(); ++i) + { + if (details::is_whitespace(result[i])) result[i] = ' '; + } + + return result; + } + + static const precedence_level default_precedence = e_level00; + + struct state_t + { + inline void set(const precedence_level& l, + const precedence_level& r, + const details::operator_type& o) + { + left = l; + right = r; + operation = o; + } + + inline void reset() + { + left = e_level00; + right = e_level00; + operation = details::e_default; + } + + precedence_level left; + precedence_level right; + details::operator_type operation; + }; + + inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) + { + stack_limit_handler slh(*this); + + if (!slh) + { + return error_node(); + } + + expression_node_ptr expression = parse_branch(precedence); + + if (0 == expression) + { + return error_node(); + } + + bool break_loop = false; + + state_t current_state; + + for ( ; ; ) + { + current_state.reset(); + + switch (current_token().type) + { + case token_t::e_assign : current_state.set(e_level00,e_level00, details::e_assign); break; + case token_t::e_addass : current_state.set(e_level00,e_level00, details::e_addass); break; + case token_t::e_subass : current_state.set(e_level00,e_level00, details::e_subass); break; + case token_t::e_mulass : current_state.set(e_level00,e_level00, details::e_mulass); break; + case token_t::e_divass : current_state.set(e_level00,e_level00, details::e_divass); break; + case token_t::e_modass : current_state.set(e_level00,e_level00, details::e_modass); break; + case token_t::e_swap : current_state.set(e_level00,e_level00, details::e_swap ); break; + case token_t::e_lt : current_state.set(e_level05,e_level06, details:: e_lt); break; + case token_t::e_lte : current_state.set(e_level05,e_level06, details:: e_lte); break; + case token_t::e_eq : current_state.set(e_level05,e_level06, details:: e_eq); break; + case token_t::e_ne : current_state.set(e_level05,e_level06, details:: e_ne); break; + case token_t::e_gte : current_state.set(e_level05,e_level06, details:: e_gte); break; + case token_t::e_gt : current_state.set(e_level05,e_level06, details:: e_gt); break; + case token_t::e_add : current_state.set(e_level07,e_level08, details:: e_add); break; + case token_t::e_sub : current_state.set(e_level07,e_level08, details:: e_sub); break; + case token_t::e_div : current_state.set(e_level10,e_level11, details:: e_div); break; + case token_t::e_mul : current_state.set(e_level10,e_level11, details:: e_mul); break; + case token_t::e_mod : current_state.set(e_level10,e_level11, details:: e_mod); break; + case token_t::e_pow : current_state.set(e_level12,e_level12, details:: e_pow); break; + default : if (token_t::e_symbol == current_token().type) + { + static const std::string s_and = "and"; + static const std::string s_nand = "nand"; + static const std::string s_or = "or"; + static const std::string s_nor = "nor"; + static const std::string s_xor = "xor"; + static const std::string s_xnor = "xnor"; + static const std::string s_in = "in"; + static const std::string s_like = "like"; + static const std::string s_ilike = "ilike"; + static const std::string s_and1 = "&"; + static const std::string s_or1 = "|"; + static const std::string s_not = "not"; + + if (details::imatch(current_token().value,s_and)) + { + current_state.set(e_level03, e_level04, details::e_and); + break; + } + else if (details::imatch(current_token().value,s_and1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level03, e_level04, details::e_scand); + #else + current_state.set(e_level03, e_level04, details::e_and); + #endif + break; + } + else if (details::imatch(current_token().value,s_nand)) + { + current_state.set(e_level03, e_level04, details::e_nand); + break; + } + else if (details::imatch(current_token().value,s_or)) + { + current_state.set(e_level01, e_level02, details::e_or); + break; + } + else if (details::imatch(current_token().value,s_or1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level01, e_level02, details::e_scor); + #else + current_state.set(e_level01, e_level02, details::e_or); + #endif + break; + } + else if (details::imatch(current_token().value,s_nor)) + { + current_state.set(e_level01, e_level02, details::e_nor); + break; + } + else if (details::imatch(current_token().value,s_xor)) + { + current_state.set(e_level01, e_level02, details::e_xor); + break; + } + else if (details::imatch(current_token().value,s_xnor)) + { + current_state.set(e_level01, e_level02, details::e_xnor); + break; + } + else if (details::imatch(current_token().value,s_in)) + { + current_state.set(e_level04, e_level04, details::e_in); + break; + } + else if (details::imatch(current_token().value,s_like)) + { + current_state.set(e_level04, e_level04, details::e_like); + break; + } + else if (details::imatch(current_token().value,s_ilike)) + { + current_state.set(e_level04, e_level04, details::e_ilike); + break; + } + else if (details::imatch(current_token().value,s_not)) + { + break; + } + } + + break_loop = true; + } + + if (break_loop) + { + parse_pending_string_rangesize(expression); + break; + } + else if (current_state.left < precedence) + break; + + const lexer::token prev_token = current_token(); + + next_token(); + + expression_node_ptr right_branch = error_node(); + expression_node_ptr new_expression = error_node(); + + if (is_invalid_logic_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR010 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); + } + else if (is_invalid_arithmetic_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR011 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); + } + else if (is_invalid_inequality_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR012 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); + } + else if (is_invalid_assignment_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR013 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); + } + + if (0 != (right_branch = parse_expression(current_state.right))) + { + if ( + details::is_return_node(expression ) || + details::is_return_node(right_branch) + ) + { + free_node(node_allocator_, expression ); + free_node(node_allocator_, right_branch); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR014 - Return statements cannot be part of sub-expressions", + exprtk_error_location)); + + return error_node(); + } + + new_expression = expression_generator_ + ( + current_state.operation, + expression, + right_branch + ); + } + + if (0 == new_expression) + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + prev_token, + !synthesis_error_.empty() ? + synthesis_error_ : + "ERR015 - General parsing error at token: '" + prev_token.value + "'", + exprtk_error_location)); + } + + free_node(node_allocator_, expression ); + free_node(node_allocator_, right_branch); + + return error_node(); + } + else + { + if ( + token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && + (precedence == e_level00) + ) + { + expression = parse_ternary_conditional_statement(new_expression); + } + else + expression = new_expression; + + parse_pending_string_rangesize(expression); + } + } + + if ((0 != expression) && (expression->node_depth() > settings_.max_node_depth_)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR016 - Expression depth of " + details::to_str(static_cast(expression->node_depth())) + + " exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), + exprtk_error_location)); + + free_node(node_allocator_,expression); + + return error_node(); + } + + return expression; + } + + bool simplify_unary_negation_branch(expression_node_ptr& node) + { + { + typedef details::unary_branch_node > ubn_t; + ubn_t* n = dynamic_cast(node); + + if (n) + { + expression_node_ptr un_r = n->branch(0); + n->release(); + free_node(node_allocator_,node); + node = un_r; + + return true; + } + } + + { + typedef details::unary_variable_node > uvn_t; + + uvn_t* n = dynamic_cast(node); + + if (n) + { + const T& v = n->v(); + expression_node_ptr return_node = error_node(); + + if ( + (0 != (return_node = symtab_store_.get_variable(v))) || + (0 != (return_node = sem_ .get_variable(v))) + ) + { + free_node(node_allocator_,node); + node = return_node; + + return true; + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR017 - Failed to find variable node in symbol table", + exprtk_error_location)); + + free_node(node_allocator_,node); + + return false; + } + } + } + + return false; + } + + static inline expression_node_ptr error_node() + { + return reinterpret_cast(0); + } + + struct scoped_expression_delete + { + scoped_expression_delete(parser& pr, expression_node_ptr& expression) + : delete_ptr(true), + parser_(pr), + expression_(expression) + {} + + ~scoped_expression_delete() + { + if (delete_ptr) + { + free_node(parser_.node_allocator_, expression_); + } + } + + bool delete_ptr; + parser& parser_; + expression_node_ptr& expression_; + + private: + + scoped_expression_delete& operator=(const scoped_expression_delete&); + }; + + template + struct scoped_delete + { + typedef Type* ptr_t; + + scoped_delete(parser& pr, ptr_t& p) + : delete_ptr(true), + parser_(pr), + p_(&p) + {} + + scoped_delete(parser& pr, ptr_t (&p)[N]) + : delete_ptr(true), + parser_(pr), + p_(&p[0]) + {} + + ~scoped_delete() + { + if (delete_ptr) + { + for (std::size_t i = 0; i < N; ++i) + { + free_node(parser_.node_allocator_, p_[i]); + } + } + } + + bool delete_ptr; + parser& parser_; + ptr_t* p_; + + private: + + scoped_delete& operator=(const scoped_delete&); + }; + + template + struct scoped_deq_delete + { + typedef Type* ptr_t; + + scoped_deq_delete(parser& pr, std::deque& deq) + : delete_ptr(true), + parser_(pr), + deq_(deq) + {} + + ~scoped_deq_delete() + { + if (delete_ptr && !deq_.empty()) + { + for (std::size_t i = 0; i < deq_.size(); ++i) + { + free_node(parser_.node_allocator_,deq_[i]); + } + + deq_.clear(); + } + } + + bool delete_ptr; + parser& parser_; + std::deque& deq_; + + private: + + scoped_deq_delete& operator=(const scoped_deq_delete&); + }; + + template + struct scoped_vec_delete + { + typedef Type* ptr_t; + + scoped_vec_delete(parser& pr, std::vector& vec) + : delete_ptr(true), + parser_(pr), + vec_(vec) + {} + + ~scoped_vec_delete() + { + if (delete_ptr && !vec_.empty()) + { + for (std::size_t i = 0; i < vec_.size(); ++i) + { + free_node(parser_.node_allocator_,vec_[i]); + } + + vec_.clear(); + } + } + + bool delete_ptr; + parser& parser_; + std::vector& vec_; + + private: + + scoped_vec_delete& operator=(const scoped_vec_delete&); + }; + + struct scoped_bool_negator + { + explicit scoped_bool_negator(bool& bb) + : b(bb) + { b = !b; } + + ~scoped_bool_negator() + { b = !b; } + + bool& b; + }; + + struct scoped_bool_or_restorer + { + explicit scoped_bool_or_restorer(bool& bb) + : b(bb), + original_value_(bb) + {} + + ~scoped_bool_or_restorer() + { + b = b || original_value_; + } + + bool& b; + bool original_value_; + }; + + struct scoped_inc_dec + { + explicit scoped_inc_dec(std::size_t& v) + : v_(v) + { ++v_; } + + ~scoped_inc_dec() + { + assert(v_ > 0); + --v_; + } + + std::size_t& v_; + }; + + inline expression_node_ptr parse_function_invocation(ifunction* function, const std::string& function_name) + { + expression_node_ptr func_node = reinterpret_cast(0); + + switch (function->param_count) + { + case 0 : func_node = parse_function_call_0 (function,function_name); break; + case 1 : func_node = parse_function_call< 1>(function,function_name); break; + case 2 : func_node = parse_function_call< 2>(function,function_name); break; + case 3 : func_node = parse_function_call< 3>(function,function_name); break; + case 4 : func_node = parse_function_call< 4>(function,function_name); break; + case 5 : func_node = parse_function_call< 5>(function,function_name); break; + case 6 : func_node = parse_function_call< 6>(function,function_name); break; + case 7 : func_node = parse_function_call< 7>(function,function_name); break; + case 8 : func_node = parse_function_call< 8>(function,function_name); break; + case 9 : func_node = parse_function_call< 9>(function,function_name); break; + case 10 : func_node = parse_function_call<10>(function,function_name); break; + case 11 : func_node = parse_function_call<11>(function,function_name); break; + case 12 : func_node = parse_function_call<12>(function,function_name); break; + case 13 : func_node = parse_function_call<13>(function,function_name); break; + case 14 : func_node = parse_function_call<14>(function,function_name); break; + case 15 : func_node = parse_function_call<15>(function,function_name); break; + case 16 : func_node = parse_function_call<16>(function,function_name); break; + case 17 : func_node = parse_function_call<17>(function,function_name); break; + case 18 : func_node = parse_function_call<18>(function,function_name); break; + case 19 : func_node = parse_function_call<19>(function,function_name); break; + case 20 : func_node = parse_function_call<20>(function,function_name); break; + default : { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR018 - Invalid number of parameters for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + } + + if (func_node) + return func_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR019 - Failed to generate call to function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + } + + template + inline expression_node_ptr parse_function_call(ifunction* function, const std::string& function_name) + { + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + if (0 == NumberofParameters) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR020 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", + exprtk_error_location)); + + return error_node(); + } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + + expression_node_ptr branch[NumberofParameters]; + expression_node_ptr result = error_node(); + + std::fill_n(branch, NumberofParameters, reinterpret_cast(0)); + + scoped_delete sd((*this),branch); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR021 - Expecting argument list for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + + for (int i = 0; i < static_cast(NumberofParameters); ++i) + { + branch[i] = parse_expression(); + + if (0 == branch[i]) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR022 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (i < static_cast(NumberofParameters - 1)) + { + if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR023 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR024 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + else + result = expression_generator_.function(function,branch); + + sd.delete_ptr = (0 == result); + + return result; + } + + inline expression_node_ptr parse_function_call_0(ifunction* function, const std::string& function_name) + { + expression_node_ptr result = expression_generator_.function(function); + + state_.side_effect_present = function->has_side_effects(); + + next_token(); + + if ( + token_is(token_t::e_lbracket) && + !token_is(token_t::e_rbracket) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR025 - Expecting '()' to proceed call to function: '" + function_name + "'", + exprtk_error_location)); + + free_node(node_allocator_,result); + + return error_node(); + } + else + return result; + } + + template + inline std::size_t parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters], const std::string& function_name = "") + { + std::fill_n(param_list, MaxNumberofParameters, reinterpret_cast(0)); + + scoped_delete sd((*this),param_list); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR026 - Expected a '(' at start of function call to '" + function_name + + "', instead got: '" + current_token().value + "'", + exprtk_error_location)); + + return 0; + } + + if (token_is(token_t::e_rbracket, e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR027 - Expected at least one input parameter for function call '" + function_name + "'", + exprtk_error_location)); + + return 0; + } + + std::size_t param_index = 0; + + for (; param_index < MaxNumberofParameters; ++param_index) + { + param_list[param_index] = parse_expression(); + + if (0 == param_list[param_index]) + return 0; + else if (token_is(token_t::e_rbracket)) + { + sd.delete_ptr = false; + break; + } + else if (token_is(token_t::e_comma)) + continue; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR028 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", + exprtk_error_location)); + + return 0; + } + } + + if (sd.delete_ptr) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR029 - Invalid number of input parameters passed to function '" + function_name + "'", + exprtk_error_location)); + + return 0; + } + + return (param_index + 1); + } + + inline expression_node_ptr parse_base_operation() + { + typedef std::pair map_range_t; + + const std::string operation_name = current_token().value; + const token_t diagnostic_token = current_token(); + + map_range_t itr_range = base_ops_map_.equal_range(operation_name); + + if (0 == std::distance(itr_range.first,itr_range.second)) + { + set_error( + make_error(parser_error::e_syntax, + diagnostic_token, + "ERR030 - No entry found for base operation: " + operation_name, + exprtk_error_location)); + + return error_node(); + } + + static const std::size_t MaxNumberofParameters = 4; + expression_node_ptr param_list[MaxNumberofParameters] = {0}; + + const std::size_t parameter_count = parse_base_function_call(param_list, operation_name); + + if ((parameter_count > 0) && (parameter_count <= MaxNumberofParameters)) + { + for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) + { + const details::base_operation_t& operation = itr->second; + + if (operation.num_params == parameter_count) + { + switch (parameter_count) + { + #define base_opr_case(N) \ + case N : { \ + expression_node_ptr pl##N[N] = {0}; \ + std::copy(param_list, param_list + N, pl##N); \ + lodge_symbol(operation_name, e_st_function); \ + return expression_generator_(operation.type, pl##N); \ + } \ + + base_opr_case(1) + base_opr_case(2) + base_opr_case(3) + base_opr_case(4) + #undef base_opr_case + } + } + } + } + + for (std::size_t i = 0; i < MaxNumberofParameters; ++i) + { + free_node(node_allocator_, param_list[i]); + } + + set_error( + make_error(parser_error::e_syntax, + diagnostic_token, + "ERR031 - Invalid number of input parameters for call to function: '" + operation_name + "'", + exprtk_error_location)); + + return error_node(); + } + + inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition) + { + // Parse: [if][(][condition][,][consequent][,][alternative][)] + + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); + + bool result = true; + + if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR032 - Expected ',' between if-statement condition and consequent", + exprtk_error_location)); + result = false; + } + else if (0 == (consequent = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR033 - Failed to parse consequent for if-statement", + exprtk_error_location)); + result = false; + } + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR034 - Expected ',' between if-statement consequent and alternative", + exprtk_error_location)); + result = false; + } + else if (0 == (alternative = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR035 - Failed to parse alternative for if-statement", + exprtk_error_location)); + result = false; + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR036 - Expected ')' at the end of if-statement", + exprtk_error_location)); + result = false; + } + + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node(consequent ); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) + { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition, consequent, alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR037 - Return types of ternary if-statement differ", + exprtk_error_location)); + + result = false; + } + } + #endif + + if (!result) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); + free_node(node_allocator_, alternative); + + return error_node(); + } + else + return expression_generator_ + .conditional(condition, consequent, alternative); + } + + inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) + { + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); + + bool result = true; + + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + if (0 == (consequent = parse_multi_sequence("if-statement-01"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR038 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); + + result = false; + } + } + else + { + if ( + settings_.commutative_check_enabled() && + token_is(token_t::e_mul,prsrhlpr_t::e_hold) + ) + { + next_token(); + } + + if (0 != (consequent = parse_expression())) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR039 - Expected ';' at the end of the consequent for if-statement", + exprtk_error_location)); + + result = false; + } + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR040 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); + + result = false; + } + } + + if (result) + { + if (details::imatch(current_token().value,"else")) + { + next_token(); + + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + if (0 == (alternative = parse_multi_sequence("else-statement-01"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR041 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); + + result = false; + } + } + else if (details::imatch(current_token().value,"if")) + { + if (0 == (alternative = parse_conditional_statement())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR042 - Failed to parse body of if-else statement", + exprtk_error_location)); + + result = false; + } + } + else if (0 != (alternative = parse_expression())) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR043 - Expected ';' at the end of the 'else-if' for the if-statement", + exprtk_error_location)); + + result = false; + } + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR044 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); + + result = false; + } + } + } + + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node(consequent ); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) + { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition, consequent, alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR045 - Return types of ternary if-statement differ", + exprtk_error_location)); + + result = false; + } + } + #endif + + if (!result) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); + free_node(node_allocator_, alternative); + + return error_node(); + } + else + return expression_generator_ + .conditional(condition, consequent, alternative); + } + + inline expression_node_ptr parse_conditional_statement() + { + expression_node_ptr condition = error_node(); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR046 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", + exprtk_error_location)); + + return error_node(); + } + else if (0 == (condition = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR047 - Failed to parse condition for if-statement", + exprtk_error_location)); + + return error_node(); + } + else if (token_is(token_t::e_comma,prsrhlpr_t::e_hold)) + { + // if (x,y,z) + return parse_conditional_statement_01(condition); + } + else if (token_is(token_t::e_rbracket)) + { + // 00. if (x) y; + // 01. if (x) y; else z; + // 02. if (x) y; else {z0; ... zn;} + // 03. if (x) y; else if (z) w; + // 04. if (x) y; else if (z) w; else u; + // 05. if (x) y; else if (z) w; else {u0; ... un;} + // 06. if (x) y; else if (z) {w0; ... wn;} + // 07. if (x) {y0; ... yn;} + // 08. if (x) {y0; ... yn;} else z; + // 09. if (x) {y0; ... yn;} else {z0; ... zn;}; + // 10. if (x) {y0; ... yn;} else if (z) w; + // 11. if (x) {y0; ... yn;} else if (z) w; else u; + // 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} + // 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} + return parse_conditional_statement_02(condition); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR048 - Invalid if-statement", + exprtk_error_location)); + + free_node(node_allocator_,condition); + + return error_node(); + } + + inline expression_node_ptr parse_ternary_conditional_statement(expression_node_ptr condition) + { + // Parse: [condition][?][consequent][:][alternative] + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); + + bool result = true; + + if (0 == condition) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR049 - Encountered invalid condition branch for ternary if-statement", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_ternary)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR050 - Expected '?' after condition of ternary if-statement", + exprtk_error_location)); + + result = false; + } + else if (0 == (consequent = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR051 - Failed to parse consequent for ternary if-statement", + exprtk_error_location)); + + result = false; + } + else if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR052 - Expected ':' between ternary if-statement consequent and alternative", + exprtk_error_location)); + + result = false; + } + else if (0 == (alternative = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR053 - Failed to parse alternative for ternary if-statement", + exprtk_error_location)); + + result = false; + } + + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node(consequent ); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) + { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition, consequent, alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR054 - Return types of ternary if-statement differ", + exprtk_error_location)); + + result = false; + } + } + #endif + + if (!result) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); + free_node(node_allocator_, alternative); + + return error_node(); + } + else + return expression_generator_ + .conditional(condition, consequent, alternative); + } + + inline expression_node_ptr parse_not_statement() + { + if (settings_.logic_disabled("not")) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR055 - Invalid or disabled logic operation 'not'", + exprtk_error_location)); + + return error_node(); + } + + return parse_base_operation(); + } + + inline expression_node_ptr parse_while_loop() + { + // Parse: [while][(][test expr][)][{][expression][}] + expression_node_ptr condition = error_node(); + expression_node_ptr branch = error_node(); + expression_node_ptr result_node = error_node(); + + bool result = true; + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR056 - Expected '(' at start of while-loop condition statement", + exprtk_error_location)); + + return error_node(); + } + else if (0 == (condition = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR057 - Failed to parse condition for while-loop", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR058 - Expected ')' at end of while-loop condition statement", + exprtk_error_location)); + + result = false; + } + + brkcnt_list_.push_front(false); + + if (result) + { + scoped_inc_dec sid(state_.parsing_loop_stmt_count); + + if (0 == (branch = parse_multi_sequence("while-loop"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR059 - Failed to parse body of while-loop")); + result = false; + } + else if (0 == (result_node = expression_generator_.while_loop(condition, + branch, + brkcnt_list_.front()))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR060 - Failed to synthesize while-loop", + exprtk_error_location)); + + result = false; + } + } + + if (!result) + { + free_node(node_allocator_, branch ); + free_node(node_allocator_, condition ); + free_node(node_allocator_, result_node); + + brkcnt_list_.pop_front(); + + return error_node(); + } + else + return result_node; + } + + inline expression_node_ptr parse_repeat_until_loop() + { + // Parse: [repeat][{][expression][}][until][(][test expr][)] + expression_node_ptr condition = error_node(); + expression_node_ptr branch = error_node(); + next_token(); + + std::vector arg_list; + std::vector side_effect_list; + + scoped_vec_delete sdd((*this),arg_list); + + brkcnt_list_.push_front(false); + + if (details::imatch(current_token().value,"until")) + { + next_token(); + branch = node_allocator_.allocate >(); + } + else + { + const token_t::token_type seperator = token_t::e_eof; + + scope_handler sh(*this); + + scoped_bool_or_restorer sbr(state_.side_effect_present); + + scoped_inc_dec sid(state_.parsing_loop_stmt_count); + + for ( ; ; ) + { + state_.side_effect_present = false; + + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + { + arg_list.push_back(arg); + side_effect_list.push_back(state_.side_effect_present); + } + + if (details::imatch(current_token().value,"until")) + { + next_token(); + break; + } + + const bool is_next_until = peek_token_is(token_t::e_symbol) && + peek_token_is("until"); + + if (!token_is(seperator) && is_next_until) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR061 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", + exprtk_error_location)); + + return error_node(); + } + + if (details::imatch(current_token().value,"until")) + { + next_token(); + break; + } + } + + branch = simplify(arg_list,side_effect_list); + + sdd.delete_ptr = (0 == branch); + + if (sdd.delete_ptr) + { + brkcnt_list_.pop_front(); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR062 - Failed to parse body of repeat until loop", + exprtk_error_location)); + + return error_node(); + } + } + + if (!token_is(token_t::e_lbracket)) + { + brkcnt_list_.pop_front(); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR063 - Expected '(' before condition statement of repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_,branch); + + return error_node(); + } + else if (0 == (condition = parse_expression())) + { + brkcnt_list_.pop_front(); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR064 - Failed to parse condition for repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_,branch); + + return error_node(); + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR065 - Expected ')' after condition of repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_, branch ); + free_node(node_allocator_, condition); + + brkcnt_list_.pop_front(); + + return error_node(); + } + + expression_node_ptr result; + + result = expression_generator_ + .repeat_until_loop(condition, branch, brkcnt_list_.front()); + + if (0 == result) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR066 - Failed to synthesize repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_,condition); + + brkcnt_list_.pop_front(); + + return error_node(); + } + else + { + brkcnt_list_.pop_front(); + return result; + } + } + + inline expression_node_ptr parse_for_loop() + { + expression_node_ptr initialiser = error_node(); + expression_node_ptr condition = error_node(); + expression_node_ptr incrementor = error_node(); + expression_node_ptr loop_body = error_node(); + + scope_element* se = 0; + bool result = true; + + next_token(); + + scope_handler sh(*this); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR067 - Expected '(' at start of for-loop", + exprtk_error_location)); + + return error_node(); + } + + if (!token_is(token_t::e_eof)) + { + if ( + !token_is(token_t::e_symbol,prsrhlpr_t::e_hold) && + details::imatch(current_token().value,"var") + ) + { + next_token(); + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR068 - Expected a variable at the start of initialiser section of for-loop", + exprtk_error_location)); + + return error_node(); + } + else if (!peek_token_is(token_t::e_assign)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR069 - Expected variable assignment of initialiser section of for-loop", + exprtk_error_location)); + + return error_node(); + } + + const std::string loop_counter_symbol = current_token().value; + + se = &sem_.get_element(loop_counter_symbol); + + if ((se->name == loop_counter_symbol) && se->active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR070 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", + exprtk_error_location)); + + return error_node(); + } + else if (!symtab_store_.is_variable(loop_counter_symbol)) + { + if ( + !se->active && + (se->name == loop_counter_symbol) && + (se->type == scope_element::e_variable) + ) + { + se->active = true; + se->ref_count++; + } + else + { + scope_element nse; + nse.name = loop_counter_symbol; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR071 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + result = false; + } + else + { + exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); + + state_.activate_side_effect("parse_for_loop()"); + } + } + } + } + + if (0 == (initialiser = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR072 - Failed to parse initialiser of for-loop", + exprtk_error_location)); + + result = false; + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR073 - Expected ';' after initialiser of for-loop", + exprtk_error_location)); + + result = false; + } + } + + if (!token_is(token_t::e_eof)) + { + if (0 == (condition = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR074 - Failed to parse condition of for-loop", + exprtk_error_location)); + + result = false; + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR075 - Expected ';' after condition section of for-loop", + exprtk_error_location)); + + result = false; + } + } + + if (!token_is(token_t::e_rbracket)) + { + if (0 == (incrementor = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR076 - Failed to parse incrementor of for-loop", + exprtk_error_location)); + + result = false; + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR077 - Expected ')' after incrementor section of for-loop", + exprtk_error_location)); + + result = false; + } + } + + if (result) + { + brkcnt_list_.push_front(false); + + scoped_inc_dec sid(state_.parsing_loop_stmt_count); + + if (0 == (loop_body = parse_multi_sequence("for-loop"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR078 - Failed to parse body of for-loop", + exprtk_error_location)); + + result = false; + } + } + + if (!result) + { + if (se) + { + se->ref_count--; + } + + free_node(node_allocator_, initialiser); + free_node(node_allocator_, condition ); + free_node(node_allocator_, incrementor); + free_node(node_allocator_, loop_body ); + + if (!brkcnt_list_.empty()) + { + brkcnt_list_.pop_front(); + } + + return error_node(); + } + else + { + expression_node_ptr result_node = + expression_generator_.for_loop(initialiser, + condition, + incrementor, + loop_body, + brkcnt_list_.front()); + brkcnt_list_.pop_front(); + + return result_node; + } + } + + inline expression_node_ptr parse_switch_statement() + { + std::vector arg_list; + expression_node_ptr result = error_node(); + + if (!details::imatch(current_token().value,"switch")) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR079 - Expected keyword 'switch'", + exprtk_error_location)); + + return error_node(); + } + + scoped_vec_delete svd((*this),arg_list); + + next_token(); + + if (!token_is(token_t::e_lcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR080 - Expected '{' for call to switch statement", + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr default_statement = error_node(); + + scoped_expression_delete defstmt_delete((*this), default_statement); + + for ( ; ; ) + { + if (details::imatch("case",current_token().value)) + { + next_token(); + + expression_node_ptr condition = parse_expression(); + + if (0 == condition) + return error_node(); + else if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR081 - Expected ':' for case of switch statement", + exprtk_error_location)); + + free_node(node_allocator_, condition); + + return error_node(); + } + + expression_node_ptr consequent = parse_expression(); + + if (0 == consequent) + { + free_node(node_allocator_, condition); + + return error_node(); + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR082 - Expected ';' at end of case for switch statement", + exprtk_error_location)); + + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent); + + return error_node(); + } + + // Can we optimise away the case statement? + if (is_constant_node(condition) && is_false(condition)) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent); + } + else + { + arg_list.push_back(condition ); + arg_list.push_back(consequent); + } + + } + else if (details::imatch("default",current_token().value)) + { + if (0 != default_statement) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR083 - Multiple default cases for switch statement", + exprtk_error_location)); + + return error_node(); + } + + next_token(); + + if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR084 - Expected ':' for default of switch statement", + exprtk_error_location)); + + return error_node(); + } + + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + default_statement = parse_multi_sequence("switch-default"); + else + default_statement = parse_expression(); + + if (0 == default_statement) + return error_node(); + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR085 - Expected ';' at end of default for switch statement", + exprtk_error_location)); + + return error_node(); + } + } + else if (token_is(token_t::e_rcrlbracket)) + break; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR086 - Expected '}' at end of switch statement", + exprtk_error_location)); + + return error_node(); + } + } + + const bool default_statement_present = (0 != default_statement); + + if (default_statement_present) + { + arg_list.push_back(default_statement); + } + + result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); + + svd.delete_ptr = (0 == result); + defstmt_delete.delete_ptr = (0 == result); + + return result; + } + + inline expression_node_ptr parse_multi_switch_statement() + { + std::vector arg_list; + + if (!details::imatch(current_token().value,"[*]")) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR087 - Expected token '[*]'", + exprtk_error_location)); + + return error_node(); + } + + scoped_vec_delete svd((*this),arg_list); + + next_token(); + + if (!token_is(token_t::e_lcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR088 - Expected '{' for call to [*] statement", + exprtk_error_location)); + + return error_node(); + } + + for ( ; ; ) + { + if (!details::imatch("case",current_token().value)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR089 - Expected a 'case' statement for multi-switch", + exprtk_error_location)); + + return error_node(); + } + + next_token(); + + expression_node_ptr condition = parse_expression(); + + if (0 == condition) + return error_node(); + + if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR090 - Expected ':' for case of [*] statement", + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr consequent = parse_expression(); + + if (0 == consequent) + return error_node(); + + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR091 - Expected ';' at end of case for [*] statement", + exprtk_error_location)); + + return error_node(); + } + + // Can we optimise away the case statement? + if (is_constant_node(condition) && is_false(condition)) + { + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent); + } + else + { + arg_list.push_back(condition ); + arg_list.push_back(consequent); + } + + if (token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold)) + { + break; + } + } + + if (!token_is(token_t::e_rcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR092 - Expected '}' at end of [*] statement", + exprtk_error_location)); + + return error_node(); + } + + const expression_node_ptr result = expression_generator_.multi_switch_statement(arg_list); + + svd.delete_ptr = (0 == result); + + return result; + } + + inline expression_node_ptr parse_vararg_function() + { + std::vector arg_list; + + details::operator_type opt_type = details::e_default; + const std::string symbol = current_token().value; + + if (details::imatch(symbol,"~")) + { + next_token(); + return parse_multi_sequence(); + } + else if (details::imatch(symbol,"[*]")) + { + return parse_multi_switch_statement(); + } + else if (details::imatch(symbol, "avg" )) opt_type = details::e_avg ; + else if (details::imatch(symbol, "mand")) opt_type = details::e_mand; + else if (details::imatch(symbol, "max" )) opt_type = details::e_max ; + else if (details::imatch(symbol, "min" )) opt_type = details::e_min ; + else if (details::imatch(symbol, "mor" )) opt_type = details::e_mor ; + else if (details::imatch(symbol, "mul" )) opt_type = details::e_prod; + else if (details::imatch(symbol, "sum" )) opt_type = details::e_sum ; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR093 - Unsupported vararg function: " + symbol, + exprtk_error_location)); + + return error_node(); + } + + scoped_vec_delete sdd((*this),arg_list); + + lodge_symbol(symbol, e_st_function); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR094 - Expected '(' for call to vararg function: " + symbol, + exprtk_error_location)); + + return error_node(); + } + + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR095 - Expected ',' for call to vararg function: " + symbol, + exprtk_error_location)); + + return error_node(); + } + } + + const expression_node_ptr result = expression_generator_.vararg_function(opt_type,arg_list); + + sdd.delete_ptr = (0 == result); + return result; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression) + { + if (!token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR096 - Expected '[' as start of string range definition", + exprtk_error_location)); + + free_node(node_allocator_,expression); + + return error_node(); + } + else if (token_is(token_t::e_rsqrbracket)) + { + return node_allocator_.allocate >(expression); + } + + range_t rp; + + if (!parse_range(rp,true)) + { + free_node(node_allocator_,expression); + + return error_node(); + } + + expression_node_ptr result = expression_generator_(expression,rp); + + if (0 == result) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR097 - Failed to generate string range node", + exprtk_error_location)); + + free_node(node_allocator_,expression); + rp.free(); + } + + rp.clear(); + + return result; + } + #else + inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) + { + return error_node(); + } + #endif + + inline void parse_pending_string_rangesize(expression_node_ptr& expression) + { + // Allow no more than 100 range calls, eg: s[][][]...[][] + const std::size_t max_rangesize_parses = 100; + + std::size_t i = 0; + + while + ( + (0 != expression) && + (i++ < max_rangesize_parses) && + error_list_.empty() && + is_generally_string_node(expression) && + token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold) + ) + { + expression = parse_string_range_statement(expression); + } + } + + template class Sequence> + inline expression_node_ptr simplify(Sequence& expression_list, + Sequence& side_effect_list, + const bool specialise_on_final_type = false) + { + if (expression_list.empty()) + return error_node(); + else if (1 == expression_list.size()) + return expression_list[0]; + + Sequence tmp_expression_list; + + bool return_node_present = false; + + for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) + { + if (is_variable_node(expression_list[i])) + continue; + else if ( + is_return_node (expression_list[i]) || + is_break_node (expression_list[i]) || + is_continue_node(expression_list[i]) + ) + { + tmp_expression_list.push_back(expression_list[i]); + + // Remove all subexpressions after first short-circuit + // node has been encountered. + + for (std::size_t j = i + 1; j < expression_list.size(); ++j) + { + free_node(node_allocator_,expression_list[j]); + } + + return_node_present = true; + + break; + } + else if ( + is_constant_node(expression_list[i]) || + is_null_node (expression_list[i]) || + !side_effect_list[i] + ) + { + free_node(node_allocator_,expression_list[i]); + continue; + } + else + tmp_expression_list.push_back(expression_list[i]); + } + + if (!return_node_present) + { + tmp_expression_list.push_back(expression_list.back()); + } + + expression_list.swap(tmp_expression_list); + + if (tmp_expression_list.size() > expression_list.size()) + { + exprtk_debug(("simplify() - Reduced subexpressions from %d to %d\n", + static_cast(tmp_expression_list.size()), + static_cast(expression_list .size()))); + } + + if ( + return_node_present || + side_effect_list.back() || + (expression_list.size() > 1) + ) + state_.activate_side_effect("simplify()"); + + if (1 == expression_list.size()) + return expression_list[0]; + else if (specialise_on_final_type && is_generally_string_node(expression_list.back())) + return expression_generator_.vararg_function(details::e_smulti,expression_list); + else + return expression_generator_.vararg_function(details::e_multi,expression_list); + } + + inline expression_node_ptr parse_multi_sequence(const std::string& source = "") + { + token_t::token_type close_bracket = token_t::e_rcrlbracket; + token_t::token_type seperator = token_t::e_eof; + + if (!token_is(token_t::e_lcrlbracket)) + { + if (token_is(token_t::e_lbracket)) + { + close_bracket = token_t::e_rbracket; + seperator = token_t::e_comma; + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR098 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + + ((!source.empty()) ? std::string(" section of " + source): ""), + exprtk_error_location)); + + return error_node(); + } + } + else if (token_is(token_t::e_rcrlbracket)) + { + return node_allocator_.allocate >(); + } + + std::vector arg_list; + std::vector side_effect_list; + + expression_node_ptr result = error_node(); + + scoped_vec_delete sdd((*this),arg_list); + + scope_handler sh(*this); + + scoped_bool_or_restorer sbr(state_.side_effect_present); + + for ( ; ; ) + { + state_.side_effect_present = false; + + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + { + arg_list.push_back(arg); + side_effect_list.push_back(state_.side_effect_present); + } + + if (token_is(close_bracket)) + break; + + const bool is_next_close = peek_token_is(close_bracket); + + if (!token_is(seperator) && is_next_close) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR099 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, + exprtk_error_location)); + + return error_node(); + } + + if (token_is(close_bracket)) + break; + } + + result = simplify(arg_list,side_effect_list,source.empty()); + + sdd.delete_ptr = (0 == result); + return result; + } + + inline bool parse_range(range_t& rp, const bool skip_lsqr = false) + { + // Examples of valid ranges: + // 1. [1:5] -> 1..5 + // 2. [ :5] -> 0..5 + // 3. [1: ] -> 1..end + // 4. [x:y] -> x..y where x <= y + // 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2 + // 6. [ :y] -> 0..y where 0 <= y + // 7. [x: ] -> x..end where x <= end + + rp.clear(); + + if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR100 - Expected '[' for start of range", + exprtk_error_location)); + + return false; + } + + if (token_is(token_t::e_colon)) + { + rp.n0_c.first = true; + rp.n0_c.second = 0; + rp.cache.first = 0; + } + else + { + expression_node_ptr r0 = parse_expression(); + + if (0 == r0) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR101 - Failed parse begin section of range", + exprtk_error_location)); + + return false; + } + else if (is_constant_node(r0)) + { + const T r0_value = r0->value(); + + if (r0_value >= T(0)) + { + rp.n0_c.first = true; + rp.n0_c.second = static_cast(details::numeric::to_int64(r0_value)); + rp.cache.first = rp.n0_c.second; + } + + free_node(node_allocator_,r0); + + if (r0_value < T(0)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR102 - Range lower bound less than zero! Constraint: r0 >= 0", + exprtk_error_location)); + + return false; + } + } + else + { + rp.n0_e.first = true; + rp.n0_e.second = r0; + } + + if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR103 - Expected ':' for break in range", + exprtk_error_location)); + + rp.free(); + + return false; + } + } + + if (token_is(token_t::e_rsqrbracket)) + { + rp.n1_c.first = true; + rp.n1_c.second = std::numeric_limits::max(); + } + else + { + expression_node_ptr r1 = parse_expression(); + + if (0 == r1) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR104 - Failed parse end section of range", + exprtk_error_location)); + + rp.free(); + + return false; + } + else if (is_constant_node(r1)) + { + const T r1_value = r1->value(); + + if (r1_value >= T(0)) + { + rp.n1_c.first = true; + rp.n1_c.second = static_cast(details::numeric::to_int64(r1_value)); + rp.cache.second = rp.n1_c.second; + } + + free_node(node_allocator_,r1); + + if (r1_value < T(0)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR105 - Range upper bound less than zero! Constraint: r1 >= 0", + exprtk_error_location)); + + rp.free(); + + return false; + } + } + else + { + rp.n1_e.first = true; + rp.n1_e.second = r1; + } + + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR106 - Expected ']' for start of range", + exprtk_error_location)); + + rp.free(); + + return false; + } + } + + if (rp.const_range()) + { + std::size_t r0 = 0; + std::size_t r1 = 0; + + bool rp_result = false; + + try + { + rp_result = rp(r0, r1); + } + catch (std::runtime_error&) + {} + + if (!rp_result || (r0 > r1)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR107 - Invalid range, Constraint: r0 <= r1", + exprtk_error_location)); + + return false; + } + } + + return true; + } + + inline void lodge_symbol(const std::string& symbol, + const symbol_type st) + { + dec_.add_symbol(symbol,st); + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string() + { + const std::string symbol = current_token().value; + + typedef details::stringvar_node* strvar_node_t; + + expression_node_ptr result = error_node(); + strvar_node_t const_str_node = static_cast(0); + + scope_element& se = sem_.get_active_element(symbol); + + if (scope_element::e_string == se.type) + { + se.active = true; + result = se.str_node; + lodge_symbol(symbol, e_st_local_string); + } + else + { + if (!symtab_store_.is_conststr_stringvar(symbol)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR108 - Unknown string symbol", + exprtk_error_location)); + + return error_node(); + } + + result = symtab_store_.get_stringvar(symbol); + + if (symtab_store_.is_constant_string(symbol)) + { + const_str_node = static_cast(result); + result = expression_generator_(const_str_node->str()); + } + + lodge_symbol(symbol, e_st_string); + } + + if (peek_token_is(token_t::e_lsqrbracket)) + { + next_token(); + + if (peek_token_is(token_t::e_rsqrbracket)) + { + next_token(); + next_token(); + + if (const_str_node) + { + free_node(node_allocator_,result); + + return expression_generator_(T(const_str_node->size())); + } + else + return node_allocator_.allocate > + (static_cast*>(result)->ref()); + } + + range_t rp; + + if (!parse_range(rp)) + { + free_node(node_allocator_,result); + + return error_node(); + } + else if (const_str_node) + { + free_node(node_allocator_,result); + result = expression_generator_(const_str_node->ref(),rp); + } + else + result = expression_generator_(static_cast*> + (result)->ref(), rp); + + if (result) + rp.clear(); + } + else + next_token(); + + return result; + } + #else + inline expression_node_ptr parse_string() + { + return error_node(); + } + #endif + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_const_string() + { + const std::string const_str = current_token().value; + expression_node_ptr result = expression_generator_(const_str); + + if (peek_token_is(token_t::e_lsqrbracket)) + { + next_token(); + + if (peek_token_is(token_t::e_rsqrbracket)) + { + next_token(); + next_token(); + + free_node(node_allocator_,result); + + return expression_generator_(T(const_str.size())); + } + + range_t rp; + + if (!parse_range(rp)) + { + free_node(node_allocator_,result); + rp.free(); + + return error_node(); + } + + free_node(node_allocator_,result); + + if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits::max())) + { + rp.n1_c.second = const_str.size() - 1; + rp.cache.second = rp.n1_c.second; + } + + if ( + (rp.n0_c.first && (rp.n0_c.second >= const_str.size())) || + (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR109 - Overflow in range for string: '" + const_str + "'[" + + (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + + (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", + exprtk_error_location)); + + rp.free(); + + return error_node(); + } + + result = expression_generator_(const_str,rp); + + if (result) + rp.clear(); + } + else + next_token(); + + return result; + } + #else + inline expression_node_ptr parse_const_string() + { + return error_node(); + } + #endif + + inline expression_node_ptr parse_vector() + { + const std::string symbol = current_token().value; + + vector_holder_ptr vec = vector_holder_ptr(0); + + const scope_element& se = sem_.get_active_element(symbol); + + if ( + !details::imatch(se.name, symbol) || + (se.depth > state_.scope_depth) || + (scope_element::e_vector != se.type) + ) + { + if (0 == (vec = symtab_store_.get_vector(symbol))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR110 - Symbol '" + symbol+ " not a vector", + exprtk_error_location)); + + return error_node(); + } + } + else + vec = se.vec_node; + + expression_node_ptr index_expr = error_node(); + + next_token(); + + if (!token_is(token_t::e_lsqrbracket)) + { + return node_allocator_.allocate(vec); + } + else if (token_is(token_t::e_rsqrbracket)) + { + return expression_generator_(T(vec->size())); + } + else if (0 == (index_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR111 - Failed to parse index for vector: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR112 - Expected ']' for index of vector: '" + symbol + "'", + exprtk_error_location)); + + free_node(node_allocator_,index_expr); + + return error_node(); + } + + // Perform compile-time range check + if (details::is_constant_node(index_expr)) + { + const std::size_t index = static_cast(details::numeric::to_int32(index_expr->value())); + const std::size_t vec_size = vec->size(); + + if (index >= vec_size) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR113 - Index of " + details::to_str(index) + " out of range for " + "vector '" + symbol + "' of size " + details::to_str(vec_size), + exprtk_error_location)); + + free_node(node_allocator_,index_expr); + + return error_node(); + } + } + + return expression_generator_.vector_element(symbol, vec, index_expr); + } + + inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) + { + std::vector arg_list; + + expression_node_ptr result = error_node(); + + scoped_vec_delete sdd((*this),arg_list); + + next_token(); + + if (token_is(token_t::e_lbracket)) + { + if (token_is(token_t::e_rbracket)) + { + if (!vararg_function->allow_zero_parameters()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR114 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); + + return error_node(); + } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR115 - Expected ',' for call to vararg function: " + + vararg_function_name, + exprtk_error_location)); + + return error_node(); + } + } + } + } + else if (!vararg_function->allow_zero_parameters()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR116 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); + + return error_node(); + } + + if (arg_list.size() < vararg_function->min_num_args()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR117 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require at least " + + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters", + exprtk_error_location)); + + return error_node(); + } + else if (arg_list.size() > vararg_function->max_num_args()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR118 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require no more than " + + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters", + exprtk_error_location)); + + return error_node(); + } + + result = expression_generator_.vararg_function_call(vararg_function,arg_list); + + sdd.delete_ptr = (0 == result); + + return result; + } + + class type_checker + { + public: + + enum return_type_t + { + e_overload = ' ', + e_numeric = 'T', + e_string = 'S' + }; + + struct function_prototype_t + { + return_type_t return_type; + std::string param_seq; + }; + + typedef parser parser_t; + typedef std::vector function_definition_list_t; + + type_checker(parser_t& p, + const std::string& func_name, + const std::string& func_prototypes, + const return_type_t default_return_type) + : invalid_state_(true), + parser_(p), + function_name_(func_name), + default_return_type_(default_return_type) + { + parse_function_prototypes(func_prototypes); + } + + bool verify(const std::string& param_seq, std::size_t& pseq_index) + { + if (function_definition_list_.empty()) + return true; + + std::vector > error_list; + + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) + { + details::char_t diff_value = 0; + std::size_t diff_index = 0; + + const bool result = details::sequence_match(function_definition_list_[i].param_seq, + param_seq, + diff_index, diff_value); + + if (result) + { + pseq_index = i; + return true; + } + else + error_list.push_back(std::make_pair(diff_index, diff_value)); + } + + if (1 == error_list.size()) + { + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR119 - Failed parameter type check for function '" + function_name_ + "', " + "Expected '" + function_definition_list_[0].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); + } + else + { + // find first with largest diff_index; + std::size_t max_diff_index = 0; + + for (std::size_t i = 1; i < error_list.size(); ++i) + { + if (error_list[i].first > error_list[max_diff_index].first) + { + max_diff_index = i; + } + } + + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR120 - Failed parameter type check for function '" + function_name_ + "', " + "Best match: '" + function_definition_list_[max_diff_index].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); + } + + return false; + } + + std::size_t paramseq_count() const + { + return function_definition_list_.size(); + } + + std::string paramseq(const std::size_t& index) const + { + return function_definition_list_[index].param_seq; + } + + return_type_t return_type(const std::size_t& index) const + { + return function_definition_list_[index].return_type; + } + + bool invalid() const + { + return !invalid_state_; + } + + bool allow_zero_parameters() const + { + + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) + { + if (std::string::npos != function_definition_list_[i].param_seq.find("Z")) + { + return true; + } + } + + return false; + } + + private: + + std::vector split_param_seq(const std::string& param_seq, const details::char_t delimiter = '|') const + { + std::string::const_iterator current_begin = param_seq.begin(); + std::string::const_iterator iter = param_seq.begin(); + + std::vector result; + + while (iter != param_seq.end()) + { + if (*iter == delimiter) + { + result.push_back(std::string(current_begin, iter)); + current_begin = ++iter; + } + else + ++iter; + } + + if (current_begin != iter) + { + result.push_back(std::string(current_begin, iter)); + } + + return result; + } + + inline bool is_valid_token(std::string param_seq, + function_prototype_t& funcproto) const + { + // Determine return type + funcproto.return_type = default_return_type_; + + if (param_seq.size() > 2) + { + if (':' == param_seq[1]) + { + // Note: Only overloaded igeneric functions can have return + // type definitions. + if (type_checker::e_overload != default_return_type_) + return false; + + switch (param_seq[0]) + { + case 'T' : funcproto.return_type = type_checker::e_numeric; + break; + + case 'S' : funcproto.return_type = type_checker::e_string; + break; + + default : return false; + } + + param_seq.erase(0,2); + } + } + + if ( + (std::string::npos != param_seq.find("?*")) || + (std::string::npos != param_seq.find("**")) + ) + { + return false; + } + else if ( + (std::string::npos == param_seq.find_first_not_of("STV*?|")) || + ("Z" == param_seq) + ) + { + funcproto.param_seq = param_seq; + return true; + } + + return false; + } + + void parse_function_prototypes(const std::string& func_prototypes) + { + if (func_prototypes.empty()) + return; + + std::vector param_seq_list = split_param_seq(func_prototypes); + + typedef std::map param_seq_map_t; + param_seq_map_t param_seq_map; + + for (std::size_t i = 0; i < param_seq_list.size(); ++i) + { + function_prototype_t func_proto; + + if (!is_valid_token(param_seq_list[i], func_proto)) + { + invalid_state_ = false; + + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR121 - Invalid parameter sequence of '" + param_seq_list[i] + + "' for function: " + function_name_, + exprtk_error_location)); + return; + } + + param_seq_map_t::const_iterator seq_itr = param_seq_map.find(param_seq_list[i]); + + if (param_seq_map.end() != seq_itr) + { + invalid_state_ = false; + + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR122 - Function '" + function_name_ + "' has a parameter sequence conflict between " + + "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + + "pseq_idx[" + details::to_str(i) + "] " + + "param seq: " + param_seq_list[i], + exprtk_error_location)); + return; + } + + function_definition_list_.push_back(func_proto); + } + } + + type_checker(const type_checker&); + type_checker& operator=(const type_checker&); + + bool invalid_state_; + parser_t& parser_; + std::string function_name_; + const return_type_t default_return_type_; + function_definition_list_t function_definition_list_; + }; + + inline expression_node_ptr parse_generic_function_call(igeneric_function* function, const std::string& function_name) + { + std::vector arg_list; + + scoped_vec_delete sdd((*this),arg_list); + + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); + + if (tc.invalid()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR123 - Type checker instantiation failure for generic function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + if (token_is(token_t::e_lbracket)) + { + if (token_is(token_t::e_rbracket)) + { + if ( + !function->allow_zero_parameters() && + !tc .allow_zero_parameters() + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR124 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); + + return error_node(); + } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + + if (is_ivector_node(arg)) + param_type_list += 'V'; + else if (is_generally_string_node(arg)) + param_type_list += 'S'; + else // Everything else is assumed to be a scalar returning expression + param_type_list += 'T'; + + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR125 - Expected ',' for call to generic function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + } + } + } + else if ( + !function->parameter_sequence.empty() && + function->allow_zero_parameters () && + !tc .allow_zero_parameters () + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR126 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); + + return error_node(); + } + + std::size_t param_seq_index = 0; + + if ( + state_.type_check_enabled && + !tc.verify(param_type_list, param_seq_index) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR127 - Invalid input parameter sequence for call to generic function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr result = error_node(); + + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .generic_function_call(function, arg_list); + else + result = expression_generator_ + .generic_function_call(function, arg_list, param_seq_index); + + sdd.delete_ptr = (0 == result); + + return result; + } + + inline bool parse_igeneric_function_params(std::string& param_type_list, + std::vector& arg_list, + const std::string& function_name, + igeneric_function* function, + const type_checker& tc) + { + if (token_is(token_t::e_lbracket)) + { + if (token_is(token_t::e_rbracket)) + { + if ( + !function->allow_zero_parameters() && + !tc .allow_zero_parameters() + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR128 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); + + return false; + } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return false; + + if (is_ivector_node(arg)) + param_type_list += 'V'; + else if (is_generally_string_node(arg)) + param_type_list += 'S'; + else // Everything else is a scalar returning expression + param_type_list += 'T'; + + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR129 - Expected ',' for call to string function: " + function_name, + exprtk_error_location)); + + return false; + } + } + } + + return true; + } + else + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string_function_call(igeneric_function* function, const std::string& function_name) + { + // Move pass the function name + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); + + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) + { + return error_node(); + } + + std::vector arg_list; + scoped_vec_delete sdd((*this),arg_list); + + if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) + { + return error_node(); + } + + std::size_t param_seq_index = 0; + + if (!tc.verify(param_type_list, param_seq_index)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR130 - Invalid input parameter sequence for call to string function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr result = error_node(); + + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .string_function_call(function, arg_list); + else + result = expression_generator_ + .string_function_call(function, arg_list, param_seq_index); + + sdd.delete_ptr = (0 == result); + + return result; + } + + inline expression_node_ptr parse_overload_function_call(igeneric_function* function, const std::string& function_name) + { + // Move pass the function name + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_overload); + + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) + { + return error_node(); + } + + std::vector arg_list; + scoped_vec_delete sdd((*this),arg_list); + + if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) + { + return error_node(); + } + + std::size_t param_seq_index = 0; + + if (!tc.verify(param_type_list, param_seq_index)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR131 - Invalid input parameter sequence for call to overloaded function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr result = error_node(); + + if (type_checker::e_numeric == tc.return_type(param_seq_index)) + { + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .generic_function_call(function, arg_list); + else + result = expression_generator_ + .generic_function_call(function, arg_list, param_seq_index); + } + else if (type_checker::e_string == tc.return_type(param_seq_index)) + { + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .string_function_call(function, arg_list); + else + result = expression_generator_ + .string_function_call(function, arg_list, param_seq_index); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR132 - Invalid return type for call to overloaded function: " + function_name, + exprtk_error_location)); + } + + sdd.delete_ptr = (0 == result); + return result; + } + #endif + + template + struct parse_special_function_impl + { + static inline expression_node_ptr process(parser& p, const details::operator_type opt_type, const std::string& sf_name) + { + expression_node_ptr branch[NumberOfParameters]; + expression_node_ptr result = error_node(); + + std::fill_n(branch, NumberOfParameters, reinterpret_cast(0)); + + scoped_delete sd(p,branch); + + p.next_token(); + + if (!p.token_is(token_t::e_lbracket)) + { + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR133 - Expected '(' for special function '" + sf_name + "'", + exprtk_error_location)); + + return error_node(); + } + + for (std::size_t i = 0; i < NumberOfParameters; ++i) + { + branch[i] = p.parse_expression(); + + if (0 == branch[i]) + { + return p.error_node(); + } + else if (i < (NumberOfParameters - 1)) + { + if (!p.token_is(token_t::e_comma)) + { + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR134 - Expected ',' before next parameter of special function '" + sf_name + "'", + exprtk_error_location)); + + return p.error_node(); + } + } + } + + if (!p.token_is(token_t::e_rbracket)) + { + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR135 - Invalid number of parameters for special function '" + sf_name + "'", + exprtk_error_location)); + + return p.error_node(); + } + else + result = p.expression_generator_.special_function(opt_type,branch); + + sd.delete_ptr = (0 == result); + + return result; + } + }; + + inline expression_node_ptr parse_special_function() + { + const std::string sf_name = current_token().value; + + // Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) + if ( + !details::is_digit(sf_name[2]) || + !details::is_digit(sf_name[3]) + ) + { + set_error( + make_error(parser_error::e_token, + current_token(), + "ERR136 - Invalid special function[1]: " + sf_name, + exprtk_error_location)); + + return error_node(); + } + + const int id = (sf_name[2] - '0') * 10 + + (sf_name[3] - '0'); + + if (id >= details::e_sffinal) + { + set_error( + make_error(parser_error::e_token, + current_token(), + "ERR137 - Invalid special function[2]: " + sf_name, + exprtk_error_location)); + + return error_node(); + } + + const int sf_3_to_4 = details::e_sf48; + const details::operator_type opt_type = details::operator_type(id + 1000); + const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3U : 4U; + + switch (NumberOfParameters) + { + case 3 : return parse_special_function_impl::process((*this), opt_type, sf_name); + case 4 : return parse_special_function_impl::process((*this), opt_type, sf_name); + default : return error_node(); + } + } + + inline expression_node_ptr parse_null_statement() + { + next_token(); + return node_allocator_.allocate >(); + } + + #ifndef exprtk_disable_break_continue + inline expression_node_ptr parse_break_statement() + { + if (state_.parsing_break_stmt) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR138 - Invoking 'break' within a break call is not allowed", + exprtk_error_location)); + + return error_node(); + } + else if (0 == state_.parsing_loop_stmt_count) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR139 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); + + return error_node(); + } + + scoped_bool_negator sbn(state_.parsing_break_stmt); + + if (!brkcnt_list_.empty()) + { + next_token(); + + brkcnt_list_.front() = true; + + expression_node_ptr return_expr = error_node(); + + if (token_is(token_t::e_lsqrbracket)) + { + if (0 == (return_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR140 - Failed to parse return expression for 'break' statement", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR141 - Expected ']' at the completion of break's return expression", + exprtk_error_location)); + + free_node(node_allocator_,return_expr); + + return error_node(); + } + } + + state_.activate_side_effect("parse_break_statement()"); + + return node_allocator_.allocate >(return_expr); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR142 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); + } + + return error_node(); + } + + inline expression_node_ptr parse_continue_statement() + { + if (0 == state_.parsing_loop_stmt_count) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR143 - Invalid use of 'continue', allowed only in the scope of a loop", + exprtk_error_location)); + + return error_node(); + } + else + { + next_token(); + + brkcnt_list_.front() = true; + state_.activate_side_effect("parse_continue_statement()"); + + return node_allocator_.allocate >(); + } + } + #endif + + inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) + { + expression_node_ptr size_expr = error_node(); + + if (!token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR144 - Expected '[' as part of vector size definition", + exprtk_error_location)); + + return error_node(); + } + else if (0 == (size_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR145 - Failed to determine size of vector '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (!is_constant_node(size_expr)) + { + free_node(node_allocator_,size_expr); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR146 - Expected a literal number as size of vector '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + + const T vector_size = size_expr->value(); + + free_node(node_allocator_,size_expr); + + const T max_vector_size = T(2000000000.0); + + if ( + (vector_size <= T(0)) || + std::not_equal_to() + (T(0),vector_size - details::numeric::trunc(vector_size)) || + (vector_size > max_vector_size) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR147 - Invalid vector size. Must be an integer in the range [0,2e9], size: " + + details::to_str(details::numeric::to_int32(vector_size)), + exprtk_error_location)); + + return error_node(); + } + + std::vector vec_initilizer_list; + + scoped_vec_delete svd((*this),vec_initilizer_list); + + bool single_value_initialiser = false; + bool vec_to_vec_initialiser = false; + bool null_initialisation = false; + + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR148 - Expected ']' as part of vector size definition", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_eof)) + { + if (!token_is(token_t::e_assign)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR149 - Expected ':=' as part of vector definition", + exprtk_error_location)); + + return error_node(); + } + else if (token_is(token_t::e_lsqrbracket)) + { + expression_node_ptr initialiser = parse_expression(); + + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR150 - Failed to parse single vector initialiser", + exprtk_error_location)); + + return error_node(); + } + + vec_initilizer_list.push_back(initialiser); + + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR151 - Expected ']' to close single value vector initialiser", + exprtk_error_location)); + + return error_node(); + } + + single_value_initialiser = true; + } + else if (!token_is(token_t::e_lcrlbracket)) + { + expression_node_ptr initialiser = error_node(); + + // Is this a vector to vector assignment and initialisation? + if (token_t::e_symbol == current_token().type) + { + // Is it a locally defined vector? + const scope_element& se = sem_.get_active_element(current_token().value); + + if (scope_element::e_vector == se.type) + { + if (0 != (initialiser = parse_expression())) + vec_initilizer_list.push_back(initialiser); + else + return error_node(); + } + // Are we dealing with a user defined vector? + else if (symtab_store_.is_vector(current_token().value)) + { + lodge_symbol(current_token().value, e_st_vector); + + if (0 != (initialiser = parse_expression())) + vec_initilizer_list.push_back(initialiser); + else + return error_node(); + } + // Are we dealing with a null initialisation vector definition? + else if (token_is(token_t::e_symbol,"null")) + null_initialisation = true; + } + + if (!null_initialisation) + { + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR152 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); + + return error_node(); + } + else + vec_to_vec_initialiser = true; + } + } + else if (!token_is(token_t::e_rcrlbracket)) + { + for ( ; ; ) + { + expression_node_ptr initialiser = parse_expression(); + + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR153 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); + + return error_node(); + } + else + vec_initilizer_list.push_back(initialiser); + + if (token_is(token_t::e_rcrlbracket)) + break; + + const bool is_next_close = peek_token_is(token_t::e_rcrlbracket); + + if (!token_is(token_t::e_comma) && is_next_close) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR154 - Expected ',' between vector initialisers", + exprtk_error_location)); + + return error_node(); + } + + if (token_is(token_t::e_rcrlbracket)) + break; + } + } + + if ( + !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) + ) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR155 - Expected ';' at end of vector definition", + exprtk_error_location)); + + return error_node(); + } + } + + if (vec_initilizer_list.size() > vector_size) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR156 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + } + + typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); + + const std::size_t vec_size = static_cast(details::numeric::to_int32(vector_size)); + + scope_element& se = sem_.get_element(vec_name); + + if (se.name == vec_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR157 - Illegal redefinition of local vector: '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if ( + (se.size == vec_size) && + (scope_element::e_vector == se.type) + ) + { + vec_holder = se.vec_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == vec_holder) + { + scope_element nse; + nse.name = vec_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_vector; + nse.depth = state_.scope_depth; + nse.size = vec_size; + nse.data = new T[vec_size]; + nse.vec_node = new typename scope_element::vector_holder_t(reinterpret_cast(nse.data),nse.size); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR158 - Failed to add new local vector '" + vec_name + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + return error_node(); + } + + vec_holder = nse.vec_node; + + exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", + nse.name.c_str(), + static_cast(nse.size))); + } + + state_.activate_side_effect("parse_define_vector_statement()"); + + lodge_symbol(vec_name, e_st_local_vector); + + expression_node_ptr result = error_node(); + + if (null_initialisation) + result = expression_generator_(T(0.0)); + else if (vec_to_vec_initialiser) + { + expression_node_ptr vec_node = node_allocator_.allocate(vec_holder); + + result = expression_generator_( + details::e_assign, + vec_node, + vec_initilizer_list[0]); + } + else + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list, + single_value_initialiser); + + svd.delete_ptr = (0 == result); + + return result; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_define_string_statement(const std::string& str_name, expression_node_ptr initialisation_expression) + { + stringvar_node_t* str_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(str_name); + + if (se.name == str_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR159 - Illegal redefinition of local variable: '" + str_name + "'", + exprtk_error_location)); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); + } + else if (scope_element::e_string == se.type) + { + str_node = se.str_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == str_node) + { + scope_element nse; + nse.name = str_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_string; + nse.depth = state_.scope_depth; + nse.data = new std::string; + nse.str_node = new stringvar_node_t(*reinterpret_cast(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR160 - Failed to add new local string variable '" + str_name + "' to SEM", + exprtk_error_location)); + + free_node(node_allocator_,initialisation_expression); + + sem_.free_element(nse); + + return error_node(); + } + + str_node = nse.str_node; + + exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); + } + + lodge_symbol(str_name, e_st_local_string); + + state_.activate_side_effect("parse_define_string_statement()"); + + expression_node_ptr branch[2] = {0}; + + branch[0] = str_node; + branch[1] = initialisation_expression; + + return expression_generator_(details::e_assign,branch); + } + #else + inline expression_node_ptr parse_define_string_statement(const std::string&, expression_node_ptr) + { + return error_node(); + } + #endif + + inline bool local_variable_is_shadowed(const std::string& symbol) + { + const scope_element& se = sem_.get_element(symbol); + return (se.name == symbol) && se.active; + } + + inline expression_node_ptr parse_define_var_statement() + { + if (settings_.vardef_disabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR161 - Illegal variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (!details::imatch(current_token().value,"var")) + { + return error_node(); + } + else + next_token(); + + const std::string var_name = current_token().value; + + expression_node_ptr initialisation_expression = error_node(); + + if (!token_is(token_t::e_symbol)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR162 - Expected a symbol for variable definition", + exprtk_error_location)); + + return error_node(); + } + else if (details::is_reserved_symbol(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR163 - Illegal redefinition of reserved keyword: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (symtab_store_.symbol_exists(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR164 - Illegal redefinition of variable '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (local_variable_is_shadowed(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR165 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) + { + return parse_define_vector_statement(var_name); + } + else if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + return parse_uninitialised_var_statement(var_name); + } + else if (token_is(token_t::e_assign)) + { + if (0 == (initialisation_expression = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR166 - Failed to parse initialisation expression", + exprtk_error_location)); + + return error_node(); + } + } + + if ( + !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) + ) + { + if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR167 - Expected ';' after variable definition", + exprtk_error_location)); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); + } + } + + if ( + (0 != initialisation_expression) && + details::is_generally_string_node(initialisation_expression) + ) + { + return parse_define_string_statement(var_name,initialisation_expression); + } + + expression_node_ptr var_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR168 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + free_node(node_allocator_, initialisation_expression); + + return error_node(); + } + else if (scope_element::e_variable == se.type) + { + var_node = se.var_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == var_node) + { + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR169 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); + + free_node(node_allocator_, initialisation_expression); + + sem_.free_element(nse); + + return error_node(); + } + + var_node = nse.var_node; + + exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); + } + + state_.activate_side_effect("parse_define_var_statement()"); + + lodge_symbol(var_name, e_st_local_variable); + + expression_node_ptr branch[2] = {0}; + + branch[0] = var_node; + branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); + + return expression_generator_(details::e_assign,branch); + } + + inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) + { + if ( + !token_is(token_t::e_lcrlbracket) || + !token_is(token_t::e_rcrlbracket) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR170 - Expected a '{}' for uninitialised var definition", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR171 - Expected ';' after uninitialised variable definition", + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr var_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR172 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + return error_node(); + } + else if (scope_element::e_variable == se.type) + { + var_node = se.var_node; + se.active = true; + se.ref_count++; + } + } + + if (0 == var_node) + { + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.ip_index = sem_.next_ip_index(); + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR173 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + return error_node(); + } + + exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n", + nse.name.c_str())); + } + + lodge_symbol(var_name, e_st_local_variable); + + state_.activate_side_effect("parse_uninitialised_var_statement()"); + + return expression_generator_(T(0)); + } + + inline expression_node_ptr parse_swap_statement() + { + if (!details::imatch(current_token().value,"swap")) + { + return error_node(); + } + else + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR174 - Expected '(' at start of swap statement", + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr variable0 = error_node(); + expression_node_ptr variable1 = error_node(); + + bool variable0_generated = false; + bool variable1_generated = false; + + const std::string var0_name = current_token().value; + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR175 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); + + return error_node(); + } + else if (peek_token_is(token_t::e_lsqrbracket)) + { + if (0 == (variable0 = parse_vector())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR176 - First parameter to swap is an invalid vector element: '" + var0_name + "'", + exprtk_error_location)); + + return error_node(); + } + + variable0_generated = true; + } + else + { + if (symtab_store_.is_variable(var0_name)) + { + variable0 = symtab_store_.get_variable(var0_name); + } + + const scope_element& se = sem_.get_element(var0_name); + + if ( + (se.active) && + (se.name == var0_name) && + (scope_element::e_variable == se.type) + ) + { + variable0 = se.var_node; + } + + lodge_symbol(var0_name, e_st_variable); + + if (0 == variable0) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR177 - First parameter to swap is an invalid variable: '" + var0_name + "'", + exprtk_error_location)); + + return error_node(); + } + else + next_token(); + } + + if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR178 - Expected ',' between parameters to swap", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + return error_node(); + } + + const std::string var1_name = current_token().value; + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR179 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + return error_node(); + } + else if (peek_token_is(token_t::e_lsqrbracket)) + { + if (0 == (variable1 = parse_vector())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR180 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + return error_node(); + } + + variable1_generated = true; + } + else + { + if (symtab_store_.is_variable(var1_name)) + { + variable1 = symtab_store_.get_variable(var1_name); + } + + const scope_element& se = sem_.get_element(var1_name); + + if ( + (se.active) && + (se.name == var1_name) && + (scope_element::e_variable == se.type) + ) + { + variable1 = se.var_node; + } + + lodge_symbol(var1_name, e_st_variable); + + if (0 == variable1) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR181 - Second parameter to swap is an invalid variable: '" + var1_name + "'", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + return error_node(); + } + else + next_token(); + } + + if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR182 - Expected ')' at end of swap statement", + exprtk_error_location)); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + if (variable1_generated) + { + free_node(node_allocator_,variable1); + } + + return error_node(); + } + + typedef details::variable_node* variable_node_ptr; + + variable_node_ptr v0 = variable_node_ptr(0); + variable_node_ptr v1 = variable_node_ptr(0); + + expression_node_ptr result = error_node(); + + if ( + (0 != (v0 = dynamic_cast(variable0))) && + (0 != (v1 = dynamic_cast(variable1))) + ) + { + result = node_allocator_.allocate >(v0, v1); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + if (variable1_generated) + { + free_node(node_allocator_,variable1); + } + } + else + result = node_allocator_.allocate > + (variable0, variable1); + + state_.activate_side_effect("parse_swap_statement()"); + + return result; + } + + #ifndef exprtk_disable_return_statement + inline expression_node_ptr parse_return_statement() + { + if (state_.parsing_return_stmt) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR183 - Return call within a return call is not allowed", + exprtk_error_location)); + + return error_node(); + } + + scoped_bool_negator sbn(state_.parsing_return_stmt); + + std::vector arg_list; + + scoped_vec_delete sdd((*this),arg_list); + + if (!details::imatch(current_token().value,"return")) + { + return error_node(); + } + else + next_token(); + + if (!token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR184 - Expected '[' at start of return statement", + exprtk_error_location)); + + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + + arg_list.push_back(arg); + + if (token_is(token_t::e_rsqrbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR185 - Expected ',' between values during call to return", + exprtk_error_location)); + + return error_node(); + } + } + } + else if (settings_.zero_return_disabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR186 - Zero parameter return statement not allowed", + exprtk_error_location)); + + return error_node(); + } + + const lexer::token prev_token = current_token(); + + if (token_is(token_t::e_rsqrbracket)) + { + if (!arg_list.empty()) + { + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR187 - Invalid ']' found during return call", + exprtk_error_location)); + + return error_node(); + } + } + + std::string ret_param_type_list; + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (0 == arg_list[i]) + return error_node(); + else if (is_ivector_node(arg_list[i])) + ret_param_type_list += 'V'; + else if (is_generally_string_node(arg_list[i])) + ret_param_type_list += 'S'; + else + ret_param_type_list += 'T'; + } + + dec_.retparam_list_.push_back(ret_param_type_list); + + expression_node_ptr result = expression_generator_.return_call(arg_list); + + sdd.delete_ptr = (0 == result); + + state_.return_stmt_present = true; + + state_.activate_side_effect("parse_return_statement()"); + + return result; + } + #else + inline expression_node_ptr parse_return_statement() + { + return error_node(); + } + #endif + + inline bool post_variable_process(const std::string& symbol) + { + if ( + peek_token_is(token_t::e_lbracket ) || + peek_token_is(token_t::e_lcrlbracket) || + peek_token_is(token_t::e_lsqrbracket) + ) + { + if (!settings_.commutative_check_enabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR188 - Invalid sequence of variable '"+ symbol + "' and bracket", + exprtk_error_location)); + + return false; + } + + lexer().insert_front(token_t::e_mul); + } + + return true; + } + + inline bool post_bracket_process(const typename token_t::token_type& token, expression_node_ptr& branch) + { + bool implied_mul = false; + + if (is_generally_string_node(branch)) + return true; + + const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; + + switch (token) + { + case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + default : return true; + } + + if (implied_mul) + { + if (!settings_.commutative_check_enabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR189 - Invalid sequence of brackets", + exprtk_error_location)); + + return false; + } + else if (token_t::e_eof != current_token().type) + { + lexer().insert_front(current_token().type); + lexer().insert_front(token_t::e_mul); + next_token(); + } + } + + return true; + } + + inline expression_node_ptr parse_symtab_symbol() + { + const std::string symbol = current_token().value; + + // Are we dealing with a variable or a special constant? + expression_node_ptr variable = symtab_store_.get_variable(symbol); + + if (variable) + { + if (symtab_store_.is_constant_node(symbol)) + { + variable = expression_generator_(variable->value()); + } + + if (!post_variable_process(symbol)) + return error_node(); + + lodge_symbol(symbol, e_st_variable); + next_token(); + + return variable; + } + + // Are we dealing with a locally defined variable, vector or string? + if (!sem_.empty()) + { + scope_element& se = sem_.get_active_element(symbol); + + if (se.active && details::imatch(se.name, symbol)) + { + if (scope_element::e_variable == se.type) + { + se.active = true; + lodge_symbol(symbol, e_st_local_variable); + + if (!post_variable_process(symbol)) + return error_node(); + + next_token(); + + return se.var_node; + } + else if (scope_element::e_vector == se.type) + { + return parse_vector(); + } + #ifndef exprtk_disable_string_capabilities + else if (scope_element::e_string == se.type) + { + return parse_string(); + } + #endif + } + } + + #ifndef exprtk_disable_string_capabilities + // Are we dealing with a string variable? + if (symtab_store_.is_stringvar(symbol)) + { + return parse_string(); + } + #endif + + { + // Are we dealing with a function? + ifunction* function = symtab_store_.get_function(symbol); + + if (function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr func_node = + parse_function_invocation(function,symbol); + + if (func_node) + return func_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR190 - Failed to generate node for function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg function? + ivararg_function* vararg_function = symtab_store_.get_vararg_function(symbol); + + if (vararg_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr vararg_func_node = + parse_vararg_function_call(vararg_function, symbol); + + if (vararg_func_node) + return vararg_func_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR191 - Failed to generate node for vararg function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg generic function? + igeneric_function* generic_function = symtab_store_.get_generic_function(symbol); + + if (generic_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr genericfunc_node = + parse_generic_function_call(generic_function, symbol); + + if (genericfunc_node) + return genericfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR192 - Failed to generate node for generic function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + #ifndef exprtk_disable_string_capabilities + { + // Are we dealing with a vararg string returning function? + igeneric_function* string_function = symtab_store_.get_string_function(symbol); + + if (string_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr stringfunc_node = + parse_string_function_call(string_function, symbol); + + if (stringfunc_node) + return stringfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR193 - Failed to generate node for string function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg overloaded scalar/string returning function? + igeneric_function* overload_function = symtab_store_.get_overload_function(symbol); + + if (overload_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr overloadfunc_node = + parse_overload_function_call(overload_function, symbol); + + if (overloadfunc_node) + return overloadfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR194 - Failed to generate node for overload function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + #endif + + // Are we dealing with a vector? + if (symtab_store_.is_vector(symbol)) + { + lodge_symbol(symbol, e_st_vector); + return parse_vector(); + } + + if (details::is_reserved_symbol(symbol)) + { + if ( + settings_.function_enabled(symbol) || + !details::is_base_function(symbol) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR195 - Invalid use of reserved symbol '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + + // Should we handle unknown symbols? + if (resolve_unknown_symbol_ && unknown_symbol_resolver_) + { + if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) + { + symbol_table_t& symtab = symtab_store_.get_symbol_table(); + + std::string error_message; + + if (unknown_symbol_resolver::e_usrmode_default == unknown_symbol_resolver_->mode) + { + T default_value = T(0); + + typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type = unknown_symbol_resolver::e_usr_unknown_type; + + if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message)) + { + bool create_result = false; + + switch (usr_symbol_type) + { + case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol, default_value); + break; + + case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol, default_value); + break; + + default : create_result = false; + } + + if (create_result) + { + expression_node_ptr var = symtab_store_.get_variable(symbol); + + if (var) + { + if (symtab_store_.is_constant_node(symbol)) + { + var = expression_generator_(var->value()); + } + + lodge_symbol(symbol, e_st_variable); + + if (!post_variable_process(symbol)) + return error_node(); + + next_token(); + + return var; + } + } + } + + set_error( + make_error(parser_error::e_symtab, + current_token(), + "ERR196 - Failed to create variable: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); + + } + else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) + { + if (unknown_symbol_resolver_->process(symbol, symtab, error_message)) + { + expression_node_ptr result = parse_symtab_symbol(); + + if (result) + { + return result; + } + } + + set_error( + make_error(parser_error::e_symtab, + current_token(), + "ERR197 - Failed to resolve symbol: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message), + exprtk_error_location)); + } + + return error_node(); + } + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR198 - Undefined symbol: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + + inline expression_node_ptr parse_symbol() + { + static const std::string symbol_if = "if" ; + static const std::string symbol_while = "while" ; + static const std::string symbol_repeat = "repeat" ; + static const std::string symbol_for = "for" ; + static const std::string symbol_switch = "switch" ; + static const std::string symbol_null = "null" ; + static const std::string symbol_break = "break" ; + static const std::string symbol_continue = "continue"; + static const std::string symbol_var = "var" ; + static const std::string symbol_swap = "swap" ; + static const std::string symbol_return = "return" ; + static const std::string symbol_not = "not" ; + + if (valid_vararg_operation(current_token().value)) + { + return parse_vararg_function(); + } + else if (details::imatch(current_token().value, symbol_not)) + { + return parse_not_statement(); + } + else if (valid_base_operation(current_token().value)) + { + return parse_base_operation(); + } + else if ( + details::imatch(current_token().value, symbol_if) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_conditional_statement(); + } + else if ( + details::imatch(current_token().value, symbol_while) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_while_loop(); + } + else if ( + details::imatch(current_token().value, symbol_repeat) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_repeat_until_loop(); + } + else if ( + details::imatch(current_token().value, symbol_for) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_for_loop(); + } + else if ( + details::imatch(current_token().value, symbol_switch) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_switch_statement(); + } + else if (details::is_valid_sf_symbol(current_token().value)) + { + return parse_special_function(); + } + else if (details::imatch(current_token().value, symbol_null)) + { + return parse_null_statement(); + } + #ifndef exprtk_disable_break_continue + else if (details::imatch(current_token().value, symbol_break)) + { + return parse_break_statement(); + } + else if (details::imatch(current_token().value, symbol_continue)) + { + return parse_continue_statement(); + } + #endif + else if (details::imatch(current_token().value, symbol_var)) + { + return parse_define_var_statement(); + } + else if (details::imatch(current_token().value, symbol_swap)) + { + return parse_swap_statement(); + } + #ifndef exprtk_disable_return_statement + else if ( + details::imatch(current_token().value, symbol_return) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_return_statement(); + } + #endif + else if (symtab_store_.valid() || !sem_.empty()) + { + return parse_symtab_symbol(); + } + else + { + set_error( + make_error(parser_error::e_symtab, + current_token(), + "ERR199 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value, + exprtk_error_location)); + + return error_node(); + } + } + + inline expression_node_ptr parse_branch(precedence_level precedence = e_level00) + { + stack_limit_handler slh(*this); + + if (!slh) + { + return error_node(); + } + + expression_node_ptr branch = error_node(); + + if (token_t::e_number == current_token().type) + { + T numeric_value = T(0); + + if (details::string_to_real(current_token().value, numeric_value)) + { + expression_node_ptr literal_exp = expression_generator_(numeric_value); + + if (0 == literal_exp) + { + set_error( + make_error(parser_error::e_numeric, + current_token(), + "ERR200 - Failed generate node for scalar: '" + current_token().value + "'", + exprtk_error_location)); + + return error_node(); + } + + next_token(); + branch = literal_exp; + } + else + { + set_error( + make_error(parser_error::e_numeric, + current_token(), + "ERR201 - Failed to convert '" + current_token().value + "' to a number", + exprtk_error_location)); + + return error_node(); + } + } + else if (token_t::e_symbol == current_token().type) + { + branch = parse_symbol(); + } + #ifndef exprtk_disable_string_capabilities + else if (token_t::e_string == current_token().type) + { + branch = parse_const_string(); + } + #endif + else if (token_t::e_lbracket == current_token().type) + { + next_token(); + + if (0 == (branch = parse_expression())) + return error_node(); + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR202 - Expected ')' instead of: '" + current_token().value + "'", + exprtk_error_location)); + + free_node(node_allocator_,branch); + + return error_node(); + } + else if (!post_bracket_process(token_t::e_lbracket,branch)) + { + free_node(node_allocator_,branch); + + return error_node(); + } + } + else if (token_t::e_lsqrbracket == current_token().type) + { + next_token(); + + if (0 == (branch = parse_expression())) + return error_node(); + else if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR203 - Expected ']' instead of: '" + current_token().value + "'", + exprtk_error_location)); + + free_node(node_allocator_,branch); + + return error_node(); + } + else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) + { + free_node(node_allocator_,branch); + + return error_node(); + } + } + else if (token_t::e_lcrlbracket == current_token().type) + { + next_token(); + + if (0 == (branch = parse_expression())) + return error_node(); + else if (!token_is(token_t::e_rcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR204 - Expected '}' instead of: '" + current_token().value + "'", + exprtk_error_location)); + + free_node(node_allocator_,branch); + + return error_node(); + } + else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) + { + free_node(node_allocator_,branch); + + return error_node(); + } + } + else if (token_t::e_sub == current_token().type) + { + next_token(); + branch = parse_expression(e_level11); + + if ( + branch && + !( + details::is_neg_unary_node (branch) && + simplify_unary_negation_branch(branch) + ) + ) + { + expression_node_ptr result = expression_generator_(details::e_neg,branch); + + if (0 == result) + { + free_node(node_allocator_,branch); + + return error_node(); + } + else + branch = result; + } + } + else if (token_t::e_add == current_token().type) + { + next_token(); + branch = parse_expression(e_level13); + } + else if (token_t::e_eof == current_token().type) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR205 - Premature end of expression[1]", + exprtk_error_location)); + + return error_node(); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR206 - Premature end of expression[2]", + exprtk_error_location)); + + return error_node(); + } + + if ( + branch && + (e_level00 == precedence) && + token_is(token_t::e_ternary,prsrhlpr_t::e_hold) + ) + { + branch = parse_ternary_conditional_statement(branch); + } + + parse_pending_string_rangesize(branch); + + return branch; + } + + template + class expression_generator + { + public: + + typedef details::expression_node* expression_node_ptr; + typedef expression_node_ptr (*synthesize_functor_t)(expression_generator&, const details::operator_type& operation, expression_node_ptr (&branch)[2]); + typedef std::map synthesize_map_t; + typedef typename exprtk::parser parser_t; + typedef const Type& vtype; + typedef const Type ctype; + + inline void init_synthesize_map() + { + #ifndef exprtk_disable_enhanced_features + synthesize_map_["(v)o(v)"] = synthesize_vov_expression::process; + synthesize_map_["(c)o(v)"] = synthesize_cov_expression::process; + synthesize_map_["(v)o(c)"] = synthesize_voc_expression::process; + + #define register_synthezier(S) \ + synthesize_map_[S ::node_type::id()] = S ::process; \ + + register_synthezier(synthesize_vovov_expression0) + register_synthezier(synthesize_vovov_expression1) + register_synthezier(synthesize_vovoc_expression0) + register_synthezier(synthesize_vovoc_expression1) + register_synthezier(synthesize_vocov_expression0) + register_synthezier(synthesize_vocov_expression1) + register_synthezier(synthesize_covov_expression0) + register_synthezier(synthesize_covov_expression1) + register_synthezier(synthesize_covoc_expression0) + register_synthezier(synthesize_covoc_expression1) + register_synthezier(synthesize_cocov_expression1) + register_synthezier(synthesize_vococ_expression0) + + register_synthezier(synthesize_vovovov_expression0) + register_synthezier(synthesize_vovovoc_expression0) + register_synthezier(synthesize_vovocov_expression0) + register_synthezier(synthesize_vocovov_expression0) + register_synthezier(synthesize_covovov_expression0) + register_synthezier(synthesize_covocov_expression0) + register_synthezier(synthesize_vocovoc_expression0) + register_synthezier(synthesize_covovoc_expression0) + register_synthezier(synthesize_vococov_expression0) + + register_synthezier(synthesize_vovovov_expression1) + register_synthezier(synthesize_vovovoc_expression1) + register_synthezier(synthesize_vovocov_expression1) + register_synthezier(synthesize_vocovov_expression1) + register_synthezier(synthesize_covovov_expression1) + register_synthezier(synthesize_covocov_expression1) + register_synthezier(synthesize_vocovoc_expression1) + register_synthezier(synthesize_covovoc_expression1) + register_synthezier(synthesize_vococov_expression1) + + register_synthezier(synthesize_vovovov_expression2) + register_synthezier(synthesize_vovovoc_expression2) + register_synthezier(synthesize_vovocov_expression2) + register_synthezier(synthesize_vocovov_expression2) + register_synthezier(synthesize_covovov_expression2) + register_synthezier(synthesize_covocov_expression2) + register_synthezier(synthesize_vocovoc_expression2) + register_synthezier(synthesize_covovoc_expression2) + + register_synthezier(synthesize_vovovov_expression3) + register_synthezier(synthesize_vovovoc_expression3) + register_synthezier(synthesize_vovocov_expression3) + register_synthezier(synthesize_vocovov_expression3) + register_synthezier(synthesize_covovov_expression3) + register_synthezier(synthesize_covocov_expression3) + register_synthezier(synthesize_vocovoc_expression3) + register_synthezier(synthesize_covovoc_expression3) + register_synthezier(synthesize_vococov_expression3) + + register_synthezier(synthesize_vovovov_expression4) + register_synthezier(synthesize_vovovoc_expression4) + register_synthezier(synthesize_vovocov_expression4) + register_synthezier(synthesize_vocovov_expression4) + register_synthezier(synthesize_covovov_expression4) + register_synthezier(synthesize_covocov_expression4) + register_synthezier(synthesize_vocovoc_expression4) + register_synthezier(synthesize_covovoc_expression4) + #endif + } + + inline void set_parser(parser_t& p) + { + parser_ = &p; + } + + inline void set_uom(unary_op_map_t& unary_op_map) + { + unary_op_map_ = &unary_op_map; + } + + inline void set_bom(binary_op_map_t& binary_op_map) + { + binary_op_map_ = &binary_op_map; + } + + inline void set_ibom(inv_binary_op_map_t& inv_binary_op_map) + { + inv_binary_op_map_ = &inv_binary_op_map; + } + + inline void set_sf3m(sf3_map_t& sf3_map) + { + sf3_map_ = &sf3_map; + } + + inline void set_sf4m(sf4_map_t& sf4_map) + { + sf4_map_ = &sf4_map; + } + + inline void set_allocator(details::node_allocator& na) + { + node_allocator_ = &na; + } + + inline void set_strength_reduction_state(const bool enabled) + { + strength_reduction_enabled_ = enabled; + } + + inline bool strength_reduction_enabled() const + { + return strength_reduction_enabled_; + } + + inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) + { + typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); + + if ((*binary_op_map_).end() == bop_itr) + return false; + + bop = bop_itr->second; + + return true; + } + + inline bool valid_operator(const details::operator_type& operation, unary_functor_t& uop) + { + typename unary_op_map_t::iterator uop_itr = unary_op_map_->find(operation); + + if ((*unary_op_map_).end() == uop_itr) + return false; + + uop = uop_itr->second; + + return true; + } + + inline details::operator_type get_operator(const binary_functor_t& bop) const + { + return (*inv_binary_op_map_).find(bop)->second; + } + + inline expression_node_ptr operator() (const Type& v) const + { + return node_allocator_->allocate(v); + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr operator() (const std::string& s) const + { + return node_allocator_->allocate(s); + } + + inline expression_node_ptr operator() (std::string& s, range_t& rp) const + { + return node_allocator_->allocate_rr(s,rp); + } + + inline expression_node_ptr operator() (const std::string& s, range_t& rp) const + { + return node_allocator_->allocate_tt(s,rp); + } + + inline expression_node_ptr operator() (expression_node_ptr branch, range_t& rp) const + { + if (is_generally_string_node(branch)) + return node_allocator_->allocate_tt(branch,rp); + else + return error_node(); + } + #endif + + inline bool unary_optimisable(const details::operator_type& operation) const + { + return (details::e_abs == operation) || (details::e_acos == operation) || + (details::e_acosh == operation) || (details::e_asin == operation) || + (details::e_asinh == operation) || (details::e_atan == operation) || + (details::e_atanh == operation) || (details::e_ceil == operation) || + (details::e_cos == operation) || (details::e_cosh == operation) || + (details::e_exp == operation) || (details::e_expm1 == operation) || + (details::e_floor == operation) || (details::e_log == operation) || + (details::e_log10 == operation) || (details::e_log2 == operation) || + (details::e_log1p == operation) || (details::e_neg == operation) || + (details::e_pos == operation) || (details::e_round == operation) || + (details::e_sin == operation) || (details::e_sinc == operation) || + (details::e_sinh == operation) || (details::e_sqrt == operation) || + (details::e_tan == operation) || (details::e_tanh == operation) || + (details::e_cot == operation) || (details::e_sec == operation) || + (details::e_csc == operation) || (details::e_r2d == operation) || + (details::e_d2r == operation) || (details::e_d2g == operation) || + (details::e_g2d == operation) || (details::e_notl == operation) || + (details::e_sgn == operation) || (details::e_erf == operation) || + (details::e_erfc == operation) || (details::e_ncdf == operation) || + (details::e_frac == operation) || (details::e_trunc == operation) ; + } + + inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) const + { + typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); + + if (sf3_map_->end() == itr) + return false; + else + tfunc = itr->second.first; + + return true; + } + + inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) const + { + typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); + + if (sf4_map_->end() == itr) + return false; + else + qfunc = itr->second.first; + + return true; + } + + inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) const + { + typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); + + if (sf3_map_->end() == itr) + return false; + else + operation = itr->second.second; + + return true; + } + + inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) const + { + typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); + + if (sf4_map_->end() == itr) + return false; + else + operation = itr->second.second; + + return true; + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[1]) + { + if (0 == branch[0]) + { + return error_node(); + } + else if (details::is_null_node(branch[0])) + { + return branch[0]; + } + else if (details::is_break_node(branch[0])) + { + return error_node(); + } + else if (details::is_continue_node(branch[0])) + { + return error_node(); + } + else if (details::is_constant_node(branch[0])) + { + return synthesize_expression(operation,branch); + } + else if (unary_optimisable(operation) && details::is_variable_node(branch[0])) + { + return synthesize_uv_expression(operation,branch); + } + else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) + { + return synthesize_uvec_expression(operation,branch); + } + else + return synthesize_unary_expression(operation,branch); + } + + inline bool is_assignment_operation(const details::operator_type& operation) const + { + return ( + (details::e_addass == operation) || + (details::e_subass == operation) || + (details::e_mulass == operation) || + (details::e_divass == operation) || + (details::e_modass == operation) + ) && + parser_->settings_.assignment_enabled(operation); + } + + #ifndef exprtk_disable_string_capabilities + inline bool valid_string_operation(const details::operator_type& operation) const + { + return (details::e_add == operation) || + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_in == operation) || + (details::e_like == operation) || + (details::e_ilike == operation) || + (details::e_assign == operation) || + (details::e_addass == operation) || + (details::e_swap == operation) ; + } + #else + inline bool valid_string_operation(const details::operator_type&) const + { + return false; + } + #endif + + inline std::string to_str(const details::operator_type& operation) const + { + switch (operation) + { + case details::e_add : return "+" ; + case details::e_sub : return "-" ; + case details::e_mul : return "*" ; + case details::e_div : return "/" ; + case details::e_mod : return "%" ; + case details::e_pow : return "^" ; + case details::e_lt : return "<" ; + case details::e_lte : return "<=" ; + case details::e_gt : return ">" ; + case details::e_gte : return ">=" ; + case details::e_eq : return "==" ; + case details::e_ne : return "!=" ; + case details::e_and : return "and" ; + case details::e_nand : return "nand" ; + case details::e_or : return "or" ; + case details::e_nor : return "nor" ; + case details::e_xor : return "xor" ; + case details::e_xnor : return "xnor" ; + default : return "UNKNOWN"; + } + } + + inline bool operation_optimisable(const details::operator_type& operation) const + { + return (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) || + (details::e_mod == operation) || + (details::e_pow == operation) || + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_and == operation) || + (details::e_nand == operation) || + (details::e_or == operation) || + (details::e_nor == operation) || + (details::e_xor == operation) || + (details::e_xnor == operation) ; + } + + inline std::string branch_to_id(expression_node_ptr branch) const + { + static const std::string null_str ("(null)" ); + static const std::string const_str ("(c)" ); + static const std::string var_str ("(v)" ); + static const std::string vov_str ("(vov)" ); + static const std::string cov_str ("(cov)" ); + static const std::string voc_str ("(voc)" ); + static const std::string str_str ("(s)" ); + static const std::string strrng_str ("(rngs)" ); + static const std::string cs_str ("(cs)" ); + static const std::string cstrrng_str("(crngs)"); + + if (details::is_null_node(branch)) + return null_str; + else if (details::is_constant_node(branch)) + return const_str; + else if (details::is_variable_node(branch)) + return var_str; + else if (details::is_vov_node(branch)) + return vov_str; + else if (details::is_cov_node(branch)) + return cov_str; + else if (details::is_voc_node(branch)) + return voc_str; + else if (details::is_string_node(branch)) + return str_str; + else if (details::is_const_string_node(branch)) + return cs_str; + else if (details::is_string_range_node(branch)) + return strrng_str; + else if (details::is_const_string_range_node(branch)) + return cstrrng_str; + else if (details::is_t0ot1ot2_node(branch)) + return "(" + dynamic_cast*>(branch)->type_id() + ")"; + else if (details::is_t0ot1ot2ot3_node(branch)) + return "(" + dynamic_cast*>(branch)->type_id() + ")"; + else + return "ERROR"; + } + + inline std::string branch_to_id(expression_node_ptr (&branch)[2]) const + { + return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); + } + + inline bool cov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_constant_node(branch[0]) && + details::is_variable_node(branch[1]) ; + } + + inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_variable_node(branch[0]) && + details::is_constant_node(branch[1]) ; + } + + inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_variable_node(branch[0]) && + details::is_variable_node(branch[1]) ; + } + + inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_constant_node(branch[0]) && + !details::is_constant_node(branch[1]) ; + } + + inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return !details::is_constant_node(branch[0]) && + details::is_constant_node(branch[1]) ; + } + + inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) || + (details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])) ; + } + else + return false; + } + + inline bool coboc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) || + (details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])) ; + } + else + return false; + } + + inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_uv_node(branch[0]) && + details::is_uv_node(branch[1]) ; + } + + inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return details::is_variable_node(branch[0]) && + !details::is_variable_node(branch[1]) ; + } + + inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return !details::is_variable_node(branch[0]) && + details::is_variable_node(branch[1]) ; + } + + inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return !details::is_constant_node(branch[0]) || + !details::is_constant_node(branch[1]) ; + } + + inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (is_assignment_operation(operation)) + { + const bool b1_is_genstring = details::is_generally_string_node(branch[1]); + + if (details::is_string_node(branch[0])) + return !b1_is_genstring; + else + return ( + !details::is_variable_node (branch[0]) && + !details::is_vector_elem_node (branch[0]) && + !details::is_rebasevector_elem_node (branch[0]) && + !details::is_rebasevector_celem_node(branch[0]) && + !details::is_vector_node (branch[0]) + ) + || b1_is_genstring; + } + else + return false; + } + + inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) const + { + if ( + !details::is_constant_node(branch[1]) || + details::is_constant_node(branch[0]) || + details::is_variable_node(branch[0]) || + details::is_vector_node (branch[0]) || + details::is_generally_string_node(branch[0]) + ) + return false; + + const Type c = static_cast*>(branch[1])->value(); + + return cardinal_pow_optimisable(operation, c); + } + + inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) const + { + return ( + details::is_break_node (branch[0]) || + details::is_break_node (branch[1]) || + details::is_continue_node(branch[0]) || + details::is_continue_node(branch[1]) + ); + } + + inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + const bool b0_string = is_generally_string_node(branch[0]); + const bool b1_string = is_generally_string_node(branch[1]); + + bool result = false; + + if (b0_string != b1_string) + result = true; + else if (!valid_string_operation(operation) && b0_string && b1_string) + result = true; + + if (result) + { + parser_->set_synthesis_error("Invalid string operation"); + } + + return result; + } + + inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const + { + const bool b0_string = is_generally_string_node(branch[0]); + const bool b1_string = is_generally_string_node(branch[1]); + const bool b2_string = is_generally_string_node(branch[2]); + + bool result = false; + + if ((b0_string != b1_string) || (b1_string != b2_string)) + result = true; + else if ((details::e_inrange != operation) && b0_string && b1_string && b2_string) + result = true; + + if (result) + { + parser_->set_synthesis_error("Invalid string operation"); + } + + return result; + } + + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + const bool b0_string = is_generally_string_node(branch[0]); + const bool b1_string = is_generally_string_node(branch[1]); + + return (b0_string && b1_string && valid_string_operation(operation)); + } + + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const + { + const bool b0_string = is_generally_string_node(branch[0]); + const bool b1_string = is_generally_string_node(branch[1]); + const bool b2_string = is_generally_string_node(branch[2]); + + return (b0_string && b1_string && b2_string && (details::e_inrange == operation)); + } + + #ifndef exprtk_disable_sc_andor + inline bool is_shortcircuit_expression(const details::operator_type& operation) const + { + return ( + (details::e_scand == operation) || + (details::e_scor == operation) + ); + } + #else + inline bool is_shortcircuit_expression(const details::operator_type&) const + { + return false; + } + #endif + + inline bool is_null_present(expression_node_ptr (&branch)[2]) const + { + return ( + details::is_null_node(branch[0]) || + details::is_null_node(branch[1]) + ); + } + + inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) + return false; + else + return ( + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_equal == operation) || + (details::e_and == operation) || + (details::e_nand == operation) || + (details:: e_or == operation) || + (details:: e_nor == operation) || + (details:: e_xor == operation) || + (details::e_xnor == operation) + ); + } + + inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) + return false; + else + return ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) || + (details::e_pow == operation) + ); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + if ((0 == branch[0]) || (0 == branch[1])) + { + return error_node(); + } + else if (is_invalid_string_op(operation,branch)) + { + return error_node(); + } + else if (is_invalid_assignment_op(operation,branch)) + { + return error_node(); + } + else if (is_invalid_break_continue_op(branch)) + { + return error_node(); + } + else if (details::e_assign == operation) + { + return synthesize_assignment_expression(operation, branch); + } + else if (details::e_swap == operation) + { + return synthesize_swap_expression(branch); + } + else if (is_assignment_operation(operation)) + { + return synthesize_assignment_operation_expression(operation, branch); + } + else if (is_vector_eqineq_logic_operation(operation, branch)) + { + return synthesize_veceqineqlogic_operation_expression(operation, branch); + } + else if (is_vector_arithmetic_operation(operation, branch)) + { + return synthesize_vecarithmetic_operation_expression(operation, branch); + } + else if (is_shortcircuit_expression(operation)) + { + return synthesize_shortcircuit_expression(operation, branch); + } + else if (is_string_operation(operation, branch)) + { + return synthesize_string_expression(operation, branch); + } + else if (is_null_present(branch)) + { + return synthesize_null_expression(operation, branch); + } + #ifndef exprtk_disable_cardinal_pow_optimisation + else if (is_constpow_operation(operation, branch)) + { + return cardinal_pow_optimisation(branch); + } + #endif + + expression_node_ptr result = error_node(); + + #ifndef exprtk_disable_enhanced_features + if (synthesize_expression(operation, branch, result)) + { + return result; + } + else + #endif + + { + /* + Possible reductions: + 1. c o cob -> cob + 2. cob o c -> cob + 3. c o boc -> boc + 4. boc o c -> boc + */ + result = error_node(); + + if (cocob_optimisable(operation, branch)) + { + result = synthesize_cocob_expression::process((*this), operation, branch); + } + else if (coboc_optimisable(operation, branch) && (0 == result)) + { + result = synthesize_coboc_expression::process((*this), operation, branch); + } + + if (result) + return result; + } + + if (uvouv_optimisable(operation, branch)) + { + return synthesize_uvouv_expression(operation, branch); + } + else if (vob_optimisable(operation, branch)) + { + return synthesize_vob_expression::process((*this), operation, branch); + } + else if (bov_optimisable(operation, branch)) + { + return synthesize_bov_expression::process((*this), operation, branch); + } + else if (cob_optimisable(operation, branch)) + { + return synthesize_cob_expression::process((*this), operation, branch); + } + else if (boc_optimisable(operation, branch)) + { + return synthesize_boc_expression::process((*this), operation, branch); + } + #ifndef exprtk_disable_enhanced_features + else if (cov_optimisable(operation, branch)) + { + return synthesize_cov_expression::process((*this), operation, branch); + } + #endif + else if (binext_optimisable(operation, branch)) + { + return synthesize_binary_ext_expression::process((*this), operation, branch); + } + else + return synthesize_expression(operation, branch); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + if ( + (0 == branch[0]) || + (0 == branch[1]) || + (0 == branch[2]) + ) + { + details::free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if (is_invalid_string_op(operation, branch)) + { + return error_node(); + } + else if (is_string_operation(operation, branch)) + { + return synthesize_string_expression(operation, branch); + } + else + return synthesize_expression(operation, branch); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + return synthesize_expression(operation,branch); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr b0) + { + expression_node_ptr branch[1] = { b0 }; + return (*this)(operation,branch); + } + + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr& b0, expression_node_ptr& b1) + { + expression_node_ptr result = error_node(); + + if ((0 != b0) && (0 != b1)) + { + expression_node_ptr branch[2] = { b0, b1 }; + result = expression_generator::operator()(operation, branch); + b0 = branch[0]; + b1 = branch[1]; + } + + return result; + } + + inline expression_node_ptr conditional(expression_node_ptr condition, + expression_node_ptr consequent, + expression_node_ptr alternative) const + { + if ((0 == condition) || (0 == consequent)) + { + free_node(*node_allocator_, condition ); + free_node(*node_allocator_, consequent ); + free_node(*node_allocator_, alternative); + + return error_node(); + } + // Can the condition be immediately evaluated? if so optimise. + else if (details::is_constant_node(condition)) + { + // True branch + if (details::is_true(condition)) + { + free_node(*node_allocator_, condition ); + free_node(*node_allocator_, alternative); + + return consequent; + } + // False branch + else + { + free_node(*node_allocator_, condition ); + free_node(*node_allocator_, consequent); + + if (alternative) + return alternative; + else + return node_allocator_->allocate >(); + } + } + else if ((0 != consequent) && (0 != alternative)) + { + return node_allocator_-> + allocate(condition, consequent, alternative); + } + else + return node_allocator_-> + allocate(condition, consequent); + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr conditional_string(expression_node_ptr condition, + expression_node_ptr consequent, + expression_node_ptr alternative) const + { + if ((0 == condition) || (0 == consequent)) + { + free_node(*node_allocator_, condition ); + free_node(*node_allocator_, consequent ); + free_node(*node_allocator_, alternative); + + return error_node(); + } + // Can the condition be immediately evaluated? if so optimise. + else if (details::is_constant_node(condition)) + { + // True branch + if (details::is_true(condition)) + { + free_node(*node_allocator_, condition ); + free_node(*node_allocator_, alternative); + + return consequent; + } + // False branch + else + { + free_node(*node_allocator_, condition ); + free_node(*node_allocator_, consequent); + + if (alternative) + return alternative; + else + return node_allocator_-> + allocate_c >(""); + } + } + else if ((0 != consequent) && (0 != alternative)) + return node_allocator_-> + allocate(condition, consequent, alternative); + else + return error_node(); + } + #else + inline expression_node_ptr conditional_string(expression_node_ptr, + expression_node_ptr, + expression_node_ptr) const + { + return error_node(); + } + #endif + + inline loop_runtime_check_ptr get_loop_runtime_check(const loop_runtime_check::loop_types loop_type) const + { + if ( + parser_->loop_runtime_check_ && + (loop_type == (parser_->loop_runtime_check_->loop_set & loop_type)) + ) + { + return parser_->loop_runtime_check_; + } + + return loop_runtime_check_ptr(0); + } + + inline expression_node_ptr while_loop(expression_node_ptr& condition, + expression_node_ptr& branch, + const bool brkcont = false) const + { + if (!brkcont && details::is_constant_node(condition)) + { + expression_node_ptr result = error_node(); + if (details::is_true(condition)) + // Infinite loops are not allowed. + result = error_node(); + else + result = node_allocator_->allocate >(); + + free_node(*node_allocator_, condition); + free_node(*node_allocator_, branch ); + + return result; + } + else if (details::is_null_node(condition)) + { + free_node(*node_allocator_,condition); + + return branch; + } + else if (!brkcont) + return node_allocator_->allocate + ( + condition, + branch, + get_loop_runtime_check(loop_runtime_check::e_while_loop) + ); + #ifndef exprtk_disable_break_continue + else + return node_allocator_->allocate + ( + condition, + branch, + get_loop_runtime_check(loop_runtime_check::e_while_loop) + ); + #else + return error_node(); + #endif + } + + inline expression_node_ptr repeat_until_loop(expression_node_ptr& condition, + expression_node_ptr& branch, + const bool brkcont = false) const + { + if (!brkcont && details::is_constant_node(condition)) + { + if ( + details::is_true(condition) && + details::is_constant_node(branch) + ) + { + free_node(*node_allocator_,condition); + + return branch; + } + + free_node(*node_allocator_, condition); + free_node(*node_allocator_, branch ); + + return error_node(); + } + else if (details::is_null_node(condition)) + { + free_node(*node_allocator_,condition); + + return branch; + } + else if (!brkcont) + return node_allocator_->allocate + ( + condition, + branch, + get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop) + ); + #ifndef exprtk_disable_break_continue + else + return node_allocator_->allocate + ( + condition, + branch, + get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop) + ); + #else + return error_node(); + #endif + } + + inline expression_node_ptr for_loop(expression_node_ptr& initialiser, + expression_node_ptr& condition, + expression_node_ptr& incrementor, + expression_node_ptr& loop_body, + bool brkcont = false) const + { + if (!brkcont && details::is_constant_node(condition)) + { + expression_node_ptr result = error_node(); + + if (details::is_true(condition)) + // Infinite loops are not allowed. + result = error_node(); + else + result = node_allocator_->allocate >(); + + free_node(*node_allocator_, initialiser); + free_node(*node_allocator_, condition ); + free_node(*node_allocator_, incrementor); + free_node(*node_allocator_, loop_body ); + + return result; + } + else if (details::is_null_node(condition) || (0 == condition)) + { + free_node(*node_allocator_, initialiser); + free_node(*node_allocator_, condition ); + free_node(*node_allocator_, incrementor); + + return loop_body; + } + else if (!brkcont) + return node_allocator_->allocate + ( + initialiser, + condition, + incrementor, + loop_body, + get_loop_runtime_check(loop_runtime_check::e_for_loop) + ); + + #ifndef exprtk_disable_break_continue + else + return node_allocator_->allocate + ( + initialiser, + condition, + incrementor, + loop_body, + get_loop_runtime_check(loop_runtime_check::e_for_loop) + ); + #else + return error_node(); + #endif + } + + template class Sequence> + inline expression_node_ptr const_optimise_switch(Sequence& arg_list) + { + expression_node_ptr result = error_node(); + + for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) + { + expression_node_ptr condition = arg_list[(2 * i) ]; + expression_node_ptr consequent = arg_list[(2 * i) + 1]; + + if ((0 == result) && details::is_true(condition)) + { + result = consequent; + break; + } + } + + if (0 == result) + { + result = arg_list.back(); + } + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + expression_node_ptr current_expr = arg_list[i]; + + if (current_expr && (current_expr != result)) + { + free_node(*node_allocator_,current_expr); + } + } + + return result; + } + + template class Sequence> + inline expression_node_ptr const_optimise_mswitch(Sequence& arg_list) + { + expression_node_ptr result = error_node(); + + for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) + { + expression_node_ptr condition = arg_list[(2 * i) ]; + expression_node_ptr consequent = arg_list[(2 * i) + 1]; + + if (details::is_true(condition)) + { + result = consequent; + } + } + + if (0 == result) + { + T zero = T(0); + result = node_allocator_->allocate(zero); + } + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + expression_node_ptr& current_expr = arg_list[i]; + + if (current_expr && (current_expr != result)) + { + free_node(*node_allocator_,current_expr); + } + } + + return result; + } + + struct switch_nodes + { + typedef std::vector > arg_list_t; + + #define case_stmt(N) \ + if (is_true(arg[(2 * N)].first)) { return arg[(2 * N) + 1].first->value(); } \ + + struct switch_impl_1 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) + + assert(arg.size() == ((2 * 1) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_2 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + + assert(arg.size() == ((2 * 2) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_3 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) + + assert(arg.size() == ((2 * 3) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_4 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + + assert(arg.size() == ((2 * 4) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_5 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + case_stmt(4) + + assert(arg.size() == ((2 * 5) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_6 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + case_stmt(4) case_stmt(5) + + assert(arg.size() == ((2 * 6) + 1)); + + return arg.back().first->value(); + } + }; + + struct switch_impl_7 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + case_stmt(4) case_stmt(5) + case_stmt(6) + + assert(arg.size() == ((2 * 7) + 1)); + + return arg.back().first->value(); + } + }; + + #undef case_stmt + }; + + template class Sequence> + inline expression_node_ptr switch_statement(Sequence& arg_list, const bool default_statement_present) + { + if (arg_list.empty()) + return error_node(); + else if ( + !all_nodes_valid(arg_list) || + (!default_statement_present && (arg_list.size() < 2)) + ) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + else if (is_constant_foldable(arg_list)) + return const_optimise_switch(arg_list); + + switch ((arg_list.size() - 1) / 2) + { + #define case_stmt(N) \ + case N : \ + return node_allocator_-> \ + allocate >(arg_list); \ + + case_stmt(1) + case_stmt(2) + case_stmt(3) + case_stmt(4) + case_stmt(5) + case_stmt(6) + case_stmt(7) + #undef case_stmt + + default : return node_allocator_->allocate >(arg_list); + } + } + + template class Sequence> + inline expression_node_ptr multi_switch_statement(Sequence& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + else if (is_constant_foldable(arg_list)) + return const_optimise_mswitch(arg_list); + else + return node_allocator_->allocate >(arg_list); + } + + #define unary_opr_switch_statements \ + case_stmt(details::e_abs , details::abs_op ) \ + case_stmt(details::e_acos , details::acos_op ) \ + case_stmt(details::e_acosh , details::acosh_op) \ + case_stmt(details::e_asin , details::asin_op ) \ + case_stmt(details::e_asinh , details::asinh_op) \ + case_stmt(details::e_atan , details::atan_op ) \ + case_stmt(details::e_atanh , details::atanh_op) \ + case_stmt(details::e_ceil , details::ceil_op ) \ + case_stmt(details::e_cos , details::cos_op ) \ + case_stmt(details::e_cosh , details::cosh_op ) \ + case_stmt(details::e_exp , details::exp_op ) \ + case_stmt(details::e_expm1 , details::expm1_op) \ + case_stmt(details::e_floor , details::floor_op) \ + case_stmt(details::e_log , details::log_op ) \ + case_stmt(details::e_log10 , details::log10_op) \ + case_stmt(details::e_log2 , details::log2_op ) \ + case_stmt(details::e_log1p , details::log1p_op) \ + case_stmt(details::e_neg , details::neg_op ) \ + case_stmt(details::e_pos , details::pos_op ) \ + case_stmt(details::e_round , details::round_op) \ + case_stmt(details::e_sin , details::sin_op ) \ + case_stmt(details::e_sinc , details::sinc_op ) \ + case_stmt(details::e_sinh , details::sinh_op ) \ + case_stmt(details::e_sqrt , details::sqrt_op ) \ + case_stmt(details::e_tan , details::tan_op ) \ + case_stmt(details::e_tanh , details::tanh_op ) \ + case_stmt(details::e_cot , details::cot_op ) \ + case_stmt(details::e_sec , details::sec_op ) \ + case_stmt(details::e_csc , details::csc_op ) \ + case_stmt(details::e_r2d , details::r2d_op ) \ + case_stmt(details::e_d2r , details::d2r_op ) \ + case_stmt(details::e_d2g , details::d2g_op ) \ + case_stmt(details::e_g2d , details::g2d_op ) \ + case_stmt(details::e_notl , details::notl_op ) \ + case_stmt(details::e_sgn , details::sgn_op ) \ + case_stmt(details::e_erf , details::erf_op ) \ + case_stmt(details::e_erfc , details::erfc_op ) \ + case_stmt(details::e_ncdf , details::ncdf_op ) \ + case_stmt(details::e_frac , details::frac_op ) \ + case_stmt(details::e_trunc , details::trunc_op) \ + + inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[1]) + { + T& v = static_cast*>(branch[0])->ref(); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(v); \ + + unary_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_uvec_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[1]) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > > \ + (operation, branch[0]); \ + + unary_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[1]) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(branch[0]); \ + + unary_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation, + expression_node_ptr (&branch)[3]) + { + expression_node_ptr temp_node = error_node(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : temp_node = node_allocator_-> \ + allocate > > \ + (operation, branch); \ + break; \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) + case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) + case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) + case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) + case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) + #undef case_stmt + default : return error_node(); + } + + const T v = temp_node->value(); + + details::free_node(*node_allocator_,temp_node); + + return node_allocator_->allocate(v); + } + + inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + typedef details::variable_node* variable_ptr; + + const Type& v0 = static_cast(branch[0])->ref(); + const Type& v1 = static_cast(branch[1])->ref(); + const Type& v2 = static_cast(branch[2])->ref(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate_rrr > > \ + (v0, v1, v2); \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) + case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) + case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) + case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) + case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + if (!all_nodes_valid(branch)) + return error_node(); + else if (is_constant_foldable(branch)) + return const_optimise_sf3(operation,branch); + else if (all_nodes_variables(branch)) + return varnode_optimise_sf3(operation,branch); + else + { + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate > > \ + (operation, branch); \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) + case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) + case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) + case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) + case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) + #undef case_stmt + default : return error_node(); + } + } + } + + inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + expression_node_ptr temp_node = error_node(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : temp_node = node_allocator_-> \ + allocate > > \ + (operation, branch); \ + break; \ + + case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) + case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) + case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) + case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) + case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) + case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) + case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) + case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) + case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) + case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) + case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) + case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) + case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) + #undef case_stmt + default : return error_node(); + } + + const T v = temp_node->value(); + + details::free_node(*node_allocator_,temp_node); + + return node_allocator_->allocate(v); + } + + inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + typedef details::variable_node* variable_ptr; + + const Type& v0 = static_cast(branch[0])->ref(); + const Type& v1 = static_cast(branch[1])->ref(); + const Type& v2 = static_cast(branch[2])->ref(); + const Type& v3 = static_cast(branch[3])->ref(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate_rrrr > > \ + (v0, v1, v2, v3); \ + + case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) + case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) + case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) + case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) + case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) + case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) + case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) + case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) + case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) + case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) + case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) + case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) + case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + if (!all_nodes_valid(branch)) + return error_node(); + else if (is_constant_foldable(branch)) + return const_optimise_sf4(operation,branch); + else if (all_nodes_variables(branch)) + return varnode_optimise_sf4(operation,branch); + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate > > \ + (operation, branch); \ + + case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) + case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) + case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) + case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) + case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) + case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) + case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) + case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) + case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) + case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) + case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) + case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) + case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) + #undef case_stmt + default : return error_node(); + } + } + + template class Sequence> + inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) + { + expression_node_ptr temp_node = error_node(); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : temp_node = node_allocator_-> \ + allocate > > \ + (arg_list); \ + break; \ + + case_stmt(details::e_sum , details::vararg_add_op ) + case_stmt(details::e_prod , details::vararg_mul_op ) + case_stmt(details::e_avg , details::vararg_avg_op ) + case_stmt(details::e_min , details::vararg_min_op ) + case_stmt(details::e_max , details::vararg_max_op ) + case_stmt(details::e_mand , details::vararg_mand_op ) + case_stmt(details::e_mor , details::vararg_mor_op ) + case_stmt(details::e_multi , details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } + + const T v = temp_node->value(); + + details::free_node(*node_allocator_,temp_node); + + return node_allocator_->allocate(v); + } + + inline bool special_one_parameter_vararg(const details::operator_type& operation) const + { + return ( + (details::e_sum == operation) || + (details::e_prod == operation) || + (details::e_avg == operation) || + (details::e_min == operation) || + (details::e_max == operation) + ); + } + + template class Sequence> + inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ + + case_stmt(details::e_sum , details::vararg_add_op ) + case_stmt(details::e_prod , details::vararg_mul_op ) + case_stmt(details::e_avg , details::vararg_avg_op ) + case_stmt(details::e_min , details::vararg_min_op ) + case_stmt(details::e_max , details::vararg_max_op ) + case_stmt(details::e_mand , details::vararg_mand_op ) + case_stmt(details::e_mor , details::vararg_mor_op ) + case_stmt(details::e_multi , details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } + } + + template class Sequence> + inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) + { + if (1 == arg_list.size()) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list[0]); \ + + case_stmt(details::e_sum , details::vec_add_op) + case_stmt(details::e_prod , details::vec_mul_op) + case_stmt(details::e_avg , details::vec_avg_op) + case_stmt(details::e_min , details::vec_min_op) + case_stmt(details::e_max , details::vec_max_op) + #undef case_stmt + default : return error_node(); + } + } + else + return error_node(); + } + + template class Sequence> + inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + else if (is_constant_foldable(arg_list)) + return const_optimise_varargfunc(operation,arg_list); + else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) + return vectorize_func(operation,arg_list); + else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) + return arg_list[0]; + else if (all_nodes_variables(arg_list)) + return varnode_optimise_varargfunc(operation,arg_list); + + #ifndef exprtk_disable_string_capabilities + if (details::e_smulti == operation) + { + return node_allocator_-> + allocate > >(arg_list); + } + else + #endif + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ + + case_stmt(details::e_sum , details::vararg_add_op ) + case_stmt(details::e_prod , details::vararg_mul_op ) + case_stmt(details::e_avg , details::vararg_avg_op ) + case_stmt(details::e_min , details::vararg_min_op ) + case_stmt(details::e_max , details::vararg_max_op ) + case_stmt(details::e_mand , details::vararg_mand_op ) + case_stmt(details::e_mor , details::vararg_mor_op ) + case_stmt(details::e_multi , details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } + } + } + + template + inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N]) + { + typedef typename details::function_N_node function_N_node_t; + expression_node_ptr result = synthesize_expression(f,b); + + if (0 == result) + return error_node(); + else + { + // Can the function call be completely optimised? + if (details::is_constant_node(result)) + return result; + else if (!all_nodes_valid(b)) + { + details::free_node(*node_allocator_,result); + std::fill_n(b, N, reinterpret_cast(0)); + + return error_node(); + } + else if (N != f->param_count) + { + details::free_node(*node_allocator_,result); + std::fill_n(b, N, reinterpret_cast(0)); + + return error_node(); + } + + function_N_node_t* func_node_ptr = reinterpret_cast(result); + + if (!func_node_ptr->init_branches(b)) + { + details::free_node(*node_allocator_,result); + std::fill_n(b, N, reinterpret_cast(0)); + + return error_node(); + } + + return result; + } + } + + inline expression_node_ptr function(ifunction_t* f) + { + typedef typename details::function_N_node function_N_node_t; + return node_allocator_->allocate(f); + } + + inline expression_node_ptr vararg_function_call(ivararg_function_t* vaf, + std::vector& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + + typedef details::vararg_function_node alloc_type; + + expression_node_ptr result = node_allocator_->allocate(vaf,arg_list); + + if ( + !arg_list.empty() && + !vaf->has_side_effects() && + is_constant_foldable(arg_list) + ) + { + const Type v = result->value(); + details::free_node(*node_allocator_,result); + result = node_allocator_->allocate(v); + } + + parser_->state_.activate_side_effect("vararg_function_call()"); + + return result; + } + + inline expression_node_ptr generic_function_call(igeneric_function_t* gf, + std::vector& arg_list, + const std::size_t& param_seq_index = std::numeric_limits::max()) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + + typedef details::generic_function_node alloc_type1; + typedef details::multimode_genfunction_node alloc_type2; + + const std::size_t no_psi = std::numeric_limits::max(); + + expression_node_ptr result = error_node(); + + if (no_psi == param_seq_index) + result = node_allocator_->allocate(arg_list,gf); + else + result = node_allocator_->allocate(gf, param_seq_index, arg_list); + + alloc_type1* genfunc_node_ptr = static_cast(result); + + if ( + !arg_list.empty() && + !gf->has_side_effects() && + parser_->state_.type_check_enabled && + is_constant_foldable(arg_list) + ) + { + genfunc_node_ptr->init_branches(); + + const Type v = result->value(); + + details::free_node(*node_allocator_,result); + + return node_allocator_->allocate(v); + } + else if (genfunc_node_ptr->init_branches()) + { + parser_->state_.activate_side_effect("generic_function_call()"); + + return result; + } + else + { + details::free_node(*node_allocator_, result); + details::free_all_nodes(*node_allocator_, arg_list); + + return error_node(); + } + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr string_function_call(igeneric_function_t* gf, + std::vector& arg_list, + const std::size_t& param_seq_index = std::numeric_limits::max()) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + + typedef details::string_function_node alloc_type1; + typedef details::multimode_strfunction_node alloc_type2; + + const std::size_t no_psi = std::numeric_limits::max(); + + expression_node_ptr result = error_node(); + + if (no_psi == param_seq_index) + result = node_allocator_->allocate(gf,arg_list); + else + result = node_allocator_->allocate(gf, param_seq_index, arg_list); + + alloc_type1* strfunc_node_ptr = static_cast(result); + + if ( + !arg_list.empty() && + !gf->has_side_effects() && + is_constant_foldable(arg_list) + ) + { + strfunc_node_ptr->init_branches(); + + const Type v = result->value(); + + details::free_node(*node_allocator_,result); + + return node_allocator_->allocate(v); + } + else if (strfunc_node_ptr->init_branches()) + { + parser_->state_.activate_side_effect("string_function_call()"); + + return result; + } + else + { + details::free_node (*node_allocator_,result ); + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + } + #endif + + #ifndef exprtk_disable_return_statement + inline expression_node_ptr return_call(std::vector& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + + typedef details::return_node alloc_type; + + expression_node_ptr result = node_allocator_-> + allocate_rr(arg_list,parser_->results_ctx()); + + alloc_type* return_node_ptr = static_cast(result); + + if (return_node_ptr->init_branches()) + { + parser_->state_.activate_side_effect("return_call()"); + + return result; + } + else + { + details::free_node (*node_allocator_,result ); + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + } + + inline expression_node_ptr return_envelope(expression_node_ptr body, + results_context_t* rc, + bool*& return_invoked) + { + typedef details::return_envelope_node alloc_type; + + expression_node_ptr result = node_allocator_-> + allocate_cr(body,(*rc)); + + return_invoked = static_cast(result)->retinvk_ptr(); + + return result; + } + #else + inline expression_node_ptr return_call(std::vector&) + { + return error_node(); + } + + inline expression_node_ptr return_envelope(expression_node_ptr, + results_context_t*, + bool*&) + { + return error_node(); + } + #endif + + inline expression_node_ptr vector_element(const std::string& symbol, + vector_holder_ptr vector_base, + expression_node_ptr index) + { + expression_node_ptr result = error_node(); + + if (details::is_constant_node(index)) + { + std::size_t i = static_cast(details::numeric::to_int64(index->value())); + + details::free_node(*node_allocator_,index); + + if (vector_base->rebaseable()) + { + return node_allocator_->allocate(i,vector_base); + } + + const scope_element& se = parser_->sem_.get_element(symbol,i); + + if (se.index == i) + { + result = se.var_node; + } + else + { + scope_element nse; + nse.name = symbol; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_vecelem; + nse.index = i; + nse.depth = parser_->state_.scope_depth; + nse.data = 0; + nse.var_node = node_allocator_->allocate((*(*vector_base)[i])); + + if (!parser_->sem_.add_element(nse)) + { + parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); + + parser_->sem_.free_element(nse); + + result = error_node(); + } + + exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); + + parser_->state_.activate_side_effect("vector_element()"); + + result = nse.var_node; + } + } + else if (vector_base->rebaseable()) + result = node_allocator_->allocate(index,vector_base); + else + result = node_allocator_->allocate(index,vector_base); + + return result; + } + + private: + + template + inline bool is_constant_foldable(NodePtr (&b)[N]) const + { + for (std::size_t i = 0; i < N; ++i) + { + if (0 == b[i]) + return false; + else if (!details::is_constant_node(b[i])) + return false; + } + + return true; + } + + template class Sequence> + inline bool is_constant_foldable(const Sequence& b) const + { + for (std::size_t i = 0; i < b.size(); ++i) + { + if (0 == b[i]) + return false; + else if (!details::is_constant_node(b[i])) + return false; + } + + return true; + } + + void lodge_assignment(symbol_type cst, expression_node_ptr node) + { + parser_->state_.activate_side_effect("lodge_assignment()"); + + if (!parser_->dec_.collect_assignments()) + return; + + std::string symbol_name; + + switch (cst) + { + case e_st_variable : symbol_name = parser_->symtab_store_ + .get_variable_name(node); + break; + + #ifndef exprtk_disable_string_capabilities + case e_st_string : symbol_name = parser_->symtab_store_ + .get_stringvar_name(node); + break; + #endif + + case e_st_vector : { + typedef details::vector_holder vector_holder_t; + + vector_holder_t& vh = static_cast(node)->vec_holder(); + + symbol_name = parser_->symtab_store_.get_vector_name(&vh); + } + break; + + case e_st_vecelem : { + typedef details::vector_holder vector_holder_t; + + vector_holder_t& vh = static_cast(node)->vec_holder(); + + symbol_name = parser_->symtab_store_.get_vector_name(&vh); + + cst = e_st_vector; + } + break; + + default : return; + } + + if (!symbol_name.empty()) + { + parser_->dec_.add_assignment(symbol_name,cst); + } + } + + inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + if (details::is_variable_node(branch[0])) + { + lodge_assignment(e_st_variable,branch[0]); + + return synthesize_expression(operation,branch); + } + else if (details::is_vector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + return synthesize_expression(operation, branch); + } + else if (details::is_rebasevector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + return synthesize_expression(operation, branch); + } + else if (details::is_rebasevector_celem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + return synthesize_expression(operation, branch); + } + #ifndef exprtk_disable_string_capabilities + else if (details::is_string_node(branch[0])) + { + lodge_assignment(e_st_string,branch[0]); + + return synthesize_expression(operation, branch); + } + else if (details::is_string_range_node(branch[0])) + { + lodge_assignment(e_st_string,branch[0]); + + return synthesize_expression(operation, branch); + } + #endif + else if (details::is_vector_node(branch[0])) + { + lodge_assignment(e_st_vector,branch[0]); + + if (details::is_ivector_node(branch[1])) + return synthesize_expression(operation, branch); + else + return synthesize_expression(operation, branch); + } + else + { + parser_->set_synthesis_error("Invalid assignment operation.[1]"); + + return error_node(); + } + } + + inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + if (details::is_variable_node(branch[0])) + { + lodge_assignment(e_st_variable,branch[0]); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_celem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_node(branch[0])) + { + lodge_assignment(e_st_vector,branch[0]); + + if (details::is_ivector_node(branch[1])) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + case_stmt(details::e_addass , details::add_op) + case_stmt(details::e_subass , details::sub_op) + case_stmt(details::e_mulass , details::mul_op) + case_stmt(details::e_divass , details::div_op) + case_stmt(details::e_modass , details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + } + #ifndef exprtk_disable_string_capabilities + else if ( + (details::e_addass == operation) && + details::is_string_node(branch[0]) + ) + { + typedef details::assignment_string_node addass_t; + + lodge_assignment(e_st_string,branch[0]); + + return synthesize_expression(operation,branch); + } + #endif + else + { + parser_->set_synthesis_error("Invalid assignment operation[2]"); + + return error_node(); + } + } + + inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const bool is_b0_ivec = details::is_ivector_node(branch[0]); + const bool is_b1_ivec = details::is_ivector_node(branch[1]); + + #define batch_eqineq_logic_case \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_equal, details::equal_op) \ + case_stmt(details::e_and , details::and_op ) \ + case_stmt(details::e_nand , details::nand_op ) \ + case_stmt(details::e_or , details::or_op ) \ + case_stmt(details::e_nor , details::nor_op ) \ + case_stmt(details::e_xor , details::xor_op ) \ + case_stmt(details::e_xnor , details::xnor_op ) \ + + if (is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + batch_eqineq_logic_case + #undef case_stmt + default : return error_node(); + } + } + else if (is_b0_ivec && !is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + batch_eqineq_logic_case + #undef case_stmt + default : return error_node(); + } + } + else if (!is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + batch_eqineq_logic_case + #undef case_stmt + default : return error_node(); + } + } + else + return error_node(); + + #undef batch_eqineq_logic_case + } + + inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const bool is_b0_ivec = details::is_ivector_node(branch[0]); + const bool is_b1_ivec = details::is_ivector_node(branch[1]); + + #define vector_ops \ + case_stmt(details::e_add , details::add_op) \ + case_stmt(details::e_sub , details::sub_op) \ + case_stmt(details::e_mul , details::mul_op) \ + case_stmt(details::e_div , details::div_op) \ + case_stmt(details::e_mod , details::mod_op) \ + + if (is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + vector_ops + case_stmt(details::e_pow,details:: pow_op) + #undef case_stmt + default : return error_node(); + } + } + else if (is_b0_ivec && !is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + vector_ops + case_stmt(details::e_pow,details:: pow_op) + #undef case_stmt + default : return error_node(); + } + } + else if (!is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation, branch[0], branch[1]); \ + + vector_ops + #undef case_stmt + default : return error_node(); + } + } + else + return error_node(); + + #undef vector_ops + } + + inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2]) + { + const bool v0_is_ivar = details::is_ivariable_node(branch[0]); + const bool v1_is_ivar = details::is_ivariable_node(branch[1]); + + const bool v0_is_ivec = details::is_ivector_node (branch[0]); + const bool v1_is_ivec = details::is_ivector_node (branch[1]); + + #ifndef exprtk_disable_string_capabilities + const bool v0_is_str = details::is_generally_string_node(branch[0]); + const bool v1_is_str = details::is_generally_string_node(branch[1]); + #endif + + expression_node_ptr result = error_node(); + + if (v0_is_ivar && v1_is_ivar) + { + typedef details::variable_node* variable_node_ptr; + + variable_node_ptr v0 = variable_node_ptr(0); + variable_node_ptr v1 = variable_node_ptr(0); + + if ( + (0 != (v0 = dynamic_cast(branch[0]))) && + (0 != (v1 = dynamic_cast(branch[1]))) + ) + { + result = node_allocator_->allocate >(v0,v1); + } + else + result = node_allocator_->allocate >(branch[0],branch[1]); + } + else if (v0_is_ivec && v1_is_ivec) + { + result = node_allocator_->allocate >(branch[0],branch[1]); + } + #ifndef exprtk_disable_string_capabilities + else if (v0_is_str && v1_is_str) + { + if (is_string_node(branch[0]) && is_string_node(branch[1])) + result = node_allocator_->allocate > + (branch[0], branch[1]); + else + result = node_allocator_->allocate > + (branch[0], branch[1]); + } + #endif + else + { + parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); + + return error_node(); + } + + parser_->state_.activate_side_effect("synthesize_swap_expression()"); + + return result; + } + + #ifndef exprtk_disable_sc_andor + inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + + if (details::is_constant_node(branch[0])) + { + if ( + (details::e_scand == operation) && + std::equal_to()(T(0),branch[0]->value()) + ) + result = node_allocator_->allocate_c(T(0)); + else if ( + (details::e_scor == operation) && + std::not_equal_to()(T(0),branch[0]->value()) + ) + result = node_allocator_->allocate_c(T(1)); + } + + if (details::is_constant_node(branch[1]) && (0 == result)) + { + if ( + (details::e_scand == operation) && + std::equal_to()(T(0),branch[1]->value()) + ) + result = node_allocator_->allocate_c(T(0)); + else if ( + (details::e_scor == operation) && + std::not_equal_to()(T(0),branch[1]->value()) + ) + result = node_allocator_->allocate_c(T(1)); + } + + if (result) + { + free_node(*node_allocator_, branch[0]); + free_node(*node_allocator_, branch[1]); + + return result; + } + else if (details::e_scand == operation) + { + return synthesize_expression(operation, branch); + } + else if (details::e_scor == operation) + { + return synthesize_expression(operation, branch); + } + else + return error_node(); + } + #else + inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type&, expression_node_ptr (&)[2]) + { + return error_node(); + } + #endif + + #define basic_opr_switch_statements \ + case_stmt(details::e_add , details::add_op) \ + case_stmt(details::e_sub , details::sub_op) \ + case_stmt(details::e_mul , details::mul_op) \ + case_stmt(details::e_div , details::div_op) \ + case_stmt(details::e_mod , details::mod_op) \ + case_stmt(details::e_pow , details::pow_op) \ + + #define extended_opr_switch_statements \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_and , details::and_op ) \ + case_stmt(details::e_nand, details::nand_op) \ + case_stmt(details::e_or , details::or_op ) \ + case_stmt(details::e_nor , details::nor_op ) \ + case_stmt(details::e_xor , details::xor_op ) \ + case_stmt(details::e_xnor, details::xnor_op) \ + + #ifndef exprtk_disable_cardinal_pow_optimisation + template class IPowNode> + inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) + { + switch (p) + { + #define case_stmt(cp) \ + case cp : return node_allocator_-> \ + allocate > >(v); \ + + case_stmt( 1) case_stmt( 2) case_stmt( 3) case_stmt( 4) + case_stmt( 5) case_stmt( 6) case_stmt( 7) case_stmt( 8) + case_stmt( 9) case_stmt(10) case_stmt(11) case_stmt(12) + case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) + case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) + case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) + case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) + case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) + case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) + case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) + case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) + case_stmt(45) case_stmt(46) case_stmt(47) case_stmt(48) + case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) + case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) + case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c) + { + const bool not_recipricol = (c >= T(0)); + const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); + + if (0 == p) + return node_allocator_->allocate_c(T(1)); + else if (std::equal_to()(T(2),c)) + { + return node_allocator_-> + template allocate_rr > >(v,v); + } + else + { + if (not_recipricol) + return cardinal_pow_optimisation_impl(v,p); + else + return cardinal_pow_optimisation_impl(v,p); + } + } + + inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) const + { + return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); + } + + inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*>(branch[1])->value(); + const bool not_recipricol = (c >= T(0)); + const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); + + node_allocator_->free(branch[1]); + + if (0 == p) + { + details::free_all_nodes(*node_allocator_, branch); + + return node_allocator_->allocate_c(T(1)); + } + else if (not_recipricol) + return cardinal_pow_optimisation_impl(branch[0],p); + else + return cardinal_pow_optimisation_impl(branch[0],p); + } + #else + inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) + { + return error_node(); + } + + inline bool cardinal_pow_optimisable(const details::operator_type&, const T&) + { + return false; + } + + inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr(&)[2]) + { + return error_node(); + } + #endif + + struct synthesize_binary_ext_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const bool left_neg = is_neg_unary_node(branch[0]); + const bool right_neg = is_neg_unary_node(branch[1]); + + if (left_neg && right_neg) + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if ( + !expr_gen.parser_->simplify_unary_negation_branch(branch[0]) || + !expr_gen.parser_->simplify_unary_negation_branch(branch[1]) + ) + { + details::free_all_nodes(*expr_gen.node_allocator_,branch); + + return error_node(); + } + } + + switch (operation) + { + // -f(x + 1) + -g(y + 1) --> -(f(x + 1) + g(y + 1)) + case details::e_add : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1])); + + // -f(x + 1) - -g(y + 1) --> g(y + 1) - f(x + 1) + case details::e_sub : return expr_gen.node_allocator_-> + template allocate > > + (branch[1],branch[0]); + + default : break; + } + } + else if (left_neg && !right_neg) + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (!expr_gen.parser_->simplify_unary_negation_branch(branch[0])) + { + details::free_all_nodes(*expr_gen.node_allocator_,branch); + + return error_node(); + } + + switch (operation) + { + // -f(x + 1) + g(y + 1) --> g(y + 1) - f(x + 1) + case details::e_add : return expr_gen.node_allocator_-> + template allocate > > + (branch[1], branch[0]); + + // -f(x + 1) - g(y + 1) --> -(f(x + 1) + g(y + 1)) + case details::e_sub : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + // -f(x + 1) * g(y + 1) --> -(f(x + 1) * g(y + 1)) + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + // -f(x + 1) / g(y + 1) --> -(f(x + 1) / g(y + 1)) + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + default : return error_node(); + } + } + } + else if (!left_neg && right_neg) + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (!expr_gen.parser_->simplify_unary_negation_branch(branch[1])) + { + details::free_all_nodes(*expr_gen.node_allocator_,branch); + + return error_node(); + } + + switch (operation) + { + // f(x + 1) + -g(y + 1) --> f(x + 1) - g(y + 1) + case details::e_add : return expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1]); + + // f(x + 1) - - g(y + 1) --> f(x + 1) + g(y + 1) + case details::e_sub : return expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1]); + + // f(x + 1) * -g(y + 1) --> -(f(x + 1) * g(y + 1)) + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + // f(x + 1) / -g(y + 1) --> -(f(x + 1) / g(y + 1)) + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0], branch[1])); + + default : return error_node(); + } + } + } + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate > > \ + (branch[0], branch[1]); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_vob_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v = static_cast*>(branch[0])->ref(); + + #ifndef exprtk_disable_enhanced_features + if (details::is_sf3ext_node(branch[1])) + { + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_right + (expr_gen, v, operation, branch[1], result); + + if (synthesis_result) + { + free_node(*expr_gen.node_allocator_,branch[1]); + return result; + } + } + #endif + + if ( + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (details::is_uv_node(branch[1])) + { + typedef details::uv_base_node* uvbn_ptr_t; + + details::operator_type o = static_cast(branch[1])->operation(); + + if (details::e_neg == o) + { + const Type& v1 = static_cast(branch[1])->v(); + + free_node(*expr_gen.node_allocator_,branch[1]); + + switch (operation) + { + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v,v1)); + + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v,v1)); + + default : break; + } + } + } + } + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rc > > \ + (v, branch[1]); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_bov_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v = static_cast*>(branch[1])->ref(); + + #ifndef exprtk_disable_enhanced_features + if (details::is_sf3ext_node(branch[0])) + { + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_left + (expr_gen, v, operation, branch[0], result); + + if (synthesis_result) + { + free_node(*expr_gen.node_allocator_, branch[0]); + + return result; + } + } + #endif + + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (details::is_uv_node(branch[0])) + { + typedef details::uv_base_node* uvbn_ptr_t; + + details::operator_type o = static_cast(branch[0])->operation(); + + if (details::e_neg == o) + { + const Type& v0 = static_cast(branch[0])->v(); + + free_node(*expr_gen.node_allocator_,branch[0]); + + switch (operation) + { + case details::e_add : return expr_gen.node_allocator_-> + template allocate_rr > >(v,v0); + + case details::e_sub : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v0,v)); + + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v0,v)); + + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v0,v)); + default : break; + } + } + } + } + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (branch[0], v); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_cob_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*>(branch[0])->value(); + + free_node(*expr_gen.node_allocator_,branch[0]); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_,branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + return branch[1]; + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + return branch[1]; + + if (details::is_cob_node(branch[1])) + { + // Simplify expressions of the form: + // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) + // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x + if ( + (operation == details::e_mul) || + (operation == details::e_add) + ) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + + if (operation == cobnode->operation()) + { + switch (operation) + { + case details::e_add : cobnode->set_c(c + cobnode->c()); break; + case details::e_mul : cobnode->set_c(c * cobnode->c()); break; + default : return error_node(); + } + + return cobnode; + } + } + + if (operation == details::e_mul) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + details::operator_type cob_opr = cobnode->operation(); + + if ( + (details::e_div == cob_opr) || + (details::e_mul == cob_opr) + ) + { + switch (cob_opr) + { + case details::e_div : cobnode->set_c(c * cobnode->c()); break; + case details::e_mul : cobnode->set_c(cobnode->c() / c); break; + default : return error_node(); + } + + return cobnode; + } + } + else if (operation == details::e_div) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + details::operator_type cob_opr = cobnode->operation(); + + if ( + (details::e_div == cob_opr) || + (details::e_mul == cob_opr) + ) + { + details::expression_node* new_cobnode = error_node(); + + switch (cob_opr) + { + case details::e_div : new_cobnode = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(), cobnode->move_branch(0)); + break; + + case details::e_mul : new_cobnode = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(), cobnode->move_branch(0)); + break; + + default : return error_node(); + } + + free_node(*expr_gen.node_allocator_,branch[1]); + + return new_cobnode; + } + } + } + #ifndef exprtk_disable_enhanced_features + else if (details::is_sf3ext_node(branch[1])) + { + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_right + (expr_gen, c, operation, branch[1], result); + + if (synthesis_result) + { + free_node(*expr_gen.node_allocator_,branch[1]); + + return result; + } + } + #endif + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_tt > > \ + (c, branch[1]); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_boc_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*>(branch[1])->value(); + + details::free_node(*(expr_gen.node_allocator_), branch[1]); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + + return expr_gen(std::numeric_limits::quiet_NaN()); + } + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + return branch[0]; + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + return branch[0]; + + if (details::is_boc_node(branch[0])) + { + // Simplify expressions of the form: + // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) --> (x + 9) * 40320 + // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) --> x + 45 + if ( + (operation == details::e_mul) || + (operation == details::e_add) + ) + { + details::boc_base_node* bocnode = static_cast*>(branch[0]); + + if (operation == bocnode->operation()) + { + switch (operation) + { + case details::e_add : bocnode->set_c(c + bocnode->c()); break; + case details::e_mul : bocnode->set_c(c * bocnode->c()); break; + default : return error_node(); + } + + return bocnode; + } + } + else if (operation == details::e_div) + { + details::boc_base_node* bocnode = static_cast*>(branch[0]); + details::operator_type boc_opr = bocnode->operation(); + + if ( + (details::e_div == boc_opr) || + (details::e_mul == boc_opr) + ) + { + switch (boc_opr) + { + case details::e_div : bocnode->set_c(c * bocnode->c()); break; + case details::e_mul : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); + } + + return bocnode; + } + } + else if (operation == details::e_pow) + { + // (v ^ c0) ^ c1 --> v ^(c0 * c1) + details::boc_base_node* bocnode = static_cast*>(branch[0]); + details::operator_type boc_opr = bocnode->operation(); + + if (details::e_pow == boc_opr) + { + bocnode->set_c(bocnode->c() * c); + + return bocnode; + } + } + } + + #ifndef exprtk_disable_enhanced_features + if (details::is_sf3ext_node(branch[0])) + { + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_left + (expr_gen, c, operation, branch[0], result); + + if (synthesis_result) + { + free_node(*expr_gen.node_allocator_, branch[0]); + + return result; + } + } + #endif + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (branch[0], c); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_cocob_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + + // (cob) o c --> cob + if (details::is_cob_node(branch[0])) + { + details::cob_base_node* cobnode = static_cast*>(branch[0]); + + const Type c = static_cast*>(branch[1])->value(); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(std::numeric_limits::quiet_NaN())); + } + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + { + free_node(*expr_gen.node_allocator_, branch[1]); + + return branch[0]; + } + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_, branch[1]); + + return branch[0]; + } + else if (std::equal_to()(T(1),c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_, branch[1]); + + return branch[0]; + } + + const bool op_addsub = (details::e_add == cobnode->operation()) || + (details::e_sub == cobnode->operation()) ; + + if (op_addsub) + { + switch (operation) + { + case details::e_add : cobnode->set_c(cobnode->c() + c); break; + case details::e_sub : cobnode->set_c(cobnode->c() - c); break; + default : return error_node(); + } + + result = cobnode; + } + else if (details::e_mul == cobnode->operation()) + { + switch (operation) + { + case details::e_mul : cobnode->set_c(cobnode->c() * c); break; + case details::e_div : cobnode->set_c(cobnode->c() / c); break; + default : return error_node(); + } + + result = cobnode; + } + else if (details::e_div == cobnode->operation()) + { + if (details::e_mul == operation) + { + cobnode->set_c(cobnode->c() * c); + result = cobnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (cobnode->c() / c, cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_, branch[0]); + } + } + + if (result) + { + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + // c o (cob) --> cob + else if (details::is_cob_node(branch[1])) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + + const Type c = static_cast*>(branch[0])->value(); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(0)); + } + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + + return branch[1]; + } + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + + return branch[1]; + } + + if (details::e_add == cobnode->operation()) + { + if (details::e_add == operation) + { + cobnode->set_c(c + cobnode->c()); + result = cobnode; + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c - cobnode->c(), cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_sub == cobnode->operation()) + { + if (details::e_add == operation) + { + cobnode->set_c(c + cobnode->c()); + result = cobnode; + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c - cobnode->c(), cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_mul == cobnode->operation()) + { + if (details::e_mul == operation) + { + cobnode->set_c(c * cobnode->c()); + result = cobnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(), cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_div == cobnode->operation()) + { + if (details::e_mul == operation) + { + cobnode->set_c(c * cobnode->c()); + result = cobnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(), cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + if (result) + { + free_node(*expr_gen.node_allocator_,branch[0]); + } + } + + return result; + } + }; + + struct synthesize_coboc_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + + // (boc) o c --> boc + if (details::is_boc_node(branch[0])) + { + details::boc_base_node* bocnode = static_cast*>(branch[0]); + + const Type c = static_cast*>(branch[1])->value(); + + if (details::e_add == bocnode->operation()) + { + switch (operation) + { + case details::e_add : bocnode->set_c(bocnode->c() + c); break; + case details::e_sub : bocnode->set_c(bocnode->c() - c); break; + default : return error_node(); + } + + result = bocnode; + } + else if (details::e_mul == bocnode->operation()) + { + switch (operation) + { + case details::e_mul : bocnode->set_c(bocnode->c() * c); break; + case details::e_div : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); + } + + result = bocnode; + } + else if (details::e_sub == bocnode->operation()) + { + if (details::e_add == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (bocnode->move_branch(0), c - bocnode->c()); + + free_node(*expr_gen.node_allocator_,branch[0]); + } + else if (details::e_sub == operation) + { + bocnode->set_c(bocnode->c() + c); + result = bocnode; + } + } + else if (details::e_div == bocnode->operation()) + { + switch (operation) + { + case details::e_div : bocnode->set_c(bocnode->c() * c); break; + case details::e_mul : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); + } + + result = bocnode; + } + + if (result) + { + free_node(*expr_gen.node_allocator_, branch[1]); + } + } + + // c o (boc) --> boc + else if (details::is_boc_node(branch[1])) + { + details::boc_base_node* bocnode = static_cast*>(branch[1]); + + const Type c = static_cast*>(branch[0])->value(); + + if (details::e_add == bocnode->operation()) + { + if (details::e_add == operation) + { + bocnode->set_c(c + bocnode->c()); + result = bocnode; + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c - bocnode->c(), bocnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_sub == bocnode->operation()) + { + if (details::e_add == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (bocnode->move_branch(0), c - bocnode->c()); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c + bocnode->c(), bocnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_mul == bocnode->operation()) + { + if (details::e_mul == operation) + { + bocnode->set_c(c * bocnode->c()); + result = bocnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c / bocnode->c(), bocnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_div == bocnode->operation()) + { + if (details::e_mul == operation) + { + bocnode->set_c(bocnode->c() / c); + result = bocnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c * bocnode->c(), bocnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + if (result) + { + free_node(*expr_gen.node_allocator_,branch[0]); + } + } + + return result; + } + }; + + #ifndef exprtk_disable_enhanced_features + inline bool synthesize_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2], + expression_node_ptr& result) + { + result = error_node(); + + if (!operation_optimisable(operation)) + return false; + + const std::string node_id = branch_to_id(branch); + + const typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id); + + if (synthesize_map_.end() != itr) + { + result = itr->second((*this), operation, branch); + + return true; + } + else + return false; + } + + struct synthesize_vov_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v1 = static_cast*>(branch[0])->ref(); + const Type& v2 = static_cast*>(branch[1])->ref(); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rr > > \ + (v1, v2); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_cov_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*> (branch[0])->value(); + const Type& v = static_cast*>(branch[1])->ref (); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + return expr_gen(T(0)); + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + return expr_gen(T(0)); + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + return static_cast*>(branch[1]); + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + return static_cast*>(branch[1]); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (c, v); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_voc_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v = static_cast*>(branch[0])->ref (); + const Type c = static_cast*> (branch[1])->value(); + + details::free_node(*(expr_gen.node_allocator_), branch[1]); + + if (expr_gen.cardinal_pow_optimisable(operation,c)) + { + if (std::equal_to()(T(1),c)) + return branch[0]; + else + return expr_gen.cardinal_pow_optimisation(v,c); + } + else if (std::equal_to()(T(0),c) && (details::e_mul == operation)) + return expr_gen(T(0)); + else if (std::equal_to()(T(0),c) && (details::e_div == operation)) + return expr_gen(std::numeric_limits::quiet_NaN()); + else if (std::equal_to()(T(0),c) && (details::e_add == operation)) + return static_cast*>(branch[0]); + else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) + return static_cast*>(branch[0]); + else if (std::equal_to()(T(1),c) && (details::e_div == operation)) + return static_cast*>(branch[0]); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rc > > \ + (v, c); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_sf3ext_expression + { + template + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& sf3opr, + T0 t0, T1 t1, T2 t2) + { + switch (sf3opr) + { + #define case_stmt(op) \ + case details::e_sf##op : return details::T0oT1oT2_sf3ext >:: \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2); \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) + #undef case_stmt + default : return error_node(); + } + } + + template + static inline bool compile(expression_generator& expr_gen, const std::string& id, + T0 t0, T1 t1, T2 t2, + expression_node_ptr& result) + { + details::operator_type sf3opr; + + if (!expr_gen.sf3_optimisable(id,sf3opr)) + return false; + else + result = synthesize_sf3ext_expression::template process + (expr_gen, sf3opr, t0, t1, t2); + + return true; + } + }; + + struct synthesize_sf4ext_expression + { + template + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& sf4opr, + T0 t0, T1 t1, T2 t2, T3 t3) + { + switch (sf4opr) + { + #define case_stmt0(op) \ + case details::e_sf##op : return details::T0oT1oT2oT3_sf4ext >:: \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ + + + #define case_stmt1(op) \ + case details::e_sf4ext##op : return details::T0oT1oT2oT3_sf4ext >:: \ + allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ + + case_stmt0(48) case_stmt0(49) case_stmt0(50) case_stmt0(51) + case_stmt0(52) case_stmt0(53) case_stmt0(54) case_stmt0(55) + case_stmt0(56) case_stmt0(57) case_stmt0(58) case_stmt0(59) + case_stmt0(60) case_stmt0(61) case_stmt0(62) case_stmt0(63) + case_stmt0(64) case_stmt0(65) case_stmt0(66) case_stmt0(67) + case_stmt0(68) case_stmt0(69) case_stmt0(70) case_stmt0(71) + case_stmt0(72) case_stmt0(73) case_stmt0(74) case_stmt0(75) + case_stmt0(76) case_stmt0(77) case_stmt0(78) case_stmt0(79) + case_stmt0(80) case_stmt0(81) case_stmt0(82) case_stmt0(83) + + case_stmt1(00) case_stmt1(01) case_stmt1(02) case_stmt1(03) + case_stmt1(04) case_stmt1(05) case_stmt1(06) case_stmt1(07) + case_stmt1(08) case_stmt1(09) case_stmt1(10) case_stmt1(11) + case_stmt1(12) case_stmt1(13) case_stmt1(14) case_stmt1(15) + case_stmt1(16) case_stmt1(17) case_stmt1(18) case_stmt1(19) + case_stmt1(20) case_stmt1(21) case_stmt1(22) case_stmt1(23) + case_stmt1(24) case_stmt1(25) case_stmt1(26) case_stmt1(27) + case_stmt1(28) case_stmt1(29) case_stmt1(30) case_stmt1(31) + case_stmt1(32) case_stmt1(33) case_stmt1(34) case_stmt1(35) + case_stmt1(36) case_stmt1(37) case_stmt1(38) case_stmt1(39) + case_stmt1(40) case_stmt1(41) case_stmt1(42) case_stmt1(43) + case_stmt1(44) case_stmt1(45) case_stmt1(46) case_stmt1(47) + case_stmt1(48) case_stmt1(49) case_stmt1(50) case_stmt1(51) + case_stmt1(52) case_stmt1(53) case_stmt1(54) case_stmt1(55) + case_stmt1(56) case_stmt1(57) case_stmt1(58) case_stmt1(59) + case_stmt1(60) case_stmt1(61) + + #undef case_stmt0 + #undef case_stmt1 + default : return error_node(); + } + } + + template + static inline bool compile(expression_generator& expr_gen, const std::string& id, + T0 t0, T1 t1, T2 t2, T3 t3, + expression_node_ptr& result) + { + details::operator_type sf4opr; + + if (!expr_gen.sf4_optimisable(id,sf4opr)) + return false; + else + result = synthesize_sf4ext_expression::template process + (expr_gen, sf4opr, t0, t1, t2, t3); + + return true; + } + + // T o (sf3ext) + template + static inline bool compile_right(expression_generator& expr_gen, + ExternalType t, + const details::operator_type& operation, + expression_node_ptr& sf3node, + expression_node_ptr& result) + { + if (!details::is_sf3ext_node(sf3node)) + return false; + + typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; + + sf3ext_base_ptr n = static_cast(sf3node); + const std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; + + switch (n->type()) + { + case details::expression_node::e_covoc : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_covov : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vocov : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vovoc : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vovov : return compile_right_impl + + (expr_gen, id, t, sf3node, result); + + default : return false; + } + } + + // (sf3ext) o T + template + static inline bool compile_left(expression_generator& expr_gen, + ExternalType t, + const details::operator_type& operation, + expression_node_ptr& sf3node, + expression_node_ptr& result) + { + if (!details::is_sf3ext_node(sf3node)) + return false; + + typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; + + sf3ext_base_ptr n = static_cast(sf3node); + + const std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; + + switch (n->type()) + { + case details::expression_node::e_covoc : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_covov : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vocov : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vovoc : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + case details::expression_node::e_vovov : return compile_left_impl + + (expr_gen, id, t, sf3node, result); + + default : return false; + } + } + + template + static inline bool compile_right_impl(expression_generator& expr_gen, + const std::string& id, + ExternalType t, + expression_node_ptr& node, + expression_node_ptr& result) + { + SF3TypeNode* n = dynamic_cast(node); + + if (n) + { + T0 t0 = n->t0(); + T1 t1 = n->t1(); + T2 t2 = n->t2(); + + return synthesize_sf4ext_expression::template compile + (expr_gen, id, t, t0, t1, t2, result); + } + else + return false; + } + + template + static inline bool compile_left_impl(expression_generator& expr_gen, + const std::string& id, + ExternalType t, + expression_node_ptr& node, + expression_node_ptr& result) + { + SF3TypeNode* n = dynamic_cast(node); + + if (n) + { + T0 t0 = n->t0(); + T1 t1 = n->t1(); + T2 t2 = n->t2(); + + return synthesize_sf4ext_expression::template compile + (expr_gen, id, t0, t1, t2, t, result); + } + else + return false; + } + }; + + struct synthesize_vovov_expression0 + { + typedef typename vovov_t::type0 node_type; + typedef typename vovov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (v2) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", v0, v1, v2, result); + + exprtk_debug(("(v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_vovov_expression1 + { + typedef typename vovov_t::type1 node_type; + typedef typename vovov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0) o0 (v1 o1 v2) + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vov->v0(); + const Type& v2 = vov->v1(); + const details::operator_type o0 = operation; + const details::operator_type o1 = vov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", v0, v2, v1, result); + + exprtk_debug(("v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_vovoc_expression0 + { + typedef typename vovoc_t::type0 node_type; + typedef typename vovoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (c) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type c = static_cast*>(branch[1])->value(); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) / c --> (vovoc) v0 / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", v0, v1, c, result); + + exprtk_debug(("(v0 / v1) / c --> (vovoc) v0 / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_vovoc_expression1 + { + typedef typename vovoc_t::type1 node_type; + typedef typename vovoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0) o0 (v1 o1 c) + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = voc->v(); + const Type c = voc->c(); + const details::operator_type o0 = operation; + const details::operator_type o1 = voc->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // v0 / (v1 / c) --> (vocov) (v0 * c) / v1 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", v0, c, v1, result); + + exprtk_debug(("v0 / (v1 / c) --> (vocov) (v0 * c) / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_vocov_expression0 + { + typedef typename vocov_t::type0 node_type; + typedef typename vocov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c) o1 (v1) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const Type& v0 = voc->v(); + const Type c = voc->c(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", v0, v1, c, result); + + exprtk_debug(("(v0 / c) / v1 --> (vovoc) v0 / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_vocov_expression1 + { + typedef typename vocov_t::type1 node_type; + typedef typename vocov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0) o0 (c o1 v1) + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c = cov->c(); + const Type& v1 = cov->v(); + const details::operator_type o0 = operation; + const details::operator_type o1 = cov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // v0 / (c / v1) --> (vovoc) (v0 * v1) / c + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", v0, v1, c, result); + + exprtk_debug(("v0 / (c / v1) --> (vovoc) (v0 * v1) / c\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_covov_expression0 + { + typedef typename covov_t::type0 node_type; + typedef typename covov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c o0 v0) o1 (v1) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const Type c = cov->c(); + const Type& v0 = cov->v(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c / v0) / v1 --> (covov) c / (v0 * v1) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", c, v0, v1, result); + + exprtk_debug(("(c / v0) / v1 --> (covov) c / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_covov_expression1 + { + typedef typename covov_t::type1 node_type; + typedef typename covov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c) o0 (v0 o1 v1) + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const details::operator_type o0 = operation; + const details::operator_type o1 = vov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // c / (v0 / v1) --> (covov) (c * v1) / v0 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", c, v1, v0, result); + + exprtk_debug(("c / (v0 / v1) --> (covov) (c * v1) / v0\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_covoc_expression0 + { + typedef typename covoc_t::type0 node_type; + typedef typename covoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0 o0 v) o1 (c1) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const Type c0 = cov->c(); + const Type& v = cov->v(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0 + v) + c1 --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0 + v) + c1 --> (cov) (c0 + c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0 + v) - c1 --> (cov) (c0 - c1) + v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0 + v) - c1 --> (cov) (c0 - c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0 - v) + c1 --> (cov) (c0 + c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0 - v) + c1 --> (cov) (c0 + c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0 - v) - c1 --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0 - v) - c1 --> (cov) (c0 - c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0 * v) * c1 --> (cov) (c0 * c1) * v + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0 * v) * c1 --> (cov) (c0 * c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0 * v) / c1 --> (cov) (c0 / c1) * v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0 * v) / c1 --> (cov) (c0 / c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + // (c0 / v) * c1 --> (cov) (c0 * c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0 / v) * c1 --> (cov) (c0 * c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0 / v) / c1 --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0 / v) / c1 --> (cov) (c0 / c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_covoc_expression1 + { + typedef typename covoc_t::type1 node_type; + typedef typename covoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0) o0 (v o1 c1) + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v = voc->v(); + const Type c1 = voc->c(); + const details::operator_type o0 = operation; + const details::operator_type o1 = voc->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0) + (v + c1) --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) + (v + c1) --> (cov) (c0 + c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0) + (v - c1) --> (cov) (c0 - c1) + v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) + (v - c1) --> (cov) (c0 - c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0) - (v + c1) --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) - (v + c1) --> (cov) (c0 - c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0) - (v - c1) --> (cov) (c0 + c1) - v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) - (v - c1) --> (cov) (c0 + c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0) * (v * c1) --> (voc) v * (c0 * c1) + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) * (v * c1) --> (voc) v * (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0) * (v / c1) --> (cov) (c0 / c1) * v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) * (v / c1) --> (cov) (c0 / c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + // (c0) / (v * c1) --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) / (v * c1) --> (cov) (c0 / c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + // (c0) / (v / c1) --> (cov) (c0 * c1) / v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) / (v / c1) --> (cov) (c0 * c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_cocov_expression0 + { + typedef typename cocov_t::type0 node_type; + static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) + { + // (c0 o0 c1) o1 (v) - Not possible. + return error_node(); + } + }; + + struct synthesize_cocov_expression1 + { + typedef typename cocov_t::type1 node_type; + typedef typename cocov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0) o0 (c1 o1 v) + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type c1 = cov->c(); + const Type& v = cov->v(); + const details::operator_type o0 = operation; + const details::operator_type o1 = cov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0) + (c1 + v) --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) + (c1 + v) --> (cov) (c0 + c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0) + (c1 - v) --> (cov) (c0 + c1) - v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) + (c1 - v) --> (cov) (c0 + c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1, v); + } + // (c0) - (c1 + v) --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) - (c1 + v) --> (cov) (c0 - c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0) - (c1 - v) --> (cov) (c0 - c1) + v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) - (c1 - v) --> (cov) (c0 - c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1, v); + } + // (c0) * (c1 * v) --> (cov) (c0 * c1) * v + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) * (c1 * v) --> (cov) (c0 * c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0) * (c1 / v) --> (cov) (c0 * c1) / v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) * (c1 / v) --> (cov) (c0 * c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1, v); + } + // (c0) / (c1 * v) --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) / (c1 * v) --> (cov) (c0 / c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + // (c0) / (c1 / v) --> (cov) (c0 / c1) * v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) / (c1 / v) --> (cov) (c0 / c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1, v); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), c0, c1, v, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, c1, v, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; + } + }; + + struct synthesize_vococ_expression0 + { + typedef typename vococ_t::type0 node_type; + typedef typename vococ_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v o0 c0) o1 (c1) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const Type& v = voc->v(); + const Type& c0 = voc->c(); + const Type& c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v + c0) + c1 --> (voc) v + (c0 + c1) + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(v + c0) + c1 --> (voc) v + (c0 + c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 + c1); + } + // (v + c0) - c1 --> (voc) v + (c0 - c1) + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(v + c0) - c1 --> (voc) v + (c0 - c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 - c1); + } + // (v - c0) + c1 --> (voc) v - (c0 + c1) + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(v - c0) + c1 --> (voc) v - (c0 + c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c1 - c0); + } + // (v - c0) - c1 --> (voc) v - (c0 + c1) + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(v - c0) - c1 --> (voc) v - (c0 + c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 + c1); + } + // (v * c0) * c1 --> (voc) v * (c0 * c1) + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(v * c0) * c1 --> (voc) v * (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 * c1); + } + // (v * c0) / c1 --> (voc) v * (c0 / c1) + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(v * c0) / c1 --> (voc) v * (c0 / c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 / c1); + } + // (v / c0) * c1 --> (voc) v * (c1 / c0) + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(v / c0) * c1 --> (voc) v * (c1 / c0)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c1 / c0); + } + // (v / c0) / c1 --> (voc) v / (c0 * c1) + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(v / c0) / c1 --> (voc) v / (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 * c1); + } + // (v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1) + else if ((details::e_pow == o0) && (details::e_pow == o1)) + { + exprtk_debug(("(v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v, c0 * c1); + } + } + + const bool synthesis_result = + synthesize_sf3ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1), v, c0, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v, c0, c1, f0, f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; + } + }; + + struct synthesize_vococ_expression1 + { + typedef typename vococ_t::type0 node_type; + + static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) + { + // (v) o0 (c0 o1 c1) - Not possible. + exprtk_debug(("(v) o0 (c0 o1 c1) - Not possible.\n")); + return error_node(); + } + }; + + struct synthesize_vovovov_expression0 + { + typedef typename vovovov_t::type0 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (v2 o2 v3) + const details::vov_base_node* vov0 = static_cast*>(branch[0]); + const details::vov_base_node* vov1 = static_cast*>(branch[1]); + const Type& v0 = vov0->v0(); + const Type& v1 = vov0->v1(); + const Type& v2 = vov1->v0(); + const Type& v3 = vov1->v1(); + const details::operator_type o0 = vov0->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = vov1->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, v3, result); + + exprtk_debug(("(v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v3, v1, v2, result); + + exprtk_debug(("(v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) + else if ((details::e_add == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t+t)*(t/t)", v0, v1, v3, v2, result); + + exprtk_debug(("(v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 - v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) + else if ((details::e_sub == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t-t)*(t/t)", v0, v1, v3, v2, result); + + exprtk_debug(("(v0 - v1) / (v2 / v3) --> (vovovov) (v0 - v1) * (v3 / v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2 + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "((t*t)*t)/t", v0, v1, v3, v2, result); + + exprtk_debug(("(v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovovoc_expression0 + { + typedef typename vovovoc_t::type0 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (v2 o2 c) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type& v2 = voc->v (); + const Type c = voc->c (); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = voc->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); + + exprtk_debug(("(v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); + + exprtk_debug(("(v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovocov_expression0 + { + typedef typename vovocov_t::type0 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (c o2 v2) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type& v2 = cov->v (); + const Type c = cov->c (); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = cov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); + + exprtk_debug(("(v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); + + exprtk_debug(("(v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vocovov_expression0 + { + typedef typename vocovov_t::type0 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c) o1 (v1 o2 v2) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type c = voc->c (); + const Type& v0 = voc->v (); + const Type& v1 = vov->v0(); + const Type& v2 = vov->v1(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = vov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v1, c, v2, result); + + exprtk_debug(("(v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", v0, v2, c, v1, result); + + exprtk_debug(("(v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covovov_expression0 + { + typedef typename covovov_t::type0 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c o0 v0) o1 (v1 o2 v2) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type c = cov->c (); + const Type& v0 = cov->v (); + const Type& v1 = vov->v0(); + const Type& v2 = vov->v1(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = vov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", c, v1, v0, v2, result); + + exprtk_debug(("(c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)/(t*t)", c, v2, v0, v1, result); + + exprtk_debug(("(c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covocov_expression0 + { + typedef typename covocov_t::type0 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0 o0 v0) o1 (c1 o2 v1) + const details::cov_base_node* cov0 = static_cast*>(branch[0]); + const details::cov_base_node* cov1 = static_cast*>(branch[1]); + const Type c0 = cov0->c(); + const Type& v0 = cov0->v(); + const Type c1 = cov1->c(); + const Type& v1 = cov1->v(); + const details::operator_type o0 = cov0->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = cov1->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + + exprtk_debug(("(c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t-t)+t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v1, v0, result); + + exprtk_debug(("(c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t*(t*t)", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, specfunc, c0, v0, v1, result); + + exprtk_debug(("(c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vocovoc_expression0 + { + typedef typename vocovoc_t::type0 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c0) o1 (v1 o2 c1) + const details::voc_base_node* voc0 = static_cast*>(branch[0]); + const details::voc_base_node* voc1 = static_cast*>(branch[1]); + const Type c0 = voc0->c(); + const Type& v0 = voc0->v(); + const Type c1 = voc1->c(); + const Type& v1 = voc1->v(); + const details::operator_type o0 = voc0->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = voc1->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + + exprtk_debug(("(v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c1 - c0), v0, v1, result); + + exprtk_debug(("(v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1 + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", Type(1) / (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); + + exprtk_debug(("(v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t*(t/t)", (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t*(t/t)", Type(1) / (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)*(t+t)", v0, T(1) / c0, v1, c1, result); + + exprtk_debug(("(v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen, "(t*t)*(t-t)", v0, T(1) / c0, v1, c1, result); + + exprtk_debug(("(v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, specfunc, c0, v0, v1, result); + + exprtk_debug(("(v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c + else if ( + (std::equal_to()(c0,c1)) && + (details::e_div == o0) && + (details::e_div == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "(t+t)/t"; break; + case details::e_sub : specfunc = "(t-t)/t"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, specfunc, v0, v1, c0, result); + + exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covovoc_expression0 + { + typedef typename covovoc_t::type0 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0 o0 v0) o1 (v1 o2 c1) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type c0 = cov->c(); + const Type& v0 = cov->v(); + const Type c1 = voc->c(); + const Type& v1 = voc->v(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = voc->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + + exprtk_debug(("(c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t-(t+t)", (c0 + c1), v0, v1, result); + + exprtk_debug(("(c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t*(t/t)", (c0 / c1), v1, v0, result); + + exprtk_debug(("(c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); + + exprtk_debug(("(c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc, c0, v0, v1, result); + + exprtk_debug(("(c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vococov_expression0 + { + typedef typename vococov_t::type0 node_type; + typedef typename vococov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c0) o1 (c1 o2 v1) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type c0 = voc->c(); + const Type& v0 = voc->v(); + const Type c1 = cov->c(); + const Type& v1 = cov->v(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = cov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); + + exprtk_debug(("(v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); + + exprtk_debug(("(v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0) + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t+t)-t", v0, v1, (c1 + c0), result); + + exprtk_debug(("(v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); + + exprtk_debug(("(v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", (c0 / c1), v0, v1, result); + + exprtk_debug(("(v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)/t", Type(1) / (c0 * c1), v0, v1, result); + + exprtk_debug(("(v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1)) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, "(t*t)*t", v0, v1, Type(1) / (c0 * c1), result); + + exprtk_debug(("(v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1))\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen, specfunc, c0, v0, v1, result); + + exprtk_debug(("(v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovovov_expression1 + { + typedef typename vovovov_t::type1 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (v1 o1 (v2 o2 v3)) + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovov->t0(); + const Type& v2 = vovov->t1(); + const Type& v3 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (v1 o1 (v2 o2 v3))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vovovoc_expression1 + { + typedef typename vovovoc_t::type1 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (v1 o1 (v2 o2 c)) + typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovoc->t0(); + const Type& v2 = vovoc->t1(); + const Type c = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (v1 o1 (v2 o2 c))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vovocov_expression1 + { + typedef typename vovocov_t::type1 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (v1 o1 (c o2 v2)) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v2 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (v1 o1 (c o2 v2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vocovov_expression1 + { + typedef typename vocovov_t::type1 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (c o1 (v1 o2 v2)) + typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c = covov->t0(); + const Type& v1 = covov->t1(); + const Type& v2 = covov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covov->f0()); + const details::operator_type o2 = expr_gen.get_operator(covov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covov->f0(); + binary_functor_t f2 = covov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (c o1 (v1 o2 v2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_covovov_expression1 + { + typedef typename covovov_t::type1 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c o0 (v0 o1 (v1 o2 v2)) + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c o0 (v0 o1 (v1 o2 v2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_covocov_expression1 + { + typedef typename covocov_t::type1 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 (v0 o1 (c1 o2 v1)) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vocov->t0(); + const Type c1 = vocov->t1(); + const Type& v1 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 (v0 o1 (c1 o2 v1))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vocovoc_expression1 + { + typedef typename vocovoc_t::type1 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (c0 o1 (v1 o2 c2)) + typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c0 = covoc->t0(); + const Type& v1 = covoc->t1(); + const Type c1 = covoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covoc->f0(); + binary_functor_t f2 = covoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (c0 o1 (v1 o2 c2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_covovoc_expression1 + { + typedef typename covovoc_t::type1 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 (v0 o1 (v1 o2 c1)) + typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c1 = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 (v0 o1 (v1 o2 c1))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vococov_expression1 + { + typedef typename vococov_t::type1 node_type; + typedef typename vococov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (c0 o1 (c1 o2 v1)) + typedef typename synthesize_cocov_expression1::node_type lcl_cocov_t; + + const lcl_cocov_t* cocov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c0 = cocov->t0(); + const Type c1 = cocov->t1(); + const Type& v1 = cocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(cocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(cocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = cocov->f0(); + binary_functor_t f2 = cocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (c0 o1 (c1 o2 v1))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; + } + }; + + struct synthesize_vovovov_expression2 + { + typedef typename vovovov_t::type2 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((v1 o1 v2) o2 v3) + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovov->t0(); + const Type& v2 = vovov->t1(); + const Type& v3 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((v1 o1 v2) o2 v3)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovovoc_expression2 + { + typedef typename vovovoc_t::type2 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((v1 o1 v2) o2 c) + typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovoc->t0(); + const Type& v2 = vovoc->t1(); + const Type c = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((v1 o1 v2) o2 c)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vovocov_expression2 + { + typedef typename vovocov_t::type2 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((v1 o1 c) o2 v2) + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v2 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((v1 o1 c) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vocovov_expression2 + { + typedef typename vocovov_t::type2 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((c o1 v1) o2 v2) + typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c = covov->t0(); + const Type& v1 = covov->t1(); + const Type& v2 = covov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covov->f0()); + const details::operator_type o2 = expr_gen.get_operator(covov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covov->f0(); + binary_functor_t f2 = covov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((c o1 v1) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covovov_expression2 + { + typedef typename covovov_t::type2 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c o0 ((v1 o1 v2) o2 v3) + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c o0 ((v1 o1 v2) o2 v3)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covocov_expression2 + { + typedef typename covocov_t::type2 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 ((v0 o1 c1) o2 v1) + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vocov->t0(); + const Type c1 = vocov->t1(); + const Type& v1 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 ((v0 o1 c1) o2 v1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vocovoc_expression2 + { + typedef typename vocovoc_t::type2 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((c0 o1 v1) o2 c1) + typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c0 = covoc->t0(); + const Type& v1 = covoc->t1(); + const Type c1 = covoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covoc->f0(); + binary_functor_t f2 = covoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((c0 o1 v1) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_covovoc_expression2 + { + typedef typename covovoc_t::type2 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 ((v0 o1 v1) o2 c1) + typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c1 = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 ((v0 o1 v1) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; + } + }; + + struct synthesize_vococov_expression2 + { + typedef typename vococov_t::type2 node_type; + static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) + { + // v0 o0 ((c0 o1 c1) o2 v1) - Not possible + exprtk_debug(("v0 o0 ((c0 o1 c1) o2 v1) - Not possible\n")); + return error_node(); + } + + static inline std::string id(expression_generator&, + const details::operator_type, const details::operator_type, const details::operator_type) + { + return "INVALID"; + } + }; + + struct synthesize_vovovov_expression3 + { + typedef typename vovovov_t::type3 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 v1) o1 v2) o2 v3 + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type& v3 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 v1) o1 v2) o2 v3\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovovoc_expression3 + { + typedef typename vovovoc_t::type3 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 v1) o1 v2) o2 c + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type c = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 v1) o1 v2) o2 c\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovocov_expression3 + { + typedef typename vovocov_t::type3 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 v1) o1 c) o2 v2 + typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[0]); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c = vovoc->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovoc->f0(); + binary_functor_t f1 = vovoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 v1) o1 c) o2 v2\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vocovov_expression3 + { + typedef typename vocovov_t::type3 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 c) o1 v1) o2 v2 + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 c) o1 v1) o2 v2\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covovov_expression3 + { + typedef typename covovov_t::type3 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c o0 v0) o1 v1) o2 v2 + typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c o0 v0) o1 v1) o2 v2\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covocov_expression3 + { + typedef typename covocov_t::type3 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 v0) o1 c1) o2 v1 + typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[0]); + const Type c0 = covoc->t0(); + const Type& v0 = covoc->t1(); + const Type c1 = covoc->t2(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covoc->f0(); + binary_functor_t f1 = covoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 v0) o1 c1) o2 v1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vocovoc_expression3 + { + typedef typename vocovoc_t::type3 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 c0) o1 v1) o2 c1 + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c0 = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 c0) o1 v1) o2 c1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covovoc_expression3 + { + typedef typename covovoc_t::type3 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 v0) o1 v1) o2 c1 + typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c0 = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 v0) o1 v1) o2 c1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vococov_expression3 + { + typedef typename vococov_t::type3 node_type; + typedef typename vococov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 c0) o1 c1) o2 v1 + typedef typename synthesize_vococ_expression0::node_type lcl_vococ_t; + + const lcl_vococ_t* vococ = static_cast(branch[0]); + const Type& v0 = vococ->t0(); + const Type c0 = vococ->t1(); + const Type c1 = vococ->t2(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vococ->f0()); + const details::operator_type o1 = expr_gen.get_operator(vococ->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vococ->f0(); + binary_functor_t f1 = vococ->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 c0) o1 c1) o2 v1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovovov_expression4 + { + typedef typename vovovov_t::type4 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 (v1 o1 v2)) o2 v3 + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type& v3 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("(v0 o0 (v1 o1 v2)) o2 v3\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovovoc_expression4 + { + typedef typename vovovoc_t::type4 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (v1 o1 v2)) o2 c) + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type c = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (v1 o1 v2)) o2 c)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vovocov_expression4 + { + typedef typename vovocov_t::type4 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (v1 o1 c)) o2 v1) + typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[0]); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c = vovoc->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovoc->f0(); + binary_functor_t f1 = vovoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (v1 o1 c)) o2 v1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vocovov_expression4 + { + typedef typename vocovov_t::type4 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (c o1 v1)) o2 v2) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (c o1 v1)) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covovov_expression4 + { + typedef typename covovov_t::type4 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c o0 (v0 o1 v1)) o2 v2) + typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c o0 (v0 o1 v1)) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covocov_expression4 + { + typedef typename covocov_t::type4 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 (v0 o1 c1)) o2 v1) + typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[0]); + const Type c0 = covoc->t0(); + const Type& v0 = covoc->t1(); + const Type c1 = covoc->t2(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covoc->f0(); + binary_functor_t f1 = covoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 (v0 o1 c1)) o2 v1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vocovoc_expression4 + { + typedef typename vocovoc_t::type4 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (c0 o1 v1)) o2 c1) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c0 = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (c0 o1 v1)) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_covovoc_expression4 + { + typedef typename covovoc_t::type4 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 (v0 o1 v1)) o2 c1) + typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c0 = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + const bool synthesis_result = + synthesize_sf4ext_expression::template compile + (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); + + if (synthesis_result) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 (v0 o1 v1)) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; + } + }; + + struct synthesize_vococov_expression4 + { + typedef typename vococov_t::type4 node_type; + static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) + { + // ((v0 o0 (c0 o1 c1)) o2 v1) - Not possible + exprtk_debug(("((v0 o0 (c0 o1 c1)) o2 v1) - Not possible\n")); + return error_node(); + } + + static inline std::string id(expression_generator&, + const details::operator_type, const details::operator_type, const details::operator_type) + { + return "INVALID"; + } + }; + #endif + + inline expression_node_ptr synthesize_uvouv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + // Definition: uv o uv + details::operator_type o0 = static_cast*>(branch[0])->operation(); + details::operator_type o1 = static_cast*>(branch[1])->operation(); + const Type& v0 = static_cast*>(branch[0])->v(); + const Type& v1 = static_cast*>(branch[1])->v(); + unary_functor_t u0 = reinterpret_cast (0); + unary_functor_t u1 = reinterpret_cast (0); + binary_functor_t f = reinterpret_cast(0); + + if (!valid_operator(o0,u0)) + return error_node(); + else if (!valid_operator(o1,u1)) + return error_node(); + else if (!valid_operator(operation,f)) + return error_node(); + + expression_node_ptr result = error_node(); + + if ( + (details::e_neg == o0) && + (details::e_neg == o1) + ) + { + switch (operation) + { + // (-v0 + -v1) --> -(v0 + v1) + case details::e_add : result = (*this)(details::e_neg, + node_allocator_-> + allocate_rr > >(v0, v1)); + exprtk_debug(("(-v0 + -v1) --> -(v0 + v1)\n")); + break; + + // (-v0 - -v1) --> (v1 - v0) + case details::e_sub : result = node_allocator_-> + allocate_rr > >(v1, v0); + exprtk_debug(("(-v0 - -v1) --> (v1 - v0)\n")); + break; + + // (-v0 * -v1) --> (v0 * v1) + case details::e_mul : result = node_allocator_-> + allocate_rr > >(v0, v1); + exprtk_debug(("(-v0 * -v1) --> (v0 * v1)\n")); + break; + + // (-v0 / -v1) --> (v0 / v1) + case details::e_div : result = node_allocator_-> + allocate_rr > >(v0, v1); + exprtk_debug(("(-v0 / -v1) --> (v0 / v1)\n")); + break; + + default : break; + } + } + + if (0 == result) + { + result = node_allocator_-> + allocate_rrrrr >(v0, v1, u0, u1, f); + } + + details::free_all_nodes(*node_allocator_,branch); + return result; + } + + #undef basic_opr_switch_statements + #undef extended_opr_switch_statements + #undef unary_opr_switch_statements + + #ifndef exprtk_disable_string_capabilities + + #define string_opr_switch_statements \ + case_stmt(details::e_lt , details::lt_op ) \ + case_stmt(details::e_lte , details::lte_op ) \ + case_stmt(details::e_gt , details::gt_op ) \ + case_stmt(details::e_gte , details::gte_op ) \ + case_stmt(details::e_eq , details::eq_op ) \ + case_stmt(details::e_ne , details::ne_op ) \ + case_stmt(details::e_in , details::in_op ) \ + case_stmt(details::e_like , details::like_op ) \ + case_stmt(details::e_ilike , details::ilike_op) \ + + template + inline expression_node_ptr synthesize_str_xrox_expression_impl(const details::operator_type& opr, + T0 s0, T1 s1, + range_t rp0) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt >,T0,T1> \ + (s0, s1, rp0); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_str_xoxr_expression_impl(const details::operator_type& opr, + T0 s0, T1 s1, + range_t rp1) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt >,T0,T1> \ + (s0, s1, rp1); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_str_xroxr_expression_impl(const details::operator_type& opr, + T0 s0, T1 s1, + range_t rp0, range_t rp1) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_tttt >,T0,T1> \ + (s0, s1, rp0, rp1); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_sos_expression_impl(const details::operator_type& opr, T0 s0, T1 s1) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_tt >,T0,T1>(s0, s1); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_sos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*>(branch[0])->ref(); + std::string& s1 = static_cast*>(branch[1])->ref(); + + return synthesize_sos_expression_impl(opr, s0, s1); + } + + inline expression_node_ptr synthesize_sros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*>(branch[0])->ref (); + std::string& s1 = static_cast*> (branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + free_node(*node_allocator_,branch[0]); + + return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); + } + + inline expression_node_ptr synthesize_sosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string& s1 = static_cast*>(branch[1])->ref (); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); + } + + inline expression_node_ptr synthesize_socsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); + } + + inline expression_node_ptr synthesize_srosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*>(branch[0])->ref (); + std::string& s1 = static_cast*>(branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); + } + + inline expression_node_ptr synthesize_socs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); + std::string s1 = static_cast*>(branch[1])->str(); + + details::free_node(*node_allocator_,branch[1]); + + return synthesize_sos_expression_impl(opr, s0, s1); + } + + inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str(); + std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); + + details::free_node(*node_allocator_,branch[0]); + + return synthesize_sos_expression_impl(opr, s0, s1); + } + + inline expression_node_ptr synthesize_csosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str (); + std::string& s1 = static_cast*> (branch[1])->ref (); + range_t rp1 = static_cast*> (branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); + } + + inline expression_node_ptr synthesize_srocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp0 = static_cast*> (branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); + } + + inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp0 = static_cast*> (branch[0])->range(); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*> (branch[0])->range_ref().clear(); + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); + } + + inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str(); + const std::string s1 = static_cast*>(branch[1])->str(); + + expression_node_ptr result = error_node(); + + if (details::e_add == opr) + result = node_allocator_->allocate_c >(s0 + s1); + else if (details::e_in == opr) + result = node_allocator_->allocate_c >(details::in_op ::process(s0,s1)); + else if (details::e_like == opr) + result = node_allocator_->allocate_c >(details::like_op ::process(s0,s1)); + else if (details::e_ilike == opr) + result = node_allocator_->allocate_c >(details::ilike_op::process(s0,s1)); + else + { + expression_node_ptr temp = synthesize_sos_expression_impl(opr, s0, s1); + + const Type v = temp->value(); + + details::free_node(*node_allocator_,temp); + + result = node_allocator_->allocate(v); + } + + details::free_all_nodes(*node_allocator_,branch); + + return result; + } + + inline expression_node_ptr synthesize_csocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*> (branch[0])->str (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + free_node(*node_allocator_,branch[0]); + free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); + } + + inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str (); + std::string& s1 = static_cast*> (branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + free_node(*node_allocator_,branch[0]); + + return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); + } + + inline expression_node_ptr synthesize_csrosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str (); + std::string& s1 = static_cast*> (branch[1])->ref (); + const range_t rp0 = static_cast*>(branch[0])->range(); + const range_t rp1 = static_cast*> (branch[1])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + static_cast*> (branch[1])->range_ref().clear(); + + free_node(*node_allocator_,branch[0]); + free_node(*node_allocator_,branch[1]); + + return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); + } + + inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str (); + const std::string s1 = static_cast*> (branch[1])->str (); + const range_t rp0 = static_cast*>(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + details::free_all_nodes(*node_allocator_,branch); + + return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); + } + + inline expression_node_ptr synthesize_csrocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str (); + const std::string s1 = static_cast*>(branch[1])->str (); + const range_t rp0 = static_cast*>(branch[0])->range(); + const range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + static_cast*>(branch[1])->range_ref().clear(); + + details::free_all_nodes(*node_allocator_,branch); + + return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); + } + + inline expression_node_ptr synthesize_strogen_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt > > \ + (opr, branch[0], branch[1]); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + #endif + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + if ((0 == branch[0]) || (0 == branch[1])) + { + details::free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + + const bool b0_is_s = details::is_string_node (branch[0]); + const bool b0_is_cs = details::is_const_string_node (branch[0]); + const bool b0_is_sr = details::is_string_range_node (branch[0]); + const bool b0_is_csr = details::is_const_string_range_node(branch[0]); + + const bool b1_is_s = details::is_string_node (branch[1]); + const bool b1_is_cs = details::is_const_string_node (branch[1]); + const bool b1_is_sr = details::is_string_range_node (branch[1]); + const bool b1_is_csr = details::is_const_string_range_node(branch[1]); + + const bool b0_is_gen = details::is_string_assignment_node (branch[0]) || + details::is_genricstring_range_node(branch[0]) || + details::is_string_concat_node (branch[0]) || + details::is_string_function_node (branch[0]) || + details::is_string_condition_node (branch[0]) || + details::is_string_ccondition_node (branch[0]) || + details::is_string_vararg_node (branch[0]) ; + + const bool b1_is_gen = details::is_string_assignment_node (branch[1]) || + details::is_genricstring_range_node(branch[1]) || + details::is_string_concat_node (branch[1]) || + details::is_string_function_node (branch[1]) || + details::is_string_condition_node (branch[1]) || + details::is_string_ccondition_node (branch[1]) || + details::is_string_vararg_node (branch[1]) ; + + if (details::e_add == opr) + { + if (!b0_is_cs || !b1_is_cs) + { + return synthesize_expression(opr,branch); + } + } + + if (b0_is_gen || b1_is_gen) + { + return synthesize_strogen_expression(opr,branch); + } + else if (b0_is_s) + { + if (b1_is_s ) return synthesize_sos_expression (opr,branch); + else if (b1_is_cs ) return synthesize_socs_expression (opr,branch); + else if (b1_is_sr ) return synthesize_sosr_expression (opr,branch); + else if (b1_is_csr) return synthesize_socsr_expression (opr,branch); + } + else if (b0_is_cs) + { + if (b1_is_s ) return synthesize_csos_expression (opr,branch); + else if (b1_is_cs ) return synthesize_csocs_expression (opr,branch); + else if (b1_is_sr ) return synthesize_csosr_expression (opr,branch); + else if (b1_is_csr) return synthesize_csocsr_expression(opr,branch); + } + else if (b0_is_sr) + { + if (b1_is_s ) return synthesize_sros_expression (opr,branch); + else if (b1_is_sr ) return synthesize_srosr_expression (opr,branch); + else if (b1_is_cs ) return synthesize_srocs_expression (opr,branch); + else if (b1_is_csr) return synthesize_srocsr_expression(opr,branch); + } + else if (b0_is_csr) + { + if (b1_is_s ) return synthesize_csros_expression (opr,branch); + else if (b1_is_sr ) return synthesize_csrosr_expression (opr,branch); + else if (b1_is_cs ) return synthesize_csrocs_expression (opr,branch); + else if (b1_is_csr) return synthesize_csrocsr_expression(opr,branch); + } + + return error_node(); + } + #else + inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[2]) + { + details::free_all_nodes(*node_allocator_,branch); + return error_node(); + } + #endif + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[3]) + { + if (details::e_inrange != opr) + return error_node(); + else if ((0 == branch[0]) || (0 == branch[1]) || (0 == branch[2])) + { + details::free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if ( + details::is_const_string_node(branch[0]) && + details::is_const_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + const std::string s0 = static_cast*>(branch[0])->str(); + const std::string s1 = static_cast*>(branch[1])->str(); + const std::string s2 = static_cast*>(branch[2])->str(); + + const Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); + + details::free_all_nodes(*node_allocator_,branch); + + return node_allocator_->allocate_c >(v); + } + else if ( + details::is_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_string_node(branch[2]) + ) + { + std::string& s0 = static_cast*>(branch[0])->ref(); + std::string& s1 = static_cast*>(branch[1])->ref(); + std::string& s2 = static_cast*>(branch[2])->ref(); + + typedef typename details::sosos_node > inrange_t; + + return node_allocator_->allocate_type(s0, s1, s2); + } + else if ( + details::is_const_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + std::string s0 = static_cast*>(branch[0])->str(); + std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); + std::string s2 = static_cast*>(branch[2])->str(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[2]); + + return node_allocator_->allocate_type(s0, s1, s2); + } + else if ( + details::is_string_node(branch[0]) && + details::is_const_string_node(branch[1]) && + details::is_string_node(branch[2]) + ) + { + std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); + std::string s1 = static_cast*>(branch[1])->str(); + std::string& s2 = static_cast< details::stringvar_node*>(branch[2])->ref(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[1]); + + return node_allocator_->allocate_type(s0, s1, s2); + } + else if ( + details::is_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); + std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); + std::string s2 = static_cast*>(branch[2])->str(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[2]); + + return node_allocator_->allocate_type(s0, s1, s2); + } + else if ( + details::is_const_string_node(branch[0]) && + details:: is_string_node(branch[1]) && + details:: is_string_node(branch[2]) + ) + { + std::string s0 = static_cast*>(branch[0])->str(); + std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); + std::string& s2 = static_cast< details::stringvar_node*>(branch[2])->ref(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[0]); + + return node_allocator_->allocate_type(s0, s1, s2); + } + else + return error_node(); + } + #else + inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[3]) + { + details::free_all_nodes(*node_allocator_,branch); + return error_node(); + } + #endif + + inline expression_node_ptr synthesize_null_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + /* + Note: The following are the type promotion rules + that relate to operations that include 'null': + 0. null ==/!= null --> true false + 1. null operation null --> null + 2. x ==/!= null --> true/false + 3. null ==/!= x --> true/false + 4. x operation null --> x + 5. null operation x --> x + */ + + typedef typename details::null_eq_node nulleq_node_t; + + const bool b0_null = details::is_null_node(branch[0]); + const bool b1_null = details::is_null_node(branch[1]); + + if (b0_null && b1_null) + { + expression_node_ptr result = error_node(); + + if (details::e_eq == operation) + result = node_allocator_->allocate_c(T(1)); + else if (details::e_ne == operation) + result = node_allocator_->allocate_c(T(0)); + + if (result) + { + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return result; + } + + details::free_node(*node_allocator_,branch[1]); + + return branch[0]; + } + else if (details::e_eq == operation) + { + expression_node_ptr result = node_allocator_-> + allocate_rc(branch[b0_null ? 0 : 1],true); + + details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); + + return result; + } + else if (details::e_ne == operation) + { + expression_node_ptr result = node_allocator_-> + allocate_rc(branch[b0_null ? 0 : 1],false); + + details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); + + return result; + } + else if (b0_null) + { + details::free_node(*node_allocator_,branch[0]); + branch[0] = branch[1]; + branch[1] = error_node(); + } + else if (b1_null) + { + details::free_node(*node_allocator_,branch[1]); + branch[1] = error_node(); + } + + if ( + (details::e_add == operation) || (details::e_sub == operation) || + (details::e_mul == operation) || (details::e_div == operation) || + (details::e_mod == operation) || (details::e_pow == operation) + ) + { + return branch[0]; + } + + details::free_node(*node_allocator_, branch[0]); + + if ( + (details::e_lt == operation) || (details::e_lte == operation) || + (details::e_gt == operation) || (details::e_gte == operation) || + (details::e_and == operation) || (details::e_nand == operation) || + (details::e_or == operation) || (details::e_nor == operation) || + (details::e_xor == operation) || (details::e_xnor == operation) || + (details::e_in == operation) || (details::e_like == operation) || + (details::e_ilike == operation) + ) + { + return node_allocator_->allocate_c(T(0)); + } + + return node_allocator_->allocate >(); + } + + template + inline expression_node_ptr synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[N]) + { + if ( + (details::e_in == operation) || + (details::e_like == operation) || + (details::e_ilike == operation) + ) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if (!details::all_nodes_valid(branch)) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if ((details::e_default != operation)) + { + // Attempt simple constant folding optimisation. + expression_node_ptr expression_point = node_allocator_->allocate(operation,branch); + + if (is_constant_foldable(branch)) + { + const Type v = expression_point->value(); + details::free_node(*node_allocator_,expression_point); + + return node_allocator_->allocate(v); + } + else + return expression_point; + } + else + return error_node(); + } + + template + inline expression_node_ptr synthesize_expression(F* f, expression_node_ptr (&branch)[N]) + { + if (!details::all_nodes_valid(branch)) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + + typedef typename details::function_N_node function_N_node_t; + + // Attempt simple constant folding optimisation. + + expression_node_ptr expression_point = node_allocator_->allocate(f); + function_N_node_t* func_node_ptr = dynamic_cast(expression_point); + + if (0 == func_node_ptr) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else + func_node_ptr->init_branches(branch); + + if (is_constant_foldable(branch) && !f->has_side_effects()) + { + Type v = expression_point->value(); + details::free_node(*node_allocator_,expression_point); + + return node_allocator_->allocate(v); + } + + parser_->state_.activate_side_effect("synthesize_expression(function)"); + + return expression_point; + } + + bool strength_reduction_enabled_; + details::node_allocator* node_allocator_; + synthesize_map_t synthesize_map_; + unary_op_map_t* unary_op_map_; + binary_op_map_t* binary_op_map_; + inv_binary_op_map_t* inv_binary_op_map_; + sf3_map_t* sf3_map_; + sf4_map_t* sf4_map_; + parser_t* parser_; + }; + + inline void set_error(const parser_error::type& error_type) + { + error_list_.push_back(error_type); + } + + inline void remove_last_error() + { + if (!error_list_.empty()) + { + error_list_.pop_back(); + } + } + + inline void set_synthesis_error(const std::string& synthesis_error_message) + { + if (synthesis_error_.empty()) + { + synthesis_error_ = synthesis_error_message; + } + } + + inline void register_local_vars(expression& e) + { + for (std::size_t i = 0; i < sem_.size(); ++i) + { + scope_element& se = sem_.get_element(i); + + if ( + (scope_element::e_variable == se.type) || + (scope_element::e_vecelem == se.type) + ) + { + if (se.var_node) + { + e.register_local_var(se.var_node); + } + + if (se.data) + { + e.register_local_data(se.data, 1, 0); + } + } + else if (scope_element::e_vector == se.type) + { + if (se.vec_node) + { + e.register_local_var(se.vec_node); + } + + if (se.data) + { + e.register_local_data(se.data, se.size, 1); + } + } + #ifndef exprtk_disable_string_capabilities + else if (scope_element::e_string == se.type) + { + if (se.str_node) + { + e.register_local_var(se.str_node); + } + + if (se.data) + { + e.register_local_data(se.data, se.size, 2); + } + } + #endif + + se.var_node = 0; + se.vec_node = 0; + #ifndef exprtk_disable_string_capabilities + se.str_node = 0; + #endif + se.data = 0; + se.ref_count = 0; + se.active = false; + } + } + + inline void register_return_results(expression& e) + { + e.register_return_results(results_context_); + results_context_ = 0; + } + + inline void load_unary_operations_map(unary_op_map_t& m) + { + #define register_unary_op(Op,UnaryFunctor) \ + m.insert(std::make_pair(Op,UnaryFunctor::process)); \ + + register_unary_op(details::e_abs , details::abs_op ) + register_unary_op(details::e_acos , details::acos_op ) + register_unary_op(details::e_acosh , details::acosh_op) + register_unary_op(details::e_asin , details::asin_op ) + register_unary_op(details::e_asinh , details::asinh_op) + register_unary_op(details::e_atanh , details::atanh_op) + register_unary_op(details::e_ceil , details::ceil_op ) + register_unary_op(details::e_cos , details::cos_op ) + register_unary_op(details::e_cosh , details::cosh_op ) + register_unary_op(details::e_exp , details::exp_op ) + register_unary_op(details::e_expm1 , details::expm1_op) + register_unary_op(details::e_floor , details::floor_op) + register_unary_op(details::e_log , details::log_op ) + register_unary_op(details::e_log10 , details::log10_op) + register_unary_op(details::e_log2 , details::log2_op ) + register_unary_op(details::e_log1p , details::log1p_op) + register_unary_op(details::e_neg , details::neg_op ) + register_unary_op(details::e_pos , details::pos_op ) + register_unary_op(details::e_round , details::round_op) + register_unary_op(details::e_sin , details::sin_op ) + register_unary_op(details::e_sinc , details::sinc_op ) + register_unary_op(details::e_sinh , details::sinh_op ) + register_unary_op(details::e_sqrt , details::sqrt_op ) + register_unary_op(details::e_tan , details::tan_op ) + register_unary_op(details::e_tanh , details::tanh_op ) + register_unary_op(details::e_cot , details::cot_op ) + register_unary_op(details::e_sec , details::sec_op ) + register_unary_op(details::e_csc , details::csc_op ) + register_unary_op(details::e_r2d , details::r2d_op ) + register_unary_op(details::e_d2r , details::d2r_op ) + register_unary_op(details::e_d2g , details::d2g_op ) + register_unary_op(details::e_g2d , details::g2d_op ) + register_unary_op(details::e_notl , details::notl_op ) + register_unary_op(details::e_sgn , details::sgn_op ) + register_unary_op(details::e_erf , details::erf_op ) + register_unary_op(details::e_erfc , details::erfc_op ) + register_unary_op(details::e_ncdf , details::ncdf_op ) + register_unary_op(details::e_frac , details::frac_op ) + register_unary_op(details::e_trunc , details::trunc_op) + #undef register_unary_op + } + + inline void load_binary_operations_map(binary_op_map_t& m) + { + typedef typename binary_op_map_t::value_type value_type; + + #define register_binary_op(Op,BinaryFunctor) \ + m.insert(value_type(Op,BinaryFunctor::process)); \ + + register_binary_op(details::e_add , details::add_op ) + register_binary_op(details::e_sub , details::sub_op ) + register_binary_op(details::e_mul , details::mul_op ) + register_binary_op(details::e_div , details::div_op ) + register_binary_op(details::e_mod , details::mod_op ) + register_binary_op(details::e_pow , details::pow_op ) + register_binary_op(details::e_lt , details::lt_op ) + register_binary_op(details::e_lte , details::lte_op ) + register_binary_op(details::e_gt , details::gt_op ) + register_binary_op(details::e_gte , details::gte_op ) + register_binary_op(details::e_eq , details::eq_op ) + register_binary_op(details::e_ne , details::ne_op ) + register_binary_op(details::e_and , details::and_op ) + register_binary_op(details::e_nand , details::nand_op) + register_binary_op(details::e_or , details::or_op ) + register_binary_op(details::e_nor , details::nor_op ) + register_binary_op(details::e_xor , details::xor_op ) + register_binary_op(details::e_xnor , details::xnor_op) + #undef register_binary_op + } + + inline void load_inv_binary_operations_map(inv_binary_op_map_t& m) + { + typedef typename inv_binary_op_map_t::value_type value_type; + + #define register_binary_op(Op,BinaryFunctor) \ + m.insert(value_type(BinaryFunctor::process,Op)); \ + + register_binary_op(details::e_add , details::add_op ) + register_binary_op(details::e_sub , details::sub_op ) + register_binary_op(details::e_mul , details::mul_op ) + register_binary_op(details::e_div , details::div_op ) + register_binary_op(details::e_mod , details::mod_op ) + register_binary_op(details::e_pow , details::pow_op ) + register_binary_op(details::e_lt , details::lt_op ) + register_binary_op(details::e_lte , details::lte_op ) + register_binary_op(details::e_gt , details::gt_op ) + register_binary_op(details::e_gte , details::gte_op ) + register_binary_op(details::e_eq , details::eq_op ) + register_binary_op(details::e_ne , details::ne_op ) + register_binary_op(details::e_and , details::and_op ) + register_binary_op(details::e_nand , details::nand_op) + register_binary_op(details::e_or , details::or_op ) + register_binary_op(details::e_nor , details::nor_op ) + register_binary_op(details::e_xor , details::xor_op ) + register_binary_op(details::e_xnor , details::xnor_op) + #undef register_binary_op + } + + inline void load_sf3_map(sf3_map_t& sf3_map) + { + typedef std::pair pair_t; + + #define register_sf3(Op) \ + sf3_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + + register_sf3(00) register_sf3(01) register_sf3(02) register_sf3(03) + register_sf3(04) register_sf3(05) register_sf3(06) register_sf3(07) + register_sf3(08) register_sf3(09) register_sf3(10) register_sf3(11) + register_sf3(12) register_sf3(13) register_sf3(14) register_sf3(15) + register_sf3(16) register_sf3(17) register_sf3(18) register_sf3(19) + register_sf3(20) register_sf3(21) register_sf3(22) register_sf3(23) + register_sf3(24) register_sf3(25) register_sf3(26) register_sf3(27) + register_sf3(28) register_sf3(29) register_sf3(30) + #undef register_sf3 + + #define register_sf3_extid(Id, Op) \ + sf3_map[Id] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + + register_sf3_extid("(t-t)-t",23) // (t-t)-t --> t-(t+t) + #undef register_sf3_extid + } + + inline void load_sf4_map(sf4_map_t& sf4_map) + { + typedef std::pair pair_t; + + #define register_sf4(Op) \ + sf4_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + + register_sf4(48) register_sf4(49) register_sf4(50) register_sf4(51) + register_sf4(52) register_sf4(53) register_sf4(54) register_sf4(55) + register_sf4(56) register_sf4(57) register_sf4(58) register_sf4(59) + register_sf4(60) register_sf4(61) register_sf4(62) register_sf4(63) + register_sf4(64) register_sf4(65) register_sf4(66) register_sf4(67) + register_sf4(68) register_sf4(69) register_sf4(70) register_sf4(71) + register_sf4(72) register_sf4(73) register_sf4(74) register_sf4(75) + register_sf4(76) register_sf4(77) register_sf4(78) register_sf4(79) + register_sf4(80) register_sf4(81) register_sf4(82) register_sf4(83) + #undef register_sf4 + + #define register_sf4ext(Op) \ + sf4_map[details::sfext##Op##_op::id()] = pair_t(details::sfext##Op##_op::process,details::e_sf4ext##Op); \ + + register_sf4ext(00) register_sf4ext(01) register_sf4ext(02) register_sf4ext(03) + register_sf4ext(04) register_sf4ext(05) register_sf4ext(06) register_sf4ext(07) + register_sf4ext(08) register_sf4ext(09) register_sf4ext(10) register_sf4ext(11) + register_sf4ext(12) register_sf4ext(13) register_sf4ext(14) register_sf4ext(15) + register_sf4ext(16) register_sf4ext(17) register_sf4ext(18) register_sf4ext(19) + register_sf4ext(20) register_sf4ext(21) register_sf4ext(22) register_sf4ext(23) + register_sf4ext(24) register_sf4ext(25) register_sf4ext(26) register_sf4ext(27) + register_sf4ext(28) register_sf4ext(29) register_sf4ext(30) register_sf4ext(31) + register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35) + register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39) + register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43) + register_sf4ext(44) register_sf4ext(45) register_sf4ext(46) register_sf4ext(47) + register_sf4ext(48) register_sf4ext(49) register_sf4ext(50) register_sf4ext(51) + register_sf4ext(52) register_sf4ext(53) register_sf4ext(54) register_sf4ext(55) + register_sf4ext(56) register_sf4ext(57) register_sf4ext(58) register_sf4ext(59) + register_sf4ext(60) register_sf4ext(61) + #undef register_sf4ext + } + + inline results_context_t& results_ctx() + { + if (0 == results_context_) + { + results_context_ = new results_context_t(); + } + + return (*results_context_); + } + + inline void return_cleanup() + { + #ifndef exprtk_disable_return_statement + if (results_context_) + { + delete results_context_; + results_context_ = 0; + } + + state_.return_stmt_present = false; + #endif + } + + private: + + parser(const parser&); + parser& operator=(const parser&); + + settings_store settings_; + expression_generator expression_generator_; + details::node_allocator node_allocator_; + symtab_store symtab_store_; + dependent_entity_collector dec_; + std::deque error_list_; + std::deque brkcnt_list_; + parser_state state_; + bool resolve_unknown_symbol_; + results_context_t* results_context_; + unknown_symbol_resolver* unknown_symbol_resolver_; + unknown_symbol_resolver default_usr_; + base_ops_map_t base_ops_map_; + unary_op_map_t unary_op_map_; + binary_op_map_t binary_op_map_; + inv_binary_op_map_t inv_binary_op_map_; + sf3_map_t sf3_map_; + sf4_map_t sf4_map_; + std::string synthesis_error_; + scope_element_manager sem_; + + lexer::helper::helper_assembly helper_assembly_; + + lexer::helper::commutative_inserter commutative_inserter_; + lexer::helper::operator_joiner operator_joiner_2_; + lexer::helper::operator_joiner operator_joiner_3_; + lexer::helper::symbol_replacer symbol_replacer_; + lexer::helper::bracket_checker bracket_checker_; + lexer::helper::numeric_checker numeric_checker_; + lexer::helper::sequence_validator sequence_validator_; + lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_; + + loop_runtime_check_ptr loop_runtime_check_; + + template + friend void details::disable_type_checking(ParserType& p); + }; + + namespace details + { + template + struct collector_helper + { + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; + typedef typename parser_t::unknown_symbol_resolver usr_t; + + struct resolve_as_vector : public parser_t::unknown_symbol_resolver + { + typedef exprtk::parser parser_t; + + resolve_as_vector() + : usr_t(usr_t::e_usrmode_extended) + {} + + virtual bool process(const std::string& unknown_symbol, + symbol_table_t& symbol_table, + std::string&) + { + static T v[1]; + symbol_table.add_vector(unknown_symbol,v); + return true; + } + }; + + static inline bool collection_pass(const std::string& expression_string, + std::set& symbol_set, + const bool collect_variables, + const bool collect_functions, + const bool vector_pass, + symbol_table_t& ext_symbol_table) + { + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + resolve_as_vector vect_resolver; + + expression.register_symbol_table(symbol_table ); + expression.register_symbol_table(ext_symbol_table); + + if (vector_pass) + parser.enable_unknown_symbol_resolver(&vect_resolver); + else + parser.enable_unknown_symbol_resolver(); + + if (collect_variables) + parser.dec().collect_variables() = true; + + if (collect_functions) + parser.dec().collect_functions() = true; + + bool pass_result = false; + + details::disable_type_checking(parser); + + if (parser.compile(expression_string, expression)) + { + pass_result = true; + + std::deque symb_list; + parser.dec().symbols(symb_list); + + for (std::size_t i = 0; i < symb_list.size(); ++i) + { + symbol_set.insert(symb_list[i].first); + } + } + + return pass_result; + } + }; + } + + template class Sequence> + inline bool collect_variables(const std::string& expression, + Sequence& symbol_list) + { + typedef double T; + typedef details::collector_helper collect_t; + + collect_t::symbol_table_t null_symbol_table; + + std::set symbol_set; + + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, true, false, false, null_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, true, false, true, null_symbol_table); + + if (!variable_pass && !vector_pass) + return false; + + std::set::iterator itr = symbol_set.begin(); + + while (symbol_set.end() != itr) + { + symbol_list.push_back(*itr); + ++itr; + } + + return true; + } + + template class Sequence> + inline bool collect_variables(const std::string& expression, + exprtk::symbol_table& extrnl_symbol_table, + Sequence& symbol_list) + { + typedef details::collector_helper collect_t; + + std::set symbol_set; + + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, true, false, false, extrnl_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, true, false, true, extrnl_symbol_table); + + if (!variable_pass && !vector_pass) + return false; + + std::set::iterator itr = symbol_set.begin(); + + while (symbol_set.end() != itr) + { + symbol_list.push_back(*itr); + ++itr; + } + + return true; + } + + template class Sequence> + inline bool collect_functions(const std::string& expression, + Sequence& symbol_list) + { + typedef double T; + typedef details::collector_helper collect_t; + + collect_t::symbol_table_t null_symbol_table; + + std::set symbol_set; + + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, false, true, false, null_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, false, true, true, null_symbol_table); + + if (!variable_pass && !vector_pass) + return false; + + std::set::iterator itr = symbol_set.begin(); + + while (symbol_set.end() != itr) + { + symbol_list.push_back(*itr); + ++itr; + } + + return true; + } + + template class Sequence> + inline bool collect_functions(const std::string& expression, + exprtk::symbol_table& extrnl_symbol_table, + Sequence& symbol_list) + { + typedef details::collector_helper collect_t; + + std::set symbol_set; + + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, false, true, false, extrnl_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, false, true, true, extrnl_symbol_table); + + if (!variable_pass && !vector_pass) + return false; + + std::set::iterator itr = symbol_set.begin(); + + while (symbol_set.end() != itr) + { + symbol_list.push_back(*itr); + ++itr; + } + + return true; + } + + template + inline T integrate(const expression& e, + T& x, + const T& r0, const T& r1, + const std::size_t number_of_intervals = 1000000) + { + if (r0 > r1) + return T(0); + + const T h = (r1 - r0) / (T(2) * number_of_intervals); + T total_area = T(0); + + for (std::size_t i = 0; i < number_of_intervals; ++i) + { + x = r0 + T(2) * i * h; + const T y0 = e.value(); x += h; + const T y1 = e.value(); x += h; + const T y2 = e.value(); x += h; + total_area += h * (y0 + T(4) * y1 + y2) / T(3); + } + + return total_area; + } + + template + inline T integrate(const expression& e, + const std::string& variable_name, + const T& r0, const T& r1, + const std::size_t number_of_intervals = 1000000) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + return std::numeric_limits::quiet_NaN(); + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + const T x_original = x; + const T result = integrate(e, x, r0, r1, number_of_intervals); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T derivative(const expression& e, + T& x, + const T& h = T(0.00000001)) + { + const T x_init = x; + const T _2h = T(2) * h; + + x = x_init + _2h; + const T y0 = e.value(); + x = x_init + h; + const T y1 = e.value(); + x = x_init - h; + const T y2 = e.value(); + x = x_init - _2h; + const T y3 = e.value(); + x = x_init; + + return (-y0 + T(8) * (y1 - y2) + y3) / (T(12) * h); + } + + template + inline T second_derivative(const expression& e, + T& x, + const T& h = T(0.00001)) + { + const T x_init = x; + const T _2h = T(2) * h; + + const T y = e.value(); + x = x_init + _2h; + const T y0 = e.value(); + x = x_init + h; + const T y1 = e.value(); + x = x_init - h; + const T y2 = e.value(); + x = x_init - _2h; + const T y3 = e.value(); + x = x_init; + + return (-y0 + T(16) * (y1 + y2) - T(30) * y - y3) / (T(12) * h * h); + } + + template + inline T third_derivative(const expression& e, + T& x, + const T& h = T(0.0001)) + { + const T x_init = x; + const T _2h = T(2) * h; + + x = x_init + _2h; + const T y0 = e.value(); + x = x_init + h; + const T y1 = e.value(); + x = x_init - h; + const T y2 = e.value(); + x = x_init - _2h; + const T y3 = e.value(); + x = x_init; + + return (y0 + T(2) * (y2 - y1) - y3) / (T(2) * h * h * h); + } + + template + inline T derivative(const expression& e, + const std::string& variable_name, + const T& h = T(0.00000001)) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + { + return std::numeric_limits::quiet_NaN(); + } + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + const T x_original = x; + const T result = derivative(e, x, h); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T second_derivative(const expression& e, + const std::string& variable_name, + const T& h = T(0.00001)) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + { + return std::numeric_limits::quiet_NaN(); + } + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + const T x_original = x; + const T result = second_derivative(e, x, h); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T third_derivative(const expression& e, + const std::string& variable_name, + const T& h = T(0.0001)) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + { + return std::numeric_limits::quiet_NaN(); + } + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + const T x_original = x; + const T result = third_derivative(e, x, h); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + /* + Note: The following 'compute' routines are simple helpers, + for quickly setting up the required pieces of code in order + to evaluate an expression. By virtue of how they operate + there will be an overhead with regards to their setup and + teardown and hence should not be used in time critical + sections of code. + Furthermore they only assume a small sub set of variables, + no string variables or user defined functions. + */ + template + inline bool compute(const std::string& expression_string, T& result) + { + // No variables + symbol_table symbol_table; + symbol_table.add_constants(); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + inline bool compute(const std::string& expression_string, + const T& x, + T& result) + { + // Only 'x' + static const std::string x_var("x"); + + symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_constant(x_var,x); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + inline bool compute(const std::string& expression_string, + const T&x, const T& y, + T& result) + { + // Only 'x' and 'y' + static const std::string x_var("x"); + static const std::string y_var("y"); + + symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_constant(x_var,x); + symbol_table.add_constant(y_var,y); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + inline bool compute(const std::string& expression_string, + const T& x, const T& y, const T& z, + T& result) + { + // Only 'x', 'y' or 'z' + static const std::string x_var("x"); + static const std::string y_var("y"); + static const std::string z_var("z"); + + symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_constant(x_var,x); + symbol_table.add_constant(y_var,y); + symbol_table.add_constant(z_var,z); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + class polynomial : public ifunction + { + private: + + template + struct poly_impl { }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c12, const Type c11, const Type c10, const Type c9, const Type c8, + const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, + const Type c2, const Type c1, const Type c0) + { + // p(x) = c_12x^12 + c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((((((((c12 * x + c11) * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c11, const Type c10, const Type c9, const Type c8, const Type c7, + const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, + const Type c1, const Type c0) + { + // p(x) = c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((((((((c11 * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c10, const Type c9, const Type c8, const Type c7, const Type c6, + const Type c5, const Type c4, const Type c3, const Type c2, const Type c1, + const Type c0) + { + // p(x) = c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((((((c10 * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c9, const Type c8, const Type c7, const Type c6, const Type c5, + const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((((((c9 * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c8, const Type c7, const Type c6, const Type c5, const Type c4, + const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((((c8 * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, + const Type c2, const Type c1, const Type c0) + { + // p(x) = c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((((c7 * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, + const Type c1, const Type c0) + { + // p(x) = c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((c6 * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c5, const Type c4, const Type c3, const Type c2, + const Type c1, const Type c0) + { + // p(x) = c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((c5 * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((c4 * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((c3 * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_2x^2 + c_1x^1 + c_0x^0 + return ((c2 * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c1, const Type c0) + { + // p(x) = c_1x^1 + c_0x^0 + return (c1 * x + c0); + } + }; + + public: + + using ifunction::operator(); + + polynomial() + : ifunction((N+2 <= 20) ? (N + 2) : std::numeric_limits::max()) + { + disable_has_side_effects(*this); + } + + virtual ~polynomial() + {} + + #define poly_rtrn(NN) \ + return (NN != N) ? std::numeric_limits::quiet_NaN() : + + inline virtual T operator() (const T& x, const T& c1, const T& c0) + { + poly_rtrn(1) (poly_impl::evaluate(x, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(2) (poly_impl::evaluate(x, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(3) (poly_impl::evaluate(x, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(4) (poly_impl::evaluate(x, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(5) (poly_impl::evaluate(x, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(6) (poly_impl::evaluate(x, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(7) (poly_impl::evaluate(x, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(8) (poly_impl::evaluate(x, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(9) (poly_impl::evaluate(x, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(10) (poly_impl::evaluate(x, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(11) (poly_impl::evaluate(x, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + inline virtual T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(12) (poly_impl::evaluate(x, c12, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); + } + + #undef poly_rtrn + + inline virtual T operator() () + { + return std::numeric_limits::quiet_NaN(); + } + + inline virtual T operator() (const T&) + { + return std::numeric_limits::quiet_NaN(); + } + + inline virtual T operator() (const T&, const T&) + { + return std::numeric_limits::quiet_NaN(); + } + }; + + template + class function_compositor + { + public: + + typedef exprtk::expression expression_t; + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::parser parser_t; + typedef typename parser_t::settings_store settings_t; + + struct function + { + function() + {} + + function(const std::string& n) + : name_(n) + {} + + function(const std::string& name, + const std::string& expression) + : name_(name), + expression_(expression) + {} + + function(const std::string& name, + const std::string& expression, + const std::string& v0) + : name_(name), + expression_(expression) + { + v_.push_back(v0); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1) + : name_(name), + expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2) + : name_(name), + expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2, const std::string& v3) + : name_(name), + expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); v_.push_back(v3); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2, const std::string& v3, + const std::string& v4) + : name_(name), + expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); v_.push_back(v3); + v_.push_back(v4); + } + + inline function& name(const std::string& n) + { + name_ = n; + return (*this); + } + + inline function& expression(const std::string& e) + { + expression_ = e; + return (*this); + } + + inline function& var(const std::string& v) + { + v_.push_back(v); + return (*this); + } + + std::string name_; + std::string expression_; + std::deque v_; + }; + + private: + + struct base_func : public exprtk::ifunction + { + typedef const T& type; + typedef exprtk::ifunction function_t; + typedef std::vector varref_t; + typedef std::vector var_t; + typedef std::pair lvarref_t; + typedef std::vector lvr_vec_t; + + using exprtk::ifunction::operator(); + + base_func(const std::size_t& pc = 0) + : exprtk::ifunction(pc), + local_var_stack_size(0), + stack_depth(0) + { + v.resize(pc); + } + + virtual ~base_func() + {} + + inline void update(const T& v0) + { + (*v[0]) = v0; + } + + inline void update(const T& v0, const T& v1) + { + (*v[0]) = v0; (*v[1]) = v1; + } + + inline void update(const T& v0, const T& v1, const T& v2) + { + (*v[0]) = v0; (*v[1]) = v1; + (*v[2]) = v2; + } + + inline void update(const T& v0, const T& v1, const T& v2, const T& v3) + { + (*v[0]) = v0; (*v[1]) = v1; + (*v[2]) = v2; (*v[3]) = v3; + } + + inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) + { + (*v[0]) = v0; (*v[1]) = v1; + (*v[2]) = v2; (*v[3]) = v3; + (*v[4]) = v4; + } + + inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + { + (*v[0]) = v0; (*v[1]) = v1; + (*v[2]) = v2; (*v[3]) = v3; + (*v[4]) = v4; (*v[5]) = v5; + } + + inline function_t& setup(expression_t& expr) + { + expression = expr; + + typedef typename expression_t::control_block::local_data_list_t ldl_t; + + const ldl_t ldl = expr.local_data_list(); + + std::vector index_list; + + for (std::size_t i = 0; i < ldl.size(); ++i) + { + if (ldl[i].size) + { + index_list.push_back(i); + } + } + + std::size_t input_param_count = 0; + + for (std::size_t i = 0; i < index_list.size(); ++i) + { + const std::size_t index = index_list[i]; + + if (i < (index_list.size() - v.size())) + { + lv.push_back( + std::make_pair( + reinterpret_cast(ldl[index].pointer), + ldl[index].size)); + + local_var_stack_size += ldl[index].size; + } + else + v[input_param_count++] = reinterpret_cast(ldl[index].pointer); + } + + clear_stack(); + + return (*this); + } + + inline void pre() + { + if (stack_depth++) + { + if (!v.empty()) + { + var_t var_stack(v.size(),T(0)); + copy(v,var_stack); + param_stack.push_back(var_stack); + } + + if (!lv.empty()) + { + var_t local_var_stack(local_var_stack_size,T(0)); + copy(lv,local_var_stack); + local_stack.push_back(local_var_stack); + } + } + } + + inline void post() + { + if (--stack_depth) + { + if (!v.empty()) + { + copy(param_stack.back(),v); + param_stack.pop_back(); + } + + if (!lv.empty()) + { + copy(local_stack.back(),lv); + local_stack.pop_back(); + } + } + } + + void copy(const varref_t& src_v, var_t& dest_v) + { + for (std::size_t i = 0; i < src_v.size(); ++i) + { + dest_v[i] = (*src_v[i]); + } + } + + void copy(const var_t& src_v, varref_t& dest_v) + { + for (std::size_t i = 0; i < src_v.size(); ++i) + { + (*dest_v[i]) = src_v[i]; + } + } + + void copy(const lvr_vec_t& src_v, var_t& dest_v) + { + typename var_t::iterator itr = dest_v.begin(); + typedef typename std::iterator_traits::difference_type diff_t; + + for (std::size_t i = 0; i < src_v.size(); ++i) + { + lvarref_t vr = src_v[i]; + + if (1 == vr.second) + *itr++ = (*vr.first); + else + { + std::copy(vr.first, vr.first + vr.second, itr); + itr += static_cast(vr.second); + } + } + } + + void copy(const var_t& src_v, lvr_vec_t& dest_v) + { + typename var_t::const_iterator itr = src_v.begin(); + typedef typename std::iterator_traits::difference_type diff_t; + + for (std::size_t i = 0; i < src_v.size(); ++i) + { + lvarref_t vr = dest_v[i]; + + if (1 == vr.second) + (*vr.first) = *itr++; + else + { + std::copy(itr, itr + static_cast(vr.second), vr.first); + itr += static_cast(vr.second); + } + } + } + + inline void clear_stack() + { + for (std::size_t i = 0; i < v.size(); ++i) + { + (*v[i]) = 0; + } + } + + inline virtual T value(expression_t& e) + { + return e.value(); + } + + expression_t expression; + varref_t v; + lvr_vec_t lv; + std::size_t local_var_stack_size; + std::size_t stack_depth; + std::deque param_stack; + std::deque local_stack; + }; + + typedef std::map funcparam_t; + + struct func_0param : public base_func + { + using exprtk::ifunction::operator(); + + func_0param() : base_func(0) {} + + inline T operator() () + { + return this->value(base_func::expression); + } + }; + + typedef const T& type; + + template + struct scoped_bft + { + explicit scoped_bft(BaseFuncType& bft) + : bft_(bft) + { + bft_.pre (); + } + + ~scoped_bft() + { + bft_.post(); + } + + BaseFuncType& bft_; + + private: + + scoped_bft(scoped_bft&); + scoped_bft& operator=(scoped_bft&); + }; + + struct func_1param : public base_func + { + using exprtk::ifunction::operator(); + + func_1param() : base_func(1) {} + + inline T operator() (type v0) + { + scoped_bft sb(*this); + base_func::update(v0); + return this->value(base_func::expression); + } + }; + + struct func_2param : public base_func + { + using exprtk::ifunction::operator(); + + func_2param() : base_func(2) {} + + inline T operator() (type v0, type v1) + { + scoped_bft sb(*this); + base_func::update(v0, v1); + return this->value(base_func::expression); + } + }; + + struct func_3param : public base_func + { + using exprtk::ifunction::operator(); + + func_3param() : base_func(3) {} + + inline T operator() (type v0, type v1, type v2) + { + scoped_bft sb(*this); + base_func::update(v0, v1, v2); + return this->value(base_func::expression); + } + }; + + struct func_4param : public base_func + { + using exprtk::ifunction::operator(); + + func_4param() : base_func(4) {} + + inline T operator() (type v0, type v1, type v2, type v3) + { + scoped_bft sb(*this); + base_func::update(v0, v1, v2, v3); + return this->value(base_func::expression); + } + }; + + struct func_5param : public base_func + { + using exprtk::ifunction::operator(); + + func_5param() : base_func(5) {} + + inline T operator() (type v0, type v1, type v2, type v3, type v4) + { + scoped_bft sb(*this); + base_func::update(v0, v1, v2, v3, v4); + return this->value(base_func::expression); + } + }; + + struct func_6param : public base_func + { + using exprtk::ifunction::operator(); + + func_6param() : base_func(6) {} + + inline T operator() (type v0, type v1, type v2, type v3, type v4, type v5) + { + scoped_bft sb(*this); + base_func::update(v0, v1, v2, v3, v4, v5); + return this->value(base_func::expression); + } + }; + + static T return_value(expression_t& e) + { + typedef exprtk::results_context results_context_t; + typedef typename results_context_t::type_store_t type_t; + typedef typename type_t::scalar_view scalar_t; + + const T result = e.value(); + + if (e.return_invoked()) + { + // Due to the post compilation checks, it can be safely + // assumed that there will be at least one parameter + // and that the first parameter will always be scalar. + return scalar_t(e.results()[0])(); + } + + return result; + } + + #define def_fp_retval(N) \ + struct func_##N##param_retval : public func_##N##param \ + { \ + inline T value(expression_t& e) \ + { \ + return return_value(e); \ + } \ + }; \ + + def_fp_retval(0) + def_fp_retval(1) + def_fp_retval(2) + def_fp_retval(3) + def_fp_retval(4) + def_fp_retval(5) + def_fp_retval(6) + + template class Sequence> + inline bool add(const std::string& name, + const std::string& expression, + const Sequence& var_list, + const bool override = false) + { + const typename std::map::iterator itr = expr_map_.find(name); + + if (expr_map_.end() != itr) + { + if (!override) + { + exprtk_debug(("Compositor error(add): function '%s' already defined\n", + name.c_str())); + + return false; + } + + remove(name, var_list.size()); + } + + if (compile_expression(name,expression,var_list)) + { + const std::size_t n = var_list.size(); + + fp_map_[n][name]->setup(expr_map_[name]); + + return true; + } + else + { + exprtk_debug(("Compositor error(add): Failed to compile function '%s'\n", + name.c_str())); + + return false; + } + } + + public: + + function_compositor() + : parser_(settings_t::compile_all_opts + + settings_t::e_disable_zero_return), + fp_map_(7) + {} + + function_compositor(const symbol_table_t& st) + : symbol_table_(st), + parser_(settings_t::compile_all_opts + + settings_t::e_disable_zero_return), + fp_map_(7) + {} + + ~function_compositor() + { + clear(); + } + + inline symbol_table_t& symbol_table() + { + return symbol_table_; + } + + inline const symbol_table_t& symbol_table() const + { + return symbol_table_; + } + + inline void add_auxiliary_symtab(symbol_table_t& symtab) + { + auxiliary_symtab_list_.push_back(&symtab); + } + + void clear() + { + symbol_table_.clear(); + expr_map_ .clear(); + + for (std::size_t i = 0; i < fp_map_.size(); ++i) + { + typename funcparam_t::iterator itr = fp_map_[i].begin(); + typename funcparam_t::iterator end = fp_map_[i].end (); + + while (itr != end) + { + delete itr->second; + ++itr; + } + + fp_map_[i].clear(); + } + } + + inline bool add(const function& f, const bool override = false) + { + return add(f.name_, f.expression_, f.v_,override); + } + + private: + + template class Sequence> + bool compile_expression(const std::string& name, + const std::string& expression, + const Sequence& input_var_list, + bool return_present = false) + { + expression_t compiled_expression; + symbol_table_t local_symbol_table; + + local_symbol_table.load_from(symbol_table_); + local_symbol_table.add_constants(); + + if (!valid(name,input_var_list.size())) + return false; + + if (!forward(name, + input_var_list.size(), + local_symbol_table, + return_present)) + return false; + + compiled_expression.register_symbol_table(local_symbol_table); + + for (std::size_t i = 0; i < auxiliary_symtab_list_.size(); ++i) + { + compiled_expression.register_symbol_table((*auxiliary_symtab_list_[i])); + } + + std::string mod_expression; + + for (std::size_t i = 0; i < input_var_list.size(); ++i) + { + mod_expression += " var " + input_var_list[i] + "{};\n"; + } + + if ( + ('{' == details::front(expression)) && + ('}' == details::back (expression)) + ) + mod_expression += "~" + expression + ";"; + else + mod_expression += "~{" + expression + "};"; + + if (!parser_.compile(mod_expression,compiled_expression)) + { + exprtk_debug(("Compositor Error: %s\n",parser_.error().c_str())); + exprtk_debug(("Compositor modified expression: \n%s\n",mod_expression.c_str())); + + remove(name,input_var_list.size()); + + return false; + } + + if (!return_present && parser_.dec().return_present()) + { + remove(name,input_var_list.size()); + + return compile_expression(name, expression, input_var_list, true); + } + + // Make sure every return point has a scalar as its first parameter + if (parser_.dec().return_present()) + { + typedef std::vector str_list_t; + + str_list_t ret_param_list = parser_.dec().return_param_type_list(); + + for (std::size_t i = 0; i < ret_param_list.size(); ++i) + { + const std::string& params = ret_param_list[i]; + + if (params.empty() || ('T' != params[0])) + { + exprtk_debug(("Compositor Error: Return statement in function '%s' is invalid\n", + name.c_str())); + + remove(name,input_var_list.size()); + + return false; + } + } + } + + expr_map_[name] = compiled_expression; + + exprtk::ifunction& ifunc = (*(fp_map_[input_var_list.size()])[name]); + + if (symbol_table_.add_function(name,ifunc)) + return true; + else + { + exprtk_debug(("Compositor Error: Failed to add function '%s' to symbol table\n", + name.c_str())); + return false; + } + } + + inline bool symbol_used(const std::string& symbol) const + { + return ( + symbol_table_.is_variable (symbol) || + symbol_table_.is_stringvar (symbol) || + symbol_table_.is_function (symbol) || + symbol_table_.is_vector (symbol) || + symbol_table_.is_vararg_function(symbol) + ); + } + + inline bool valid(const std::string& name, + const std::size_t& arg_count) const + { + if (arg_count > 6) + return false; + else if (symbol_used(name)) + return false; + else if (fp_map_[arg_count].end() != fp_map_[arg_count].find(name)) + return false; + else + return true; + } + + inline bool forward(const std::string& name, + const std::size_t& arg_count, + symbol_table_t& sym_table, + const bool ret_present = false) + { + switch (arg_count) + { + #define case_stmt(N) \ + case N : (fp_map_[arg_count])[name] = \ + (!ret_present) ? static_cast \ + (new func_##N##param) : \ + static_cast \ + (new func_##N##param_retval) ; \ + break; \ + + case_stmt(0) case_stmt(1) case_stmt(2) + case_stmt(3) case_stmt(4) case_stmt(5) + case_stmt(6) + #undef case_stmt + } + + exprtk::ifunction& ifunc = (*(fp_map_[arg_count])[name]); + + return sym_table.add_function(name,ifunc); + } + + inline void remove(const std::string& name, const std::size_t& arg_count) + { + if (arg_count > 6) + return; + + const typename std::map::iterator em_itr = expr_map_.find(name); + + if (expr_map_.end() != em_itr) + { + expr_map_.erase(em_itr); + } + + const typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); + + if (fp_map_[arg_count].end() != fp_itr) + { + delete fp_itr->second; + fp_map_[arg_count].erase(fp_itr); + } + + symbol_table_.remove_function(name); + } + + private: + + symbol_table_t symbol_table_; + parser_t parser_; + std::map expr_map_; + std::vector fp_map_; + std::vector auxiliary_symtab_list_; + }; + + template + inline bool pgo_primer() + { + static const std::string expression_list[] = + { + "(y + x)", + "2 * (y + x)", + "(2 * y + 2 * x)", + "(y + x / y) * (x - y / x)", + "x / ((x + y) * (x - y)) / y", + "1 - ((x * y) + (y / x)) - 3", + "sin(2 * x) + cos(pi / y)", + "1 - sin(2 * x) + cos(pi / y)", + "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", + "(x^2 / sin(2 * pi / y)) -x / 2", + "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", + "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", + "iclamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", + "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", + "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x", + "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^4 - 5.5x^5 + 6.6y^6 - 7.7x^27 + 8.8y^55", + "(yy + xx)", + "2 * (yy + xx)", + "(2 * yy + 2 * xx)", + "(yy + xx / yy) * (xx - yy / xx)", + "xx / ((xx + yy) * (xx - yy)) / yy", + "1 - ((xx * yy) + (yy / xx)) - 3", + "sin(2 * xx) + cos(pi / yy)", + "1 - sin(2 * xx) + cos(pi / yy)", + "sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3)", + "(xx^2 / sin(2 * pi / yy)) -xx / 2", + "xx + (cos(yy - sin(2 / xx * pi)) - sin(xx - cos(2 * yy / pi))) - yy", + "clamp(-1.0, sin(2 * pi * xx) + cos(yy / 2 * pi), +1.0)", + "max(3.33, min(sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3), 1.11))", + "if(avg(xx,yy) <= xx + yy, xx - yy, xx * yy) + 2 * pi / xx", + "1.1xx^1 + 2.2yy^2 - 3.3xx^3 + 4.4yy^4 - 5.5xx^5 + 6.6yy^6 - 7.7xx^27 + 8.8yy^55", + "(1.1*(2.2*(3.3*(4.4*(5.5*(6.6*(7.7*(8.8*(9.9+x)))))))))", + "(((((((((x+9.9)*8.8)*7.7)*6.6)*5.5)*4.4)*3.3)*2.2)*1.1)", + "(x + y) * z", "x + (y * z)", "(x + y) * 7", "x + (y * 7)", + "(x + 7) * y", "x + (7 * y)", "(7 + x) * y", "7 + (x * y)", + "(2 + x) * 3", "2 + (x * 3)", "(2 + 3) * x", "2 + (3 * x)", + "(x + 2) * 3", "x + (2 * 3)", + "(x + y) * (z / w)", "(x + y) * (z / 7)", "(x + y) * (7 / z)", "(x + 7) * (y / z)", + "(7 + x) * (y / z)", "(2 + x) * (y / z)", "(x + 2) * (y / 3)", "(2 + x) * (y / 3)", + "(x + 2) * (3 / y)", "x + (y * (z / w))", "x + (y * (z / 7))", "x + (y * (7 / z))", + "x + (7 * (y / z))", "7 + (x * (y / z))", "2 + (x * (3 / y))", "x + (2 * (y / 4))", + "2 + (x * (y / 3))", "x + (2 * (3 / y))", + "x + ((y * z) / w)", "x + ((y * z) / 7)", "x + ((y * 7) / z)", "x + ((7 * y) / z)", + "7 + ((y * z) / w)", "2 + ((x * 3) / y)", "x + ((2 * y) / 3)", "2 + ((x * y) / 3)", + "x + ((2 * 3) / y)", "(((x + y) * z) / w)", + "(((x + y) * z) / 7)", "(((x + y) * 7) / z)", "(((x + 7) * y) / z)", "(((7 + x) * y) / z)", + "(((2 + x) * 3) / y)", "(((x + 2) * y) / 3)", "(((2 + x) * y) / 3)", "(((x + 2) * 3) / y)", + "((x + (y * z)) / w)", "((x + (y * z)) / 7)", "((x + (y * 7)) / y)", "((x + (7 * y)) / z)", + "((7 + (x * y)) / z)", "((2 + (x * 3)) / y)", "((x + (2 * y)) / 3)", "((2 + (x * y)) / 3)", + "((x + (2 * 3)) / y)", + "(xx + yy) * zz", "xx + (yy * zz)", + "(xx + yy) * 7", "xx + (yy * 7)", + "(xx + 7) * yy", "xx + (7 * yy)", + "(7 + xx) * yy", "7 + (xx * yy)", + "(2 + x) * 3", "2 + (x * 3)", + "(2 + 3) * x", "2 + (3 * x)", + "(x + 2) * 3", "x + (2 * 3)", + "(xx + yy) * (zz / ww)", "(xx + yy) * (zz / 7)", + "(xx + yy) * (7 / zz)", "(xx + 7) * (yy / zz)", + "(7 + xx) * (yy / zz)", "(2 + xx) * (yy / zz)", + "(xx + 2) * (yy / 3)", "(2 + xx) * (yy / 3)", + "(xx + 2) * (3 / yy)", "xx + (yy * (zz / ww))", + "xx + (yy * (zz / 7))", "xx + (yy * (7 / zz))", + "xx + (7 * (yy / zz))", "7 + (xx * (yy / zz))", + "2 + (xx * (3 / yy))", "xx + (2 * (yy / 4))", + "2 + (xx * (yy / 3))", "xx + (2 * (3 / yy))", + "xx + ((yy * zz) / ww)", "xx + ((yy * zz) / 7)", + "xx + ((yy * 7) / zz)", "xx + ((7 * yy) / zz)", + "7 + ((yy * zz) / ww)", "2 + ((xx * 3) / yy)", + "xx + ((2 * yy) / 3)", "2 + ((xx * yy) / 3)", + "xx + ((2 * 3) / yy)", "(((xx + yy) * zz) / ww)", + "(((xx + yy) * zz) / 7)", "(((xx + yy) * 7) / zz)", + "(((xx + 7) * yy) / zz)", "(((7 + xx) * yy) / zz)", + "(((2 + xx) * 3) / yy)", "(((xx + 2) * yy) / 3)", + "(((2 + xx) * yy) / 3)", "(((xx + 2) * 3) / yy)", + "((xx + (yy * zz)) / ww)", "((xx + (yy * zz)) / 7)", + "((xx + (yy * 7)) / yy)", "((xx + (7 * yy)) / zz)", + "((7 + (xx * yy)) / zz)", "((2 + (xx * 3)) / yy)", + "((xx + (2 * yy)) / 3)", "((2 + (xx * yy)) / 3)", + "((xx + (2 * 3)) / yy)" + }; + + static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); + + T x = T(0); + T y = T(0); + T z = T(0); + T w = T(0); + T xx = T(0); + T yy = T(0); + T zz = T(0); + T ww = T(0); + + exprtk::symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_variable( "x", x); + symbol_table.add_variable( "y", y); + symbol_table.add_variable( "z", z); + symbol_table.add_variable( "w", w); + symbol_table.add_variable("xx",xx); + symbol_table.add_variable("yy",yy); + symbol_table.add_variable("zz",zz); + symbol_table.add_variable("ww",ww); + + typedef typename std::deque > expr_list_t; + expr_list_t expr_list; + + const std::size_t rounds = 50; + + { + for (std::size_t r = 0; r < rounds; ++r) + { + expr_list.clear(); + exprtk::parser parser; + + for (std::size_t i = 0; i < expression_list_size; ++i) + { + exprtk::expression expression; + expression.register_symbol_table(symbol_table); + + if (!parser.compile(expression_list[i],expression)) + { + return false; + } + + expr_list.push_back(expression); + } + } + } + + struct execute + { + static inline T process(T& x, T& y, expression& expression) + { + static const T lower_bound = T(-20); + static const T upper_bound = T(+20); + static const T delta = T(0.1); + + T total = T(0); + + for (x = lower_bound; x <= upper_bound; x += delta) + { + for (y = lower_bound; y <= upper_bound; y += delta) + { + total += expression.value(); + } + } + + return total; + } + }; + + for (std::size_t i = 0; i < expr_list.size(); ++i) + { + execute::process( x, y, expr_list[i]); + execute::process(xx, yy, expr_list[i]); + } + + { + for (std::size_t i = 0; i < 10000; ++i) + { + const T v = T(123.456 + i); + + if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T(1))))) + return false; + + #define else_stmt(N) \ + else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T(N))))) \ + return false; \ + + else_stmt( 2) else_stmt( 3) else_stmt( 4) else_stmt( 5) + else_stmt( 6) else_stmt( 7) else_stmt( 8) else_stmt( 9) + else_stmt(10) else_stmt(11) else_stmt(12) else_stmt(13) + else_stmt(14) else_stmt(15) else_stmt(16) else_stmt(17) + else_stmt(18) else_stmt(19) else_stmt(20) else_stmt(21) + else_stmt(22) else_stmt(23) else_stmt(24) else_stmt(25) + else_stmt(26) else_stmt(27) else_stmt(28) else_stmt(29) + else_stmt(30) else_stmt(31) else_stmt(32) else_stmt(33) + else_stmt(34) else_stmt(35) else_stmt(36) else_stmt(37) + else_stmt(38) else_stmt(39) else_stmt(40) else_stmt(41) + else_stmt(42) else_stmt(43) else_stmt(44) else_stmt(45) + else_stmt(46) else_stmt(47) else_stmt(48) else_stmt(49) + else_stmt(50) else_stmt(51) else_stmt(52) else_stmt(53) + else_stmt(54) else_stmt(55) else_stmt(56) else_stmt(57) + else_stmt(58) else_stmt(59) else_stmt(60) else_stmt(61) + } + } + + return true; + } +} + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# ifndef NOMINMAX +# define NOMINMAX +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +#else +# include +# include +# include +#endif + +namespace exprtk +{ + class timer + { + public: + + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + timer() + : in_use_(false) + { + QueryPerformanceFrequency(&clock_frequency_); + } + + inline void start() + { + in_use_ = true; + QueryPerformanceCounter(&start_time_); + } + + inline void stop() + { + QueryPerformanceCounter(&stop_time_); + in_use_ = false; + } + + inline double time() const + { + return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart); + } + + #else + + timer() + : in_use_(false) + { + start_time_.tv_sec = 0; + start_time_.tv_usec = 0; + stop_time_.tv_sec = 0; + stop_time_.tv_usec = 0; + } + + inline void start() + { + in_use_ = true; + gettimeofday(&start_time_,0); + } + + inline void stop() + { + gettimeofday(&stop_time_, 0); + in_use_ = false; + } + + inline unsigned long long int usec_time() const + { + if (!in_use_) + { + if (stop_time_.tv_sec >= start_time_.tv_sec) + { + return 1000000LLU * static_cast(stop_time_.tv_sec - start_time_.tv_sec ) + + static_cast(stop_time_.tv_usec - start_time_.tv_usec) ; + } + else + return std::numeric_limits::max(); + } + else + return std::numeric_limits::max(); + } + + inline double time() const + { + return usec_time() * 0.000001; + } + + #endif + + inline bool in_use() const + { + return in_use_; + } + + private: + + bool in_use_; + + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + LARGE_INTEGER start_time_; + LARGE_INTEGER stop_time_; + LARGE_INTEGER clock_frequency_; + #else + struct timeval start_time_; + struct timeval stop_time_; + #endif + }; + +} // namespace exprtk + +#ifndef exprtk_disable_rtl_io +namespace exprtk +{ + namespace rtl { namespace io { namespace details + { + template + inline void print_type(const std::string& fmt, + const T v, + exprtk::details::numeric::details::real_type_tag) + { + printf(fmt.c_str(),v); + } + + template + struct print_impl + { + typedef typename igeneric_function::generic_type generic_type; + typedef typename igeneric_function::parameter_list_t parameter_list_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + typedef typename generic_type::string_view string_t; + typedef typename exprtk::details::numeric::details::number_type::type num_type; + + static void process(const std::string& scalar_format, parameter_list_t parameters) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + generic_type& gt = parameters[i]; + + switch (gt.type) + { + case generic_type::e_scalar : print(scalar_format,scalar_t(gt)); + break; + + case generic_type::e_vector : print(scalar_format,vector_t(gt)); + break; + + case generic_type::e_string : print(string_t(gt)); + break; + + default : continue; + } + } + } + + static inline void print(const std::string& scalar_format, const scalar_t& s) + { + print_type(scalar_format,s(),num_type()); + } + + static inline void print(const std::string& scalar_format, const vector_t& v) + { + for (std::size_t i = 0; i < v.size(); ++i) + { + print_type(scalar_format,v[i],num_type()); + + if ((i + 1) < v.size()) + printf(" "); + } + } + + static inline void print(const string_t& s) + { + printf("%s",to_str(s).c_str()); + } + }; + + } // namespace exprtk::rtl::io::details + + template + struct print : public exprtk::igeneric_function + { + typedef typename igeneric_function::parameter_list_t parameter_list_t; + + using exprtk::igeneric_function::operator(); + + print(const std::string& scalar_format = "%10.5f") + : scalar_format_(scalar_format) + { + exprtk::enable_zero_parameters(*this); + } + + inline T operator() (parameter_list_t parameters) + { + details::print_impl::process(scalar_format_,parameters); + return T(0); + } + + std::string scalar_format_; + }; + + template + struct println : public exprtk::igeneric_function + { + typedef typename igeneric_function::parameter_list_t parameter_list_t; + + using exprtk::igeneric_function::operator(); + + println(const std::string& scalar_format = "%10.5f") + : scalar_format_(scalar_format) + { + exprtk::enable_zero_parameters(*this); + } + + inline T operator() (parameter_list_t parameters) + { + details::print_impl::process(scalar_format_,parameters); + printf("\n"); + return T(0); + } + + std::string scalar_format_; + }; + + template + struct package + { + print p; + println pl; + + bool register_package(exprtk::symbol_table& symtab) + { + #define exprtk_register_function(FunctionName,FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::io::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + + exprtk_register_function("print" , p ) + exprtk_register_function("println", pl) + #undef exprtk_register_function + + return true; + } + }; + + } // namespace exprtk::rtl::io + } // namespace exprtk::rtl +} // namespace exprtk +#endif + +#ifndef exprtk_disable_rtl_io_file +#include +namespace exprtk +{ + namespace rtl { namespace io { namespace file { namespace details + { + enum file_mode + { + e_error = 0, + e_read = 1, + e_write = 2, + e_rdwrt = 4 + }; + + struct file_descriptor + { + file_descriptor(const std::string& fname, const std::string& access) + : stream_ptr(0), + mode(get_file_mode(access)), + file_name(fname) + {} + + void* stream_ptr; + file_mode mode; + std::string file_name; + + bool open() + { + if (e_read == mode) + { + std::ifstream* stream = new std::ifstream(file_name.c_str(),std::ios::binary); + + if (!(*stream)) + { + file_name.clear(); + delete stream; + + return false; + } + else + stream_ptr = stream; + + return true; + } + else if (e_write == mode) + { + std::ofstream* stream = new std::ofstream(file_name.c_str(),std::ios::binary); + + if (!(*stream)) + { + file_name.clear(); + delete stream; + + return false; + } + else + stream_ptr = stream; + + return true; + } + else if (e_rdwrt == mode) + { + std::fstream* stream = new std::fstream(file_name.c_str(),std::ios::binary); + + if (!(*stream)) + { + file_name.clear(); + delete stream; + + return false; + } + else + stream_ptr = stream; + + return true; + } + else + return false; + } + + template + void close(Ptr& p) + { + Stream* stream = reinterpret_cast(p); + stream->close(); + delete stream; + p = reinterpret_cast(0); + } + + bool close() + { + switch (mode) + { + case e_read : close(stream_ptr); + break; + + case e_write : close(stream_ptr); + break; + + case e_rdwrt : close (stream_ptr); + break; + + default : return false; + } + + return true; + } + + template + bool write(const View& view, const std::size_t amount, const std::size_t offset = 0) + { + switch (mode) + { + case e_write : reinterpret_cast(stream_ptr)-> + write(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); + break; + + case e_rdwrt : reinterpret_cast(stream_ptr)-> + write(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); + break; + + default : return false; + } + + return true; + } + + template + bool read(View& view, const std::size_t amount, const std::size_t offset = 0) + { + switch (mode) + { + case e_read : reinterpret_cast(stream_ptr)-> + read(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); + break; + + case e_rdwrt : reinterpret_cast(stream_ptr)-> + read(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); + break; + + default : return false; + } + + return true; + } + + bool getline(std::string& s) + { + switch (mode) + { + case e_read : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); + case e_rdwrt : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); + default : return false; + } + } + + bool eof() const + { + switch (mode) + { + case e_read : return reinterpret_cast(stream_ptr)->eof(); + case e_write : return reinterpret_cast(stream_ptr)->eof(); + case e_rdwrt : return reinterpret_cast(stream_ptr)->eof(); + default : return true; + } + } + + file_mode get_file_mode(const std::string& access) const + { + if (access.empty() || access.size() > 2) + return e_error; + + std::size_t w_cnt = 0; + std::size_t r_cnt = 0; + + for (std::size_t i = 0; i < access.size(); ++i) + { + switch (std::tolower(access[i])) + { + case 'r' : r_cnt++; break; + case 'w' : w_cnt++; break; + default : return e_error; + } + } + + if ((0 == r_cnt) && (0 == w_cnt)) + return e_error; + else if ((r_cnt > 1) || (w_cnt > 1)) + return e_error; + else if ((1 == r_cnt) && (1 == w_cnt)) + return e_rdwrt; + else if (1 == r_cnt) + return e_read; + else + return e_write; + } + }; + + template + file_descriptor* make_handle(T v) + { + file_descriptor* fd = reinterpret_cast(0); + + std::memcpy(reinterpret_cast(&fd), + reinterpret_cast(&v), + sizeof(fd)); + return fd; + } + + template + void perform_check() + { + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + if (sizeof(T) < sizeof(void*)) + { + throw std::runtime_error("exprtk::rtl::io::file - Error - pointer size larger than holder."); + } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + } + + } // namespace exprtk::rtl::io::file::details + + template + class open : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + + using exprtk::igeneric_function::operator(); + + open() + : exprtk::igeneric_function("S|SS") + { details::perform_check(); } + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + std::string file_name = to_str(string_t(parameters[0])); + std::string access; + + if (file_name.empty()) + return T(0); + + if (0 == ps_index) + access = "r"; + else if (0 == string_t(parameters[1]).size()) + return T(0); + else + access = to_str(string_t(parameters[1])); + + details::file_descriptor* fd = new details::file_descriptor(file_name,access); + + if (fd->open()) + { + T t = T(0); + + std::memcpy(reinterpret_cast(&t ), + reinterpret_cast(&fd), + sizeof(fd)); + return t; + } + else + { + delete fd; + return T(0); + } + } + }; + + template + struct close : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + close() + : exprtk::ifunction(1) + { details::perform_check(); } + + inline T operator() (const T& v) + { + details::file_descriptor* fd = details::make_handle(v); + + if (!fd->close()) + return T(0); + + delete fd; + + return T(1); + } + }; + + template + class write : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + write() + : igfun_t("TS|TST|TV|TVT") + { details::perform_check(); } + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + + std::size_t amount = 0; + + switch (ps_index) + { + case 0 : { + const string_t buffer(parameters[1]); + amount = buffer.size(); + return T(fd->write(buffer, amount) ? 1 : 0); + } + + case 1 : { + const string_t buffer(parameters[1]); + amount = std::min(buffer.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->write(buffer, amount) ? 1 : 0); + } + + case 2 : { + const vector_t vec(parameters[1]); + amount = vec.size(); + return T(fd->write(vec, amount) ? 1 : 0); + } + + case 3 : { + const vector_t vec(parameters[1]); + amount = std::min(vec.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->write(vec, amount) ? 1 : 0); + } + } + + return T(0); + } + }; + + template + class read : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + read() + : igfun_t("TS|TST|TV|TVT") + { details::perform_check(); } + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + + std::size_t amount = 0; + + switch (ps_index) + { + case 0 : { + string_t buffer(parameters[1]); + amount = buffer.size(); + return T(fd->read(buffer,amount) ? 1 : 0); + } + + case 1 : { + string_t buffer(parameters[1]); + amount = std::min(buffer.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->read(buffer,amount) ? 1 : 0); + } + + case 2 : { + vector_t vec(parameters[1]); + amount = vec.size(); + return T(fd->read(vec,amount) ? 1 : 0); + } + + case 3 : { + vector_t vec(parameters[1]); + amount = std::min(vec.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->read(vec,amount) ? 1 : 0); + } + } + + return T(0); + } + }; + + template + class getline : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::scalar_view scalar_t; + + using exprtk::igeneric_function::operator(); + + getline() + : igfun_t("T",igfun_t::e_rtrn_string) + { details::perform_check(); } + + inline T operator() (std::string& result, + parameter_list_t parameters) + { + details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + return T(fd->getline(result) ? 1 : 0); + } + }; + + template + struct eof : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + eof() + : exprtk::ifunction(1) + { details::perform_check(); } + + inline T operator() (const T& v) + { + details::file_descriptor* fd = details::make_handle(v); + + return (fd->eof() ? T(1) : T(0)); + } + }; + + template + struct package + { + open o; + close c; + write w; + read r; + getline g; + eof e; + + bool register_package(exprtk::symbol_table& symtab) + { + #define exprtk_register_function(FunctionName,FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::io::file::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + + exprtk_register_function("open" , o) + exprtk_register_function("close" , c) + exprtk_register_function("write" , w) + exprtk_register_function("read" , r) + exprtk_register_function("getline", g) + exprtk_register_function("eof" , e) + #undef exprtk_register_function + + return true; + } + }; + + } // namespace exprtk::rtl::io::file + } // namespace exprtk::rtl::io + } // namespace exprtk::rtl +} // namespace exprtk +#endif + +#ifndef exprtk_disable_rtl_vecops +namespace exprtk +{ + namespace rtl { namespace vecops { + + namespace helper + { + template + inline bool invalid_range(const Vector& v, const std::size_t r0, const std::size_t r1) + { + if (r0 > (v.size() - 1)) + return true; + else if (r1 > (v.size() - 1)) + return true; + else if (r1 < r0) + return true; + else + return false; + } + + template + struct load_vector_range + { + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + static inline bool process(parameter_list_t& parameters, + std::size_t& r0, std::size_t& r1, + const std::size_t& r0_prmidx, + const std::size_t& r1_prmidx, + const std::size_t vec_idx = 0) + { + if (r0_prmidx >= parameters.size()) + return false; + + if (r1_prmidx >= parameters.size()) + return false; + + if (!scalar_t(parameters[r0_prmidx]).to_uint(r0)) + return false; + + if (!scalar_t(parameters[r1_prmidx]).to_uint(r1)) + return false; + + return !invalid_range(vector_t(parameters[vec_idx]), r0, r1); + } + }; + } + + namespace details + { + template + inline void kahan_sum(T& sum, T& error, const T v) + { + const T x = v - error; + const T y = sum + x; + error = (y - sum) - x; + sum = y; + } + + } // namespace exprtk::rtl::details + + template + class all_true : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + all_true() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] == T(0)) + { + return T(0); + } + } + + return T(1); + } + }; + + template + class all_false : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + all_false() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) + { + return T(0); + } + } + + return T(1); + } + }; + + template + class any_true : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + any_true() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) + { + return T(1); + } + } + + return T(0); + } + }; + + template + class any_false : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + any_false() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] == T(0)) + { + return T(1); + } + } + + return T(0); + } + }; + + template + class count : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + count() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) + ) + return std::numeric_limits::quiet_NaN(); + + std::size_t cnt = 0; + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) ++cnt; + } + + return T(cnt); + } + }; + + template + class copy : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + copy() + : exprtk::igeneric_function("VV|VTTVTT") + /* + Overloads: + 0. VV - x(vector), y(vector) + 1. VTTVTT - x(vector), xr0, xr1, y(vector), yr0, yr1, + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[0]); + vector_t y(parameters[(0 == ps_index) ? 1 : 3]); + + std::size_t xr0 = 0; + std::size_t xr1 = x.size() - 1; + + std::size_t yr0 = 0; + std::size_t yr1 = y.size() - 1; + + if (1 == ps_index) + { + if ( + !helper::load_vector_range::process(parameters, xr0, xr1, 1, 2, 0) || + !helper::load_vector_range::process(parameters, yr0, yr1, 4, 5, 3) + ) + return T(0); + } + + const std::size_t n = std::min(xr1 - xr0 + 1, yr1 - yr0 + 1); + + std::copy(x.begin() + xr0, x.begin() + xr0 + n, y.begin() + yr0); + + return T(n); + } + }; + + template + class rol : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + rol() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) + ) + return T(0); + + const std::size_t dist = r1 - r0 + 1; + const std::size_t shift = n % dist; + + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + shift, + vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class ror : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + ror() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) + ) + return T(0); + + std::size_t dist = r1 - r0 + 1; + std::size_t shift = (dist - (n % dist)) % dist; + + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + shift, + vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class shift_left : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + shift_left() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) + ) + return T(0); + + const std::size_t dist = r1 - r0 + 1; + + if (n > dist) + return T(0); + + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + n, + vec.begin() + r1 + 1); + + for (std::size_t i = r1 - n + 1; i <= r1; ++i) + { + vec[i] = T(0); + } + + return T(1); + } + }; + + template + class shift_right : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + shift_right() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ( + (1 == ps_index) && + !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) + ) + return T(0); + + const std::size_t dist = r1 - r0 + 1; + + if (n > dist) + return T(0); + + const std::size_t shift = (dist - (n % dist)) % dist; + + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + shift, + vec.begin() + r1 + 1); + + for (std::size_t i = r0; i < r0 + n; ++i) + { + vec[i] = T(0); + } + + return T(1); + } + }; + + template + class sort : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + sort() + : exprtk::igeneric_function("V|VTT|VS|VSTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + 2. VS - vector, string + 3. VSTT - vector, string, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0)) + return T(0); + if ((3 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return T(0); + + bool ascending = true; + + if ((2 == ps_index) || (3 == ps_index)) + { + if (exprtk::details::imatch(to_str(string_t(parameters[1])),"ascending")) + ascending = true; + else if (exprtk::details::imatch(to_str(string_t(parameters[1])),"descending")) + ascending = false; + else + return T(0); + } + + if (ascending) + std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::less ()); + else + std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::greater()); + + return T(1); + } + }; + + template + class nthelement : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + nthelement() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, nth-element + 1. VTTT - vector, nth-element, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return std::numeric_limits::quiet_NaN(); + + std::nth_element(vec.begin() + r0, vec.begin() + r0 + n , vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class iota : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + iota() + : exprtk::igeneric_function("VT|VTT|VTTT|VTTTT") + /* + Overloads: + 0. VT - vector, increment + 1. VTT - vector, increment, base + 2. VTTTT - vector, increment, r0, r1 + 3. VTTTT - vector, increment, base, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + T increment = scalar_t(parameters[1])(); + T base = ((1 == ps_index) || (3 == ps_index)) ? scalar_t(parameters[2])() : T(0); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((2 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return std::numeric_limits::quiet_NaN(); + else if ((3 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 0)) + return std::numeric_limits::quiet_NaN(); + else + { + long long j = 0; + + for (std::size_t i = r0; i <= r1; ++i, ++j) + { + vec[i] = base + (increment * j); + } + } + + return T(1); + } + }; + + template + class sumk : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + sumk() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0)) + return std::numeric_limits::quiet_NaN(); + + T result = T(0); + T error = T(0); + + for (std::size_t i = r0; i <= r1; ++i) + { + details::kahan_sum(result, error, vec[i]); + } + + return result; + } + }; + + template + class axpy : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpy() + : exprtk::igeneric_function("TVV|TVVTT") + /* + y <- ax + y + Overloads: + 0. TVV - a, x(vector), y(vector) + 1. TVVTT - a, x(vector), y(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + vector_t y(parameters[2]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + y[i] = (a * x[i]) + y[i]; + } + + return T(1); + } + }; + + template + class axpby : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpby() + : exprtk::igeneric_function("TVTV|TVTVTT") + /* + y <- ax + by + Overloads: + 0. TVTV - a, x(vector), b, y(vector) + 1. TVTVTT - a, x(vector), b, y(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + vector_t y(parameters[3]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + y[i] = (a * x[i]) + (b * y[i]); + } + + return T(1); + } + }; + + template + class axpyz : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpyz() + : exprtk::igeneric_function("TVVV|TVVVTT") + /* + z <- ax + y + Overloads: + 0. TVVV - a, x(vector), y(vector), z(vector) + 1. TVVVTT - a, x(vector), y(vector), z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + const vector_t y(parameters[2]); + vector_t z(parameters[3]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = (a * x[i]) + y[i]; + } + + return T(1); + } + }; + + template + class axpbyz : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpbyz() + : exprtk::igeneric_function("TVTVV|TVTVVTT") + /* + z <- ax + by + Overloads: + 0. TVTVV - a, x(vector), b, y(vector), z(vector) + 1. TVTVVTT - a, x(vector), b, y(vector), z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + const vector_t y(parameters[3]); + vector_t z(parameters[4]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = (a * x[i]) + (b * y[i]); + } + + return T(1); + } + }; + + template + class axpbz : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpbz() + : exprtk::igeneric_function("TVTV|TVTVTT") + /* + z <- ax + b + Overloads: + 0. TVTV - a, x(vector), b, z(vector) + 1. TVTVTT - a, x(vector), b, z(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[1]); + vector_t z(parameters[3]); + + std::size_t r0 = 0; + std::size_t r1 = x.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = (a * x[i]) + b; + } + + return T(1); + } + }; + + template + class dot : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + dot() + : exprtk::igeneric_function("VV|VVTT") + /* + Overloads: + 0. VV - x(vector), y(vector) + 1. VVTT - x(vector), y(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[0]); + const vector_t y(parameters[1]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + T result = T(0); + + for (std::size_t i = r0; i <= r1; ++i) + { + result += (x[i] * y[i]); + } + + return result; + } + }; + + template + class dotk : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + dotk() + : exprtk::igeneric_function("VV|VVTT") + /* + Overloads: + 0. VV - x(vector), y(vector) + 1. VVTT - x(vector), y(vector), r0, r1 + */ + {} + + inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t x(parameters[0]); + const vector_t y(parameters[1]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y, r0, r1)) + return std::numeric_limits::quiet_NaN(); + + T result = T(0); + T error = T(0); + + for (std::size_t i = r0; i <= r1; ++i) + { + details::kahan_sum(result, error, (x[i] * y[i])); + } + + return result; + } + }; + + template + struct package + { + all_true at; + all_false af; + any_true nt; + any_false nf; + count c; + copy cp; + rol rl; + ror rr; + shift_left sl; + shift_right sr; + sort st; + nthelement ne; + iota ia; + sumk sk; + axpy b1_axpy; + axpby b1_axpby; + axpyz b1_axpyz; + axpbyz b1_axpbyz; + axpbz b1_axpbz; + dot dt; + dotk dtk; + + bool register_package(exprtk::symbol_table& symtab) + { + #define exprtk_register_function(FunctionName,FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::vecops::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + + exprtk_register_function("all_true" , at ) + exprtk_register_function("all_false" , af ) + exprtk_register_function("any_true" , nt ) + exprtk_register_function("any_false" , nf ) + exprtk_register_function("count" , c ) + exprtk_register_function("copy" , cp ) + exprtk_register_function("rotate_left" , rl ) + exprtk_register_function("rol" , rl ) + exprtk_register_function("rotate_right" , rr ) + exprtk_register_function("ror" , rr ) + exprtk_register_function("shftl" , sl ) + exprtk_register_function("shftr" , sr ) + exprtk_register_function("sort" , st ) + exprtk_register_function("nth_element" , ne ) + exprtk_register_function("iota" , ia ) + exprtk_register_function("sumk" , sk ) + exprtk_register_function("axpy" , b1_axpy ) + exprtk_register_function("axpby" , b1_axpby ) + exprtk_register_function("axpyz" , b1_axpyz ) + exprtk_register_function("axpbyz" , b1_axpbyz) + exprtk_register_function("axpbz" , b1_axpbz ) + exprtk_register_function("dot" , dt ) + exprtk_register_function("dotk" , dtk ) + #undef exprtk_register_function + + return true; + } + }; + + } // namespace exprtk::rtl::vecops + } // namespace exprtk::rtl +} // namespace exprtk +#endif + +namespace exprtk +{ + namespace information + { + static const char* library = "Mathematical Expression Toolkit"; + static const char* version = "2.718281828459045235360287471352" + "66249775724709369995957496696762" + "77240766303535475945713821785251" + "66427427466391932003059921817413"; + static const char* date = "20210101"; + + static inline std::string data() + { + static const std::string info_str = std::string(library) + + std::string(" v") + std::string(version) + + std::string(" (") + date + std::string(")"); + return info_str; + } + + } // namespace information + + #ifdef exprtk_debug + #undef exprtk_debug + #endif + + #ifdef exprtk_error_location + #undef exprtk_error_location + #endif + + #ifdef exprtk_disable_fallthrough_begin + #undef exprtk_disable_fallthrough_begin + #endif + + #ifdef exprtk_disable_fallthrough_end + #undef exprtk_disable_fallthrough_end + #endif + + #ifdef exprtk_override + #undef exprtk_override + #endif + + #ifdef exprtk_final + #undef exprtk_final + #endif + +} // namespace exprtk + +#endif diff --git a/gui/source/file.cpp b/gui/source/file.cpp new file mode 100644 index 0000000..9c1830e --- /dev/null +++ b/gui/source/file.cpp @@ -0,0 +1,168 @@ +/** + * @file file.cpp + * @brief Contains code for file-management-related UI elements and logic. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "imgui.h" +#include "backends/imgui_impl_sdl2.h" +#include "backends/imgui_impl_opengl2.h" +#include "ImGuiFileDialog.h" +#include "TextEditor.h" + +#include "stmdsp_code.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern TextEditor editor; +extern void log(const std::string& str); + +enum class FileAction { + None, + Open, + Save, + SaveAs +}; + +static FileAction fileAction = FileAction::None; +static std::string fileCurrentPath; +static std::vector fileExampleList; + +static void saveCurrentFile() +{ + if (std::ofstream ofs (fileCurrentPath, std::ios::binary); ofs.good()) { + const auto& text = editor.GetText(); + ofs.write(text.data(), text.size()); + log("Saved."); + } +} + +static void openCurrentFile() +{ + if (std::ifstream ifs (fileCurrentPath); ifs.good()) { + std::ostringstream sstr; + sstr << ifs.rdbuf(); + editor.SetText(sstr.str()); + } +} + +static void openNewFile() +{ + fileCurrentPath.clear(); + editor.SetText(stmdsp::file_content); +} + +static std::vector fileScanExamples() +{ + const auto path = std::filesystem::current_path() / "examples"; + const std::filesystem::recursive_directory_iterator rdi (path); + + std::vector list; + std::transform( + std::filesystem::begin(rdi), + std::filesystem::end(rdi), + std::back_inserter(list), + [](const auto& file) { return file.path(); }); + std::sort(list.begin(), list.end()); + return list; +} + +void fileInit() +{ + fileExampleList = fileScanExamples(); + openNewFile(); +} + +void fileRenderMenu() +{ + if (ImGui::BeginMenu("File")) { + if (ImGui::MenuItem("New")) { + // TODO modified? + openNewFile(); + log("Ready."); + } + + if (ImGui::MenuItem("Open")) { + fileAction = FileAction::Open; + ImGuiFileDialog::Instance()->OpenDialog( + "ChooseFileOpenSave", "Choose File", ".cpp", ".", 1, nullptr, ImGuiFileDialogFlags_Modal); + } + + if (ImGui::BeginMenu("Open Example")) { + for (const auto& file : fileExampleList) { + if (ImGui::MenuItem(file.filename().string().c_str())) { + fileCurrentPath = file.string(); + openCurrentFile(); + + // Treat like new file. + fileCurrentPath.clear(); + log("Ready."); + } + } + + ImGui::EndMenu(); + } + + if (ImGui::MenuItem("Save")) { + if (fileCurrentPath.size() > 0) { + saveCurrentFile(); + } else { + fileAction = FileAction::SaveAs; + ImGuiFileDialog::Instance()->OpenDialog( + "ChooseFileOpenSave", "Choose File", ".cpp", ".", 1, nullptr, ImGuiFileDialogFlags_Modal); + } + } + + if (ImGui::MenuItem("Save As")) { + fileAction = FileAction::SaveAs; + ImGuiFileDialog::Instance()->OpenDialog( + "ChooseFileOpenSave", "Choose File", ".cpp", ".", 1, nullptr, ImGuiFileDialogFlags_Modal); + } + + ImGui::Separator(); + if (ImGui::MenuItem("Quit")) { + SDL_Event quitEvent (SDL_QUIT); + SDL_PushEvent(&quitEvent); + } + + ImGui::EndMenu(); + } +} + +void fileRenderDialog() +{ + if (ImGuiFileDialog::Instance()->Display("ChooseFileOpenSave", + ImGuiWindowFlags_NoCollapse, + ImVec2(460, 540))) + { + if (ImGuiFileDialog::Instance()->IsOk()) { + std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); + + if (fileAction == FileAction::Open) { + fileCurrentPath = filePathName; + openCurrentFile(); + log("Ready."); + } else if (fileAction == FileAction::SaveAs) { + fileCurrentPath = filePathName; + saveCurrentFile(); + } + } + + ImGuiFileDialog::Instance()->Close(); + } +} + diff --git a/gui/source/gui.cpp b/gui/source/gui.cpp new file mode 100644 index 0000000..45bdf66 --- /dev/null +++ b/gui/source/gui.cpp @@ -0,0 +1,151 @@ +/** + * @file gui.cpp + * @brief Contains code for GUI-related logic. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "imgui.h" +#include "imgui_internal.h" +#include "backends/imgui_impl_sdl2.h" +#include "backends/imgui_impl_opengl2.h" + +#include +#include + +bool guiInitialize(); +void guiRender(); +bool guiHandleEvents(); +void guiShutdown(); + +static SDL_Window *window = nullptr; +static SDL_GLContext gl_context; + +bool guiInitialize() +{ + if (SDL_Init(0) != 0) { + printf("Error: %s\n", SDL_GetError()); + return false; + } + + // Setup window + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + window = SDL_CreateWindow("stmdsp gui", + SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + 640, 700, + SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE /*| SDL_WINDOW_ALLOW_HIGHDPI*/); + + if (window == nullptr) { + puts("Error: Could not create the window!"); + return false; + } + + SDL_SetWindowMinimumSize(window, 320, 320); + + gl_context = SDL_GL_CreateContext(window); + SDL_GL_MakeCurrent(window, gl_context); + SDL_GL_SetSwapInterval(1); // Enable vsync + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + //io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + + ImGui_ImplSDL2_InitForOpenGL(window, gl_context); + ImGui_ImplOpenGL2_Init(); + + ImGui::StyleColorsLight(); + ImGuiStyle& style = ImGui::GetStyle(); + style.WindowRounding = 5; + style.FrameRounding = 3; + style.ScrollbarRounding = 1; + +//#define ACCENT1 0.26f, 0.59f, 0.98f +#define ACCENT1 0.6f, 0.6f, 0.6f +#define ACCENT2 0.4f, 0.4f, 0.4f + + style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(ACCENT1, 0.40f); + style.Colors[ImGuiCol_FrameBgActive] = ImVec4(ACCENT1, 0.67f); + style.Colors[ImGuiCol_CheckMark] = ImVec4(ACCENT1, 1.00f); + style.Colors[ImGuiCol_SliderGrab] = ImVec4(ACCENT1, 0.78f); + style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f); + style.Colors[ImGuiCol_Button] = ImVec4(ACCENT1, 0.40f); + style.Colors[ImGuiCol_ButtonHovered] = ImVec4(ACCENT1, 1.00f); + style.Colors[ImGuiCol_ButtonActive] = ImVec4(ACCENT2, 1.00f); + style.Colors[ImGuiCol_Header] = ImVec4(ACCENT1, 0.31f); + style.Colors[ImGuiCol_HeaderHovered] = ImVec4(ACCENT1, 0.80f); + style.Colors[ImGuiCol_HeaderActive] = ImVec4(ACCENT1, 1.00f); + style.Colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f); + style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); + style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); + style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(ACCENT1, 0.67f); + style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(ACCENT1, 0.95f); + style.Colors[ImGuiCol_TableHeaderBg] = ImVec4(0.78f, 0.87f, 0.98f, 1.00f); + style.Colors[ImGuiCol_TableBorderStrong] = ImVec4(0.57f, 0.57f, 0.64f, 1.00f); + style.Colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); + style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(ACCENT1, 0.35f); + style.Colors[ImGuiCol_DragDropTarget] = ImVec4(ACCENT1, 0.95f); + + style.Colors[ImGuiCol_Tab] = ImLerp(style.Colors[ImGuiCol_Header], style.Colors[ImGuiCol_TitleBgActive], 0.90f); + style.Colors[ImGuiCol_TabHovered] = style.Colors[ImGuiCol_HeaderHovered]; + style.Colors[ImGuiCol_TabActive] = ImLerp(style.Colors[ImGuiCol_HeaderActive], style.Colors[ImGuiCol_TitleBgActive], 0.60f); + style.Colors[ImGuiCol_TabUnfocused] = ImLerp(style.Colors[ImGuiCol_Tab], style.Colors[ImGuiCol_TitleBg], 0.80f); + style.Colors[ImGuiCol_TabUnfocusedActive] = ImLerp(style.Colors[ImGuiCol_TabActive], style.Colors[ImGuiCol_TitleBg], 0.40f); + style.Colors[ImGuiCol_NavHighlight] = style.Colors[ImGuiCol_HeaderHovered]; + + return true; +} + +void guiRender() +{ + ImGui::Render(); + + const auto& displaySize = ImGui::GetIO().DisplaySize; + const int sizeX = static_cast(displaySize.x); + const int sizeY = static_cast(displaySize.y); + + glViewport(0, 0, sizeX, sizeY); + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); + SDL_GL_SwapWindow(window); +} + +bool guiHandleEvents() +{ + bool done = false; + + for (SDL_Event event; SDL_PollEvent(&event);) { + ImGui_ImplSDL2_ProcessEvent(&event); + if (event.type == SDL_QUIT) { + done = true; + } else if (event.type == SDL_WINDOWEVENT) { + const auto& ew = event.window; + const auto wid = SDL_GetWindowID(window); + if (ew.event == SDL_WINDOWEVENT_CLOSE && ew.windowID == wid) + done = true; + } + } + + return done; +} + +void guiShutdown() +{ + ImGui_ImplOpenGL2_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + + SDL_GL_DeleteContext(gl_context); + SDL_DestroyWindow(window); + SDL_Quit(); +} + diff --git a/gui/source/gui_code.cpp b/gui/source/gui_code.cpp new file mode 100644 index 0000000..b7b56dd --- /dev/null +++ b/gui/source/gui_code.cpp @@ -0,0 +1,68 @@ +/** + * @file code.cpp + * @brief Contains code for algorithm-code-related UI elements and logic. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "code.hpp" +#include "imgui.h" +#include "backends/imgui_impl_sdl2.h" +#include "backends/imgui_impl_opengl2.h" +#include "TextEditor.h" + +#include + +TextEditor editor; // file.cpp + +static std::string editorCompiled; + +static void codeCompile(); +static void codeDisassemble(); + +void codeEditorInit() +{ + editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus()); + editor.SetPalette(TextEditor::GetLightPalette()); +} + +void codeRenderMenu() +{ + if (ImGui::BeginMenu("Code")) { + if (ImGui::MenuItem("Compile")) + codeCompile(); + if (ImGui::MenuItem("Disassemble")) + codeDisassemble(); + + ImGui::EndMenu(); + } +} + +void codeRenderToolbar() +{ + if (ImGui::Button("Compile")) + codeCompile(); +} + +void codeRenderWidgets(const ImVec2& size) +{ + editor.Render("code", size, true); +} + +static void codeCompile() +{ + compileEditorCode(editor.GetText()); + editorCompiled = editor.GetText().compare(editorCompiled); +} + +static void codeDisassemble() +{ + if (editor.GetText().compare(editorCompiled) != 0) + codeCompile(); + disassembleCode(); +} + diff --git a/gui/source/gui_device.cpp b/gui/source/gui_device.cpp new file mode 100644 index 0000000..b048abf --- /dev/null +++ b/gui/source/gui_device.cpp @@ -0,0 +1,439 @@ +#include "circular.hpp" +#include "imgui.h" +#include "imgui_internal.h" +#include "ImGuiFileDialog.h" + +#include "stmdsp.hpp" + +#include +#include +#include +#include +#include + +namespace ImGui +{ + void PushDisabled() + { + ImGuiContext& g = *GImGui; + bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + if (!was_disabled) + PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.6f); + PushItemFlag(ImGuiItemFlags_Disabled, true); + } + + void PopDisabled() + { + ImGuiContext& g = *GImGui; + bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + PopItemFlag(); + if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0) + PopStyleVar(); + } +} + +// Used for status queries and buffer size configuration. +extern std::shared_ptr m_device; + +void deviceAlgorithmUnload(); +void deviceAlgorithmUpload(); +bool deviceConnect(); +void deviceGenLoadFormula(const std::string& list); +void deviceGenLoadList(std::string_view list); +bool deviceGenStartToggle(); +void deviceLoadAudioFile(const std::string& file); +void deviceLoadLogFile(const std::string& file); +void deviceSetSampleRate(unsigned int index); +void deviceSetInputDrawing(bool enabled); +void deviceStart(bool logResults, bool drawSamples); +void deviceStartMeasurement(); +void deviceUpdateDrawBufferSize(double timeframe); +std::size_t pullFromDrawQueue( + CircularBuffer& circ); +std::size_t pullFromInputDrawQueue( + CircularBuffer& circ); + +static std::string sampleRatePreview = "?"; +static bool measureCodeTime = false; +static bool logResults = false; +static bool drawSamples = false; +static bool popupRequestBuffer = false; +static bool popupRequestSiggen = false; +static bool popupRequestLog = false; +static double drawSamplesTimeframe = 1.0; // seconds + +static std::string getSampleRatePreview(unsigned int rate) +{ + return std::to_string(rate / 1000) + " kHz"; +} + +static std::string connectLabel ("Connect"); +void deviceRenderDisconnect() +{ + connectLabel = "Connect"; + measureCodeTime = false; + logResults = false; + drawSamples = false; +} + +void deviceRenderMenu() +{ + auto addMenuItem = [](const std::string& label, bool enable, auto action) { + if (ImGui::MenuItem(label.c_str(), nullptr, false, enable)) { + action(); + } + }; + + if (ImGui::BeginMenu("Device")) { + addMenuItem(connectLabel, !m_device || !m_device->is_running(), [&] { + if (deviceConnect()) { + connectLabel = "Disconnect"; + sampleRatePreview = + getSampleRatePreview(m_device->get_sample_rate()); + deviceUpdateDrawBufferSize(drawSamplesTimeframe); + } else { + deviceRenderDisconnect(); + } + }); + + const bool isConnected = m_device ? true : false; + const bool isRunning = isConnected && m_device->is_running(); + + ImGui::Separator(); + + static std::string startLabel ("Start"); + addMenuItem(startLabel, isConnected, [&] { + startLabel = isRunning ? "Start" : "Stop"; + deviceStart(logResults, drawSamples); + if (logResults && isRunning) + logResults = false; + }); + addMenuItem("Upload algorithm", isConnected && !isRunning, + deviceAlgorithmUpload); + addMenuItem("Unload algorithm", isConnected && !isRunning, + deviceAlgorithmUnload); + addMenuItem("Measure Code Time", isRunning, deviceStartMeasurement); + + ImGui::Separator(); + if (!isConnected || isRunning) + ImGui::PushDisabled(); // Hey, pushing disabled! + + ImGui::Checkbox("Draw samples", &drawSamples); + if (ImGui::Checkbox("Log results...", &logResults)) { + if (logResults) + popupRequestLog = true; + } + addMenuItem("Set buffer size...", true, [] { popupRequestBuffer = true; }); + + if (!isConnected || isRunning) + ImGui::PopDisabled(); + ImGui::Separator(); + + addMenuItem("Load signal generator", + isConnected && !m_device->is_siggening() && !m_device->is_running(), + [] { popupRequestSiggen = true; }); + + static std::string startSiggenLabel ("Start signal generator"); + addMenuItem(startSiggenLabel, isConnected, [&] { + const bool running = deviceGenStartToggle(); + startSiggenLabel = running ? "Stop signal generator" + : "Start signal generator"; + }); + + ImGui::EndMenu(); + } +} + +void deviceRenderToolbar() +{ + ImGui::SameLine(); + if (ImGui::Button("Upload")) + deviceAlgorithmUpload(); + ImGui::SameLine(); + ImGui::SetNextItemWidth(100); + + const bool enable = + m_device && !m_device->is_running() && !m_device->is_siggening(); + if (!enable) + ImGui::PushDisabled(); + + if (ImGui::BeginCombo("", sampleRatePreview.c_str())) { + extern std::array sampleRateInts; + + for (const auto& r : sampleRateInts) { + const auto s = getSampleRatePreview(r); + if (ImGui::Selectable(s.c_str())) { + sampleRatePreview = s; + deviceSetSampleRate(r); + deviceUpdateDrawBufferSize(drawSamplesTimeframe); + } + } + + ImGui::EndCombo(); + } + + if (!enable) + ImGui::PopDisabled(); +} + +void deviceRenderWidgets() +{ + static std::string siggenInput (32768, '\0'); + static int siggenOption = 0; + + if (popupRequestSiggen) { + popupRequestSiggen = false; + ImGui::OpenPopup("siggen"); + } else if (popupRequestBuffer) { + popupRequestBuffer = false; + ImGui::OpenPopup("buffer"); + } else if (popupRequestLog) { + popupRequestLog = false; + ImGuiFileDialog::Instance()->OpenDialog( + "ChooseFileLog", "Choose File", ".csv", ".", 1, nullptr, ImGuiFileDialogFlags_Modal); + } + + if (ImGui::BeginPopup("siggen")) { + if (ImGui::RadioButton("List", &siggenOption, 0)) { + siggenInput.resize(32768); + siggenInput[0] = '\0'; + } + ImGui::SameLine(); + if (ImGui::RadioButton("Formula", &siggenOption, 1)) { + siggenInput.resize(1024); + siggenInput[0] = '\0'; + } + ImGui::SameLine(); + if (ImGui::RadioButton("Audio File", &siggenOption, 2)) + siggenInput.clear(); + + if (siggenOption == 2) { + if (ImGui::Button("Choose File")) { + // This dialog will override the siggen popup, closing it. + ImGuiFileDialog::Instance()->OpenDialog( + "ChooseFileGen", "Choose File", ".wav", ".", 1, nullptr, ImGuiFileDialogFlags_Modal); + } + } else { + ImGui::Text(siggenOption == 0 ? "Enter a list of numbers:" + : "Enter a formula. x = sample #, y = -1 to 1.\nf(x) = "); + ImGui::PushStyleColor(ImGuiCol_FrameBg, {.8, .8, .8, 1}); + ImGui::InputText("", siggenInput.data(), siggenInput.size()); + ImGui::PopStyleColor(); + } + + if (ImGui::Button("Save")) { + switch (siggenOption) { + case 0: + deviceGenLoadList(siggenInput.substr(0, siggenInput.find('\0'))); + break; + case 1: + deviceGenLoadFormula(siggenInput.substr(0, siggenInput.find('\0'))); + break; + case 2: + break; + } + + ImGui::CloseCurrentPopup(); + } + + ImGui::SameLine(); + if (ImGui::Button("Cancel")) { + siggenInput.clear(); + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + + if (ImGui::BeginPopup("buffer")) { + static std::string bufferSizeInput ("4096"); + ImGui::Text("Please enter a new sample buffer size (100-4096):"); + ImGui::PushStyleColor(ImGuiCol_FrameBg, {.8, .8, .8, 1}); + ImGui::InputText("", + bufferSizeInput.data(), + bufferSizeInput.size(), + ImGuiInputTextFlags_CharsDecimal); + ImGui::PopStyleColor(); + if (ImGui::Button("Save")) { + if (m_device) { + int n = std::clamp(std::stoi(bufferSizeInput), 100, 4096); + m_device->continuous_set_buffer_size(n); + } + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + + if (ImGuiFileDialog::Instance()->Display("ChooseFileLog", + ImGuiWindowFlags_NoCollapse, + ImVec2(460, 540))) + { + if (ImGuiFileDialog::Instance()->IsOk()) { + const auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); + deviceLoadLogFile(filePathName); + } else { + logResults = false; + } + + ImGuiFileDialog::Instance()->Close(); + } + + if (ImGuiFileDialog::Instance()->Display("ChooseFileGen", + ImGuiWindowFlags_NoCollapse, + ImVec2(460, 540))) + { + if (ImGuiFileDialog::Instance()->IsOk()) { + const auto filePathName = ImGuiFileDialog::Instance()->GetFilePathName(); + deviceLoadAudioFile(filePathName); + } + + ImGuiFileDialog::Instance()->Close(); + } +} + +void deviceRenderDraw() +{ + if (drawSamples) { + static std::vector buffer; + static std::vector bufferInput; + static auto bufferCirc = CircularBuffer(buffer); + static auto bufferInputCirc = CircularBuffer(bufferInput); + + static bool drawSamplesInput = false; + static unsigned int yMinMax = 4095; + + ImGui::Begin("draw", &drawSamples); + ImGui::Text("Draw input "); + ImGui::SameLine(); + if (ImGui::Checkbox("", &drawSamplesInput)) { + deviceSetInputDrawing(drawSamplesInput); + if (drawSamplesInput) { + bufferCirc.reset(2048); + bufferInputCirc.reset(2048); + } + } + ImGui::SameLine(); + ImGui::Text("Time: %0.3f sec", drawSamplesTimeframe); + ImGui::SameLine(); + if (ImGui::Button("-", {30, 0})) { + drawSamplesTimeframe = std::max(drawSamplesTimeframe / 2., 0.0078125); + deviceUpdateDrawBufferSize(drawSamplesTimeframe); + } + ImGui::SameLine(); + if (ImGui::Button("+", {30, 0})) { + drawSamplesTimeframe = std::min(drawSamplesTimeframe * 2, 32.); + deviceUpdateDrawBufferSize(drawSamplesTimeframe); + } + ImGui::SameLine(); + ImGui::Text("Y: +/-%1.2fV", 3.3f * (static_cast(yMinMax) / 4095.f)); + ImGui::SameLine(); + if (ImGui::Button(" - ", {30, 0})) { + yMinMax = std::max(63u, yMinMax >> 1); + } + ImGui::SameLine(); + if (ImGui::Button(" + ", {30, 0})) { + yMinMax = std::min(4095u, (yMinMax << 1) | 1); + } + + auto newSize = pullFromDrawQueue(bufferCirc); + if (newSize > 0) { + buffer.resize(newSize); + bufferCirc = CircularBuffer(buffer); + pullFromDrawQueue(bufferCirc); + } + + if (drawSamplesInput) { + auto newSize = pullFromInputDrawQueue(bufferInputCirc); + if (newSize > 0) { + bufferInput.resize(newSize); + bufferInputCirc = CircularBuffer(bufferInput); + pullFromInputDrawQueue(bufferInputCirc); + } + } + + auto drawList = ImGui::GetWindowDrawList(); + ImVec2 p0 = ImGui::GetWindowPos(); + auto size = ImGui::GetWindowSize(); + p0.y += 65; + size.y -= 70; + drawList->AddRectFilled(p0, {p0.x + size.x, p0.y + size.y}, IM_COL32_BLACK); + + const auto lcMinor = ImGui::GetColorU32(IM_COL32(40, 40, 40, 255)); + const auto lcMajor = ImGui::GetColorU32(IM_COL32(140, 140, 140, 255)); + + { + const float yinc = (3. / 3.3) * size.y / 12.f; + const float center = p0.y + size.y / 2; + drawList->AddLine({p0.x, center}, {p0.x + size.x, center}, ImGui::GetColorU32(IM_COL32_WHITE)); + for (int i = 1; i < 7; ++i) { + drawList->AddLine({p0.x, center + i * yinc}, {p0.x + size.x, center + i * yinc}, (i % 2) ? lcMinor : lcMajor); + drawList->AddLine({p0.x, center - i * yinc}, {p0.x + size.x, center - i * yinc}, (i % 2) ? lcMinor : lcMajor); + } + } + { + const float xinc = size.x / 16.f; + const float center = p0.x + size.x / 2; + drawList->AddLine({center, p0.y}, {center, p0.y + size.y}, ImGui::GetColorU32(IM_COL32_WHITE)); + for (int i = 1; i < 8; ++i) { + drawList->AddLine({center + i * xinc, p0.y}, {center + i * xinc, p0.y + size.y}, (i % 2) ? lcMinor : lcMajor); + drawList->AddLine({center - i * xinc, p0.y}, {center - i * xinc, p0.y + size.y}, (i % 2) ? lcMinor : lcMajor); + } + } + + const float di = static_cast(buffer.size()) / size.x; + const float dx = std::ceil(size.x / static_cast(buffer.size())); + ImVec2 pp = p0; + float i = 0; + while (pp.x < p0.x + size.x) { + unsigned int idx = i; + float n = std::clamp((buffer[idx] - 2048.) / yMinMax, -0.5, 0.5); + i += di; + + ImVec2 next (pp.x + dx, p0.y + size.y * (0.5 - n)); + drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(255, 0, 0, 255))); + pp = next; + } + + if (drawSamplesInput) { + ImVec2 pp = p0; + float i = 0; + while (pp.x < p0.x + size.x) { + unsigned int idx = i; + float n = std::clamp((bufferInput[idx] - 2048.) / yMinMax, -0.5, 0.5); + i += di; + + ImVec2 next (pp.x + dx, p0.y + size.y * (0.5 - n)); + drawList->AddLine(pp, next, ImGui::GetColorU32(IM_COL32(0, 0, 255, 255))); + pp = next; + } + } + + const auto mouse = ImGui::GetMousePos(); + if (mouse.x > p0.x && mouse.x < p0.x + size.x && + mouse.y > p0.y && mouse.y < p0.y + size.y) + { + char buf[16]; + drawList->AddLine({mouse.x, p0.y}, {mouse.x, p0.y + size.y}, IM_COL32(255, 255, 0, 255)); + + { + const std::size_t si = (mouse.x - p0.x) / size.x * buffer.size(); + const float s = buffer[si] / 4095.f * 6.6f - 3.3f; + snprintf(buf, sizeof(buf), " %1.3fV", s); + drawList->AddText(mouse, IM_COL32(255, 0, 0, 255), buf); + } + + if (drawSamplesInput) { + const std::size_t si = (mouse.x - p0.x) / size.x * bufferInput.size(); + const float s = bufferInput[si] / 4095.f * 6.6f - 3.3f; + snprintf(buf, sizeof(buf), " %1.3fV", s); + drawList->AddText({mouse.x, mouse.y + 20}, IM_COL32(0, 0, 255, 255), buf); + } + } + + ImGui::End(); + } +} + diff --git a/gui/source/gui_help.cpp b/gui/source/gui_help.cpp new file mode 100644 index 0000000..66ca955 --- /dev/null +++ b/gui/source/gui_help.cpp @@ -0,0 +1,124 @@ +/** + * @file gui_help.cpp + * @brief Defines the "Help" menu and provides its functionality. + * + * Copyright (C) 2022 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "imgui.h" +#include "ImGuiFileDialog.h" + +#include +#include +#include +#include + +void log(const std::string& str); + +static bool showDownloadFirmware = false; +static bool showHelp = false; +static std::string firmwareFile; + +static void helpDownloadThread(); + +void helpRenderMenu() +{ + if (ImGui::BeginMenu("Help")) { + if (ImGui::MenuItem("Open wiki...")) { +#ifdef STMDSP_WIN32 + system("start " +#else + system("xdg-open " +#endif + "https://code.bitgloo.com/clyne/stmdspgui/wiki"); + } + + if (ImGui::MenuItem("Download firmware...")) { + showDownloadFirmware = true; + } + + ImGui::Separator(); + if (ImGui::MenuItem("About")) { + showHelp = true; + } + + ImGui::EndMenu(); + } +} + +void helpRenderDialog() +{ + if (showDownloadFirmware) { + showDownloadFirmware = false; + ImGuiFileDialog::Instance()->OpenDialog( + "ChooseFileFW", "Choose Firmware File", ".hex", ".", 1, nullptr, ImGuiFileDialogFlags_Modal); + } + + if (ImGuiFileDialog::Instance()->Display("ChooseFileFW", + ImGuiWindowFlags_NoCollapse, + ImVec2(460, 540))) + { + if (ImGuiFileDialog::Instance()->IsOk()) { + firmwareFile = ImGuiFileDialog::Instance()->GetFilePathName(); +#ifdef STMDSP_WIN32 + size_t i = 0; + while ((i = firmwareFile.find('\\', i)) != std::string::npos) { + firmwareFile.replace(i, 1, "\\\\"); + i += 2; + } +#endif + + std::thread(helpDownloadThread).detach(); + } + + ImGuiFileDialog::Instance()->Close(); + } + + if (showHelp) { + ImGui::Begin("help"); + + ImGui::Text("stmdspgui\nCompiled on " __DATE__ ".\n\nWritten by Clyne Sullivan.\n"); + + if (ImGui::Button("Close")) { + showHelp = false; + } + + ImGui::End(); + } + + if (!firmwareFile.empty()) { + ImGui::Begin("Downloading"); + + ImGui::Text("Downloading firmware to device..."); + + ImGui::End(); + } +} + +void helpDownloadThread() +{ + std::string command ( +#ifdef STMDSP_WIN32 + "openocd\\bin\\openocd.exe" +#else + "openocd" +#endif + " -f openocd.cfg -c \"program $0 reset exit\""); + + command.replace(command.find("$0"), 2, firmwareFile); + + std::cout << "Run: " << command << std::endl; + + if (system(command.c_str()) == 0) { + log("Programming finished."); + } else { + log("Error while programming device!"); + } + + firmwareFile.clear(); +} + diff --git a/gui/source/gui_help.hpp b/gui/source/gui_help.hpp new file mode 100644 index 0000000..89c00ec --- /dev/null +++ b/gui/source/gui_help.hpp @@ -0,0 +1,19 @@ +/** + * @file gui_help.hpp + * @brief Defines the "Help" menu and provides its functionality. + * + * Copyright (C) 2022 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSPGUI_GUI_HELP +#define STMDSPGUI_GUI_HELP + +void helpRenderMenu(); +void helpRenderDialog(); + +#endif // STMDSPGUI_GUI_HELP + diff --git a/gui/source/imgui b/gui/source/imgui new file mode 160000 index 0000000..bc3c0ce --- /dev/null +++ b/gui/source/imgui @@ -0,0 +1 @@ +Subproject commit bc3c0ce7728f39530020a979a19bfc176e4e8596 diff --git a/gui/source/logview.cpp b/gui/source/logview.cpp new file mode 100644 index 0000000..5a771bf --- /dev/null +++ b/gui/source/logview.cpp @@ -0,0 +1,82 @@ +#include "logview.h" + +LogView::LogView() +{ + Clear(); +} + +void LogView::Clear() +{ + Buf.clear(); + LineOffsets.clear(); + LineOffsets.push_back(0); + updated = false; +} + +void LogView::AddLog(const std::string& str) +{ + AddLog(str.c_str()); +} + +void LogView::AddLog(const char* fmt, ...) +{ + int old_size = Buf.size(); + va_list args; + va_start(args, fmt); + Buf.appendfv(fmt, args); + Buf.appendfv("\n", args); + va_end(args); + for (int new_size = Buf.size(); old_size < new_size; old_size++) + if (Buf[old_size] == '\n') + LineOffsets.push_back(old_size + 1); + updated = true; +} + +void LogView::Draw(const char* title, bool* p_open, ImGuiWindowFlags flags) +{ + if (!ImGui::Begin(title, p_open, flags)) + { + ImGui::End(); + return; + } + + ImGui::Text("Log "); + ImGui::SameLine(ImGui::GetWindowWidth() - 120); + if (ImGui::Button("Clear")) + Clear(); + ImGui::SameLine(); + if (ImGui::Button("Copy")) + ImGui::LogToClipboard(); + ImGui::Separator(); + ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); + + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + const char* buf = Buf.begin(); + const char* buf_end = Buf.end(); + + ImGuiListClipper clipper; + clipper.Begin(LineOffsets.Size); + + while (clipper.Step()) + { + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + ImGui::TextUnformatted(line_start, line_end); + } + } + clipper.End(); + + ImGui::PopStyleVar(); + + if (updated) { + ImGui::SetScrollHereY(); + updated = false; + } + + ImGui::EndChild(); + ImGui::End(); +} + diff --git a/gui/source/logview.h b/gui/source/logview.h new file mode 100644 index 0000000..3c6acf1 --- /dev/null +++ b/gui/source/logview.h @@ -0,0 +1,26 @@ +#ifndef LOGVIEW_H +#define LOGVIEW_H + +#include + +#include "imgui.h" + +// Adapted from ExampleAppLog from imgui_demo.cpp +class LogView +{ +public: + LogView(); + + void Clear(); + void AddLog(const std::string& str); + void AddLog(const char* fmt, ...) IM_FMTARGS(2); + void Draw(const char* title, bool* p_open = NULL, ImGuiWindowFlags flags = 0); + +private: + ImGuiTextBuffer Buf; + ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. + bool updated; +}; + +#endif // LOGVIEW_H + diff --git a/gui/source/main.cpp b/gui/source/main.cpp new file mode 100644 index 0000000..83f40bd --- /dev/null +++ b/gui/source/main.cpp @@ -0,0 +1,148 @@ +/** + * @file main.cpp + * @brief Program entry point and main loop. + * + * Copyright (C) 2022 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "imgui.h" +#include "backends/imgui_impl_sdl2.h" +#include "backends/imgui_impl_opengl2.h" + +#include "gui_help.hpp" +#include "logview.h" +#include "main.hpp" +#include "stmdsp.hpp" + +#include +#include +#include +#include +#include + +void codeEditorInit(); +void codeRenderMenu(); +void codeRenderToolbar(); +void codeRenderWidgets(const ImVec2& size); +void deviceRenderDraw(); +void deviceRenderMenu(); +void deviceRenderToolbar(); +void deviceRenderWidgets(); +void fileRenderMenu(); +void fileRenderDialog(); +void fileInit(); +bool guiInitialize(); +bool guiHandleEvents(); +void guiShutdown(); +void guiRender(); + +static LogView logView; +static ImFont *fontSans = nullptr; +static ImFont *fontMono = nullptr; + +template +static void renderWindow(); + +int main(int, char **) +{ + if (!guiInitialize()) + return -1; + + auto& io = ImGui::GetIO(); + fontSans = io.Fonts->AddFontFromFileTTF("fonts/Roboto-Regular.ttf", 20); + fontMono = io.Fonts->AddFontFromFileTTF("fonts/RobotoMono-Regular.ttf", 20); + if (fontSans == nullptr || fontMono == nullptr) { + std::cout << "Failed to load fonts!" << std::endl; + return -1; + } + + codeEditorInit(); + fileInit(); + + renderWindow(); + + while (1) { + constexpr std::chrono::duration fpsDelay (1. / 60.); + const auto endTime = std::chrono::steady_clock::now() + fpsDelay; + + const bool isDone = guiHandleEvents(); + if (!isDone) { + renderWindow(); + std::this_thread::sleep_until(endTime); + } else { + break; + } + } + + guiShutdown(); + return 0; +} + +void log(const std::string& str) +{ + logView.AddLog(str); +} + +template +void renderWindow() +{ + // Start the new window frame and render the menu bar. + ImGui_ImplOpenGL2_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + + if (ImGui::BeginMainMenuBar()) { + fileRenderMenu(); + deviceRenderMenu(); + codeRenderMenu(); + helpRenderMenu(); + + ImGui::EndMainMenuBar(); + } + + if constexpr (first) { + ImGui::SetNextWindowSize({550, 440}); + } + + constexpr int MainTopMargin = 22; + const auto& displaySize = ImGui::GetIO().DisplaySize; + + ImGui::SetNextWindowPos({0, MainTopMargin}); + ImGui::SetNextWindowSizeConstraints({displaySize.x, 150}, {displaySize.x, displaySize.y - 150}); + ImGui::Begin("main", nullptr, + ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | + ImGuiWindowFlags_NoBringToFrontOnFocus); + + const float mainWindowHeight = ImGui::GetWindowHeight(); + + ImGui::PushFont(fontSans); + codeRenderToolbar(); + deviceRenderToolbar(); + fileRenderDialog(); + helpRenderDialog(); + deviceRenderWidgets(); + ImGui::PopFont(); + + ImGui::PushFont(fontMono); + codeRenderWidgets({displaySize.x - 16, mainWindowHeight - MainTopMargin - 24}); + ImGui::PopFont(); + + ImGui::End(); + + // The log window is kept separate from "main" to support panel resizing. + ImGui::PushFont(fontMono); + ImGui::SetNextWindowPos({0, mainWindowHeight + MainTopMargin}); + ImGui::SetNextWindowSize({displaySize.x, displaySize.y - mainWindowHeight - MainTopMargin}); + logView.Draw("log", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus); + ImGui::PopFont(); + + deviceRenderDraw(); + + // Draw everything to the screen. + guiRender(); +} + diff --git a/gui/source/main.hpp b/gui/source/main.hpp new file mode 100644 index 0000000..921d1ef --- /dev/null +++ b/gui/source/main.hpp @@ -0,0 +1,20 @@ +/** + * @file main.hpp + * @brief Common functions. + * + * Copyright (C) 2022 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSPGUI_MAIN_HPP +#define STMDSPGUI_MAIN_HPP + +#include + +void log(const std::string& str); + +#endif // STMDSPGUI_MAIN_HPP + diff --git a/gui/source/serial b/gui/source/serial new file mode 160000 index 0000000..69e0372 --- /dev/null +++ b/gui/source/serial @@ -0,0 +1 @@ +Subproject commit 69e0372cf0d3796e84ce9a09aff1d74496f68720 diff --git a/gui/source/stmdsp/stmdsp.cpp b/gui/source/stmdsp/stmdsp.cpp new file mode 100644 index 0000000..c50845f --- /dev/null +++ b/gui/source/stmdsp/stmdsp.cpp @@ -0,0 +1,331 @@ +/** + * @file stmdsp.cpp + * @brief Interface for communication with stmdsp device over serial. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#include "stmdsp.hpp" + +#include + +#include +#include + +extern void log(const std::string& str); + +std::array sampleRateInts {{ + 8'000, + 16'000, + 20'000, + 32'000, + 48'000, + 96'000 +}}; + +namespace stmdsp +{ + const std::forward_list& scanner::scan() + { + auto devices = serial::list_ports(); + auto foundDevicesEnd = std::remove_if( + devices.begin(), devices.end(), + [](const auto& dev) { + return dev.hardware_id.find(STMDSP_USB_ID) == std::string::npos; + }); + std::transform(devices.begin(), foundDevicesEnd, + std::front_inserter(m_available_devices), + [](const auto& dev) { return dev.port; }); + return m_available_devices; + } + + device::device(const std::string& file) + { + // This could throw! + // Note: Windows needs a not-simple, positive timeout like this to + // ensure that reads block. + m_serial.reset(new serial::Serial(file, 921'600 /*8'000'000*/, serial::Timeout(1000, 1000, 1, 1000, 1))); + + // Test the ID command. + m_serial->flush(); + m_serial->write("i"); + auto id = m_serial->read(7); + + if (id.starts_with("stmdsp")) { + if (id.back() == 'h') + m_platform = platform::H7; + else if (id.back() == 'l') + m_platform = platform::L4; + else + m_serial.release(); + } else { + m_serial.release(); + } + } + + device::~device() + { + disconnect(); + } + + bool device::connected() { + if (m_serial && !m_serial->isOpen()) + m_serial.release(); + + return m_serial ? true : false; + } + + void device::disconnect() { + if (m_serial) + m_serial.release(); + } + + bool device::try_command(std::basic_string cmd) { + bool success = false; + + if (connected()) { + try { + std::scoped_lock lock (m_lock); + m_serial->write(cmd.data(), cmd.size()); + success = true; + } catch (...) { + handle_disconnect(); + } + } + + return success; + } + + bool device::try_read(std::basic_string cmd, uint8_t *dest, unsigned int dest_size) { + bool success = false; + + if (connected() && dest && dest_size > 0) { + try { + std::scoped_lock lock (m_lock); + m_serial->write(cmd.data(), cmd.size()); + m_serial->read(dest, dest_size); + success = true; + } catch (...) { + handle_disconnect(); + } + } + + return success; + } + + void device::continuous_set_buffer_size(unsigned int size) { + if (try_command({ + 'B', + static_cast(size), + static_cast(size >> 8)})) + { + m_buffer_size = size; + } + } + + void device::set_sample_rate(unsigned int rate) { + auto it = std::find( + sampleRateInts.cbegin(), + sampleRateInts.cend(), + rate); + + if (it != sampleRateInts.cend()) { + const auto i = std::distance(sampleRateInts.cbegin(), it); + try_command({ + 'r', + static_cast(i) + }); + } + } + + unsigned int device::get_sample_rate() { + if (!is_running()) { + uint8_t result = 0xFF; + if (try_read({'r', 0xFF}, &result, 1)) + m_sample_rate = result; + } + + return m_sample_rate < sampleRateInts.size() ? + sampleRateInts[m_sample_rate] : + 0; + } + + void device::continuous_start() { + if (try_command({'R'})) + m_is_running = true; + } + + void device::measurement_start() { + try_command({'M'}); + } + + uint32_t device::measurement_read() { + uint32_t count = 0; + try_read({'m'}, reinterpret_cast(&count), sizeof(uint32_t)); + return count / 2; + } + + std::vector device::continuous_read() { + if (connected()) { + try { + m_serial->write("s"); + unsigned char sizebytes[2]; + m_serial->read(sizebytes, 2); + unsigned int size = sizebytes[0] | (sizebytes[1] << 8); + if (size > 0) { + std::vector data (size); + unsigned int total = size * sizeof(adcsample_t); + unsigned int offset = 0; + + while (total > 512) { + m_serial->read(reinterpret_cast(&data[0]) + offset, 512); + m_serial->write("n"); + offset += 512; + total -= 512; + } + m_serial->read(reinterpret_cast(&data[0]) + offset, total); + m_serial->write("n"); + return data; + + } + } catch (...) { + handle_disconnect(); + } + } + + return {}; + } + + std::vector device::continuous_read_input() { + if (connected()) { + try { + m_serial->write("t"); + unsigned char sizebytes[2]; + m_serial->read(sizebytes, 2); + unsigned int size = sizebytes[0] | (sizebytes[1] << 8); + if (size > 0) { + std::vector data (size); + unsigned int total = size * sizeof(adcsample_t); + unsigned int offset = 0; + + while (total > 512) { + m_serial->read(reinterpret_cast(&data[0]) + offset, 512); + m_serial->write("n"); + offset += 512; + total -= 512; + } + m_serial->read(reinterpret_cast(&data[0]) + offset, total); + m_serial->write("n"); + return data; + + } + } catch (...) { + handle_disconnect(); + } + } + + return {}; + } + + void device::continuous_stop() { + if (try_command({'S'})) + m_is_running = false; + } + + bool device::siggen_upload(dacsample_t *buffer, unsigned int size) { + if (connected()) { + uint8_t request[3] = { + 'D', + static_cast(size), + static_cast(size >> 8) + }; + + if (!m_is_siggening) { + try { + m_serial->write(request, 3); + m_serial->write((uint8_t *)buffer, size * sizeof(dacsample_t)); + } catch (...) { + handle_disconnect(); + } + } else { + try { + m_serial->write(request, 3); + if (m_serial->read(1)[0] == 0) + return false; + else + m_serial->write((uint8_t *)buffer, size * sizeof(dacsample_t)); + } catch (...) { + handle_disconnect(); + } + } + + return true; + } else { + return false; + } + } + + void device::siggen_start() { + if (try_command({'W'})) + m_is_siggening = true; + } + + void device::siggen_stop() { + if (try_command({'w'})) + m_is_siggening = false; + } + + void device::upload_filter(unsigned char *buffer, size_t size) { + if (connected()) { + uint8_t request[3] = { + 'E', + static_cast(size), + static_cast(size >> 8) + }; + + try { + m_serial->write(request, 3); + m_serial->write(buffer, size); + } catch (...) { + handle_disconnect(); + } + } + } + + void device::unload_filter() { + try_command({'e'}); + } + + std::pair device::get_status() { + std::pair ret; + + unsigned char buf[2]; + if (try_read({'I'}, buf, 2)) { + ret = { + static_cast(buf[0]), + static_cast(buf[1]) + }; + + bool running = ret.first == RunStatus::Running; + if (m_is_running != running) + m_is_running = running; + } else if (m_disconnect_error_flag) { + m_disconnect_error_flag = false; + return {RunStatus::Idle, Error::GUIDisconnect}; + } + + return ret; + } + + void device::handle_disconnect() + { + m_disconnect_error_flag = true; + m_serial.release(); + log("Lost connection!"); + } +} // namespace stmdsp + diff --git a/gui/source/stmdsp/stmdsp.hpp b/gui/source/stmdsp/stmdsp.hpp new file mode 100644 index 0000000..efed8a3 --- /dev/null +++ b/gui/source/stmdsp/stmdsp.hpp @@ -0,0 +1,166 @@ +/** + * @file stmdsp.hpp + * @brief Interface for communication with stmdsp device over serial. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_HPP_ +#define STMDSP_HPP_ + +#include + +#include +#include +#include +#include +#include +#include + +namespace stmdsp +{ + /** + * The largest possible size of an ADC or DAC sample buffer, as a sample count. + * Maximum byte size would be `SAMPLES_MAX * sizeof(XXXsample_t)`. + */ + constexpr unsigned int SAMPLES_MAX = 4096; + + /** + * ADC samples on all platforms are stored as 16-bit unsigned integers. + */ + using adcsample_t = uint16_t; + /** + * DAC samples on all platforms are stored as 16-bit unsigned integers. + */ + using dacsample_t = uint16_t; + + /** + * List of all available platforms. + * Note that some platforms in this list may not have complete support. + */ + enum class platform { + Unknown, + H7, /* Some feature support */ + L4, /* Complete feature support */ + G4 /* Unsupported, but planned */ + }; + + /** + * Run status states, valued to match what the stmdsp firmware reports. + */ + enum class RunStatus : char { + Idle = '1', /* Device ready for commands or execution. */ + Running, /* Device currently executing its algorithm. */ + Recovering /* Device recovering from fault caused by algorithm. */ + }; + + /** + * Error messages that are reported by the firmware. + */ + enum class Error : char { + None = 0, + BadParam, /* An invalid parameter was passed for a command. */ + BadParamSize, /* An invaild param. size was given for a command. */ + BadUserCodeLoad, /* Device failed to load the given algorithm. */ + BadUserCodeSize, /* The given algorithm is too large for the device. */ + NotIdle, /* An idle-only command was received while not Idle. */ + ConversionAborted, /* A conversion was aborted due to a fault. */ + NotRunning, /* A running-only command was received while not Running. */ + + GUIDisconnect = 100 /* The GUI lost connection with the device. */ + }; + + /** + * Provides functionality to scan the system for stmdsp devices. + * A list of devices is returned, though the GUI only interacts with one + * device at a time. + */ + class scanner + { + public: + /** + * Scans for connected devices, returning a list of ports with + * connected stmdsp devices. + */ + const std::forward_list& scan(); + + /** + * Retrieves the results of the last scan(). + */ + const std::forward_list& devices() const noexcept { + return m_available_devices; + } + + private: + constexpr static const char *STMDSP_USB_ID = +#ifndef STMDSP_WIN32 + "USB VID:PID=0483:5740"; +#else + "USB\\VID_0483&PID_5740"; +#endif + + std::forward_list m_available_devices; + }; + + class device + { + public: + device(const std::string& file); + ~device(); + + bool connected(); + void disconnect(); + + auto get_platform() const { return m_platform; } + + void continuous_set_buffer_size(unsigned int size); + unsigned int get_buffer_size() const { return m_buffer_size; } + + void set_sample_rate(unsigned int rate); + unsigned int get_sample_rate(); + + void continuous_start(); + void continuous_stop(); + + void measurement_start(); + uint32_t measurement_read(); + + std::vector continuous_read(); + std::vector continuous_read_input(); + + bool siggen_upload(dacsample_t *buffer, unsigned int size); + void siggen_start(); + void siggen_stop(); + + bool is_siggening() const { return m_is_siggening; } + bool is_running() const { return m_is_running; } + + // buffer is ELF binary + void upload_filter(unsigned char *buffer, size_t size); + void unload_filter(); + + std::pair get_status(); + + private: + std::unique_ptr m_serial; + platform m_platform = platform::Unknown; + unsigned int m_buffer_size = SAMPLES_MAX; + unsigned int m_sample_rate = 0; + bool m_is_siggening = false; + bool m_is_running = false; + bool m_disconnect_error_flag = false; + + std::mutex m_lock; + + bool try_command(std::basic_string data); + bool try_read(std::basic_string cmd, uint8_t *dest, unsigned int dest_size); + void handle_disconnect(); + }; +} + +#endif // STMDSP_HPP_ + diff --git a/gui/source/stmdsp/stmdsp_code.hpp b/gui/source/stmdsp/stmdsp_code.hpp new file mode 100644 index 0000000..7ba0ed2 --- /dev/null +++ b/gui/source/stmdsp/stmdsp_code.hpp @@ -0,0 +1,199 @@ +/** + * @file stmdsp_code.hpp + * @brief Source code and build scripts for stmdsp device algorithms. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef STMDSP_CODE_HPP +#define STMDSP_CODE_HPP + +#ifdef STMDSP_WIN32 +#define NEWLINE "\r\n" +#define COPY "copy" +#else +#define NEWLINE "\n" +#define COPY "cp" +#endif + +namespace stmdsp { + +// $0 = temp file name +// TODO try -ffunction-sections -fdata-sections -Wl,--gc-sections +static std::string makefile_text_h7 = +#ifdef STMDSP_WIN32 + "echo off" NEWLINE +#endif + "arm-none-eabi-g++ -x c++ -Os -std=c++20 -fno-exceptions -fno-rtti " + "-mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-d16 -mtune=cortex-m7 " + "-nostartfiles " + "-Wl,-Ttext-segment=0x00000000 -Wl,-zmax-page-size=512 -Wl,-eprocess_data_entry " + "$0 -o $0.o" NEWLINE + COPY " $0.o $0.orig.o" NEWLINE + "arm-none-eabi-strip -s -S --strip-unneeded $0.o" NEWLINE + "arm-none-eabi-objcopy --remove-section .ARM.attributes " + "--remove-section .comment " + "--remove-section .noinit " + "$0.o" NEWLINE + "arm-none-eabi-size $0.o" NEWLINE; +static std::string makefile_text_l4 = +#ifdef STMDSP_WIN32 + "echo off" NEWLINE +#endif + "arm-none-eabi-g++ -x c++ -Os -std=c++20 -fno-exceptions -fno-rtti " + "-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mtune=cortex-m4 " + "-nostartfiles -I$1/cmsis " + "-Wl,-Ttext-segment=0x10000000 -Wl,-zmax-page-size=512 -Wl,-eprocess_data_entry " + "$0 -o $0.o" NEWLINE + COPY " $0.o $0.orig.o" NEWLINE + "arm-none-eabi-strip -s -S --strip-unneeded $0.o" NEWLINE + "arm-none-eabi-objcopy --remove-section .ARM.attributes " + "--remove-section .comment " + "--remove-section .noinit " + "$0.o" NEWLINE + "arm-none-eabi-size $0.o" NEWLINE; + +// $0 = buffer size +static std::string file_header_h7 = R"cpp( +#include +#include + +using Sample = uint16_t; +using Samples = std::span; + +Sample *process_data(Samples samples); +extern "C" void process_data_entry() +{ + Sample *samples; + asm("mov %0, r0" : "=r" (samples)); + process_data(Samples(samples, $0)); +} + +static double PI = 3.14159265358979323846L; +__attribute__((naked)) +auto sin(double x) { +asm("vmov.f64 r1, r2, d0;" + "eor r0, r0;" + "svc 1;" + "vmov.f64 d0, r1, r2;" + "bx lr"); +return 0; +} +__attribute__((naked)) +auto cos(double x) { +asm("vmov.f64 r1, r2, d0;" + "mov r0, #1;" + "svc 1;" + "vmov.f64 d0, r1, r2;" + "bx lr"); +return 0; +} +__attribute__((naked)) +auto tan(double x) { +asm("vmov.f64 r1, r2, d0;" + "mov r0, #2;" + "svc 1;" + "vmov.f64 d0, r1, r2;" + "bx lr"); +return 0; +} +__attribute__((naked)) +auto sqrt(double x) { +asm("vsqrt.f64 d0, d0; bx lr"); +return 0; +} + +auto readalt() { +Sample s; +asm("svc 3; mov %0, r0" : "=&r"(s)); +return s; +} + +// End stmdspgui header code + +)cpp"; +static std::string file_header_l4 = R"cpp( +#include + +using Sample = uint16_t; +using Samples = Sample[$0]; +constexpr unsigned int SIZE = $0; + +Sample *process_data(Samples samples); +extern "C" void process_data_entry() +{ + Sample *samples; + asm("mov %0, r0" : "=r" (samples)); + process_data(samples); +} + +static inline float PI = 3.14159265358979L; +__attribute__((naked)) +static inline auto sin(float x) { + asm("vmov.f32 r1, s0;" + "eor r0, r0;" + "svc 1;" + "vmov.f32 s0, r1;" + "bx lr"); + return 0; +} +__attribute__((naked)) +static inline auto cos(float x) { + asm("vmov.f32 r1, s0;" + "mov r0, #1;" + "svc 1;" + "vmov.f32 s0, r1;" + "bx lr"); + return 0; +} +__attribute__((naked)) +static inline auto tan(float x) { + asm("vmov.f32 r1, s0;" + "mov r0, #2;" + "svc 1;" + "vmov.f32 s0, r1;" + "bx lr"); + return 0; +} +__attribute__((naked)) +static inline auto sqrt(float) { + asm("vsqrt.f32 s0, s0; bx lr"); + return 0; +} + +static inline auto param1() { + Sample s; + asm("eor r0, r0; svc 3; mov %0, r0" : "=r" (s) :: "r0"); + return s; +} +static inline auto param2() { + Sample s; + asm("mov r0, #1; svc 3; mov %0, r0" : "=r" (s) :: "r0"); + return s; +} + +//static inline void puts(const char *s) { +// // 's' will already be in r0. +// asm("push {r4-r6}; svc 4; pop {r4-r6}"); +//} + +// End stmdspgui header code + +)cpp"; + + +static std::string file_content = +R"cpp(Sample* process_data(Samples samples) +{ + return samples; +} +)cpp"; + +} // namespace stmdsp + +#endif // STMDSP_CODE_HPP + diff --git a/gui/source/wav.hpp b/gui/source/wav.hpp new file mode 100644 index 0000000..e20776a --- /dev/null +++ b/gui/source/wav.hpp @@ -0,0 +1,97 @@ +#ifndef WAV_HPP_ +#define WAV_HPP_ + +#include +#include +#include +#include +#include + +namespace wav +{ + struct header { + char riff[4]; // "RIFF" + uint32_t filesize; // Total file size minus eight bytes + char wave[4]; // "WAVE" + + bool valid() const { + return strncmp(riff, "RIFF", 4) == 0 && filesize > 8 && strncmp(wave, "WAVE", 4) == 0; + } + } __attribute__ ((packed)); + + struct format { + char fmt_[4]; // "fmt " + uint32_t size; + uint16_t type; + uint16_t channelcount; + uint32_t samplerate; + uint32_t byterate; + uint16_t unused; + uint16_t bps; + + bool valid() const { + return strncmp(fmt_, "fmt ", 4) == 0; + } + } __attribute__ ((packed)); + + struct data { + char data[4]; // "data" + uint32_t size; + + bool valid() const { + return strncmp(data, "data", 4) == 0; + } + } __attribute__ ((packed)); + + class clip { + public: + clip(const std::string& path) { + std::ifstream file (path); + if (!file.good()) + return; + { + header h; + file.read(reinterpret_cast(&h), sizeof(header)); + if (!h.valid()) + return; + } + { + format f; + file.read(reinterpret_cast(&f), sizeof(format)); + if (!f.valid() || f.type != 1) // ensure PCM + return; + } + { + wav::data d; + file.read(reinterpret_cast(&d), sizeof(wav::data)); + if (!d.valid()) + return; + m_data.resize(d.size / sizeof(int16_t)); + m_next = m_data.begin(); + file.read(reinterpret_cast(m_data.data()), d.size); + } + } + clip() = default; + + bool valid() const { + return !m_data.empty(); + } + const int16_t *data() const { + return m_data.data(); + } + void next(int16_t *buf, unsigned int size) { + for (unsigned int i = 0; i < size; ++i) { + if (m_next == m_data.end()) + m_next = m_data.begin(); + else + *buf++ = *m_next++; + } + } + private: + std::vector m_data; + decltype(m_data.begin()) m_next; + }; +} + +#endif // WAV_HPP_ + diff --git a/hardware/DSP PAW add-on board.kicad_pro b/hardware/DSP PAW add-on board.kicad_pro new file mode 100755 index 0000000..bb1726d --- /dev/null +++ b/hardware/DSP PAW add-on board.kicad_pro @@ -0,0 +1,352 @@ +{ + "board": { + "3dviewports": [], + "design_settings": { + "defaults": { + "board_outline_line_width": 0.1, + "copper_line_width": 0.2, + "copper_text_size_h": 1.5, + "copper_text_size_v": 1.5, + "copper_text_thickness": 0.3, + "other_line_width": 0.15, + "silk_line_width": 0.15, + "silk_text_size_h": 1.0, + "silk_text_size_v": 1.0, + "silk_text_thickness": 0.15 + }, + "diff_pair_dimensions": [], + "drc_exclusions": [], + "rules": { + "min_copper_edge_clearance": 0.0, + "solder_mask_clearance": 0.0, + "solder_mask_min_width": 0.0 + }, + "track_widths": [], + "via_dimensions": [] + }, + "layer_presets": [], + "viewports": [] + }, + "boards": [], + "cvpcb": { + "equivalence_files": [] + }, + "erc": { + "erc_exclusions": [ + "power_pin_not_driven|2184400|939800|a4e547a7-29d8-439d-b01e-1a601ce2877f|00000000-0000-0000-0000-000000000000|||", + "power_pin_not_driven|2387600|1104900|d93ff3db-bdfb-4d71-83ae-9eb3adbc430b|00000000-0000-0000-0000-000000000000|||", + "power_pin_not_driven|838200|660400|17dc7a2c-d6c1-4236-91fa-2b37d621dec2|00000000-0000-0000-0000-000000000000|||" + ], + "meta": { + "version": 0 + }, + "pin_map": [ + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 2 + ], + [ + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 1, + 1, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2 + ], + [ + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2 + ], + [ + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 2 + ], + [ + 0, + 2, + 1, + 2, + 0, + 0, + 1, + 0, + 2, + 2, + 2, + 2 + ], + [ + 0, + 2, + 0, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2 + ], + [ + 0, + 2, + 1, + 1, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2 + ], + [ + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2 + ] + ], + "rule_severities": { + "bus_definition_conflict": "error", + "bus_entry_needed": "error", + "bus_to_bus_conflict": "error", + "bus_to_net_conflict": "error", + "conflicting_netclasses": "error", + "different_unit_footprint": "error", + "different_unit_net": "error", + "duplicate_reference": "error", + "duplicate_sheet_names": "error", + "endpoint_off_grid": "warning", + "extra_units": "error", + "global_label_dangling": "warning", + "hier_label_mismatch": "error", + "label_dangling": "error", + "lib_symbol_issues": "warning", + "missing_bidi_pin": "warning", + "missing_input_pin": "warning", + "missing_power_pin": "error", + "missing_unit": "warning", + "multiple_net_names": "warning", + "net_not_bus_member": "warning", + "no_connect_connected": "warning", + "no_connect_dangling": "warning", + "pin_not_connected": "error", + "pin_not_driven": "error", + "pin_to_pin": "error", + "power_pin_not_driven": "error", + "similar_labels": "warning", + "simulation_model_issue": "error", + "unannotated": "error", + "unit_value_mismatch": "error", + "unresolved_variable": "error", + "wire_dangling": "error" + } + }, + "libraries": { + "pinned_footprint_libs": [], + "pinned_symbol_libs": [] + }, + "meta": { + "filename": "DSP PAW add-on board.kicad_pro", + "version": 1 + }, + "net_settings": { + "classes": [ + { + "bus_width": 12, + "clearance": 0.2, + "diff_pair_gap": 0.25, + "diff_pair_via_gap": 0.25, + "diff_pair_width": 0.2, + "line_style": 0, + "microvia_diameter": 0.3, + "microvia_drill": 0.1, + "name": "Default", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "schematic_color": "rgba(0, 0, 0, 0.000)", + "track_width": 0.25, + "via_diameter": 0.8, + "via_drill": 0.4, + "wire_width": 6 + } + ], + "meta": { + "version": 3 + }, + "net_colors": null, + "netclass_assignments": null, + "netclass_patterns": [] + }, + "pcbnew": { + "last_paths": { + "gencad": "", + "idf": "", + "netlist": "", + "specctra_dsn": "", + "step": "", + "vrml": "" + }, + "page_layout_descr_file": "" + }, + "schematic": { + "annotate_start_num": 0, + "drawing": { + "dashed_lines_dash_length_ratio": 12.0, + "dashed_lines_gap_length_ratio": 3.0, + "default_line_thickness": 6.0, + "default_text_size": 50.0, + "field_names": [], + "intersheets_ref_own_page": false, + "intersheets_ref_prefix": "", + "intersheets_ref_short": false, + "intersheets_ref_show": false, + "intersheets_ref_suffix": "", + "junction_size_choice": 3, + "label_size_ratio": 0.375, + "pin_symbol_size": 25.0, + "text_offset_ratio": 0.15 + }, + "legacy_lib_dir": "", + "legacy_lib_list": [], + "meta": { + "version": 1 + }, + "net_format_name": "", + "page_layout_descr_file": "", + "plot_directory": "", + "spice_current_sheet_as_root": false, + "spice_external_command": "spice \"%I\"", + "spice_model_current_sheet_as_root": true, + "spice_save_all_currents": false, + "spice_save_all_voltages": false, + "subpart_first_id": 65, + "subpart_id_separator": 0 + }, + "sheets": [ + [ + "c291319b-d76e-4fda-91cc-061acff65f9f", + "" + ], + [ + "684072e7-f538-4528-bfb8-b14c31b5b1f0", + "Analog IO" + ], + [ + "97fc232a-dbc7-49da-a6a0-e33e9aacbabd", + "Power regulation" + ], + [ + "270d19d2-3af2-41db-ad1c-33373417ec82", + "Board connectors" + ], + [ + "7798c5d5-f9b1-4b2e-811c-a15abcd34bfa", + "User IO" + ] + ], + "text_variables": {} +} diff --git a/hardware/DSP PAW add-on board.kicad_sch b/hardware/DSP PAW add-on board.kicad_sch new file mode 100755 index 0000000..d6edd69 --- /dev/null +++ b/hardware/DSP PAW add-on board.kicad_sch @@ -0,0 +1,98 @@ +(kicad_sch (version 20230121) (generator eeschema) + + (uuid c291319b-d76e-4fda-91cc-061acff65f9f) + + (paper "A4") + + (title_block + (title "DSP PAW add-on board") + (date "2023-08-08") + (company "bitgloo") + (comment 1 "Released under the CERN Open Hardware Licence Version 2 - Strongly Reciprocal") + ) + + (lib_symbols + ) + + + (sheet (at 25.4 76.2) (size 50.8 12.7) (fields_autoplaced) + (stroke (width 0.1524) (type solid)) + (fill (color 0 0 0 0.0000)) + (uuid 270d19d2-3af2-41db-ad1c-33373417ec82) + (property "Sheetname" "Board connectors" (at 25.4 75.4884 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + ) + (property "Sheetfile" "board_connectors.kicad_sch" (at 25.4 89.4846 0) + (effects (font (size 1.27 1.27)) (justify left top)) + ) + (property "Field2" "" (at 25.4 76.2 0) + (effects (font (size 1.27 1.27)) hide) + ) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" (page "4")) + ) + ) + ) + + (sheet (at 25.4 25.4) (size 50.8 12.7) (fields_autoplaced) + (stroke (width 0.1524) (type solid)) + (fill (color 0 0 0 0.0000)) + (uuid 684072e7-f538-4528-bfb8-b14c31b5b1f0) + (property "Sheetname" "Analog IO" (at 25.4 24.6884 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + ) + (property "Sheetfile" "analog_io.kicad_sch" (at 25.4 38.6846 0) + (effects (font (size 1.27 1.27)) (justify left top)) + ) + (property "Field2" "" (at 25.4 25.4 0) + (effects (font (size 1.27 1.27)) hide) + ) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" (page "2")) + ) + ) + ) + + (sheet (at 25.4 101.6) (size 50.8 12.7) (fields_autoplaced) + (stroke (width 0.1524) (type solid)) + (fill (color 0 0 0 0.0000)) + (uuid 7798c5d5-f9b1-4b2e-811c-a15abcd34bfa) + (property "Sheetname" "User IO" (at 25.4 100.8884 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + ) + (property "Sheetfile" "user_io.kicad_sch" (at 25.4 114.8846 0) + (effects (font (size 1.27 1.27)) (justify left top)) + ) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" (page "5")) + ) + ) + ) + + (sheet (at 25.4 50.8) (size 50.8 12.7) (fields_autoplaced) + (stroke (width 0.1524) (type solid)) + (fill (color 0 0 0 0.0000)) + (uuid 97fc232a-dbc7-49da-a6a0-e33e9aacbabd) + (property "Sheetname" "Power regulation" (at 25.4 50.0884 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + ) + (property "Sheetfile" "power_regulation.kicad_sch" (at 25.4 64.0846 0) + (effects (font (size 1.27 1.27)) (justify left top)) + ) + (property "Field2" "" (at 25.4 50.8 0) + (effects (font (size 1.27 1.27)) hide) + ) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" (page "3")) + ) + ) + ) + + (sheet_instances + (path "/" (page "1")) + ) +) diff --git a/hardware/DSP PAW add-on board.xml b/hardware/DSP PAW add-on board.xml new file mode 100755 index 0000000..5a26ecd --- /dev/null +++ b/hardware/DSP PAW add-on board.xml @@ -0,0 +1,1962 @@ + + + + /home/clyne/Documents/kicad/DSP PAW add-on board/DSP PAW add-on board.kicad_sch + Sat 22 Jul 2023 04:20:30 PM EDT + Eeschema 7.0.1 + + + + <company/> + <rev/> + <date/> + <source>DSP PAW add-on board.kicad_sch</source> + <comment number="1" value=""/> + <comment number="2" value=""/> + <comment number="3" value=""/> + <comment number="4" value=""/> + <comment number="5" value=""/> + <comment number="6" value=""/> + <comment number="7" value=""/> + <comment number="8" value=""/> + <comment number="9" value=""/> + </title_block> + </sheet> + <sheet number="2" name="/Analog IO/" tstamps="/684072e7-f538-4528-bfb8-b14c31b5b1f0/"> + <title_block> + <title>Analog signal conditioning + + + + analog_io.kicad_sch + + + + + + + + + + + + + + Power regulation + + + + power_regulation.kicad_sch + + + + + + + + + + + + + + Board connectors + + + + board_connectors.kicad_sch + + + + + + + + + + + + + + User I/O + + + + user_io.kicad_sch + + + + + + + + + + + + + + + 100p + Capacitor_SMD:C_0603_1608Metric + + CC0603KPX7R9BB101 + + + + + + + + + + 5f13d707-5314-4204-95ff-e7023dbf1390 + + + 10u + Capacitor_SMD:C_0805_2012Metric + + CL21A106KOQNNNE + + + + + + + + + + b7446dbf-b5bf-4307-9edc-e98dcd42c78d + + + 274p + Capacitor_SMD:C_0603_1608Metric + + CC0603KRX7R9BB271 + + + + + + + + + + 12a9fbfe-dee3-47f7-8a33-6ece0a6a5e21 + + + DNP + Capacitor_SMD:C_0603_1608Metric + + + + + + + + 88e74efe-ba6a-4380-a952-50b4a27eb246 + + + 105p + Capacitor_SMD:C_0603_1608Metric + + CC0603KPX7R9BB101 + + + + + + + + + + 63c2c207-40b2-47ce-b8a2-f9c77921a2b5 + + + 10u + Capacitor_SMD:C_0805_2012Metric + + CL21A106KOQNNNE + + + + + + + + + + b0bfe7db-09da-4802-8a23-6a20984ec23f + + + 100p + Capacitor_SMD:C_0603_1608Metric + + CC0603KPX7R9BB101 + + + + + + + + + + 623d4de9-4003-498d-bb94-d973ca58f06f + + + DNP + Capacitor_SMD:C_0603_1608Metric + + + + + + + + 4bd163bd-4e71-45f4-aa51-12c0c8894738 + + + 105p + Capacitor_SMD:C_0603_1608Metric + + CC0603KPX7R9BB101 + + + + + + + + + + eb3ad263-4383-4973-9b0c-7fde9947d384 + + + 10u + Capacitor_SMD:C_0805_2012Metric + + CL21A106KOQNNNE + + + + + + + + + + 99c91ccc-b2c3-4d6a-a11f-c11c2ab3496d + + + 100p + Capacitor_SMD:C_0603_1608Metric + + CC0603KPX7R9BB101 + + + + + + + + + + 77594052-576e-4ede-837c-0cea441b7b38 + + + DNP + Capacitor_SMD:C_0603_1608Metric + + + + + + + + 3ffe3182-5bf2-4df2-8625-80c9083156c0 + + + 9.09k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE079K09L + + + + + + + + + + f0ce9f99-0d2b-47ad-955e-a115d88f2423 + + + 10k/0.1% + Resistor_SMD:R_0603_1608Metric + + RN73R1JTTD1002B25 + + + + + + + + + + 77903c71-4695-45df-ae74-1ca7380bcb51 + + + 9.09k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE079K09L + + + + + + + + + + 22077614-3367-4e4d-93bb-9d3cc32003bf + + + 6.34k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE076K34L + + + + + + + + + + 68ea83d2-5dc0-4430-a711-4c94c4e55ef4 + + + 20k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE0720KL + + + + + + + + + + 09763a12-feda-48e1-afe9-d8a81a7439cb + + + 0 + Resistor_SMD:R_0603_1608Metric + + RMCF0603ZT0R00 + + + + + + + + + + b1cf4a1c-d6f7-46a0-8fae-ab2466b84cbc + + + 10k/0.1% + Resistor_SMD:R_0603_1608Metric + + RN73R1JTTD1002B25 + + + + + + + + + + c5790ffe-38a3-462e-88e9-7a0e67c0f3b4 + + + 22.1k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE0722K1L + + + + + + + + + + 95dedd7c-c752-4712-9aea-ee0143445b87 + + + 6.81k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE076K81L + + + + + + + + + + 2d0a2ddc-1a7a-4738-b65d-75dfc8aed08c + + + 0 + Resistor_SMD:R_0603_1608Metric + + RMCF0603ZT0R00 + + + + + + + + + + 6aab9e7e-b33f-47a1-8408-1806df557085 + + + 10k/0.1% + Resistor_SMD:R_0603_1608Metric + + RN73R1JTTD1002B25 + + + + + + + + + + a97dfe8c-7bb6-43dd-9b12-e26f02e8d594 + + + 2.49k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE072K49L + + + + + + + + + + 34e1c64c-0f60-433f-ae2a-8d2833c48e4f + + + 2.49k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE072K49L + + + + + + + + + + e9a26256-ad58-4b4e-aeb9-27b97c5cf7a4 + + + 22.1k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE0722K1L + + + + + + + + + + af2574b7-1459-4b58-a3e2-46c8e623030f + + + 6.81k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE076K81L + + + + + + + + + + 6de7c3e2-ccb1-4bda-b6b9-7e265de95076 + + + 0 + Resistor_SMD:R_0603_1608Metric + + RMCF0603ZT0R00 + + + + + + + + + + 95db5be2-27f2-47d0-bd88-021be9957d2d + + + 2.49k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE072K49L + + + + + + + + + + 0b777e25-6648-4258-86f0-5ac639e20017 + + + 2.49k + Resistor_SMD:R_0603_1608Metric + + RT0603DRE072K49L + + + + + + + + + + b79fe011-5fd4-4b0f-bb62-51fff45eb70a + + + TLV9162 + Package_SO:SOIC-8_3.9x4.9mm_P1.27mm + https://www.ti.com/lit/ds/symlink/tlv9162.pdf + + TLV9162IDR + + + + + + + + + + b7a8ee36-8943-426a-b182-3c32ea14e286 ada410a1-682d-4a65-a2fe-bdbaa9ec75fc 8c9bfe4c-5a4e-45a1-8b6a-8480aa78343e + + + OPA1678 + Package_SO:SOIC-8_3.9x4.9mm_P1.27mm + + ADA4001-2ARZ + + + + + + + + + + 4014b31a-906d-4e54-9260-18b76b511e9b 0d35ce54-c1cf-4a8a-ba3b-4486213d9285 0bba421f-7d3e-4e1e-9f66-4037ea1e27ad + + + 10n + Capacitor_SMD:C_0603_1608Metric + + CC0603KRX7R9BB103 + + + + + + + + + + f2d797f3-24bb-4aa5-ba81-171b8a49029e + + + 100n + Capacitor_SMD:C_0603_1608Metric + + CL10B104KB8NNWC + + + + + + + + + + a3e00720-9b71-4fec-8b36-e7a5cdc4ca07 + + + 4.7u + Capacitor_SMD:C_0603_1608Metric + + CL10A475KP8NNNC + + + + + + + + + + 98f2b9b9-6327-4bc8-b876-121d7ad6905e + + + 4.7u + Capacitor_SMD:C_0603_1608Metric + + CL10A475KP8NNNC + + + + + + + + + + 8f35c64f-1632-4c1b-b8fa-42e58819b677 + + + 1u + Capacitor_SMD:C_0603_1608Metric + + CL10B105KP8NNNC + + + + + + + + + + 219a1fe6-d5bc-49e5-ba83-808476b87bcb + + + 4.7u + Capacitor_SMD:C_0603_1608Metric + + CL10A475KP8NNNC + + + + + + + + + + 17e9eb2e-3859-4b1d-b315-52d3f5671c2b + + + 2.2u + Capacitor_SMD:C_0603_1608Metric + + CL10B225KP8NNNC + + + + + + + + + + 75cccab0-1f63-406c-b256-08197905c2d8 + + + 1u + Capacitor_SMD:C_0603_1608Metric + + CL10B105KP8NNNC + + + + + + + + + + 1dcdc424-fb22-42bf-8874-89ad7acc92ec + + + 4.7u + Capacitor_SMD:C_0603_1608Metric + + CL10A475KP8NNNC + + + + + + + + + + 5a538b70-0a4a-472f-85a3-5d86c644f91a + + + 33@100MHz + Inductor_SMD:L_0603_1608Metric + + BLM18PG330SN1D + + + + + + + + + + e1dbf950-0e9a-4d00-a47a-b30cf1090893 + + + 174k + Resistor_SMD:R_0603_1608Metric + + RMCF0603FT174K + + + + + + + + + + 4928232b-2208-4ba3-94a3-4f551edb95e6 + + + 0 + Resistor_SMD:R_0603_1608Metric + + RMCF0603ZT0R00 + + + + + + + + + + 8e04a020-c831-4020-a547-acddae80ca1b + + + 56k + Resistor_SMD:R_0603_1608Metric + + RMCF0603FT56K0 + + + + + + + + + + a1ea9e3c-6800-4e35-b5e2-cc7438c29b4e + + + TestPoint + TestPoint:TestPoint_Pad_D1.0mm + + + + + + + + 1362f62f-0013-4579-bfe3-657f3da88a4c + + + TestPoint + TestPoint:TestPoint_Pad_D1.0mm + + + + + + + + 6c19d262-a0fe-4278-9e4c-98da07eea5c9 + + + TestPoint + TestPoint:TestPoint_Pad_D1.0mm + + + + + + + + 9563d063-75b0-44ce-b3ce-3dcaef0a8a7b + + + TestPoint + TestPoint:TestPoint_Pad_D1.0mm + + + + + + + + 1e9bd7fc-0998-4613-aa5b-48cd00451144 + + + MAX6106 + Package_TO_SOT_SMD:SOT-23 + http://datasheets.maximintegrated.com/en/ds/MAX6100-MAX6107.pdf + + MAX6106EUR+T + + + + + + + + + + 2721a4bf-a486-4e4a-95f3-7833d023f203 + + + LM27761 + Package_SON:WSON-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mm + http://www.ti.com/lit/ds/symlink/lm27761.pdf + + LM27761DSGR + + + + + + + + + + ab5ba760-1b9a-48fc-8a36-c943d7f45f9f + + + ESD5Zxx + Diode_SMD:D_SOD-523 + https://www.onsemi.com/pdf/datasheet/esd5z2.5t1-d.pdf + + ESD5Z2.5T1G + + + + + + + + + + 50abfadf-fb6c-48a1-9415-dba8320ad18e + + + ESD5Zxx + Diode_SMD:D_SOD-523 + https://www.onsemi.com/pdf/datasheet/esd5z2.5t1-d.pdf + + ESD5Z2.5T1G + + + + + + + + + + 5dffc28c-19cd-4431-a7ba-b33bafb430ee + + + ESD5Zxx + Diode_SMD:D_SOD-523 + https://www.onsemi.com/pdf/datasheet/esd5z2.5t1-d.pdf + + ESD5Z2.5T1G + + + + + + + + + + 2fddc873-d43d-46d7-9c1a-d0acddc1a966 + + + DF2B7AFS,L3M + Diode_SMD:D_SOD-923 + https://www.onsemi.com/pub/Collateral/ESD9B-D.PDF + + DF2B7AFS,L3M + + + + + + + + + + 0dee484c-3850-4bfd-ac52-a058e497e313 + + + DF2B7AFS,L3M + Diode_SMD:D_SOD-923 + https://www.onsemi.com/pub/Collateral/ESD9B-D.PDF + + DF2B7AFS,L3M + + + + + + + + + + 2f36a1b8-dd88-4fdd-80cc-b6a7d1336b74 + + + DF2B7AFS,L3M + Diode_SMD:D_SOD-923 + https://www.onsemi.com/pub/Collateral/ESD9B-D.PDF + + DF2B7AFS,L3M + + + + + + + + + + d707892a-1c20-45ac-bb77-11891c2394e4 + + + AudioJack2_Ground + Connector_Audio:Jack_3.5mm_CUI_SJ-3523-SMT_Horizontal + + SJ-3523-SMT-TR + + + + + + + + + + 7694e2a6-3372-4fab-895b-9744296f2da7 + + + Conn_02x10_Odd_Even + Connector_PinHeader_2.54mm:PinHeader_2x10_P2.54mm_Vertical + + PPPC102LFBN-RC + + + + + + + + + + 8475bff6-cb36-4a34-84ec-774f48f03d90 + + + Conn_02x10_Odd_Even + Connector_PinHeader_2.54mm:PinHeader_2x10_P2.54mm_Vertical + + PPPC102LFBN-RC + + + + + + + + + + ec63f71a-7153-47f9-b86f-860fe7e45e10 + + + Conn_02x03_Odd_Even + Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_Horizontal + + PH2RA-06-UA + + + + + + + + + + de87bdea-3e5b-416f-bfb4-ea751dfca070 + + + AudioJack2_Ground + Connector_Audio:Jack_3.5mm_CUI_SJ-3523-SMT_Horizontal + + SJ-3523-SMT-TR + + + + + + + + + + 2f551abf-6373-4e81-b42b-ccb46e78a8d3 + + + Conn_02x10_Odd_Even + Connector_PinHeader_2.54mm:PinHeader_2x10_P2.54mm_Vertical + + PPPC102LFBN-RC + + + + + + + + + + 3c409af7-d0f8-44c1-a8e3-ea5a071f1b52 + + + AudioJack2_Ground + Connector_Audio:Jack_3.5mm_CUI_SJ-3523-SMT_Horizontal + + SJ-3523-SMT-TR + + + + + + + + + + 8ca59ac3-e703-4c21-a6a5-9119fbd2e6c2 + + + USB_B_Micro + Connector_USB:USB_Micro-B_Amphenol_10104110_Horizontal + + 10104110-0001LF + + + + + + + + + + 78555264-1178-42da-8282-385afceb94d8 + + + 0 + Resistor_SMD:R_0603_1608Metric + + RMCF0603ZT0R00 + + + + + + + + + + 9f0f3415-176c-4496-afca-6588b7686c1e + + + LED_RAGB + LED_SMD:LED_Kingbright_AAA3528ESGCT + + AAA3528SEEZGKQBKS + + + + + + + + + 9ec9653f-c3a4-41f7-9b1c-80cc24251ffe + + + 560 + Resistor_SMD:R_0603_1608Metric + + RC0603JR-07560RL + + + + + + + + + 63c4f82c-3aee-47eb-aaf9-4ff013fc8a40 + + + 240 + Resistor_SMD:R_0603_1608Metric + + RC0603JR-07240RL + + + + + + + + + 29f7e662-f721-4c3d-848d-61fc5171ba42 + + + 240 + Resistor_SMD:R_0603_1608Metric + + RC0603JR-07240RL + + + + + + + + + d04657bd-c6dc-4346-b2bd-fdac6c2c8be6 + + + 10K + Potentiometer_THT:Potentiometer_Bourns_3386P_Vertical + + 3386P-1-103TLF + + + + + + + + + f4a975b9-7021-410d-9761-44f0c502022e + + + 10K + Potentiometer_THT:Potentiometer_Bourns_3386P_Vertical + + 3386P-1-103TLF + + + + + + + + + 04ebdf1c-ac9d-479f-992a-1ea0aeec5c23 + + + + + Dual operational amplifier, 300 uV Offset, SOIC-8 + https://www.ti.com/lit/ds/symlink/tlv9062.pdf + + SOIC*3.9x4.9mm*P1.27mm* + + + U + TLV9062xD + Package_SO:SOIC-8_3.9x4.9mm_P1.27mm + https://www.ti.com/lit/ds/symlink/tlv9062.pdf + + + + + + + + + + + + + + test point + ~ + + Pin* + Test* + + + TP + TestPoint + ~ + + + + + + + USB Micro Type B connector + ~ + + USB* + + + J + USB_B_Micro + ~ + + + + + + + + + + + + Audio Jack, 2 Poles (Mono / TS), Grounded Sleeve + ~ + + Jack* + + + J + AudioJack2_Ground + ~ + + + + + + + + + Generic connector, double row, 02x03, odd/even pin numbering scheme (row 1 odd numbers, row 2 even numbers), script generated (kicad-library-utils/schlib/autogen/connector/) + ~ + + Connector*:*_2x??_* + + + J + Conn_02x03_Odd_Even + ~ + + + + + + + + + + + + Generic connector, double row, 02x10, odd/even pin numbering scheme (row 1 odd numbers, row 2 even numbers), script generated (kicad-library-utils/schlib/autogen/connector/) + ~ + + Connector*:*_2x??_* + + + J + Conn_02x10_Odd_Even + ~ + + + + + + + + + + + + + + + + + + + + + + + + + + Unpolarized capacitor + ~ + + C_* + + + C + C + ~ + + + + + + + + Inductor + ~ + + Choke_* + *Coil* + Inductor_* + L_* + + + L + L + ~ + + + + + + + + RGB LED, red/anode/green/blue + ~ + + LED* + LED_SMD:* + LED_THT:* + + + D + LED_RAGB + ~ + + + + + + + + + + Potentiometer, US symbol + ~ + + Potentiometer* + + + RV + R_Potentiometer_US + ~ + + + + + + + + + Resistor, US symbol + ~ + + R_* + + + R + R_US + ~ + + + + + + + + ESD Protection Diode, SOD-523 + https://www.onsemi.com/pdf/datasheet/esd5z2.5t1-d.pdf + + D?SOD?523* + + + D + ESD5Zxx + Diode_SMD:D_SOD-523 + https://www.onsemi.com/pdf/datasheet/esd5z2.5t1-d.pdf + + + + + + + + ESD protection diode, 5.0Vrwm, SOD-923 + https://www.onsemi.com/pub/Collateral/ESD9B-D.PDF + + D*SOD?923* + + + D + ESD9B5.0ST5G + Diode_SMD:D_SOD-923 + https://www.onsemi.com/pub/Collateral/ESD9B-D.PDF + + + + + + + + Low-dropout high current voltage reference, 2.048V, ±0.4% accuracy, SOT-23 + http://datasheets.maximintegrated.com/en/ds/MAX6100-MAX6107.pdf + + SOT?23* + + + U + MAX6106 + Package_TO_SOT_SMD:SOT-23 + http://datasheets.maximintegrated.com/en/ds/MAX6100-MAX6107.pdf + + + + + + + + + low-noise regulated switched-capacitor voltage inverter with 2.7V-5.5V input to -1.5 to -5V Output Voltage, WSON-8 + http://www.ti.com/lit/ds/symlink/lm27761.pdf + + WSON*1EP?2x2mm*P0.5mm* + + + U + LM27761 + Package_SON:WSON-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mm + http://www.ti.com/lit/ds/symlink/lm27761.pdf + + + + + + + + + + + + + + + + + /usr/share/kicad/symbols//Amplifier_Operational.kicad_sym + + + /usr/share/kicad/symbols//Connector.kicad_sym + + + /usr/share/kicad/symbols//Connector_Audio.kicad_sym + + + /usr/share/kicad/symbols//Connector_Generic.kicad_sym + + + /usr/share/kicad/symbols//Device.kicad_sym + + + /usr/share/kicad/symbols//Diode.kicad_sym + + + /usr/share/kicad/symbols//Reference_Voltage.kicad_sym + + + /usr/share/kicad/symbols//Regulator_SwitchedCapacitor.kicad_sym + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hardware/LICENSE b/hardware/LICENSE new file mode 100644 index 0000000..364c873 --- /dev/null +++ b/hardware/LICENSE @@ -0,0 +1,290 @@ +CERN Open Hardware Licence Version 2 - Strongly Reciprocal + + +Preamble + +CERN has developed this licence to promote collaboration among +hardware designers and to provide a legal tool which supports the +freedom to use, study, modify, share and distribute hardware designs +and products based on those designs. Version 2 of the CERN Open +Hardware Licence comes in three variants: CERN-OHL-P (permissive); and +two reciprocal licences: CERN-OHL-W (weakly reciprocal) and this +licence, CERN-OHL-S (strongly reciprocal). + +The CERN-OHL-S is copyright CERN 2020. Anyone is welcome to use it, in +unmodified form only. + +Use of this Licence does not imply any endorsement by CERN of any +Licensor or their designs nor does it imply any involvement by CERN in +their development. + + +1 Definitions + + 1.1 'Licence' means this CERN-OHL-S. + + 1.2 'Compatible Licence' means + + a) any earlier version of the CERN Open Hardware licence, or + + b) any version of the CERN-OHL-S, or + + c) any licence which permits You to treat the Source to which + it applies as licensed under CERN-OHL-S provided that on + Conveyance of any such Source, or any associated Product You + treat the Source in question as being licensed under + CERN-OHL-S. + + 1.3 'Source' means information such as design materials or digital + code which can be applied to Make or test a Product or to + prepare a Product for use, Conveyance or sale, regardless of its + medium or how it is expressed. It may include Notices. + + 1.4 'Covered Source' means Source that is explicitly made available + under this Licence. + + 1.5 'Product' means any device, component, work or physical object, + whether in finished or intermediate form, arising from the use, + application or processing of Covered Source. + + 1.6 'Make' means to create or configure something, whether by + manufacture, assembly, compiling, loading or applying Covered + Source or another Product or otherwise. + + 1.7 'Available Component' means any part, sub-assembly, library or + code which: + + a) is licensed to You as Complete Source under a Compatible + Licence; or + + b) is available, at the time a Product or the Source containing + it is first Conveyed, to You and any other prospective + licensees + + i) as a physical part with sufficient rights and + information (including any configuration and + programming files and information about its + characteristics and interfaces) to enable it either to + be Made itself, or to be sourced and used to Make the + Product; or + ii) as part of the normal distribution of a tool used to + design or Make the Product. + + 1.8 'Complete Source' means the set of all Source necessary to Make + a Product, in the preferred form for making modifications, + including necessary installation and interfacing information + both for the Product, and for any included Available Components. + If the format is proprietary, it must also be made available in + a format (if the proprietary tool can create it) which is + viewable with a tool available to potential licensees and + licensed under a licence approved by the Free Software + Foundation or the Open Source Initiative. Complete Source need + not include the Source of any Available Component, provided that + You include in the Complete Source sufficient information to + enable a recipient to Make or source and use the Available + Component to Make the Product. + + 1.9 'Source Location' means a location where a Licensor has placed + Covered Source, and which that Licensor reasonably believes will + remain easily accessible for at least three years for anyone to + obtain a digital copy. + + 1.10 'Notice' means copyright, acknowledgement and trademark notices, + Source Location references, modification notices (subsection + 3.3(b)) and all notices that refer to this Licence and to the + disclaimer of warranties that are included in the Covered + Source. + + 1.11 'Licensee' or 'You' means any person exercising rights under + this Licence. + + 1.12 'Licensor' means a natural or legal person who creates or + modifies Covered Source. A person may be a Licensee and a + Licensor at the same time. + + 1.13 'Convey' means to communicate to the public or distribute. + + +2 Applicability + + 2.1 This Licence governs the use, copying, modification, Conveying + of Covered Source and Products, and the Making of Products. By + exercising any right granted under this Licence, You irrevocably + accept these terms and conditions. + + 2.2 This Licence is granted by the Licensor directly to You, and + shall apply worldwide and without limitation in time. + + 2.3 You shall not attempt to restrict by contract or otherwise the + rights granted under this Licence to other Licensees. + + 2.4 This Licence is not intended to restrict fair use, fair dealing, + or any other similar right. + + +3 Copying, Modifying and Conveying Covered Source + + 3.1 You may copy and Convey verbatim copies of Covered Source, in + any medium, provided You retain all Notices. + + 3.2 You may modify Covered Source, other than Notices, provided that + You irrevocably undertake to make that modified Covered Source + available from a Source Location should You Convey a Product in + circumstances where the recipient does not otherwise receive a + copy of the modified Covered Source. In each case subsection 3.3 + shall apply. + + You may only delete Notices if they are no longer applicable to + the corresponding Covered Source as modified by You and You may + add additional Notices applicable to Your modifications. + Including Covered Source in a larger work is modifying the + Covered Source, and the larger work becomes modified Covered + Source. + + 3.3 You may Convey modified Covered Source (with the effect that You + shall also become a Licensor) provided that You: + + a) retain Notices as required in subsection 3.2; + + b) add a Notice to the modified Covered Source stating that You + have modified it, with the date and brief description of how + You have modified it; + + c) add a Source Location Notice for the modified Covered Source + if You Convey in circumstances where the recipient does not + otherwise receive a copy of the modified Covered Source; and + + d) license the modified Covered Source under the terms and + conditions of this Licence (or, as set out in subsection + 8.3, a later version, if permitted by the licence of the + original Covered Source). Such modified Covered Source must + be licensed as a whole, but excluding Available Components + contained in it, which remain licensed under their own + applicable licences. + + +4 Making and Conveying Products + +You may Make Products, and/or Convey them, provided that You either +provide each recipient with a copy of the Complete Source or ensure +that each recipient is notified of the Source Location of the Complete +Source. That Complete Source is Covered Source, and You must +accordingly satisfy Your obligations set out in subsection 3.3. If +specified in a Notice, the Product must visibly and securely display +the Source Location on it or its packaging or documentation in the +manner specified in that Notice. + + +5 Research and Development + +You may Convey Covered Source, modified Covered Source or Products to +a legal entity carrying out development, testing or quality assurance +work on Your behalf provided that the work is performed on terms which +prevent the entity from both using the Source or Products for its own +internal purposes and Conveying the Source or Products or any +modifications to them to any person other than You. Any modifications +made by the entity shall be deemed to be made by You pursuant to +subsection 3.2. + + +6 DISCLAIMER AND LIABILITY + + 6.1 DISCLAIMER OF WARRANTY -- The Covered Source and any Products + are provided 'as is' and any express or implied warranties, + including, but not limited to, implied warranties of + merchantability, of satisfactory quality, non-infringement of + third party rights, and fitness for a particular purpose or use + are disclaimed in respect of any Source or Product to the + maximum extent permitted by law. The Licensor makes no + representation that any Source or Product does not or will not + infringe any patent, copyright, trade secret or other + proprietary right. The entire risk as to the use, quality, and + performance of any Source or Product shall be with You and not + the Licensor. This disclaimer of warranty is an essential part + of this Licence and a condition for the grant of any rights + granted under this Licence. + + 6.2 EXCLUSION AND LIMITATION OF LIABILITY -- The Licensor shall, to + the maximum extent permitted by law, have no liability for + direct, indirect, special, incidental, consequential, exemplary, + punitive or other damages of any character including, without + limitation, procurement of substitute goods or services, loss of + use, data or profits, or business interruption, however caused + and on any theory of contract, warranty, tort (including + negligence), product liability or otherwise, arising in any way + in relation to the Covered Source, modified Covered Source + and/or the Making or Conveyance of a Product, even if advised of + the possibility of such damages, and You shall hold the + Licensor(s) free and harmless from any liability, costs, + damages, fees and expenses, including claims by third parties, + in relation to such use. + + +7 Patents + + 7.1 Subject to the terms and conditions of this Licence, each + Licensor hereby grants to You a perpetual, worldwide, + non-exclusive, no-charge, royalty-free, irrevocable (except as + stated in subsections 7.2 and 8.4) patent licence to Make, have + Made, use, offer to sell, sell, import, and otherwise transfer + the Covered Source and Products, where such licence applies only + to those patent claims licensable by such Licensor that are + necessarily infringed by exercising rights under the Covered + Source as Conveyed by that Licensor. + + 7.2 If You institute patent litigation against any entity (including + a cross-claim or counterclaim in a lawsuit) alleging that the + Covered Source or a Product constitutes direct or contributory + patent infringement, or You seek any declaration that a patent + licensed to You under this Licence is invalid or unenforceable + then any rights granted to You under this Licence shall + terminate as of the date such process is initiated. + + +8 General + + 8.1 If any provisions of this Licence are or subsequently become + invalid or unenforceable for any reason, the remaining + provisions shall remain effective. + + 8.2 You shall not use any of the name (including acronyms and + abbreviations), image, or logo by which the Licensor or CERN is + known, except where needed to comply with section 3, or where + the use is otherwise allowed by law. Any such permitted use + shall be factual and shall not be made so as to suggest any kind + of endorsement or implication of involvement by the Licensor or + its personnel. + + 8.3 CERN may publish updated versions and variants of this Licence + which it considers to be in the spirit of this version, but may + differ in detail to address new problems or concerns. New + versions will be published with a unique version number and a + variant identifier specifying the variant. If the Licensor has + specified that a given variant applies to the Covered Source + without specifying a version, You may treat that Covered Source + as being released under any version of the CERN-OHL with that + variant. If no variant is specified, the Covered Source shall be + treated as being released under CERN-OHL-S. The Licensor may + also specify that the Covered Source is subject to a specific + version of the CERN-OHL or any later version in which case You + may apply this or any later version of CERN-OHL with the same + variant identifier published by CERN. + + 8.4 This Licence shall terminate with immediate effect if You fail + to comply with any of its terms and conditions. + + 8.5 However, if You cease all breaches of this Licence, then Your + Licence from any Licensor is reinstated unless such Licensor has + terminated this Licence by giving You, while You remain in + breach, a notice specifying the breach and requiring You to cure + it within 30 days, and You have failed to come into compliance + in all material respects by the end of the 30 day period. Should + You repeat the breach after receipt of a cure notice and + subsequent reinstatement, this Licence will terminate + immediately and permanently. Section 6 shall continue to apply + after any termination. + + 8.6 This Licence shall not be enforceable except by a Licensor + acting as such, and third party beneficiary rights are + specifically excluded. + diff --git a/hardware/analog_io.kicad_sch b/hardware/analog_io.kicad_sch new file mode 100755 index 0000000..1320a55 --- /dev/null +++ b/hardware/analog_io.kicad_sch @@ -0,0 +1,2464 @@ +(kicad_sch (version 20230121) (generator eeschema) + + (uuid 441a9488-1fb7-4b51-b2c7-6d1e46b0a32c) + + (paper "A4") + + (title_block + (title "Analog signal transformation") + (date "2023-08-08") + (company "bitgloo") + (comment 1 "Released under the CERN Open Hardware Licence Version 2 - Strongly Reciprocal") + ) + + (lib_symbols + (symbol "Amplifier_Operational:TLV9062xD" (pin_names (offset 0.127)) (in_bom yes) (on_board yes) + (property "Reference" "U" (at 2.54 6.35 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "TLV9062xD" (at 2.54 3.81 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 2.54 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.ti.com/lit/ds/symlink/tlv9062.pdf" (at 6.35 3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_locked" "" (at 0 0 0) + (effects (font (size 1.27 1.27))) + ) + (property "ki_keywords" "dual op-amp low power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Dual operational amplifier, 300 uV Offset, SOIC-8" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "SOIC*3.9x4.9mm*P1.27mm*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "TLV9062xD_1_1" + (polyline + (pts + (xy 5.08 0) + (xy -5.08 5.08) + (xy -5.08 -5.08) + (xy 5.08 0) + ) + (stroke (width 0.254) (type default)) + (fill (type background)) + ) + (pin output line (at 7.62 0 180) (length 2.54) + (name "~" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at -7.62 -2.54 0) (length 2.54) + (name "-" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at -7.62 2.54 0) (length 2.54) + (name "+" (effects (font (size 1.27 1.27)))) + (number "3" (effects (font (size 1.27 1.27)))) + ) + ) + (symbol "TLV9062xD_2_1" + (polyline + (pts + (xy 5.08 0) + (xy -5.08 5.08) + (xy -5.08 -5.08) + (xy 5.08 0) + ) + (stroke (width 0.254) (type default)) + (fill (type background)) + ) + (pin input line (at -7.62 2.54 0) (length 2.54) + (name "+" (effects (font (size 1.27 1.27)))) + (number "5" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at -7.62 -2.54 0) (length 2.54) + (name "-" (effects (font (size 1.27 1.27)))) + (number "6" (effects (font (size 1.27 1.27)))) + ) + (pin output line (at 7.62 0 180) (length 2.54) + (name "~" (effects (font (size 1.27 1.27)))) + (number "7" (effects (font (size 1.27 1.27)))) + ) + ) + (symbol "TLV9062xD_3_1" + (pin power_in line (at 0 -7.62 90) (length 3.81) + (name "V-" (effects (font (size 1.27 1.27)))) + (number "4" (effects (font (size 1.27 1.27)))) + ) + (pin power_in line (at 0 7.62 270) (length 3.81) + (name "V+" (effects (font (size 1.27 1.27)))) + (number "8" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Device:C" (pin_numbers hide) (pin_names (offset 0.254)) (in_bom yes) (on_board yes) + (property "Reference" "C" (at 0.635 2.54 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "C" (at 0.635 -2.54 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "" (at 0.9652 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "cap capacitor" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Unpolarized capacitor" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "C_*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "C_0_1" + (polyline + (pts + (xy -2.032 -0.762) + (xy 2.032 -0.762) + ) + (stroke (width 0.508) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -2.032 0.762) + (xy 2.032 0.762) + ) + (stroke (width 0.508) (type default)) + (fill (type none)) + ) + ) + (symbol "C_1_1" + (pin passive line (at 0 3.81 270) (length 2.794) + (name "~" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 0 -3.81 90) (length 2.794) + (name "~" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Device:R_US" (pin_numbers hide) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "R" (at 2.54 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "R_US" (at -2.54 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 1.016 -0.254 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "R res resistor" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Resistor, US symbol" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "R_*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "R_US_0_1" + (polyline + (pts + (xy 0 -2.286) + (xy 0 -2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.286) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 -0.762) + (xy 1.016 -1.143) + (xy 0 -1.524) + (xy -1.016 -1.905) + (xy 0 -2.286) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0.762) + (xy 1.016 0.381) + (xy 0 0) + (xy -1.016 -0.381) + (xy 0 -0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.286) + (xy 1.016 1.905) + (xy 0 1.524) + (xy -1.016 1.143) + (xy 0 0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "R_US_1_1" + (pin passive line (at 0 3.81 270) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 0 -3.81 90) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:+5V" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 0 3.556 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"+5V\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "+5V_0_1" + (polyline + (pts + (xy -0.762 1.27) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0.762 1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "+5V_1_1" + (pin power_in line (at 0 0 90) (length 0) hide + (name "+5V" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:-5V" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 2.54 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "-5V" (at 0 3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"-5V\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "-5V_0_0" + (pin power_in line (at 0 0 90) (length 0) hide + (name "-5V" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + (symbol "-5V_0_1" + (polyline + (pts + (xy 0 0) + (xy 0 1.27) + (xy 0.762 1.27) + (xy 0 2.54) + (xy -0.762 1.27) + (xy 0 1.27) + ) + (stroke (width 0) (type default)) + (fill (type outline)) + ) + ) + ) + (symbol "power:GND" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -6.35 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 0 -3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"GND\" , ground" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "GND_0_1" + (polyline + (pts + (xy 0 0) + (xy 0 -1.27) + (xy 1.27 -1.27) + (xy 0 -2.54) + (xy -1.27 -1.27) + (xy 0 -1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "GND_1_1" + (pin power_in line (at 0 0 270) (length 0) hide + (name "GND" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:VDDA" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VDDA" (at 0 3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"VDDA\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "VDDA_0_1" + (polyline + (pts + (xy -0.762 1.27) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0.762 1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "VDDA_1_1" + (pin power_in line (at 0 0 90) (length 0) hide + (name "VDDA" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + ) + + + (junction (at 76.2 160.02) (diameter 0) (color 0 0 0 0) + (uuid 13ca57e4-cb64-4610-8602-f6b3b79b4e4d) + ) + (junction (at 96.52 173.99) (diameter 0) (color 0 0 0 0) + (uuid 14baa294-32e6-4d79-933f-f598a3401be8) + ) + (junction (at 254 101.6) (diameter 0) (color 0 0 0 0) + (uuid 1cec0460-226d-417d-8a64-e91e92531e84) + ) + (junction (at 77.47 45.72) (diameter 0) (color 0 0 0 0) + (uuid 2a686120-7c2b-40a8-94b4-ff352bbed22c) + ) + (junction (at 97.79 104.14) (diameter 0) (color 0 0 0 0) + (uuid 544a1e6d-0eba-425e-a387-613fa5a3e4ba) + ) + (junction (at 102.87 104.14) (diameter 0) (color 0 0 0 0) + (uuid 555b2ed8-b23d-4699-90af-9ec06e3f7c9d) + ) + (junction (at 77.47 106.68) (diameter 0) (color 0 0 0 0) + (uuid 58b50289-d890-4170-b5db-23a006184ec8) + ) + (junction (at 100.33 45.72) (diameter 0) (color 0 0 0 0) + (uuid 643fd8e9-3057-4bb3-beab-7b64665cb158) + ) + (junction (at 149.86 57.15) (diameter 0) (color 0 0 0 0) + (uuid 6a4a19a7-5df2-44f4-ae40-75dd293319a0) + ) + (junction (at 54.61 106.68) (diameter 0) (color 0 0 0 0) + (uuid 6a4bb706-dcc5-4872-b86b-74860967c0eb) + ) + (junction (at 128.27 54.61) (diameter 0) (color 0 0 0 0) + (uuid 6d4eb889-ecae-423b-aa28-b01041e96c3e) + ) + (junction (at 97.79 120.65) (diameter 0) (color 0 0 0 0) + (uuid 7505d28d-42d4-4141-ba06-8adb7fd6091d) + ) + (junction (at 101.6 157.48) (diameter 0) (color 0 0 0 0) + (uuid 771dbe8c-e2bc-40e6-b3f9-d246824bbc97) + ) + (junction (at 100.33 57.15) (diameter 0) (color 0 0 0 0) + (uuid 792fbb65-a6d1-41e2-9ca9-0934048113bc) + ) + (junction (at 77.47 54.61) (diameter 0) (color 0 0 0 0) + (uuid bb0f3e97-91ef-4c38-b0d6-996ae4d77785) + ) + (junction (at 53.34 160.02) (diameter 0) (color 0 0 0 0) + (uuid cd0dc2f5-2bbf-4407-89b7-12f64f275e27) + ) + (junction (at 96.52 157.48) (diameter 0) (color 0 0 0 0) + (uuid dd48d0dc-1a30-4855-b672-b884e88b6f39) + ) + (junction (at 59.69 54.61) (diameter 0) (color 0 0 0 0) + (uuid e8de15ad-a3c1-43d2-99e8-9736cc4fc0a7) + ) + + (wire (pts (xy 128.27 54.61) (xy 115.57 54.61)) + (stroke (width 0) (type default)) + (uuid 01cbda64-51ea-4b25-ac59-1d6840aad4d0) + ) + (wire (pts (xy 57.15 160.02) (xy 53.34 160.02)) + (stroke (width 0) (type default)) + (uuid 079a36ff-c903-46d1-8586-80db49aeb9e6) + ) + (wire (pts (xy 161.29 57.15) (xy 167.64 57.15)) + (stroke (width 0) (type default)) + (uuid 0907e7f6-3ca3-4104-92e1-e21d7d590578) + ) + (wire (pts (xy 129.54 157.48) (xy 133.35 157.48)) + (stroke (width 0) (type default)) + (uuid 0b8ac979-0d2f-4d8e-876a-825807fd8b0d) + ) + (wire (pts (xy 140.97 157.48) (xy 147.32 157.48)) + (stroke (width 0) (type default)) + (uuid 0cdab281-29ae-4e6d-a0db-cfce77096b35) + ) + (wire (pts (xy 55.88 54.61) (xy 59.69 54.61)) + (stroke (width 0) (type default)) + (uuid 0e00d3ac-ddd2-4c17-96ae-a390318f8524) + ) + (wire (pts (xy 147.32 57.15) (xy 149.86 57.15)) + (stroke (width 0) (type default)) + (uuid 11a2874e-6279-4dbb-a9f4-e378690f94f9) + ) + (wire (pts (xy 77.47 106.68) (xy 77.47 120.65)) + (stroke (width 0) (type default)) + (uuid 172bca92-63fe-4e66-b337-8afca1343ca7) + ) + (wire (pts (xy 119.38 176.53) (xy 119.38 173.99)) + (stroke (width 0) (type default)) + (uuid 18a12969-71e9-4591-ab64-9501b7c7aea4) + ) + (wire (pts (xy 100.33 34.29) (xy 100.33 45.72)) + (stroke (width 0) (type default)) + (uuid 199b0b32-87e1-41fa-8a26-ab433d22b54c) + ) + (wire (pts (xy 43.18 54.61) (xy 48.26 54.61)) + (stroke (width 0) (type default)) + (uuid 1deb107f-8ee6-4f20-a7c8-042735521459) + ) + (wire (pts (xy 142.24 104.14) (xy 148.59 104.14)) + (stroke (width 0) (type default)) + (uuid 1eaa98a8-10c5-4362-a75a-a97f64524926) + ) + (wire (pts (xy 77.47 106.68) (xy 77.47 91.44)) + (stroke (width 0) (type default)) + (uuid 20cbc10b-171f-4139-8623-6865fae119fb) + ) + (wire (pts (xy 97.79 104.14) (xy 102.87 104.14)) + (stroke (width 0) (type default)) + (uuid 2343068f-d79f-46b4-a982-0ae2aa0b6572) + ) + (wire (pts (xy 81.28 59.69) (xy 77.47 59.69)) + (stroke (width 0) (type default)) + (uuid 27ed1140-35fa-4731-8aec-ac4042413c80) + ) + (wire (pts (xy 96.52 157.48) (xy 96.52 144.78)) + (stroke (width 0) (type default)) + (uuid 2b43fe7c-7845-416f-8391-db903b4d546f) + ) + (wire (pts (xy 85.09 45.72) (xy 77.47 45.72)) + (stroke (width 0) (type default)) + (uuid 30e1940d-ac9d-43c2-81ac-84544cdb94f8) + ) + (wire (pts (xy 254 101.6) (xy 254 105.41)) + (stroke (width 0) (type default)) + (uuid 3a7a3d64-783e-4d0f-b8a7-8c496426d4b0) + ) + (wire (pts (xy 102.87 104.14) (xy 102.87 105.41)) + (stroke (width 0) (type default)) + (uuid 43cc69c6-d118-438d-96a2-1216d8d001c0) + ) + (wire (pts (xy 58.42 106.68) (xy 54.61 106.68)) + (stroke (width 0) (type default)) + (uuid 45dbe678-c722-4305-a559-ff5e89421c47) + ) + (wire (pts (xy 53.34 160.02) (xy 53.34 162.56)) + (stroke (width 0) (type default)) + (uuid 4ae0d717-a858-4543-bfc5-8c7b7900bf45) + ) + (wire (pts (xy 50.8 106.68) (xy 54.61 106.68)) + (stroke (width 0) (type default)) + (uuid 4bb92711-010f-4110-b584-dbb65656d05c) + ) + (wire (pts (xy 101.6 157.48) (xy 109.22 157.48)) + (stroke (width 0) (type default)) + (uuid 4f1cbd2b-3712-4e94-908b-3c622c1d113d) + ) + (wire (pts (xy 54.61 106.68) (xy 54.61 109.22)) + (stroke (width 0) (type default)) + (uuid 50d53083-32d0-4e43-bb1c-db7ffa29e205) + ) + (wire (pts (xy 115.57 54.61) (xy 115.57 57.15)) + (stroke (width 0) (type default)) + (uuid 53357090-105c-4c23-8dd4-63f08b386d13) + ) + (wire (pts (xy 97.79 120.65) (xy 110.49 120.65)) + (stroke (width 0) (type default)) + (uuid 5ab35d18-5d5b-4512-94bd-a49e2e37830b) + ) + (wire (pts (xy 64.77 160.02) (xy 76.2 160.02)) + (stroke (width 0) (type default)) + (uuid 5c49ebf4-8114-4eb0-a400-cdac65114eee) + ) + (wire (pts (xy 77.47 120.65) (xy 83.82 120.65)) + (stroke (width 0) (type default)) + (uuid 6077e6f2-98f5-4c34-808b-f6b0dd2c0444) + ) + (wire (pts (xy 76.2 173.99) (xy 82.55 173.99)) + (stroke (width 0) (type default)) + (uuid 650ed807-9c2c-4baa-b8ea-e63fc4119580) + ) + (wire (pts (xy 76.2 160.02) (xy 76.2 144.78)) + (stroke (width 0) (type default)) + (uuid 67dc7098-e276-4138-849e-4b96f0b1965c) + ) + (wire (pts (xy 101.6 157.48) (xy 101.6 158.75)) + (stroke (width 0) (type default)) + (uuid 67ea9d8e-8189-4ba9-afce-bf2c8312a8cc) + ) + (wire (pts (xy 130.81 104.14) (xy 134.62 104.14)) + (stroke (width 0) (type default)) + (uuid 6a560e8c-0e2b-490c-9653-6c5a6fdf1375) + ) + (wire (pts (xy 66.04 106.68) (xy 77.47 106.68)) + (stroke (width 0) (type default)) + (uuid 6c98525b-07a3-45f7-9586-6b91565c4d74) + ) + (wire (pts (xy 120.65 123.19) (xy 120.65 120.65)) + (stroke (width 0) (type default)) + (uuid 6f1ddcec-373c-4ff2-88dd-04c55517ae10) + ) + (wire (pts (xy 76.2 144.78) (xy 82.55 144.78)) + (stroke (width 0) (type default)) + (uuid 74feeb8c-fdbc-41c1-b6e4-36ac971e1557) + ) + (wire (pts (xy 77.47 34.29) (xy 77.47 45.72)) + (stroke (width 0) (type default)) + (uuid 75de3747-8d55-43a5-9329-d60e1ab39780) + ) + (wire (pts (xy 96.52 173.99) (xy 109.22 173.99)) + (stroke (width 0) (type default)) + (uuid 796ceed9-5299-4e1b-aa41-b75e2a020bdd) + ) + (wire (pts (xy 167.64 60.96) (xy 167.64 57.15)) + (stroke (width 0) (type default)) + (uuid 7cc7f718-00da-4907-a8d4-eb46ec038edd) + ) + (wire (pts (xy 49.53 160.02) (xy 53.34 160.02)) + (stroke (width 0) (type default)) + (uuid 824b6317-5ee3-4183-b962-d579a52e061c) + ) + (wire (pts (xy 96.52 162.56) (xy 96.52 173.99)) + (stroke (width 0) (type default)) + (uuid 884a34e6-2bea-4fdc-958d-5138593702ff) + ) + (wire (pts (xy 93.98 157.48) (xy 96.52 157.48)) + (stroke (width 0) (type default)) + (uuid 885f3c93-e1e0-4b2b-87a7-c08fa48987bf) + ) + (wire (pts (xy 119.38 173.99) (xy 116.84 173.99)) + (stroke (width 0) (type default)) + (uuid 8a2cb018-f384-4d62-bc58-f2683c0d87c6) + ) + (wire (pts (xy 149.86 57.15) (xy 153.67 57.15)) + (stroke (width 0) (type default)) + (uuid 9096db32-8a77-44b2-97f3-b225f83e7059) + ) + (wire (pts (xy 100.33 45.72) (xy 100.33 57.15)) + (stroke (width 0) (type default)) + (uuid 9103dbf4-8ff6-4fca-a83f-418fe22abf47) + ) + (wire (pts (xy 149.86 45.72) (xy 149.86 57.15)) + (stroke (width 0) (type default)) + (uuid 9129b90c-9c2a-4842-9dbd-455d7423abb8) + ) + (wire (pts (xy 254 101.6) (xy 257.81 101.6)) + (stroke (width 0) (type default)) + (uuid 9270bc15-18a9-43e0-82b5-a8011bc79f6b) + ) + (wire (pts (xy 95.25 104.14) (xy 97.79 104.14)) + (stroke (width 0) (type default)) + (uuid 93633cde-6fce-4d19-8109-d32c96972d19) + ) + (wire (pts (xy 96.52 57.15) (xy 100.33 57.15)) + (stroke (width 0) (type default)) + (uuid 9586f1e7-8a81-40e2-9b64-ccae75882ffd) + ) + (wire (pts (xy 59.69 54.61) (xy 59.69 58.42)) + (stroke (width 0) (type default)) + (uuid 958f6745-de05-4545-baa6-d06abc9ea9f4) + ) + (wire (pts (xy 96.52 157.48) (xy 101.6 157.48)) + (stroke (width 0) (type default)) + (uuid 96340d5e-a21a-4826-88b9-e6d475d8fe6f) + ) + (wire (pts (xy 120.65 120.65) (xy 118.11 120.65)) + (stroke (width 0) (type default)) + (uuid 97985406-fa08-49fb-b550-7287a3f657f2) + ) + (wire (pts (xy 76.2 160.02) (xy 78.74 160.02)) + (stroke (width 0) (type default)) + (uuid 9816a452-9e75-4958-bf35-daf6efb3e319) + ) + (wire (pts (xy 96.52 144.78) (xy 90.17 144.78)) + (stroke (width 0) (type default)) + (uuid a6ed5323-2af3-45c5-9615-75e24477cbcd) + ) + (wire (pts (xy 77.47 54.61) (xy 81.28 54.61)) + (stroke (width 0) (type default)) + (uuid a82847a6-0562-4e43-a56f-20758a032215) + ) + (wire (pts (xy 132.08 54.61) (xy 128.27 54.61)) + (stroke (width 0) (type default)) + (uuid ae499b69-7960-47f4-94b1-868442379983) + ) + (wire (pts (xy 77.47 106.68) (xy 80.01 106.68)) + (stroke (width 0) (type default)) + (uuid b008c5f1-2061-4c18-8d4b-e961b69c6221) + ) + (wire (pts (xy 77.47 59.69) (xy 77.47 66.04)) + (stroke (width 0) (type default)) + (uuid b5179481-c40d-4aba-81ac-d8bc98db2d31) + ) + (wire (pts (xy 254 97.79) (xy 254 101.6)) + (stroke (width 0) (type default)) + (uuid b6e25c05-a4e6-43d1-bf57-78c397010090) + ) + (wire (pts (xy 111.76 57.15) (xy 115.57 57.15)) + (stroke (width 0) (type default)) + (uuid b7b2cf01-8da6-449f-b4bc-514b9df7d393) + ) + (wire (pts (xy 118.11 104.14) (xy 123.19 104.14)) + (stroke (width 0) (type default)) + (uuid b7f886b9-0859-40d9-a3f6-a6683c341740) + ) + (wire (pts (xy 95.25 109.22) (xy 97.79 109.22)) + (stroke (width 0) (type default)) + (uuid b87dbe6c-b5ab-47e7-894b-ab3611a3eefa) + ) + (wire (pts (xy 100.33 57.15) (xy 104.14 57.15)) + (stroke (width 0) (type default)) + (uuid b914df1b-aa28-44c7-8708-9ca845805cb6) + ) + (wire (pts (xy 85.09 34.29) (xy 77.47 34.29)) + (stroke (width 0) (type default)) + (uuid bb98d78f-4922-43c1-a016-24830e3d6d64) + ) + (wire (pts (xy 128.27 45.72) (xy 128.27 54.61)) + (stroke (width 0) (type default)) + (uuid bdb7fa6e-cbee-42f3-b15c-5af443eb5580) + ) + (wire (pts (xy 77.47 91.44) (xy 83.82 91.44)) + (stroke (width 0) (type default)) + (uuid c51f3e45-8fee-4484-87df-75ac220f37c5) + ) + (wire (pts (xy 116.84 157.48) (xy 121.92 157.48)) + (stroke (width 0) (type default)) + (uuid c804f2eb-852b-4d46-91ae-670d149a2864) + ) + (wire (pts (xy 93.98 162.56) (xy 96.52 162.56)) + (stroke (width 0) (type default)) + (uuid cf31c0ab-f87c-4f7d-85c3-0c7e17c95ace) + ) + (wire (pts (xy 71.12 54.61) (xy 77.47 54.61)) + (stroke (width 0) (type default)) + (uuid d032f367-c762-4ba9-969e-73f235ff53ea) + ) + (wire (pts (xy 102.87 104.14) (xy 110.49 104.14)) + (stroke (width 0) (type default)) + (uuid d636a217-cad9-421a-9f13-39961341ebe9) + ) + (wire (pts (xy 77.47 45.72) (xy 77.47 54.61)) + (stroke (width 0) (type default)) + (uuid df123dd8-4923-452a-b8da-4665d45f61ca) + ) + (wire (pts (xy 92.71 34.29) (xy 100.33 34.29)) + (stroke (width 0) (type default)) + (uuid e7407b15-7fe3-441d-a571-d716631a2b1d) + ) + (wire (pts (xy 91.44 120.65) (xy 97.79 120.65)) + (stroke (width 0) (type default)) + (uuid e75622b7-18c9-4e5b-82b3-f0cf29de6416) + ) + (wire (pts (xy 97.79 104.14) (xy 97.79 91.44)) + (stroke (width 0) (type default)) + (uuid efaa7f19-342f-4d8c-aee7-b09fdc7dad93) + ) + (wire (pts (xy 97.79 109.22) (xy 97.79 120.65)) + (stroke (width 0) (type default)) + (uuid efed7f9a-c25b-4b12-8502-09c4399ba710) + ) + (wire (pts (xy 90.17 173.99) (xy 96.52 173.99)) + (stroke (width 0) (type default)) + (uuid f0f48c9a-12ee-4367-aa73-0abefbe73bf0) + ) + (wire (pts (xy 135.89 45.72) (xy 128.27 45.72)) + (stroke (width 0) (type default)) + (uuid f1b8a59d-2d22-4be3-b9aa-ef59f0e4cf6f) + ) + (wire (pts (xy 59.69 54.61) (xy 63.5 54.61)) + (stroke (width 0) (type default)) + (uuid f328d5ec-77b5-43e3-81c3-1bc3673a2a4e) + ) + (wire (pts (xy 143.51 45.72) (xy 149.86 45.72)) + (stroke (width 0) (type default)) + (uuid f33d5a85-b58e-4315-b793-98019259497c) + ) + (wire (pts (xy 97.79 91.44) (xy 91.44 91.44)) + (stroke (width 0) (type default)) + (uuid fe09fbec-243b-4a4a-8ce9-d5dbb2f125ae) + ) + (wire (pts (xy 76.2 160.02) (xy 76.2 173.99)) + (stroke (width 0) (type default)) + (uuid fed811b4-edf5-42fd-b3c2-d12f670345bb) + ) + (wire (pts (xy 92.71 45.72) (xy 100.33 45.72)) + (stroke (width 0) (type default)) + (uuid ffb2af50-256e-4a32-82aa-87c6bfb25395) + ) + + (text "Cancel DC offset" (at 31.75 60.96 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 0c255578-cbec-4af6-8a8f-914b2a4af8a6) + ) + (text "2nd-order low-pass Bessel filter\nFc = 100kHz, G = 2\nnon-inverting (Sallen-Key)" + (at 102.87 91.44 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 11759ad9-6dd7-41a3-871a-342ee2b5fb5b) + ) + (text "Operational amplifier options:\n - TLV9162: Good for input, low GBW for output\n - OPA1678: Good for output, low stock\n - TL972: Good balance as choice for both (12MHz)\n - MC33078D: Also a good choice for both (15MHz)\n\nInput requires GBW between 8-15MHz; output requires >14.7MHz" + (at 209.55 53.34 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 1298cbaa-a693-47ae-987b-082155ee1893) + ) + (text "Low-pass RC filter\nto increase drop beyond Fc" (at 154.94 48.26 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 187aacc2-0fff-498f-ae6b-86d2f27b6642) + ) + (text "2nd-order low-pass Bessel filter\nFc = 100kHz, G = 1\ninverting (MFB)" + (at 38.1 38.1 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 2db69c83-1c30-4290-876e-1ab4e087452c) + ) + (text "Cancel DC offset" (at 129.54 162.56 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 2ddab52d-e5d5-4b55-99a7-4b82b0d74488) + ) + (text "Cancel DC offset" (at 130.81 109.22 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 4d37f2a9-553f-44c3-88e8-f0b7f0eb294f) + ) + (text "Inverting amplifier\nG = 0.5, Offset = 1V\n0-2V output for MCU" + (at 110.49 38.1 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 7ff24ca8-45ac-404e-b354-ab2d4f4a4a56) + ) + (text "Signal generator output" (at 15.875 134.62 0) + (effects (font (size 2.54 2.54)) (justify left bottom)) + (uuid a8262b1a-df9c-4ba8-9de2-e1e787ef16d3) + ) + (text "2nd-order low-pass Bessel filter\nFc = 100kHz, G = 2\nnon-inverting (Sallen-Key)" + (at 101.6 144.78 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid b339f83c-48d6-4510-8f56-d7e7635e2b35) + ) + (text "Low-pass RC filter\nto increase drop beyond Fc" (at 66.04 97.79 0) + (effects (font (size 1.27 1.27)) (justify right bottom)) + (uuid b359bad7-cd76-42ef-96c0-69d394af2379) + ) + (text "Input signal" (at 15.875 26.67 0) + (effects (font (size 2.54 2.54)) (justify left bottom)) + (uuid b564d06f-c9fd-49a8-a95e-a877b22ac096) + ) + (text "Low-pass RC filter\nto increase drop beyond Fc" (at 64.77 151.13 0) + (effects (font (size 1.27 1.27)) (justify right bottom)) + (uuid bf8bd8cd-d4f7-44a1-ad1b-31e7ccf62047) + ) + (text "Output signal" (at 15.875 82.55 0) + (effects (font (size 2.54 2.54)) (justify left bottom)) + (uuid e8957e1d-c031-4004-9296-84b44028970b) + ) + + (global_label "GENERATOR" (shape input) (at 49.53 160.02 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid 0446309d-a8ba-4da1-acb0-acccff8f98c9) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 35.799 160.02 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "SIGNAL_IN_MCU" (shape input) (at 167.64 57.15 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 0f8f9aed-d237-4cff-a02a-edbc5f8dbbf4) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 184.9997 57.15 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "VDDA{slash}2" (shape input) (at 257.81 101.6 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 4fb7b295-e678-4a16-b835-5b5ab5e6ef90) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 267.973 101.6 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "GENERATOR_MCU" (shape input) (at 147.32 157.48 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 7fd78e2d-c200-4df3-9413-8f9a4cfa81ce) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 166.0705 157.48 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "SIGNAL_OUT_MCU" (shape input) (at 148.59 104.14 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid b5a5cc41-eed0-4ce9-9e3c-1e43cb81d7a7) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 167.643 104.14 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "VDDA{slash}2" (shape input) (at 132.08 59.69 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid ccd7ea87-758e-4bb4-a684-bd62b838741d) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 121.917 59.69 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "SIGNAL_IN" (shape input) (at 35.56 54.61 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid d8e7c267-f8b7-40a7-822f-600a8a7b2e2e) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 23.2198 54.61 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "SIGNAL_OUT" (shape input) (at 50.8 106.68 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid fe685e56-e4e9-4f3f-9e67-0eaa629e96c4) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 36.7665 106.68 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + + (symbol (lib_id "power:GND") (at 102.87 113.03 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 0644252a-1b0b-4fcc-80c7-a4a62f93d012) + (property "Reference" "#PWR02" (at 102.87 119.38 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 102.87 118.11 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 102.87 113.03 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 102.87 113.03 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 49ed74ec-3a30-44e9-bc32-74708afa0d6f)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR02") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR09") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 107.95 57.15 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 09763a12-feda-48e1-afe9-d8a81a7439cb) + (property "Reference" "R4" (at 107.95 52.07 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "20k" (at 107.95 54.61 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 108.204 56.134 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 107.95 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE0720KL" (at 107.95 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 6611f1b9-8e1b-492e-955d-247b29c6d327)) + (pin "2" (uuid 7c771bcf-0adb-46f1-a6aa-7e8c78837392)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "R4") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R5") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 86.36 173.99 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 0b777e25-6648-4258-86f0-5ac639e20017) + (property "Reference" "R17" (at 86.36 168.91 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "2.49k" (at 86.36 171.45 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 86.614 172.974 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 86.36 173.99 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE072K49L" (at 86.36 173.99 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c93944d4-c30c-42f9-bf5b-391c69879cbf)) + (pin "2" (uuid 69bda8ee-4704-47e0-84ff-d3df01165524)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R17") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Amplifier_Operational:TLV9062xD") (at 86.36 160.02 0) (mirror y) (unit 2) + (in_bom yes) (on_board yes) (dnp no) + (uuid 0bba421f-7d3e-4e1e-9f66-4037ea1e27ad) + (property "Reference" "U2" (at 86.36 151.13 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "OPA1678" (at 86.36 153.67 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 83.82 160.02 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 80.01 156.21 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "OPA1652AID" (at 86.36 160.02 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 1f61a1ea-98b2-4f14-aef5-263de62de786)) + (pin "2" (uuid d1835242-f5eb-4194-bf86-2922798a3626)) + (pin "3" (uuid 3e29f86f-c9b3-48d3-b9ee-7a04e7402329)) + (pin "5" (uuid 05f0d4ef-1c6c-4305-9974-02b11d54e7a1)) + (pin "6" (uuid 1eee25d9-41e6-435a-8282-5677e1ab7994)) + (pin "7" (uuid 7e13f8b1-8471-49c0-a7c4-f430eb568801)) + (pin "4" (uuid 6bf340e5-1823-4308-a64e-18f1c6f01bc2)) + (pin "8" (uuid 73c818e5-90ee-45d8-a985-168e76b95c95)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "U2") (unit 2) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "U2") (unit 2) + ) + ) + ) + ) + + (symbol (lib_id "Amplifier_Operational:TLV9062xD") (at 218.44 101.6 0) (unit 3) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 0d35ce54-c1cf-4a8a-ba3b-4486213d9285) + (property "Reference" "U2" (at 219.71 100.965 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "OPA1678" (at 219.71 103.505 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 220.98 101.6 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 224.79 97.79 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "OPA1652AID" (at 218.44 101.6 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 66d39042-8a71-462a-b9a9-1ca367067f3d)) + (pin "2" (uuid 1c9a0b39-dfe4-460c-a72a-9e1182732a31)) + (pin "3" (uuid c823d86f-b632-4b28-b0fa-8e92be1e3edf)) + (pin "5" (uuid d9181019-6f28-4b66-aba4-ee3297e161e3)) + (pin "6" (uuid caf50f42-6307-4795-9bdb-553383434304)) + (pin "7" (uuid 5731784d-1008-4ea7-b598-23e49c572152)) + (pin "4" (uuid d33767b3-df7d-4842-877e-c255ad77ccc8)) + (pin "8" (uuid a4e547a7-29d8-439d-b01e-1a601ce2877f)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "U2") (unit 3) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "U2") (unit 3) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 59.69 66.04 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 1063e76b-79dd-42d8-a5b9-3a1dc5ab4ffd) + (property "Reference" "#PWR01" (at 59.69 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 59.69 71.12 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 59.69 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 59.69 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 71a3f27d-3333-465a-8fe8-e3dfb6c45173)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR01") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR01") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 59.69 62.23 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 12a9fbfe-dee3-47f7-8a33-6ece0a6a5e21) + (property "Reference" "C1" (at 63.5 61.595 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "274p" (at 63.5 64.135 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 60.6552 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 59.69 62.23 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CC0603KRX7R9BB271" (at 59.69 62.23 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 6fdc265c-2317-4a7e-a795-ce750f52008f)) + (pin "2" (uuid 42b60269-a437-4d44-af42-e7d52bd8670a)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "C1") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C3") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 167.64 68.58 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 15d86f1c-6e1d-4e83-bc8c-152584093027) + (property "Reference" "#PWR02" (at 167.64 74.93 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 167.64 73.66 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 167.64 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 167.64 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid a4764405-0495-4c52-8224-19e3d8bfd178)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR02") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR03") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:-5V") (at 237.49 109.22 180) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 1af02c4c-1c94-4791-8ac6-070fe9a60b9c) + (property "Reference" "#PWR08" (at 237.49 111.76 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "-5V" (at 237.49 114.3 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 237.49 109.22 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 237.49 109.22 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid e092b399-178a-4593-b707-e805c3bff0c7)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR08") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR08") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 101.6 166.37 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 1f3d7225-9a9b-486a-b3c1-2613dae4d720) + (property "Reference" "#PWR02" (at 101.6 172.72 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 101.6 171.45 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 101.6 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 101.6 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 3e9e0c47-e269-4be9-9f01-2905d74f0424)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR02") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR013") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 52.07 54.61 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 22077614-3367-4e4d-93bb-9d3cc32003bf) + (property "Reference" "R1" (at 52.07 49.53 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "9.09k" (at 52.07 52.07 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 52.324 53.594 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 52.07 54.61 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE079K09L" (at 52.07 54.61 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 96e0b48e-77bd-47d6-8390-29484650cea3)) + (pin "2" (uuid fe349b81-f850-437a-87de-9a284c706f1b)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "R1") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R3") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 127 104.14 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 2d0a2ddc-1a7a-4738-b65d-75dfc8aed08c) + (property "Reference" "R9" (at 127 99.06 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "6.81k" (at 127 101.6 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 127.254 103.124 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 127 104.14 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE076K81L" (at 127 104.14 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid a65e8c4e-375b-4814-add8-7ccf7111819a)) + (pin "2" (uuid 64090c02-5cb4-4571-b15d-9b44b284ae3f)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R9") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 87.63 120.65 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 34e1c64c-0f60-433f-ae2a-8d2833c48e4f) + (property "Reference" "R12" (at 87.63 115.57 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "2.49k" (at 87.63 118.11 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 87.884 119.634 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 87.63 120.65 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE072K49L" (at 87.63 120.65 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 32bb3e32-35bf-47f1-bde9-eb411cf66f0d)) + (pin "2" (uuid b1f25ba7-a26e-4e64-b1fe-8e88f089afec)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R12") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 254 113.03 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 3e30a194-251d-470d-a890-0baee49de02b) + (property "Reference" "#PWR05" (at 254 119.38 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 254 118.11 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 254 113.03 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 254 113.03 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 6cff9016-7c95-4818-96c4-cc8f70542aa6)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR05") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR010") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 53.34 166.37 180) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 3ffe3182-5bf2-4df2-8625-80c9083156c0) + (property "Reference" "C12" (at 57.15 165.735 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "DNP" (at 57.15 168.275 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 52.3748 162.56 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 53.34 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid e7f74963-292e-45b9-ab8c-91a5764b765e)) + (pin "2" (uuid 9729df06-5e8e-4dad-84d0-f0f9dc2598fd)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C12") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Amplifier_Operational:TLV9062xD") (at 87.63 106.68 0) (mirror y) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid 4014b31a-906d-4e54-9260-18b76b511e9b) + (property "Reference" "U2" (at 87.63 97.79 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "OPA1678" (at 87.63 100.33 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 85.09 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 81.28 102.87 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "OPA1652AID" (at 87.63 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c8cffe73-6aa8-4d3c-93e2-a94535394a28)) + (pin "2" (uuid bbaf461e-ae38-4e0e-878f-9652294d8158)) + (pin "3" (uuid ba25295c-435b-400c-9bf1-ecd183fca919)) + (pin "5" (uuid e4ab79d0-22b3-4a21-806d-e49b748eabe4)) + (pin "6" (uuid 7ca522ff-b1ba-4a83-9a7e-37f8d4e9b39f)) + (pin "7" (uuid 119d118c-ad1d-4ec6-a78c-ce77a4a8a638)) + (pin "4" (uuid 7e4b0450-b24a-43cd-aa72-83851fcc4c80)) + (pin "8" (uuid 152e8a15-6676-49e0-9c91-5d1da146a15d)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "U2") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "U2") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 54.61 113.03 180) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 4bd163bd-4e71-45f4-aa51-12c0c8894738) + (property "Reference" "C8" (at 58.42 112.395 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "DNP" (at 58.42 114.935 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 53.6448 109.22 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 54.61 113.03 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 9be65c66-1afa-4765-b611-db1cb0114523)) + (pin "2" (uuid e506969b-3ff3-4998-b48d-8b0875e0fef3)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C8") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 88.9 45.72 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 5f13d707-5314-4204-95ff-e7023dbf1390) + (property "Reference" "C2" (at 88.9 39.37 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "100p" (at 88.9 41.91 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 92.71 44.7548 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 88.9 45.72 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CC0603KPX7R9BB101" (at 88.9 45.72 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 45a25271-bcc0-47e3-a8e7-7d256aadbca0)) + (pin "2" (uuid 6829677c-0d98-4f83-a3f3-95946cce1178)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "C2") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C1") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 102.87 109.22 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 623d4de9-4003-498d-bb94-d973ca58f06f) + (property "Reference" "C7" (at 106.68 108.585 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "100p" (at 106.68 111.125 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 103.8352 113.03 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 102.87 109.22 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CC0603KPX7R9BB101" (at 102.87 109.22 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 5ca17ef7-5119-4aea-b2fc-5df05367a0d8)) + (pin "2" (uuid 468fc0bb-223d-4282-a793-4cd2a25d836b)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C7") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 77.47 66.04 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 62a7acc6-bac9-44e6-89a6-1cab2d22ca59) + (property "Reference" "#PWR02" (at 77.47 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 77.47 71.12 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 77.47 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 77.47 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 2b2a5e9c-adb3-461c-8665-30285382f988)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR02") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR02") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 87.63 91.44 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 63c2c207-40b2-47ce-b8a2-f9c77921a2b5) + (property "Reference" "C5" (at 87.63 85.09 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "105p" (at 87.63 87.63 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 91.44 90.4748 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 87.63 91.44 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CC0603KPX7R9BB101" (at 87.63 91.44 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid d6c1ad4e-4363-4a74-92ff-ca08e6d4ec5f)) + (pin "2" (uuid 1fc9d465-8fad-4fd3-a830-30dc6adbf3b2)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C5") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 67.31 54.61 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 68ea83d2-5dc0-4430-a711-4c94c4e55ef4) + (property "Reference" "R2" (at 67.31 49.53 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "6.34k" (at 67.31 52.07 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 67.564 53.594 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 67.31 54.61 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE076K34L" (at 67.31 54.61 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 388ac2ff-e1b0-46fe-bb18-df208c66e7f1)) + (pin "2" (uuid 2467a834-c99b-4539-8e40-186d5ddb860a)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "R2") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R4") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 62.23 106.68 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 6aab9e7e-b33f-47a1-8408-1806df557085) + (property "Reference" "R10" (at 62.23 101.6 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "0" (at 62.23 104.14 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 62.484 105.664 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 62.23 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RMCF0603ZT0R00" (at 62.23 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 749c90dc-eeb5-4ea9-b923-187074b37738)) + (pin "2" (uuid 100de8b7-e2be-4464-aa8a-86b4ddc88662)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R10") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VDDA") (at 254 90.17 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 6bb37a30-601d-4b78-add7-b6eaf0d233fb) + (property "Reference" "#PWR06" (at 254 93.98 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VDDA" (at 254 86.36 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 254 90.17 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 254 90.17 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid a83c3b8e-afa5-444a-94f6-7a76312d9888)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR06") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR04") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 125.73 157.48 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 6de7c3e2-ccb1-4bda-b6b9-7e265de95076) + (property "Reference" "R15" (at 125.73 152.4 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "6.81k" (at 125.73 154.94 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 125.984 156.464 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 125.73 157.48 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE076K81L" (at 125.73 157.48 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c0ce4fe5-e3ff-40cf-ab00-8557ad4fc7d5)) + (pin "2" (uuid 21c31c37-7300-47fd-8c86-f07c4a4f3541)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R15") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 218.44 93.98 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 754c3c87-dd31-495a-8b6e-875194a6f038) + (property "Reference" "#PWR07" (at 218.44 97.79 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 218.44 90.17 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 218.44 93.98 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 218.44 93.98 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid ffb94f6b-43c6-46a5-a336-3d3e4d3aa679)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR07") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR05") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 101.6 162.56 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 77594052-576e-4ede-837c-0cea441b7b38) + (property "Reference" "C11" (at 105.41 161.925 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "100p" (at 105.41 164.465 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 102.5652 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 101.6 162.56 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CC0603KPX7R9BB101" (at 101.6 162.56 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 7f966cbf-d036-471d-84a3-c48685acc885)) + (pin "2" (uuid 7db36809-9cc3-4266-b9c7-15900e3691fc)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C11") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 139.7 45.72 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 77903c71-4695-45df-ae74-1ca7380bcb51) + (property "Reference" "R7" (at 139.7 40.64 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "10k/0.1%" (at 139.7 43.18 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 139.954 44.704 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 139.7 45.72 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RN73R1JTTD1002B25" (at 139.7 45.72 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid d1ae68a4-d545-4e9e-b67c-dea4c1ecd866)) + (pin "2" (uuid 2732cc5c-562f-427b-bb0c-e7fab4426e08)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "R7") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R2") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 237.49 93.98 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 81ccd8b5-9d95-4261-b85a-7edd690df830) + (property "Reference" "#PWR07" (at 237.49 97.79 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 237.49 90.17 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 237.49 93.98 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 237.49 93.98 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 5641c513-3df3-40ae-a91f-5cab931cd3be)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR07") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR06") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 167.64 64.77 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 88e74efe-ba6a-4380-a952-50b4a27eb246) + (property "Reference" "C4" (at 171.45 64.135 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "DNP" (at 171.45 66.675 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 168.6052 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 167.64 64.77 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 1ce2fc37-267c-44a5-81f6-9df6887c66ce)) + (pin "2" (uuid 7f866abb-41f7-46b0-8b7e-cffe216766c1)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C4") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Amplifier_Operational:TLV9062xD") (at 237.49 101.6 0) (unit 3) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 8c9bfe4c-5a4e-45a1-8b6a-8480aa78343e) + (property "Reference" "U1" (at 238.76 100.965 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "TLV9162" (at 238.76 103.505 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 240.03 101.6 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.ti.com/lit/ds/symlink/tlv9162.pdf" (at 243.84 97.79 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "TLV9162IDR" (at 237.49 101.6 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid e1d7395e-fa07-43ca-983f-4cb0f447e8c2)) + (pin "2" (uuid 1443d506-f486-4d8e-a73f-ab2ee559ec37)) + (pin "3" (uuid 304101b1-2173-4b4a-8359-86b3843e4309)) + (pin "5" (uuid 7fd0783b-4c9a-46ec-a645-9b3483f6c033)) + (pin "6" (uuid 8614b269-5bed-417b-8b7d-79a068767925)) + (pin "7" (uuid 78247ffa-6f2f-40b3-8af9-36d937ce8754)) + (pin "4" (uuid 29f98b05-419f-47bf-9552-3973c7a0e813)) + (pin "8" (uuid d93ff3db-bdfb-4d71-83ae-9eb3adbc430b)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "U1") (unit 3) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "U1") (unit 3) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 53.34 170.18 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 8d9071cf-171c-4b0a-8acf-30c3a1a0fcd2) + (property "Reference" "#PWR01" (at 53.34 176.53 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 53.34 175.26 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 53.34 170.18 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 53.34 170.18 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid de2da121-0adb-42fe-b814-77a6c2f676d1)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR01") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR014") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:-5V") (at 218.44 109.22 180) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 9330e2e5-e962-4235-8327-3a89a62ddcd2) + (property "Reference" "#PWR08" (at 218.44 111.76 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "-5V" (at 218.44 114.3 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 218.44 109.22 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 218.44 109.22 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 9b21a1d6-dee7-4d1e-be71-b86425f0627e)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR08") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR07") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 60.96 160.02 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 95db5be2-27f2-47d0-bd88-021be9957d2d) + (property "Reference" "R16" (at 60.96 154.94 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "0" (at 60.96 157.48 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 61.214 159.004 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 60.96 160.02 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RMCF0603ZT0R00" (at 60.96 160.02 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c2a70843-85f3-4f54-a0b3-79626011b504)) + (pin "2" (uuid 5a8cf6ad-d3ac-4065-bb84-f08cc9a4e556)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R16") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 114.3 104.14 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 95dedd7c-c752-4712-9aea-ee0143445b87) + (property "Reference" "R8" (at 114.3 99.06 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "22.1k" (at 114.3 101.6 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 114.554 103.124 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 114.3 104.14 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE0722K1L" (at 114.3 104.14 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid f9aa0b93-68bc-4919-aaa9-1cfee0e256c0)) + (pin "2" (uuid 718d5583-4741-49c0-a741-632e7c73c064)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R8") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 137.16 157.48 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 99c91ccc-b2c3-4d6a-a11f-c11c2ab3496d) + (property "Reference" "C5" (at 137.16 151.13 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "10u" (at 137.16 153.67 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 140.97 156.5148 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 137.16 157.48 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL21A106KOQNNNE" (at 137.16 157.48 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid b930ea1c-9b17-4f90-b3d2-75acb31181fd)) + (pin "2" (uuid 8d69e19a-6474-4f45-9edc-2aeab636e721)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "C5") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C10") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 120.65 123.19 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid a31f3ed6-e728-4293-b760-25b5c2bdcb46) + (property "Reference" "#PWR02" (at 120.65 129.54 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 120.65 128.27 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 120.65 123.19 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 120.65 123.19 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 55ebe991-a6fe-4845-86b6-cba590785800)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR02") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR012") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 119.38 176.53 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid a96847c8-e767-4fad-9b42-191f8c5416e9) + (property "Reference" "#PWR02" (at 119.38 182.88 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 119.38 181.61 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 119.38 176.53 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 119.38 176.53 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid d71e15a3-92d4-4e9d-9a64-d80381b82b20)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR02") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR015") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 254 109.22 180) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid a97dfe8c-7bb6-43dd-9b12-e26f02e8d594) + (property "Reference" "R6" (at 256.54 108.585 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "10k/0.1%" (at 256.54 111.125 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 252.984 108.966 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 254 109.22 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RN73R1JTTD1002B25" (at 254 109.22 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 230676bd-f9d7-4135-bf94-5bd32a6c6817)) + (pin "2" (uuid 9c2995b3-c3fd-4325-a38a-02d453a8d712)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "R6") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R11") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Amplifier_Operational:TLV9062xD") (at 139.7 57.15 0) (mirror x) (unit 2) + (in_bom yes) (on_board yes) (dnp no) + (uuid ada410a1-682d-4a65-a2fe-bdbaa9ec75fc) + (property "Reference" "U1" (at 139.7 66.04 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "TLV9162" (at 139.7 63.5 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 142.24 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.ti.com/lit/ds/symlink/tlv9162.pdf" (at 146.05 60.96 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "TLV9162IDR" (at 139.7 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 70cbb8b0-b842-4326-aada-dae0717f5282)) + (pin "2" (uuid e5340e6e-6714-4211-9a29-b399cdd97942)) + (pin "3" (uuid a1871b0d-f1f1-4ee5-a636-483e7fd30b10)) + (pin "5" (uuid 34830b8e-7271-4349-a750-2834597d6bfa)) + (pin "6" (uuid c17cc6f8-3293-4f37-99af-22100f912684)) + (pin "7" (uuid 167a70b1-9f97-4d3e-9a04-030bee9b9f21)) + (pin "4" (uuid 91412848-38fa-48ee-8d47-f24df08baf30)) + (pin "8" (uuid 66822d18-13db-4d1a-8c58-63a9a2ab2bee)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "U1") (unit 2) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "U1") (unit 2) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 113.03 157.48 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid af2574b7-1459-4b58-a3e2-46c8e623030f) + (property "Reference" "R14" (at 113.03 152.4 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "22.1k" (at 113.03 154.94 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 113.284 156.464 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 113.03 157.48 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE0722K1L" (at 113.03 157.48 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 9155210f-f1db-403a-b9f1-e1400b8030cc)) + (pin "2" (uuid cb24e826-7310-439a-8775-626d726466f1)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R14") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 138.43 104.14 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid b0bfe7db-09da-4802-8a23-6a20984ec23f) + (property "Reference" "C5" (at 138.43 97.79 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "10u" (at 138.43 100.33 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 142.24 103.1748 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 138.43 104.14 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL21A106KOQNNNE" (at 138.43 104.14 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 1bfbf1bf-e80b-4a39-b2a7-f400e35b7470)) + (pin "2" (uuid 49533bad-0162-4c94-8789-d89aac72e635)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "C5") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C6") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 157.48 57.15 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid b1cf4a1c-d6f7-46a0-8fae-ab2466b84cbc) + (property "Reference" "R6" (at 157.48 52.07 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "0" (at 157.48 54.61 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 157.734 56.134 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 157.48 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RMCF0603ZT0R00" (at 157.48 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 8c757545-9373-43a0-85a5-bbbda107cd9e)) + (pin "2" (uuid 450a2be7-651f-4979-9655-ae6450471d9b)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R6") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 54.61 116.84 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid b220f110-d3c5-4af7-b47d-d29abe2f4aed) + (property "Reference" "#PWR01" (at 54.61 123.19 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 54.61 121.92 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 54.61 116.84 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 54.61 116.84 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c57fd86a-ca36-40a3-bbfe-9346fdfce204)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "#PWR01") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "#PWR011") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 39.37 54.61 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid b7446dbf-b5bf-4307-9edc-e98dcd42c78d) + (property "Reference" "C5" (at 39.37 48.26 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "10u" (at 39.37 50.8 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 43.18 53.6448 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 39.37 54.61 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL21A106KOQNNNE" (at 39.37 54.61 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid ac1fe170-2eb1-42f3-ac4e-7c4ffceba4f6)) + (pin "2" (uuid 14a894dc-f8fa-46d9-a8e0-57a2289ada05)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "C5") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C2") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 113.03 173.99 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid b79fe011-5fd4-4b0f-bb62-51fff45eb70a) + (property "Reference" "R18" (at 113.03 168.91 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "2.49k" (at 113.03 171.45 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 113.284 172.974 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 113.03 173.99 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE072K49L" (at 113.03 173.99 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid f9e943f6-0226-49f5-9611-99036b23f957)) + (pin "2" (uuid 2d8b2997-5a40-4d79-be80-3371ed7c49e3)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R18") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Amplifier_Operational:TLV9062xD") (at 88.9 57.15 0) (mirror x) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid b7a8ee36-8943-426a-b182-3c32ea14e286) + (property "Reference" "U1" (at 88.9 66.04 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "TLV9162" (at 88.9 63.5 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 91.44 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.ti.com/lit/ds/symlink/tlv9162.pdf" (at 95.25 60.96 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "TLV9162IDR" (at 88.9 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 14db3c56-fa76-48fa-823e-cc555eaa2472)) + (pin "2" (uuid 0500565d-dcc2-4e13-9e37-d38fe95b83f0)) + (pin "3" (uuid 02e1b336-e9a6-4186-a02a-3f2eaf52dd8b)) + (pin "5" (uuid 7b01a7a7-d2bc-486f-a8e3-e57b57dd8762)) + (pin "6" (uuid 760dfb5f-385e-4704-856c-525e1b4098f3)) + (pin "7" (uuid 06251b44-55dd-4579-b6f2-1ef0134bd4d2)) + (pin "4" (uuid 8de3edc6-dd14-459f-b596-3c091eb0dfe7)) + (pin "8" (uuid eb256e96-db70-450f-b88a-892c9bf0748e)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "U1") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "U1") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 254 93.98 180) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid c5790ffe-38a3-462e-88e9-7a0e67c0f3b4) + (property "Reference" "R5" (at 256.54 93.345 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "10k/0.1%" (at 256.54 95.885 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 252.984 93.726 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 254 93.98 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RN73R1JTTD1002B25" (at 254 93.98 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 1b22a07d-8dd1-4067-ac70-790d7b7ebe81)) + (pin "2" (uuid b25739ce-c4df-41f6-9b5c-e304d523b167)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "R5") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R7") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 114.3 120.65 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid e9a26256-ad58-4b4e-aeb9-27b97c5cf7a4) + (property "Reference" "R13" (at 114.3 115.57 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "2.49k" (at 114.3 118.11 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 114.554 119.634 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 114.3 120.65 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE072K49L" (at 114.3 120.65 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 40064330-1af5-4413-a1ec-6af3a0586598)) + (pin "2" (uuid 462ea222-73ad-4847-9b24-844ec39d56cc)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R13") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 86.36 144.78 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid eb3ad263-4383-4973-9b0c-7fde9947d384) + (property "Reference" "C9" (at 86.36 138.43 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "105p" (at 86.36 140.97 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 90.17 143.8148 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 86.36 144.78 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CC0603KPX7R9BB101" (at 86.36 144.78 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c0d232bf-caa5-496c-be11-29715961f4b8)) + (pin "2" (uuid 043e1f6d-0813-4628-afef-ffc4fcbccf1f)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "C9") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 88.9 34.29 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid f0ce9f99-0d2b-47ad-955e-a115d88f2423) + (property "Reference" "R3" (at 88.9 29.21 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "9.09k" (at 88.9 31.75 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 89.154 33.274 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 88.9 34.29 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RT0603DRE079K09L" (at 88.9 34.29 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 1eee0348-dd93-450c-aca6-b1e8b82b5960)) + (pin "2" (uuid afd92469-5138-4218-8ce8-ca192ddbe89a)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f" + (reference "R3") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/684072e7-f538-4528-bfb8-b14c31b5b1f0" + (reference "R1") (unit 1) + ) + ) + ) + ) +) diff --git a/hardware/board_connectors.kicad_sch b/hardware/board_connectors.kicad_sch new file mode 100755 index 0000000..867e8da --- /dev/null +++ b/hardware/board_connectors.kicad_sch @@ -0,0 +1,2475 @@ +(kicad_sch (version 20230121) (generator eeschema) + + (uuid db8d8453-0abf-41fc-8f7a-e13f9795dae1) + + (paper "A4") + + (title_block + (title "Board and I/O connectors") + (date "2023-08-08") + (company "bitgloo") + (comment 1 "Released under the CERN Open Hardware Licence Version 2 - Strongly Reciprocal") + ) + + (lib_symbols + (symbol "Connector:USB_B_Micro" (pin_names (offset 1.016)) (in_bom yes) (on_board yes) + (property "Reference" "J" (at -5.08 11.43 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "USB_B_Micro" (at -5.08 8.89 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "" (at 3.81 -1.27 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 3.81 -1.27 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "connector USB micro" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "USB Micro Type B connector" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "USB*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "USB_B_Micro_0_1" + (rectangle (start -5.08 -7.62) (end 5.08 7.62) + (stroke (width 0.254) (type default)) + (fill (type background)) + ) + (circle (center -3.81 2.159) (radius 0.635) + (stroke (width 0.254) (type default)) + (fill (type outline)) + ) + (circle (center -0.635 3.429) (radius 0.381) + (stroke (width 0.254) (type default)) + (fill (type outline)) + ) + (rectangle (start -0.127 -7.62) (end 0.127 -6.858) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.905 2.159) + (xy 0.635 2.159) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -3.175 2.159) + (xy -2.54 2.159) + (xy -1.27 3.429) + (xy -0.635 3.429) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -2.54 2.159) + (xy -1.905 2.159) + (xy -1.27 0.889) + (xy 0 0.889) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0.635 2.794) + (xy 0.635 1.524) + (xy 1.905 2.159) + (xy 0.635 2.794) + ) + (stroke (width 0.254) (type default)) + (fill (type outline)) + ) + (polyline + (pts + (xy -4.318 5.588) + (xy -1.778 5.588) + (xy -2.032 4.826) + (xy -4.064 4.826) + (xy -4.318 5.588) + ) + (stroke (width 0) (type default)) + (fill (type outline)) + ) + (polyline + (pts + (xy -4.699 5.842) + (xy -4.699 5.588) + (xy -4.445 4.826) + (xy -4.445 4.572) + (xy -1.651 4.572) + (xy -1.651 4.826) + (xy -1.397 5.588) + (xy -1.397 5.842) + (xy -4.699 5.842) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (rectangle (start 0.254 1.27) (end -0.508 0.508) + (stroke (width 0.254) (type default)) + (fill (type outline)) + ) + (rectangle (start 5.08 -5.207) (end 4.318 -4.953) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (rectangle (start 5.08 -2.667) (end 4.318 -2.413) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (rectangle (start 5.08 -0.127) (end 4.318 0.127) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (rectangle (start 5.08 4.953) (end 4.318 5.207) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "USB_B_Micro_1_1" + (pin power_out line (at 7.62 5.08 180) (length 2.54) + (name "VBUS" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin bidirectional line (at 7.62 -2.54 180) (length 2.54) + (name "D-" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + (pin bidirectional line (at 7.62 0 180) (length 2.54) + (name "D+" (effects (font (size 1.27 1.27)))) + (number "3" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 -5.08 180) (length 2.54) + (name "ID" (effects (font (size 1.27 1.27)))) + (number "4" (effects (font (size 1.27 1.27)))) + ) + (pin power_out line (at 0 -10.16 90) (length 2.54) + (name "GND" (effects (font (size 1.27 1.27)))) + (number "5" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -2.54 -10.16 90) (length 2.54) + (name "Shield" (effects (font (size 1.27 1.27)))) + (number "6" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Connector_Audio:AudioJack2_Ground" (in_bom yes) (on_board yes) + (property "Reference" "J" (at 0 8.89 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "AudioJack2_Ground" (at 0 6.35 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "audio jack receptacle mono phone headphone TS connector" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Audio Jack, 2 Poles (Mono / TS), Grounded Sleeve" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "Jack*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "AudioJack2_Ground_0_1" + (rectangle (start -2.54 -2.54) (end -3.81 0) + (stroke (width 0.254) (type default)) + (fill (type outline)) + ) + (polyline + (pts + (xy 0 0) + (xy 0.635 -0.635) + (xy 1.27 0) + (xy 2.54 0) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 2.54 2.54) + (xy -0.635 2.54) + (xy -0.635 0) + (xy -1.27 -0.635) + (xy -1.905 0) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (rectangle (start 2.54 3.81) (end -2.54 -2.54) + (stroke (width 0.254) (type default)) + (fill (type background)) + ) + ) + (symbol "AudioJack2_Ground_1_1" + (pin passive line (at 0 -5.08 90) (length 2.54) + (name "~" (effects (font (size 1.27 1.27)))) + (number "G" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 5.08 2.54 180) (length 2.54) + (name "~" (effects (font (size 1.27 1.27)))) + (number "S" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 5.08 0 180) (length 2.54) + (name "~" (effects (font (size 1.27 1.27)))) + (number "T" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Connector_Generic:Conn_02x03_Odd_Even" (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes) + (property "Reference" "J" (at 1.27 5.08 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "Conn_02x03_Odd_Even" (at 1.27 -5.08 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "connector" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Generic connector, double row, 02x03, odd/even pin numbering scheme (row 1 odd numbers, row 2 even numbers), script generated (kicad-library-utils/schlib/autogen/connector/)" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "Connector*:*_2x??_*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "Conn_02x03_Odd_Even_1_1" + (rectangle (start -1.27 -2.413) (end 0 -2.667) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 0.127) (end 0 -0.127) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 2.667) (end 0 2.413) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 3.81) (end 3.81 -3.81) + (stroke (width 0.254) (type default)) + (fill (type background)) + ) + (rectangle (start 3.81 -2.413) (end 2.54 -2.667) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 0.127) (end 2.54 -0.127) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 2.667) (end 2.54 2.413) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (pin passive line (at -5.08 2.54 0) (length 3.81) + (name "Pin_1" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 2.54 180) (length 3.81) + (name "Pin_2" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 0 0) (length 3.81) + (name "Pin_3" (effects (font (size 1.27 1.27)))) + (number "3" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 0 180) (length 3.81) + (name "Pin_4" (effects (font (size 1.27 1.27)))) + (number "4" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 -2.54 0) (length 3.81) + (name "Pin_5" (effects (font (size 1.27 1.27)))) + (number "5" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 -2.54 180) (length 3.81) + (name "Pin_6" (effects (font (size 1.27 1.27)))) + (number "6" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Connector_Generic:Conn_02x10_Odd_Even" (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes) + (property "Reference" "J" (at 1.27 12.7 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "Conn_02x10_Odd_Even" (at 1.27 -15.24 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "connector" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Generic connector, double row, 02x10, odd/even pin numbering scheme (row 1 odd numbers, row 2 even numbers), script generated (kicad-library-utils/schlib/autogen/connector/)" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "Connector*:*_2x??_*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "Conn_02x10_Odd_Even_1_1" + (rectangle (start -1.27 -12.573) (end 0 -12.827) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 -10.033) (end 0 -10.287) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 -7.493) (end 0 -7.747) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 -4.953) (end 0 -5.207) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 -2.413) (end 0 -2.667) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 0.127) (end 0 -0.127) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 2.667) (end 0 2.413) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 5.207) (end 0 4.953) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 7.747) (end 0 7.493) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 10.287) (end 0 10.033) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start -1.27 11.43) (end 3.81 -13.97) + (stroke (width 0.254) (type default)) + (fill (type background)) + ) + (rectangle (start 3.81 -12.573) (end 2.54 -12.827) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 -10.033) (end 2.54 -10.287) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 -7.493) (end 2.54 -7.747) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 -4.953) (end 2.54 -5.207) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 -2.413) (end 2.54 -2.667) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 0.127) (end 2.54 -0.127) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 2.667) (end 2.54 2.413) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 5.207) (end 2.54 4.953) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 7.747) (end 2.54 7.493) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (rectangle (start 3.81 10.287) (end 2.54 10.033) + (stroke (width 0.1524) (type default)) + (fill (type none)) + ) + (pin passive line (at -5.08 10.16 0) (length 3.81) + (name "Pin_1" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 0 180) (length 3.81) + (name "Pin_10" (effects (font (size 1.27 1.27)))) + (number "10" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 -2.54 0) (length 3.81) + (name "Pin_11" (effects (font (size 1.27 1.27)))) + (number "11" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 -2.54 180) (length 3.81) + (name "Pin_12" (effects (font (size 1.27 1.27)))) + (number "12" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 -5.08 0) (length 3.81) + (name "Pin_13" (effects (font (size 1.27 1.27)))) + (number "13" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 -5.08 180) (length 3.81) + (name "Pin_14" (effects (font (size 1.27 1.27)))) + (number "14" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 -7.62 0) (length 3.81) + (name "Pin_15" (effects (font (size 1.27 1.27)))) + (number "15" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 -7.62 180) (length 3.81) + (name "Pin_16" (effects (font (size 1.27 1.27)))) + (number "16" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 -10.16 0) (length 3.81) + (name "Pin_17" (effects (font (size 1.27 1.27)))) + (number "17" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 -10.16 180) (length 3.81) + (name "Pin_18" (effects (font (size 1.27 1.27)))) + (number "18" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 -12.7 0) (length 3.81) + (name "Pin_19" (effects (font (size 1.27 1.27)))) + (number "19" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 10.16 180) (length 3.81) + (name "Pin_2" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 -12.7 180) (length 3.81) + (name "Pin_20" (effects (font (size 1.27 1.27)))) + (number "20" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 7.62 0) (length 3.81) + (name "Pin_3" (effects (font (size 1.27 1.27)))) + (number "3" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 7.62 180) (length 3.81) + (name "Pin_4" (effects (font (size 1.27 1.27)))) + (number "4" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 5.08 0) (length 3.81) + (name "Pin_5" (effects (font (size 1.27 1.27)))) + (number "5" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 5.08 180) (length 3.81) + (name "Pin_6" (effects (font (size 1.27 1.27)))) + (number "6" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 2.54 0) (length 3.81) + (name "Pin_7" (effects (font (size 1.27 1.27)))) + (number "7" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 7.62 2.54 180) (length 3.81) + (name "Pin_8" (effects (font (size 1.27 1.27)))) + (number "8" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 0 0) (length 3.81) + (name "Pin_9" (effects (font (size 1.27 1.27)))) + (number "9" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Device:R_US" (pin_numbers hide) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "R" (at 2.54 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "R_US" (at -2.54 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 1.016 -0.254 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "R res resistor" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Resistor, US symbol" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "R_*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "R_US_0_1" + (polyline + (pts + (xy 0 -2.286) + (xy 0 -2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.286) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 -0.762) + (xy 1.016 -1.143) + (xy 0 -1.524) + (xy -1.016 -1.905) + (xy 0 -2.286) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0.762) + (xy 1.016 0.381) + (xy 0 0) + (xy -1.016 -0.381) + (xy 0 -0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.286) + (xy 1.016 1.905) + (xy 0 1.524) + (xy -1.016 1.143) + (xy 0 0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "R_US_1_1" + (pin passive line (at 0 3.81 270) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 0 -3.81 90) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Diode:ESD5Zxx" (pin_numbers hide) (pin_names hide) (in_bom yes) (on_board yes) + (property "Reference" "D" (at 0 2.54 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "ESD5Zxx" (at 0 -2.54 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Diode_SMD:D_SOD-523" (at 0 -4.445 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.onsemi.com/pdf/datasheet/esd5z2.5t1-d.pdf" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "esd tvs unidirectional diode" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "ESD Protection Diode, SOD-523" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "D?SOD?523*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "ESD5Zxx_0_1" + (polyline + (pts + (xy 1.27 0) + (xy -1.27 0) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 -1.27) + (xy -1.27 1.27) + (xy -0.762 1.27) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 1.27 -1.27) + (xy 1.27 1.27) + (xy -1.27 0) + (xy 1.27 -1.27) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + ) + (symbol "ESD5Zxx_1_1" + (pin passive line (at -3.81 0 0) (length 2.54) + (name "K" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 3.81 0 180) (length 2.54) + (name "A" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Diode:ESD9B5.0ST5G" (pin_numbers hide) (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes) + (property "Reference" "D" (at 0 2.54 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "ESD9B5.0ST5G" (at 0 -2.54 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Diode_SMD:D_SOD-923" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.onsemi.com/pub/Collateral/ESD9B-D.PDF" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "diode TVS ESD" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "ESD protection diode, 5.0Vrwm, SOD-923" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "D*SOD?923*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "ESD9B5.0ST5G_0_1" + (polyline + (pts + (xy 1.27 0) + (xy -1.27 0) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -2.54 -1.27) + (xy 0 0) + (xy -2.54 1.27) + (xy -2.54 -1.27) + ) + (stroke (width 0.2032) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0.508 1.27) + (xy 0 1.27) + (xy 0 -1.27) + (xy -0.508 -1.27) + ) + (stroke (width 0.2032) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 2.54 1.27) + (xy 2.54 -1.27) + (xy 0 0) + (xy 2.54 1.27) + ) + (stroke (width 0.2032) (type default)) + (fill (type none)) + ) + ) + (symbol "ESD9B5.0ST5G_1_1" + (pin passive line (at -3.81 0 0) (length 2.54) + (name "A1" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 3.81 0 180) (length 2.54) + (name "A2" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:GND" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -6.35 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 0 -3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"GND\" , ground" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "GND_0_1" + (polyline + (pts + (xy 0 0) + (xy 0 -1.27) + (xy 1.27 -1.27) + (xy 0 -2.54) + (xy -1.27 -1.27) + (xy 0 -1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "GND_1_1" + (pin power_in line (at 0 0 270) (length 0) hide + (name "GND" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:VBUS" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VBUS" (at 0 3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"VBUS\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "VBUS_0_1" + (polyline + (pts + (xy -0.762 1.27) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0.762 1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "VBUS_1_1" + (pin power_in line (at 0 0 90) (length 0) hide + (name "VBUS" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:VCC" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VCC" (at 0 3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"VCC\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "VCC_0_1" + (polyline + (pts + (xy -0.762 1.27) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0.762 1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "VCC_1_1" + (pin power_in line (at 0 0 90) (length 0) hide + (name "VCC" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:VDDA" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VDDA" (at 0 3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"VDDA\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "VDDA_0_1" + (polyline + (pts + (xy -0.762 1.27) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0.762 1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "VDDA_1_1" + (pin power_in line (at 0 0 90) (length 0) hide + (name "VDDA" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + ) + + + (junction (at 64.77 153.67) (diameter 0) (color 0 0 0 0) + (uuid 341d7753-7745-4e80-b0d0-3726c431b28c) + ) + (junction (at 194.31 50.8) (diameter 0) (color 0 0 0 0) + (uuid 626c56db-b0b0-4ac0-9ec0-63491613099f) + ) + (junction (at 73.66 156.21) (diameter 0) (color 0 0 0 0) + (uuid 6c193457-5f43-4341-87b8-71d0ba6cac19) + ) + (junction (at 194.31 81.28) (diameter 0) (color 0 0 0 0) + (uuid 6e53c4d1-157e-4543-982e-4f7ac4a3c3bf) + ) + (junction (at 257.81 68.58) (diameter 0) (color 0 0 0 0) + (uuid 8172661d-4213-4d2c-9ece-dadb6d46dd4d) + ) + (junction (at 55.88 148.59) (diameter 0) (color 0 0 0 0) + (uuid d21c0f1c-b9d1-4039-b9b1-8a0ef306ea0b) + ) + (junction (at 194.31 113.03) (diameter 0) (color 0 0 0 0) + (uuid d92d6a8f-280b-46e1-8666-fc542978c136) + ) + (junction (at 257.81 71.12) (diameter 0) (color 0 0 0 0) + (uuid f29364eb-6f9a-44ee-9ada-b9530a4818e5) + ) + + (no_connect (at 105.41 60.96) (uuid 02e14ecb-281f-4f3d-8f5b-f03c2be2774a)) + (no_connect (at 52.07 68.58) (uuid 10837e33-4e68-49e7-8045-56d254f760c3)) + (no_connect (at 39.37 53.34) (uuid 1276f9f6-f1d7-4db1-8b1a-ed942a730c6f)) + (no_connect (at 92.71 87.63) (uuid 141fb05e-0fc8-4331-94fb-6e594633c365)) + (no_connect (at 105.41 92.71) (uuid 175f6a1e-b8a8-4cb2-9876-72aa853a9c21)) + (no_connect (at 105.41 107.95) (uuid 19a07d42-bbb8-4ed1-b026-dd44dbce7745)) + (no_connect (at 105.41 95.25) (uuid 1ab53dd2-9b40-44f6-8a0b-f4ff48f61a95)) + (no_connect (at 105.41 63.5) (uuid 2946a5ed-dea8-436d-a403-f12e42cffda9)) + (no_connect (at 92.71 60.96) (uuid 2c37091f-0b69-4f11-b40b-a8f2b99fdfef)) + (no_connect (at 39.37 58.42) (uuid 2e6c9d78-135a-4139-881c-2e15369bbe4e)) + (no_connect (at 52.07 50.8) (uuid 340f5bad-722f-4dd7-ad02-e0296963f516)) + (no_connect (at 105.41 85.09) (uuid 342f6dff-72d6-42c2-9862-e253d4c4fee3)) + (no_connect (at 105.41 105.41) (uuid 37641353-8510-4784-bcd9-6d0af8a34902)) + (no_connect (at 105.41 71.12) (uuid 446b82c6-eaf6-4c61-93a4-7025f35cadf3)) + (no_connect (at 92.71 71.12) (uuid 4ba37343-3f89-4d5d-9e27-f7e4e5789126)) + (no_connect (at 52.07 48.26) (uuid 56e11a62-be7d-49fd-a1ee-aea7ccccbcb1)) + (no_connect (at 52.07 71.12) (uuid 57b40ce3-bcb7-40a8-a790-90c07b8d6424)) + (no_connect (at 92.71 63.5) (uuid 5fe6fbc7-cc4b-49fb-8dd1-41c4b1db3ebe)) + (no_connect (at 92.71 58.42) (uuid 690fdb80-122c-499d-9875-61e86269071e)) + (no_connect (at 92.71 95.25) (uuid 799a0e24-3068-4766-b6fe-f2226ac69c95)) + (no_connect (at 39.37 71.12) (uuid 7a9c0c96-0d24-4f7a-86ae-39e74f01a86c)) + (no_connect (at 52.07 66.04) (uuid 86d141df-a196-4d3e-ad74-24246dc70d09)) + (no_connect (at 39.37 66.04) (uuid 9546d86c-4f8e-4a63-8f83-08b4bfa49a3d)) + (no_connect (at 52.07 53.34) (uuid 9aecb32b-1505-4873-8f4b-724bc72199bc)) + (no_connect (at 105.41 53.34) (uuid 9b4d6cea-7131-4481-a956-5aa03b6d3247)) + (no_connect (at 39.37 50.8) (uuid a0863bea-b3bd-4ffd-b3ff-73675473c622)) + (no_connect (at 105.41 55.88) (uuid a1bf8dbe-78db-4ebe-afec-5180968da477)) + (no_connect (at 105.41 58.42) (uuid a43bcfe3-77fd-4209-a3ac-b34ec193a4f8)) + (no_connect (at 105.41 100.33) (uuid a728d9e4-163a-4f3a-9c16-110f3fe011ea)) + (no_connect (at 39.37 55.88) (uuid a8867314-4c7e-4773-9990-39e904f0e4e5)) + (no_connect (at 52.07 63.5) (uuid ab373b53-cc53-406d-ad4f-496e243b78a8)) + (no_connect (at 92.71 50.8) (uuid ba8b447b-c057-4be3-a5ec-c2f04676a218)) + (no_connect (at 49.53 158.75) (uuid bdbcbbc5-096b-4cb4-b887-0651b9672f1c)) + (no_connect (at 92.71 85.09) (uuid bf00cb17-b71b-4181-b6b5-10dfce6d0abb)) + (no_connect (at 105.41 90.17) (uuid c04ce474-d6e3-459c-b2e9-39dff966ac76)) + (no_connect (at 105.41 97.79) (uuid c195b8d1-0d6c-425c-9278-3f7cf59f372b)) + (no_connect (at 39.37 68.58) (uuid cc070b88-f5a4-431c-af7e-214f9d773271)) + (no_connect (at 105.41 87.63) (uuid cd428b6a-8153-4a89-aeac-4e71c52a517b)) + (no_connect (at 39.37 48.26) (uuid d21adaaa-7a9f-4901-87bd-e27c382495d9)) + (no_connect (at 105.41 102.87) (uuid d8deda2a-71eb-4ce6-9ae1-49df15c8dea2)) + (no_connect (at 92.71 90.17) (uuid ddc360d4-d4a8-4189-8b10-d6b9392e045b)) + (no_connect (at 105.41 68.58) (uuid e8703331-4f08-466b-bc7c-cafd62064081)) + (no_connect (at 92.71 100.33) (uuid e87f31be-867e-4128-a625-5d1ddf924da5)) + (no_connect (at 105.41 66.04) (uuid ef1e1548-d018-4bfe-bc4f-9ca3264693d5)) + (no_connect (at 92.71 68.58) (uuid f3395491-fcf5-4736-a8ee-cbace5525f0e)) + (no_connect (at 92.71 107.95) (uuid f3fd5de1-4ed9-439d-9dc7-ceb87d290f48)) + + (wire (pts (xy 257.81 68.58) (xy 251.46 68.58)) + (stroke (width 0) (type default)) + (uuid 01138170-73f9-4823-9506-1738d24bf2a6) + ) + (wire (pts (xy 182.88 110.49) (xy 186.69 110.49)) + (stroke (width 0) (type default)) + (uuid 11a34e7f-e14e-457d-b0c7-c16335ff1669) + ) + (wire (pts (xy 257.81 71.12) (xy 257.81 73.66)) + (stroke (width 0) (type default)) + (uuid 17c5a835-0904-4d1c-b2f2-e4ae4a6c73df) + ) + (wire (pts (xy 55.88 147.32) (xy 55.88 148.59)) + (stroke (width 0) (type default)) + (uuid 1a304211-dc86-4443-9db3-54bb237bf277) + ) + (wire (pts (xy 186.69 78.74) (xy 186.69 91.44)) + (stroke (width 0) (type default)) + (uuid 1ba98c24-1533-4438-9210-c16715cabd31) + ) + (wire (pts (xy 86.36 92.71) (xy 92.71 92.71)) + (stroke (width 0) (type default)) + (uuid 2160dd6d-268f-46f0-9ba6-785df017111d) + ) + (wire (pts (xy 52.07 55.88) (xy 55.88 55.88)) + (stroke (width 0) (type default)) + (uuid 25f541ae-3e1c-4bbb-8af6-684e35c590ec) + ) + (wire (pts (xy 194.31 113.03) (xy 198.12 113.03)) + (stroke (width 0) (type default)) + (uuid 271ad314-beff-4448-8bfa-83b95756b2fc) + ) + (wire (pts (xy 257.81 68.58) (xy 257.81 71.12)) + (stroke (width 0) (type default)) + (uuid 2a3a9bba-40e4-4f83-a857-2d364199c688) + ) + (wire (pts (xy 194.31 50.8) (xy 198.12 50.8)) + (stroke (width 0) (type default)) + (uuid 2c938643-5232-413b-8485-dea4ededa847) + ) + (wire (pts (xy 52.07 58.42) (xy 55.88 58.42)) + (stroke (width 0) (type default)) + (uuid 30195f84-a019-40ee-badd-009ad4355ad9) + ) + (wire (pts (xy 88.9 74.93) (xy 88.9 55.88)) + (stroke (width 0) (type default)) + (uuid 3960e16a-7fe8-4649-85fc-c52bbb1347a3) + ) + (wire (pts (xy 186.69 110.49) (xy 186.69 123.19)) + (stroke (width 0) (type default)) + (uuid 3e933706-f819-47e7-a77a-70b1cc24e18c) + ) + (wire (pts (xy 73.66 156.21) (xy 77.47 156.21)) + (stroke (width 0) (type default)) + (uuid 4cec1375-8ab8-4479-9227-a4b3064b5121) + ) + (wire (pts (xy 88.9 53.34) (xy 88.9 44.45)) + (stroke (width 0) (type default)) + (uuid 5009ab8f-15ae-4ef9-883e-151f8e97ec07) + ) + (wire (pts (xy 194.31 50.8) (xy 194.31 53.34)) + (stroke (width 0) (type default)) + (uuid 5420cddc-ff30-4142-adbb-79d9b2e6ffb1) + ) + (wire (pts (xy 92.71 53.34) (xy 88.9 53.34)) + (stroke (width 0) (type default)) + (uuid 562f4726-10c4-40c8-91cc-d9346788ae5a) + ) + (wire (pts (xy 49.53 153.67) (xy 64.77 153.67)) + (stroke (width 0) (type default)) + (uuid 56e90dd9-8312-4290-ad05-bb760b9a76e5) + ) + (wire (pts (xy 86.36 48.26) (xy 92.71 48.26)) + (stroke (width 0) (type default)) + (uuid 57ff3361-b0f6-4b30-a36d-1df4890f5f08) + ) + (wire (pts (xy 186.69 48.26) (xy 186.69 60.96)) + (stroke (width 0) (type default)) + (uuid 59fe13b0-e8f7-4bed-9fc0-30b7c0ce3a14) + ) + (wire (pts (xy 49.53 156.21) (xy 73.66 156.21)) + (stroke (width 0) (type default)) + (uuid 5dd8066c-24b3-4f94-b7d6-ff6f778fab5b) + ) + (wire (pts (xy 194.31 81.28) (xy 194.31 83.82)) + (stroke (width 0) (type default)) + (uuid 63e5ef50-ebff-405d-a4b1-c89364ac9493) + ) + (wire (pts (xy 49.53 148.59) (xy 55.88 148.59)) + (stroke (width 0) (type default)) + (uuid 67898f17-331d-4fd9-8cf3-8cfaae2f4f29) + ) + (wire (pts (xy 194.31 81.28) (xy 198.12 81.28)) + (stroke (width 0) (type default)) + (uuid 6b65ae4d-cfd7-4271-b6d9-ebb2d8a2942e) + ) + (wire (pts (xy 44.45 165.1) (xy 41.91 165.1)) + (stroke (width 0) (type default)) + (uuid 91824ee3-2983-424e-9c63-5d5c1cd56dd7) + ) + (wire (pts (xy 182.88 48.26) (xy 186.69 48.26)) + (stroke (width 0) (type default)) + (uuid 94be8937-f540-41ed-8cc3-984047c8cc62) + ) + (wire (pts (xy 194.31 113.03) (xy 194.31 115.57)) + (stroke (width 0) (type default)) + (uuid 94ee4d1a-3e5b-4eeb-848b-5d84e6300b27) + ) + (wire (pts (xy 257.81 66.04) (xy 257.81 68.58)) + (stroke (width 0) (type default)) + (uuid 9772b1fc-e148-4b2d-9844-4d80b227df7a) + ) + (wire (pts (xy 39.37 163.83) (xy 39.37 165.1)) + (stroke (width 0) (type default)) + (uuid 9aa8dbd0-d333-4d47-a312-48f4ff8bf29e) + ) + (wire (pts (xy 55.88 148.59) (xy 55.88 162.56)) + (stroke (width 0) (type default)) + (uuid 9eaf94c6-4a3c-41bf-b91d-690f57d4b0c6) + ) + (wire (pts (xy 257.81 66.04) (xy 251.46 66.04)) + (stroke (width 0) (type default)) + (uuid b1266ec8-3985-494d-96f0-283ff2d6bd6d) + ) + (wire (pts (xy 44.45 166.37) (xy 44.45 165.1)) + (stroke (width 0) (type default)) + (uuid b1d7b782-2212-44d4-a34a-e41b80e37307) + ) + (wire (pts (xy 41.91 165.1) (xy 41.91 163.83)) + (stroke (width 0) (type default)) + (uuid b8f10e73-35e2-4840-85fe-e875b97f9c85) + ) + (wire (pts (xy 64.77 153.67) (xy 64.77 162.56)) + (stroke (width 0) (type default)) + (uuid bbd6bee0-d345-4bca-82f0-a75fe857d8b5) + ) + (wire (pts (xy 52.07 60.96) (xy 59.69 60.96)) + (stroke (width 0) (type default)) + (uuid c092cdd3-feef-47ef-8d61-8f353c03443f) + ) + (wire (pts (xy 251.46 71.12) (xy 257.81 71.12)) + (stroke (width 0) (type default)) + (uuid c206ebf0-12f3-43fe-81a2-9074704a3577) + ) + (wire (pts (xy 83.82 66.04) (xy 92.71 66.04)) + (stroke (width 0) (type default)) + (uuid c2becea2-9330-4c82-8464-0fa054673117) + ) + (wire (pts (xy 55.88 58.42) (xy 55.88 74.93)) + (stroke (width 0) (type default)) + (uuid c7566461-9a25-492b-a37e-d1ec5a366f02) + ) + (wire (pts (xy 86.36 97.79) (xy 92.71 97.79)) + (stroke (width 0) (type default)) + (uuid c9200dbc-f5e9-414c-b83b-ff0c88df91c9) + ) + (wire (pts (xy 182.88 81.28) (xy 194.31 81.28)) + (stroke (width 0) (type default)) + (uuid c9941a1b-b9e3-48a9-9b29-e20195bb0bbf) + ) + (wire (pts (xy 182.88 50.8) (xy 194.31 50.8)) + (stroke (width 0) (type default)) + (uuid d790cd63-8757-4a83-abf9-f94ef01f8125) + ) + (wire (pts (xy 182.88 113.03) (xy 194.31 113.03)) + (stroke (width 0) (type default)) + (uuid e4ba08dc-824b-4666-89d5-d26151c1e18e) + ) + (wire (pts (xy 88.9 55.88) (xy 92.71 55.88)) + (stroke (width 0) (type default)) + (uuid e58cfdb7-876b-40f8-80e8-d0b645634cf8) + ) + (wire (pts (xy 64.77 153.67) (xy 77.47 153.67)) + (stroke (width 0) (type default)) + (uuid ef4a0796-a016-4a30-86f1-eff3ba5a7480) + ) + (wire (pts (xy 182.88 78.74) (xy 186.69 78.74)) + (stroke (width 0) (type default)) + (uuid f0474fd5-8895-4177-81b4-c9fefc3d8571) + ) + (wire (pts (xy 73.66 156.21) (xy 73.66 162.56)) + (stroke (width 0) (type default)) + (uuid fa4c2aa9-82a5-46bc-a149-c4d6c9dda92a) + ) + + (text "USB to host computer" (at 49.53 125.73 0) + (effects (font (size 2.54 2.54) (thickness 0.254) bold) (justify left bottom)) + (uuid 0db574be-a011-4b48-808c-f57996c7a78d) + ) + (text "PA4" (at 86.36 97.79 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 1477f792-83df-4152-8e8b-7586d1e4836f) + ) + (text "ST Morpho connector to NUCLEO" (at 40.64 30.48 0) + (effects (font (size 2.54 2.54) (thickness 0.254) bold) (justify left bottom)) + (uuid 2502b80e-2d58-4f05-9c42-ec05876180ed) + ) + (text "PA5" (at 59.69 60.96 0) + (effects (font (size 1.27 1.27)) (justify right bottom)) + (uuid 43c6f8c7-26c2-4658-b3be-4ca33fffb425) + ) + (text "PA0" (at 86.36 92.71 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 4ed82dd3-23b9-4d09-9068-6c7e0bb936a8) + ) + (text "PA12\nPA11" (at 22.86 64.77 0) + (effects (font (size 1.27 1.27)) (justify left bottom)) + (uuid 93bd8bd3-5680-417a-b52a-42fafd50a3ad) + ) + (text "External signal connectors" (at 186.69 30.48 0) + (effects (font (size 2.54 2.54) (thickness 0.254) bold) (justify left bottom)) + (uuid ce7bd745-4a1d-45e1-8c00-36ffa40fc6f2) + ) + + (global_label "SIGNAL_OUT" (shape input) (at 198.12 81.28 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 10d89912-e360-4ee2-9758-91137e1628f1) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 212.1535 81.28 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "PC1{slash}POT2" (shape input) (at 92.71 102.87 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid 1f63dc8c-8b72-4fbf-911f-67600cb72c69) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 80.4393 102.7906 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "SIGNAL_OUT_MCU" (shape input) (at 86.36 97.79 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid 2c4389f5-c05b-46ec-bcf2-697a8b6668fc) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 67.307 97.79 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "SIGNAL_IN" (shape input) (at 198.12 113.03 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 32d30b1c-b7c1-4411-8e76-b9502fe536db) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 210.4602 113.03 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "GENERATOR" (shape input) (at 198.12 50.8 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 48ac5c15-d529-48d1-b279-d5574d115fbc) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 211.851 50.8 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "GENERATOR_MCU" (shape input) (at 59.69 60.96 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 4bb74090-1e71-4ca0-8b6b-b61fb5a02492) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 78.4405 60.96 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "PC10{slash}LED_R" (shape input) (at 105.41 48.26 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 57cd2906-d9ab-4fca-999f-94b7fa14fb20) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 119.7974 48.1806 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "SIGNAL_OUT" (shape input) (at 238.76 68.58 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid 660918bc-91c1-4bfa-a6fa-4e80f52f503a) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 224.7265 68.58 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "PC12{slash}LED_B" (shape input) (at 105.41 50.8 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 68048f48-82b3-4e13-bbd3-31d79d1afe3e) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 119.7974 50.7206 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "PC11{slash}LED_G" (shape input) (at 86.36 48.26 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid 7f283649-04c7-43a8-ac25-96e75dac14ec) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 71.9726 48.1806 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "USB_D_P" (shape input) (at 77.47 153.67 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 80ed805e-29a0-4561-ad7e-28956861b9ec) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 88.1683 153.5906 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "PC0{slash}POT1" (shape input) (at 92.71 105.41 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid 8492e551-add7-4c91-91ab-521e53e1e74d) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 80.4393 105.3306 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "GENERATOR" (shape input) (at 238.76 66.04 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid 89067483-99cd-4587-8e11-8f7db1996941) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 225.029 66.04 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "USB_D_N" (shape input) (at 39.37 63.5 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid af2aef39-3174-4b72-85b8-71cb0a568e2e) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 28.6112 63.4206 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "SIGNAL_IN" (shape input) (at 238.76 71.12 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid b34a2611-f563-4cec-b5fc-edfa38c6e9be) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 226.4198 71.12 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "SIGNAL_IN_MCU" (shape input) (at 86.36 92.71 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid e3973062-506c-431f-92b9-9cb618502756) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 69.0003 92.71 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "USB_D_P" (shape input) (at 39.37 60.96 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid eaeb3048-ee91-4825-b6fa-5cc8b40a6ff8) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 28.6717 60.8806 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "USB_D_N" (shape input) (at 77.47 156.21 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid f9fe0c63-fae4-43d0-9dd0-e7229fbaf9a5) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 88.2288 156.1306 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + + (symbol (lib_id "Diode:ESD9B5.0ST5G") (at 55.88 166.37 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 0dee484c-3850-4bfd-ac52-a058e497e313) + (property "Reference" "D4" (at 58.42 165.735 90) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "DF2B7AFS,L3M" (at 58.42 168.275 90) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Diode_SMD:D_SOD-923" (at 55.88 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.onsemi.com/pub/Collateral/ESD9B-D.PDF" (at 55.88 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "DF2B7AFS,L3M" (at 55.88 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 8eb33409-faa8-40d4-9d7a-18638942d26f)) + (pin "2" (uuid 5ec6112b-76d7-490e-bb18-3bc29d4108df)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "D4") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 64.77 170.18 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 1a32f1bc-ab0d-4d13-a98a-8d0cda7ca98f) + (property "Reference" "#PWR038" (at 64.77 176.53 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 64.77 175.26 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 64.77 170.18 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 64.77 170.18 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid e396a3f6-dccc-40db-93ad-733b024d4813)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR038") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR064") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 186.69 91.44 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 202c75b6-1292-4802-8ef4-b35ec29dbc4f) + (property "Reference" "#PWR034" (at 186.69 97.79 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 186.69 96.52 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 186.69 91.44 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 186.69 91.44 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 284ad767-8db3-4db9-a2fe-1e95fd1f704c)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR034") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR056") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 257.81 73.66 0) (mirror y) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 27814364-c174-4bf5-8304-524845c1fb46) + (property "Reference" "#PWR036" (at 257.81 80.01 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 257.81 78.74 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 257.81 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 257.81 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 7c310584-25a5-4ff3-8943-9974f60654b9)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR036") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR052") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 186.69 60.96 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 2ae9fd91-8ea4-49c9-8c30-b20f94310ca0) + (property "Reference" "#PWR032" (at 186.69 67.31 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 186.69 66.04 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 186.69 60.96 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 186.69 60.96 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 8d71c6d1-8221-4843-846e-8f0e278eb339)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR032") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR049") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Diode:ESD9B5.0ST5G") (at 64.77 166.37 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 2f36a1b8-dd88-4fdd-80cc-b6a7d1336b74) + (property "Reference" "D5" (at 67.31 165.735 90) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "DF2B7AFS,L3M" (at 67.31 168.275 90) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Diode_SMD:D_SOD-923" (at 64.77 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.onsemi.com/pub/Collateral/ESD9B-D.PDF" (at 64.77 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "DF2B7AFS,L3M" (at 64.77 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c8365dfe-a49f-480a-ac00-dbd50c440bcb)) + (pin "2" (uuid 64e434b0-e31c-4a55-8804-dcbc6cfc24ad)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "D5") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector_Audio:AudioJack2_Ground") (at 177.8 81.28 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 2f551abf-6373-4e81-b42b-ccb46e78a8d3) + (property "Reference" "J5" (at 177.165 73.66 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "AudioJack2_Ground" (at 177.165 76.2 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Connector_Audio:Jack_3.5mm_CUI_SJ-3523-SMT_Horizontal" (at 177.8 81.28 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 177.8 81.28 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "SJ-3523-SMT-TR" (at 177.8 81.28 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "G" (uuid 64e15694-9c93-43bc-9414-b7987c45d427)) + (pin "S" (uuid 7d01e566-80c6-4eac-aacf-ef6f563b8f09)) + (pin "T" (uuid 56e1b378-8db4-4e6f-9dc6-a57b418bb3c3)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "J5") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Diode:ESD5Zxx") (at 194.31 119.38 270) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 2fddc873-d43d-46d7-9c1a-d0acddc1a966) + (property "Reference" "D3" (at 196.85 118.745 90) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "ESD5Zxx" (at 196.85 121.285 90) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Diode_SMD:D_SOD-523" (at 189.865 119.38 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.onsemi.com/pdf/datasheet/esd5z2.5t1-d.pdf" (at 194.31 119.38 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "ESD5Z2.5T1G" (at 194.31 119.38 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid b3573e45-9382-43b1-8a68-7846ffae5f73)) + (pin "2" (uuid 5da17751-d15c-4093-a954-a0db73824f5b)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "D3") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 186.69 123.19 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 354ed183-c965-45c7-b7a5-eea091706c94) + (property "Reference" "#PWR034" (at 186.69 129.54 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 186.69 128.27 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 186.69 123.19 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 186.69 123.19 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid b7469cda-ddbd-4179-bd91-61557e068358)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR034") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR059") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector_Generic:Conn_02x10_Odd_Even") (at 97.79 95.25 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 3c409af7-d0f8-44c1-a8e3-ea5a071f1b52) + (property "Reference" "J3" (at 99.06 78.74 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "Conn_02x10_Odd_Even" (at 99.06 81.28 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_2x10_P2.54mm_Vertical" (at 97.79 95.25 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 97.79 95.25 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "PPPC102LFBN-RC" (at 97.79 95.25 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 0eaaccb3-4b12-44db-83b1-5795c548f312)) + (pin "10" (uuid 8420daf5-6660-46ff-b47f-d0a303cde603)) + (pin "11" (uuid 0ab8500b-cc2a-4ae9-a58c-d44e801ce050)) + (pin "12" (uuid 5fbc71d4-6912-4646-b0c8-4215639357b2)) + (pin "13" (uuid 99d675e1-3c2b-4166-a68d-b7f713e99b1b)) + (pin "14" (uuid 7c75078d-26ce-4e95-aef4-d5a9f894ba06)) + (pin "15" (uuid 65e269db-f019-4159-baa3-df49b6a67013)) + (pin "16" (uuid cb136bb4-f8ee-4a36-b940-67d90d7ac3c3)) + (pin "17" (uuid 542d92fe-07c6-4847-b692-9b61c5a4b399)) + (pin "18" (uuid a4b31083-5779-4119-9876-ca34df3ee275)) + (pin "19" (uuid a901d116-cddd-49ac-b209-8cae1d337d62)) + (pin "2" (uuid a1401b6a-48c7-424b-95da-6d50c6441453)) + (pin "20" (uuid c03be84e-b08e-4bff-aab1-97fefeea019a)) + (pin "3" (uuid 1c87293d-1af2-4b32-9cd4-4035572955bb)) + (pin "4" (uuid 9effd2fb-426e-4603-88e7-970d67013313)) + (pin "5" (uuid 0a3c6c04-c97f-4254-aae8-e6650395030d)) + (pin "6" (uuid 1b12880f-0c62-44a8-bae8-fe1fd95c803b)) + (pin "7" (uuid 807a616b-4a4f-4c01-9032-c6ec9acc3108)) + (pin "8" (uuid 782d5277-e656-4ca1-8362-b913ee4a59b2)) + (pin "9" (uuid d5dfdb19-cc97-4ffe-a210-0335b2104f0b)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "J3") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "J6") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 44.45 166.37 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 3c44300d-4194-4273-ac1c-8e16d11cb43d) + (property "Reference" "#PWR038" (at 44.45 172.72 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 44.45 171.45 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 44.45 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 44.45 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 443d6396-1ec5-432d-a5b2-633d93cdeb5b)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR038") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR062") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 55.88 170.18 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 3d2f6da2-64d6-4af2-8092-72a600be7d57) + (property "Reference" "#PWR038" (at 55.88 176.53 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 55.88 175.26 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 55.88 170.18 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 55.88 170.18 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid e65c94de-6862-4a12-a15c-4e41fce7374f)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR038") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR063") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 177.8 86.36 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid 3d4813c6-9f98-46fc-aee5-70acb4705268) + (property "Reference" "#PWR032" (at 177.8 92.71 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 177.8 91.44 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 177.8 86.36 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 177.8 86.36 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 38543618-7202-42f9-a573-e07a171d2113)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR032") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR055") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VBUS") (at 55.88 147.32 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 3f05b989-e02f-490f-a033-8a49f2e32908) + (property "Reference" "#PWR061" (at 55.88 151.13 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VBUS" (at 55.88 143.51 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 55.88 147.32 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 55.88 147.32 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid d273aedf-7245-41a4-941c-3554a2176f5e)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR061") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Diode:ESD5Zxx") (at 194.31 57.15 270) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 50abfadf-fb6c-48a1-9415-dba8320ad18e) + (property "Reference" "D1" (at 196.85 56.515 90) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "ESD5Zxx" (at 196.85 59.055 90) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Diode_SMD:D_SOD-523" (at 189.865 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.onsemi.com/pdf/datasheet/esd5z2.5t1-d.pdf" (at 194.31 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "ESD5Z2.5T1G" (at 194.31 57.15 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid ca8fb78d-320c-46ed-8ee2-d3e4017ea044)) + (pin "2" (uuid 5098f8fa-78e2-498c-a17d-5416fd0472c0)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "D1") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 177.8 55.88 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 53812d1e-6cb4-4564-944c-12ca50f5498b) + (property "Reference" "#PWR032" (at 177.8 62.23 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 177.8 60.96 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 177.8 55.88 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 177.8 55.88 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 7e626491-6adc-4d63-b0ac-d9146bbb898b)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR032") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR048") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Diode:ESD5Zxx") (at 194.31 87.63 270) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 5dffc28c-19cd-4431-a7ba-b33bafb430ee) + (property "Reference" "D2" (at 196.85 86.995 90) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "ESD5Zxx" (at 196.85 89.535 90) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Diode_SMD:D_SOD-523" (at 189.865 87.63 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.onsemi.com/pdf/datasheet/esd5z2.5t1-d.pdf" (at 194.31 87.63 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "ESD5Z2.5T1G" (at 194.31 87.63 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid a344bd0f-f193-4fa8-b038-a83c4f395d1e)) + (pin "2" (uuid c4d6819b-49d3-40ae-9dac-6aef5fdcbee3)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "D2") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VDDA") (at 55.88 55.88 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 6e9d5039-1f23-42de-af49-829ced31aae6) + (property "Reference" "#PWR04" (at 55.88 59.69 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VDDA" (at 55.88 50.8 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 55.88 55.88 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 55.88 55.88 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c6232a67-c758-4f86-8e7b-b79c0211c586)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR04") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR047") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector_Audio:AudioJack2_Ground") (at 177.8 50.8 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 7694e2a6-3372-4fab-895b-9744296f2da7) + (property "Reference" "J1" (at 177.165 43.18 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "AudioJack2_Ground" (at 177.165 45.72 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Connector_Audio:Jack_3.5mm_CUI_SJ-3523-SMT_Horizontal" (at 177.8 50.8 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 177.8 50.8 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "SJ-3523-SMT-TR" (at 177.8 50.8 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "G" (uuid 0f05d796-6150-45cf-94da-2c8798cc6f86)) + (pin "S" (uuid bbd4f69e-1bbc-4633-bc2b-9086a9729329)) + (pin "T" (uuid f0a9fef1-a57e-4888-a226-d3bf9724656e)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "J1") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector:USB_B_Micro") (at 41.91 153.67 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 78555264-1178-42da-8282-385afceb94d8) + (property "Reference" "J7" (at 41.91 140.97 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "USB_B_Micro" (at 41.91 143.51 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Connector_USB:USB_Micro-B_Amphenol_10104110_Horizontal" (at 45.72 154.94 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 45.72 154.94 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "10104110-0001LF" (at 41.91 153.67 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 11a09a66-afe0-497b-8f7b-213919809f31)) + (pin "2" (uuid ed1359c5-8991-4aa7-bbed-563d9ca0fd76)) + (pin "3" (uuid be5f2ca5-ff80-4355-823b-5493b1d5a1d0)) + (pin "4" (uuid bfd1a233-2c74-4306-8f44-87c4c8b61cf6)) + (pin "5" (uuid 7aaca5cb-84b1-4e7f-8640-8dc917a9ce5b)) + (pin "6" (uuid cabc509a-7bb6-408b-8f4b-241d298cd5ee)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "J7") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "J8") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 194.31 91.44 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 79b31dce-cbe5-427b-b46e-fcc62c592022) + (property "Reference" "#PWR032" (at 194.31 97.79 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 194.31 96.52 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 194.31 91.44 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 194.31 91.44 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid b2c463fc-0143-439a-8e24-bae8b22f5f87)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR032") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR057") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector_Generic:Conn_02x10_Odd_Even") (at 44.45 58.42 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 8475bff6-cb36-4a34-84ec-774f48f03d90) + (property "Reference" "J1" (at 45.72 41.91 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "Conn_02x10_Odd_Even" (at 45.72 44.45 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_2x10_P2.54mm_Vertical" (at 44.45 58.42 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 44.45 58.42 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "PPPC102LFBN-RC" (at 44.45 58.42 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 4c47940c-98bb-44d3-939e-29b2c5c45971)) + (pin "10" (uuid a35c423f-d6b4-47fc-b807-daa86f6a73c2)) + (pin "11" (uuid d8e76a4c-7993-4f37-b339-9d4b02131f3e)) + (pin "12" (uuid 74374593-853b-4040-b66a-c0d4d1a57786)) + (pin "13" (uuid 956c2fb9-525a-4948-a30e-e98c5399d3b6)) + (pin "14" (uuid 605dafb7-a42d-4a78-a475-b585d0e62b49)) + (pin "15" (uuid 0b86922c-178f-470b-aaca-954c9f96bda1)) + (pin "16" (uuid fa27b227-7528-4fa2-9d7a-594c6297c26e)) + (pin "17" (uuid 17ddbd7f-f691-4a34-9895-ab71d5c47926)) + (pin "18" (uuid 6c252ffd-a4e7-4764-8b0f-f80223e1601e)) + (pin "19" (uuid 0b7e0856-149b-432d-9251-52d95d266a41)) + (pin "2" (uuid 9c33d1ec-9f6a-4eb6-b9fe-d6ccb6fdf565)) + (pin "20" (uuid 540ba65e-f1d1-4d5f-ba32-62673667da76)) + (pin "3" (uuid bbe6f617-5bae-486c-8a74-ca1f6eea356c)) + (pin "4" (uuid 2988955b-81e4-4b52-b89b-e7a06ba97abd)) + (pin "5" (uuid 76ebf496-0b49-42e6-8b30-8030c4c7ffc7)) + (pin "6" (uuid 5337e377-0dac-42be-9f63-545482f94793)) + (pin "7" (uuid 1ecfde4b-c3df-4972-accd-e00d2604cad6)) + (pin "8" (uuid e84b46fe-2581-4f5f-93c3-13b01de1bbe3)) + (pin "9" (uuid 249176b3-4cc0-4008-9cb0-11cca57f158c)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "J1") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "J2") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector_Audio:AudioJack2_Ground") (at 177.8 113.03 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 8ca59ac3-e703-4c21-a6a5-9119fbd2e6c2) + (property "Reference" "J7" (at 177.165 105.41 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "AudioJack2_Ground" (at 177.165 107.95 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Connector_Audio:Jack_3.5mm_CUI_SJ-3523-SMT_Horizontal" (at 177.8 113.03 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 177.8 113.03 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "SJ-3523-SMT-TR" (at 177.8 113.03 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "G" (uuid a80cd669-8ef2-4632-9728-28a2b9eacfdf)) + (pin "S" (uuid 879ca810-33c3-4be3-9d19-01414f43b355)) + (pin "T" (uuid 142f9914-dafd-47bc-bc98-5d8aaa505a93)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "J7") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 194.31 123.19 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 9e4a32e2-b480-45f8-9942-42d21a488813) + (property "Reference" "#PWR032" (at 194.31 129.54 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 194.31 128.27 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 194.31 123.19 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 194.31 123.19 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid e0046b0d-9f80-42d0-90cc-a34c2e2bfa9c)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR032") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR060") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 39.37 168.91 0) (mirror y) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid 9f0f3415-176c-4496-afca-6588b7686c1e) + (property "Reference" "R22" (at 36.83 168.275 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "0" (at 36.83 170.815 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 38.354 169.164 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 39.37 168.91 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RMCF0603ZT0R00" (at 39.37 168.91 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 449ea0e2-47fe-40e6-b0ea-f36520e1b0d4)) + (pin "2" (uuid feebb300-b386-445a-8727-e8a9747d6dbd)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "R22") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VCC") (at 83.82 66.04 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid a075c7b2-6b75-48b7-ba62-feffb2e8424d) + (property "Reference" "#PWR015" (at 83.82 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VCC" (at 83.82 60.96 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 83.82 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 83.82 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 17dc7a2c-d6c1-4236-91fa-2b37d621dec2)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR015") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR051") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 177.8 118.11 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid b150da0e-7b6f-4b96-b4b8-58828104dc0c) + (property "Reference" "#PWR032" (at 177.8 124.46 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 177.8 123.19 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 177.8 118.11 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 177.8 118.11 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid f16cebc1-550a-404b-a1d8-3bcfac8dea9c)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR032") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR058") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 55.88 74.93 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid c29cd35b-b63c-4c61-baeb-7950ba97a481) + (property "Reference" "#PWR023" (at 55.88 81.28 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 55.88 80.01 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 55.88 74.93 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 55.88 74.93 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 167403de-dcb3-4b78-b5af-37ef33b1ddaf)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR023") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR053") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 73.66 170.18 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid cfd353e4-0331-4ed6-9450-7c1ebb5ef956) + (property "Reference" "#PWR038" (at 73.66 176.53 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 73.66 175.26 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 73.66 170.18 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 73.66 170.18 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 6b7d8f8c-5565-4036-bb9a-b1834a7c90f0)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR038") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR065") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Diode:ESD9B5.0ST5G") (at 73.66 166.37 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid d707892a-1c20-45ac-bb77-11891c2394e4) + (property "Reference" "D6" (at 76.2 165.735 90) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "DF2B7AFS,L3M" (at 76.2 168.275 90) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Diode_SMD:D_SOD-923" (at 73.66 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "https://www.onsemi.com/pub/Collateral/ESD9B-D.PDF" (at 73.66 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "DF2B7AFS,L3M" (at 73.66 166.37 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 1badecf4-422b-4d5d-8437-f04a2f25d1e8)) + (pin "2" (uuid 77b2372d-097a-4747-8b15-07f0a66045db)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "D6") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VBUS") (at 88.9 44.45 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid d8958fa9-595e-4eea-b400-f6cbaf16d851) + (property "Reference" "#PWR046" (at 88.9 48.26 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VBUS" (at 88.9 40.64 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 88.9 44.45 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 88.9 44.45 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 023e4509-34a0-4227-b4e4-1d81d00aac18)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR046") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector_Generic:Conn_02x03_Odd_Even") (at 243.84 68.58 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid de87bdea-3e5b-416f-bfb4-ea751dfca070) + (property "Reference" "J6" (at 245.11 59.69 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "Conn_02x03_Odd_Even" (at 245.11 62.23 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_Horizontal" (at 243.84 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 243.84 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "PH2RA-06-UA" (at 243.84 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 0d0b164f-a07e-416d-97b5-231df3d7b14c)) + (pin "2" (uuid 176e7f06-8e36-4716-a845-b9657880ee9e)) + (pin "3" (uuid 6e268613-0dde-4f5e-890e-1d9c3b61f29e)) + (pin "4" (uuid f336bc2d-12ba-4cd9-9c94-278c9dcc4661)) + (pin "5" (uuid 7a2c4018-7434-44de-bae6-b7e90b816fde)) + (pin "6" (uuid fe457608-883a-4c19-9511-9d20606bd4a8)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "J6") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "J4") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 194.31 60.96 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid e3aa6d05-70bd-4cde-bf05-6c7655d5d84b) + (property "Reference" "#PWR032" (at 194.31 67.31 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 194.31 66.04 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 194.31 60.96 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 194.31 60.96 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c0ed9697-37a9-405d-813c-af9db23ccce3)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR032") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR050") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector_Generic:Conn_02x10_Odd_Even") (at 97.79 58.42 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid ec63f71a-7153-47f9-b86f-860fe7e45e10) + (property "Reference" "J2" (at 99.06 41.91 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "Conn_02x10_Odd_Even" (at 99.06 44.45 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_2x10_P2.54mm_Vertical" (at 97.79 58.42 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 97.79 58.42 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "PPPC102LFBN-RC" (at 97.79 58.42 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 392a853d-04fc-443f-871d-a69644d936d8)) + (pin "10" (uuid 242b105e-3167-472e-8d80-e6308ea335a2)) + (pin "11" (uuid 0f2274fd-0b27-4b22-9d63-7fca06a8d067)) + (pin "12" (uuid a8b98539-e862-4ddb-8bea-e67519deadf9)) + (pin "13" (uuid c8606985-2245-4c63-9d43-019e8c742fb6)) + (pin "14" (uuid 473964c0-e3ac-4c3f-9584-befe7cf69216)) + (pin "15" (uuid 863dc14f-e1f4-4baa-8c7f-00a739bbd00f)) + (pin "16" (uuid ea80c488-cddb-46fe-a3e2-0fac75c185ce)) + (pin "17" (uuid e3aa0362-9e46-43c6-a055-bd9b58705da7)) + (pin "18" (uuid 32551ce7-cb9c-45f6-8d6f-471c93426176)) + (pin "19" (uuid 23daedb3-522c-48b6-a787-fadeea602b64)) + (pin "2" (uuid f7546210-f6c7-4205-bf4c-a4e6de1e6013)) + (pin "20" (uuid 3c04cda5-c51f-4eef-a743-b99a01a0b658)) + (pin "3" (uuid 1a1916ec-30d2-45f3-be28-a46f614eb449)) + (pin "4" (uuid f9c1ad21-2427-4315-8f0e-1737a603e262)) + (pin "5" (uuid 260af566-7606-4ab8-96a9-97ad307004ca)) + (pin "6" (uuid b4ed07a4-fcf9-4c3f-8b58-6b58b30ff0cc)) + (pin "7" (uuid f664e483-9587-4dbf-b40a-e86e0ef170c9)) + (pin "8" (uuid 6ac8f5e0-6a25-4976-ba18-50f3e81eb160)) + (pin "9" (uuid 6c69fb36-24ef-4cb1-85a0-5736f84173ab)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "J2") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "J3") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 39.37 172.72 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid f18f5482-3c4d-44ab-935a-46c400a9b2b4) + (property "Reference" "#PWR038" (at 39.37 179.07 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 39.37 177.8 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 39.37 172.72 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 39.37 172.72 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid a964d6d9-c115-49a0-8460-0ea0e4ad135c)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR038") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR066") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 88.9 74.93 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid ffe29d7b-7789-4faa-9fb7-cdb8b1797bec) + (property "Reference" "#PWR024" (at 88.9 81.28 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 88.9 80.01 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 88.9 74.93 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 88.9 74.93 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 8a764283-4bfb-4d5f-878f-f01468f09d41)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR024") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR054") (unit 1) + ) + ) + ) + ) +) diff --git a/hardware/power_regulation.kicad_sch b/hardware/power_regulation.kicad_sch new file mode 100755 index 0000000..01a445c --- /dev/null +++ b/hardware/power_regulation.kicad_sch @@ -0,0 +1,2236 @@ +(kicad_sch (version 20230121) (generator eeschema) + + (uuid c6aeebbe-489b-412e-bd61-4ab6df7b25be) + + (paper "A4") + + (title_block + (title "Power regulation") + (date "2023-08-08") + (company "bitgloo") + (comment 1 "Released under the CERN Open Hardware Licence Version 2 - Strongly Reciprocal") + ) + + (lib_symbols + (symbol "Connector:TestPoint" (pin_numbers hide) (pin_names (offset 0.762) hide) (in_bom yes) (on_board yes) + (property "Reference" "TP" (at 0 6.858 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "TestPoint" (at 0 5.08 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 5.08 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 5.08 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "test point tp" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "test point" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "Pin* Test*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "TestPoint_0_1" + (circle (center 0 3.302) (radius 0.762) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "TestPoint_1_1" + (pin passive line (at 0 0 90) (length 2.54) + (name "1" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Device:C" (pin_numbers hide) (pin_names (offset 0.254)) (in_bom yes) (on_board yes) + (property "Reference" "C" (at 0.635 2.54 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "C" (at 0.635 -2.54 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "" (at 0.9652 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "cap capacitor" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Unpolarized capacitor" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "C_*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "C_0_1" + (polyline + (pts + (xy -2.032 -0.762) + (xy 2.032 -0.762) + ) + (stroke (width 0.508) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -2.032 0.762) + (xy 2.032 0.762) + ) + (stroke (width 0.508) (type default)) + (fill (type none)) + ) + ) + (symbol "C_1_1" + (pin passive line (at 0 3.81 270) (length 2.794) + (name "~" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 0 -3.81 90) (length 2.794) + (name "~" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Device:L" (pin_numbers hide) (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes) + (property "Reference" "L" (at -1.27 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "L" (at 1.905 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "inductor choke coil reactor magnetic" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Inductor" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "Choke_* *Coil* Inductor_* L_*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "L_0_1" + (arc (start 0 -2.54) (mid 0.6323 -1.905) (end 0 -1.27) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (arc (start 0 -1.27) (mid 0.6323 -0.635) (end 0 0) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (arc (start 0 0) (mid 0.6323 0.635) (end 0 1.27) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (arc (start 0 1.27) (mid 0.6323 1.905) (end 0 2.54) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "L_1_1" + (pin passive line (at 0 3.81 270) (length 1.27) + (name "1" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 0 -3.81 90) (length 1.27) + (name "2" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Device:R_US" (pin_numbers hide) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "R" (at 2.54 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "R_US" (at -2.54 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 1.016 -0.254 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "R res resistor" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Resistor, US symbol" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "R_*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "R_US_0_1" + (polyline + (pts + (xy 0 -2.286) + (xy 0 -2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.286) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 -0.762) + (xy 1.016 -1.143) + (xy 0 -1.524) + (xy -1.016 -1.905) + (xy 0 -2.286) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0.762) + (xy 1.016 0.381) + (xy 0 0) + (xy -1.016 -0.381) + (xy 0 -0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.286) + (xy 1.016 1.905) + (xy 0 1.524) + (xy -1.016 1.143) + (xy 0 0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "R_US_1_1" + (pin passive line (at 0 3.81 270) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 0 -3.81 90) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Reference_Voltage:MAX6106" (in_bom yes) (on_board yes) + (property "Reference" "U" (at 0 6.35 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "MAX6106" (at 2.54 -6.35 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 2.54 -7.62 0) + (effects (font (size 1.27 1.27) italic) hide) + ) + (property "Datasheet" "http://datasheets.maximintegrated.com/en/ds/MAX6100-MAX6107.pdf" (at 2.54 -8.89 0) + (effects (font (size 1.27 1.27) italic) hide) + ) + (property "ki_keywords" "voltage reference ldo" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Low-dropout high current voltage reference, 2.048V, ±0.4% accuracy, SOT-23" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "SOT?23*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "MAX6106_0_1" + (rectangle (start -5.08 5.08) (end 5.08 -5.08) + (stroke (width 0.254) (type default)) + (fill (type background)) + ) + ) + (symbol "MAX6106_1_1" + (pin power_in line (at -2.54 7.62 270) (length 2.54) + (name "IN" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin power_out line (at 7.62 0 180) (length 2.54) + (name "OUT" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + (pin power_in line (at -2.54 -7.62 90) (length 2.54) + (name "GND" (effects (font (size 1.27 1.27)))) + (number "3" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Regulator_SwitchedCapacitor:LM27761" (in_bom yes) (on_board yes) + (property "Reference" "U" (at -6.35 11.43 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "LM27761" (at 3.302 11.43 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Package_SON:WSON-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mm" (at 3.81 -12.7 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + (property "Datasheet" "http://www.ti.com/lit/ds/symlink/lm27761.pdf" (at 63.5 -10.16 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "low-noise switched capacitor voltage converter invert" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "low-noise regulated switched-capacitor voltage inverter with 2.7V-5.5V input to -1.5 to -5V Output Voltage, WSON-8" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "WSON*1EP?2x2mm*P0.5mm*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "LM27761_0_1" + (rectangle (start -7.62 10.16) (end 7.62 -10.16) + (stroke (width 0.254) (type default)) + (fill (type background)) + ) + ) + (symbol "LM27761_1_1" + (pin power_in line (at -10.16 7.62 0) (length 2.54) + (name "VIN" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin power_in line (at 0 -12.7 90) (length 2.54) + (name "GND" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + (pin power_out line (at 10.16 -2.54 180) (length 2.54) + (name "CPOUT" (effects (font (size 1.27 1.27)))) + (number "3" (effects (font (size 1.27 1.27)))) + ) + (pin power_out line (at 10.16 7.62 180) (length 2.54) + (name "VOUT" (effects (font (size 1.27 1.27)))) + (number "4" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at 10.16 2.54 180) (length 2.54) + (name "VFB" (effects (font (size 1.27 1.27)))) + (number "5" (effects (font (size 1.27 1.27)))) + ) + (pin input line (at -10.16 5.08 0) (length 2.54) + (name "EN" (effects (font (size 1.27 1.27)))) + (number "6" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -10.16 -7.62 0) (length 2.54) + (name "C-" (effects (font (size 1.27 1.27)))) + (number "7" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -10.16 0 0) (length 2.54) + (name "C+" (effects (font (size 1.27 1.27)))) + (number "8" (effects (font (size 1.27 1.27)))) + ) + (pin power_in line (at 2.54 -12.7 90) (length 2.54) + (name "PAD" (effects (font (size 1.27 1.27)))) + (number "9" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:+5V" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 0 3.556 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"+5V\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "+5V_0_1" + (polyline + (pts + (xy -0.762 1.27) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0.762 1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "+5V_1_1" + (pin power_in line (at 0 0 90) (length 0) hide + (name "+5V" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:-5V" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 2.54 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "-5V" (at 0 3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"-5V\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "-5V_0_0" + (pin power_in line (at 0 0 90) (length 0) hide + (name "-5V" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + (symbol "-5V_0_1" + (polyline + (pts + (xy 0 0) + (xy 0 1.27) + (xy 0.762 1.27) + (xy 0 2.54) + (xy -0.762 1.27) + (xy 0 1.27) + ) + (stroke (width 0) (type default)) + (fill (type outline)) + ) + ) + ) + (symbol "power:GND" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -6.35 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 0 -3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"GND\" , ground" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "GND_0_1" + (polyline + (pts + (xy 0 0) + (xy 0 -1.27) + (xy 1.27 -1.27) + (xy 0 -2.54) + (xy -1.27 -1.27) + (xy 0 -1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "GND_1_1" + (pin power_in line (at 0 0 270) (length 0) hide + (name "GND" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:VBUS" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VBUS" (at 0 3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"VBUS\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "VBUS_0_1" + (polyline + (pts + (xy -0.762 1.27) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0.762 1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "VBUS_1_1" + (pin power_in line (at 0 0 90) (length 0) hide + (name "VBUS" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:VDDA" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VDDA" (at 0 3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"VDDA\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "VDDA_0_1" + (polyline + (pts + (xy -0.762 1.27) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0.762 1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "VDDA_1_1" + (pin power_in line (at 0 0 90) (length 0) hide + (name "VDDA" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + ) + + (junction (at 102.87 135.89) (diameter 0) (color 0 0 0 0) + (uuid 2b0a7097-d58e-48f5-b1a9-557408f83890) + ) + (junction (at 77.47 151.13) (diameter 0) (color 0 0 0 0) + (uuid f0c3cd13-cf0e-4352-8da8-28cf5041eb05) + ) + + (wire (pts (xy 87.63 130.81) (xy 91.44 130.81)) + (stroke (width 0) (type default)) + (uuid 0941c4c7-5558-4fc0-bf47-2aaa34586146) + ) + (wire (pts (xy 59.69 71.12) (xy 59.69 72.39)) + (stroke (width 0) (type default)) + (uuid 24337116-ae1a-4aa2-9f89-77b0a194aa7b) + ) + (wire (pts (xy 59.69 133.35) (xy 67.31 133.35)) + (stroke (width 0) (type default)) + (uuid 259048b4-459b-4a53-9a4d-4f37995be0c7) + ) + (wire (pts (xy 102.87 135.89) (xy 102.87 137.16)) + (stroke (width 0) (type default)) + (uuid 355c07f9-a55c-4467-be61-b5c7e66bf130) + ) + (wire (pts (xy 102.87 135.89) (xy 102.87 134.62)) + (stroke (width 0) (type default)) + (uuid 475964ab-ce70-4f9c-aee4-45c1b2f0b4d6) + ) + (wire (pts (xy 48.26 133.35) (xy 52.07 133.35)) + (stroke (width 0) (type default)) + (uuid 556536a6-4230-44c2-a32d-6d2fca3f6ea0) + ) + (wire (pts (xy 80.01 71.12) (xy 80.01 72.39)) + (stroke (width 0) (type default)) + (uuid 63b8704f-625f-4014-8864-9ea515dcf5e2) + ) + (wire (pts (xy 87.63 135.89) (xy 102.87 135.89)) + (stroke (width 0) (type default)) + (uuid 73bf79cc-52eb-4d3e-8902-3bca69d9b345) + ) + (wire (pts (xy 63.5 138.43) (xy 67.31 138.43)) + (stroke (width 0) (type default)) + (uuid ae462b14-232e-49da-aca3-2ec258e00648) + ) + (wire (pts (xy 63.5 130.81) (xy 67.31 130.81)) + (stroke (width 0) (type default)) + (uuid af9639c6-1088-48da-97df-b1fa7835072a) + ) + (wire (pts (xy 208.28 72.39) (xy 212.09 72.39)) + (stroke (width 0) (type default)) + (uuid c9875964-8070-4e31-ac03-a067eb0f07c3) + ) + (wire (pts (xy 63.5 146.05) (xy 67.31 146.05)) + (stroke (width 0) (type default)) + (uuid cac804d7-b44d-496d-950d-d0c4d8a260ab) + ) + (wire (pts (xy 59.69 72.39) (xy 66.04 72.39)) + (stroke (width 0) (type default)) + (uuid ccad4a4b-fdb7-421d-a11f-d4d544c25aa0) + ) + (wire (pts (xy 87.63 140.97) (xy 91.44 140.97)) + (stroke (width 0) (type default)) + (uuid d5247eca-6402-4a11-8810-c55c35a6fe00) + ) + (wire (pts (xy 73.66 72.39) (xy 80.01 72.39)) + (stroke (width 0) (type default)) + (uuid e629ff71-f7b5-4684-84ef-100ee8c2426a) + ) + (wire (pts (xy 77.47 151.13) (xy 80.01 151.13)) + (stroke (width 0) (type default)) + (uuid e73c5c82-c125-4861-8f10-4f799cb4ab6b) + ) + + (text "Analog voltage reference" (at 195.58 53.34 0) + (effects (font (size 2.54 2.54) (thickness 0.254) bold) (justify left bottom)) + (uuid 2b9ac247-ad34-4af4-9f1f-81ad5cac97a2) + ) + (text "+5V inverter" (at 80.01 114.3 0) + (effects (font (size 2.54 2.54) (thickness 0.254) bold) (justify left bottom)) + (uuid 2bf0fe52-ea5c-44a4-a994-2b774ae0c185) + ) + (text "Supply test points" (at 201.93 114.3 0) + (effects (font (size 2.54 2.54) (thickness 0.254) bold) (justify left bottom)) + (uuid 4e9e691e-e51c-49c5-9490-5c283eed198e) + ) + (text "Noise filtering for +5V from VBUS" (at 57.15 54.61 0) + (effects (font (size 2.54 2.54) (thickness 0.254) bold) (justify left bottom)) + (uuid ddf750d9-baac-4dbc-88dc-0d7e3b1b3e53) + ) + + (symbol (lib_id "power:GND") (at 231.14 135.89 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 046decc0-a39e-4aa3-832a-2417ed5faec3) + (property "Reference" "#PWR014" (at 231.14 142.24 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 231.14 140.97 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 231.14 135.89 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 231.14 135.89 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid a7900495-903c-4b9e-9a6c-dc133799e5f6)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR014") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR034") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR040") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:-5V") (at 102.87 127 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 0fe8caa4-7926-43c0-8da8-836c298f3377) + (property "Reference" "#PWR012" (at 102.87 124.46 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "-5V" (at 102.87 121.92 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 102.87 127 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 102.87 127 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c91dff7c-18ec-45f6-afd0-1aa6e8749947)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR012") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR032") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR031") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector:TestPoint") (at 204.47 134.62 180) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 1362f62f-0013-4579-bfe3-657f3da88a4c) + (property "Reference" "TP1" (at 207.01 136.6519 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "TestPoint" (at 207.01 139.1919 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + (property "Footprint" "TestPoint:TestPoint_Pad_D1.0mm" (at 199.39 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 199.39 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c61524bf-721c-4283-bb99-5b3940bcef7e)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "TP1") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "TP1") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "TP1") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 118.11 135.89 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 17e9eb2e-3859-4b1d-b315-52d3f5671c2b) + (property "Reference" "C18" (at 121.92 135.255 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "4.7u" (at 121.92 137.795 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 119.0752 139.7 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 118.11 135.89 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL10A475KP8NNNC" (at 118.11 135.89 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 0cda965f-94fd-4ace-b335-096456ad673d)) + (pin "2" (uuid cbcda09c-636a-4082-b3fb-7d121927b9e7)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "C18") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 63.5 130.81 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 1861e3f2-cef4-4cde-9405-5cfacef90eed) + (property "Reference" "#PWR011" (at 63.5 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 63.5 125.73 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 63.5 130.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 63.5 130.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid d26031c0-e4dc-4bcd-836d-469b08f659a0)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR011") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR030") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR032") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 48.26 133.35 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 1ba35b23-4f63-4c21-abcc-c8fdc06bea89) + (property "Reference" "#PWR011" (at 48.26 137.16 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 48.26 128.27 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 48.26 133.35 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 48.26 133.35 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 51f13e1c-169b-4716-b1f9-e8bb4416ab37)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR011") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR030") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR036") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 63.5 142.24 0) (mirror y) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid 1dcdc424-fb22-42bf-8874-89ad7acc92ec) + (property "Reference" "C20" (at 59.69 141.605 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "1u" (at 59.69 144.145 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 62.5348 146.05 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 63.5 142.24 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL10B105KP8NNNC" (at 63.5 142.24 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 4481173a-a6d6-4807-b57a-bce35d3f144d)) + (pin "2" (uuid 69e8e48f-d1f9-42ed-a9bf-a6d69c02a29c)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "C20") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector:TestPoint") (at 231.14 135.89 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 1e9bd7fc-0998-4613-aa5b-48cd00451144) + (property "Reference" "TP4" (at 233.68 132.5879 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "TestPoint" (at 228.6 131.3181 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + (property "Footprint" "TestPoint:TestPoint_Pad_D1.0mm" (at 236.22 135.89 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 236.22 135.89 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 24676cf7-af6a-426e-bb6f-4b5f913fdeeb)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "TP4") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "TP4") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "TP4") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 242.57 72.39 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 219a1fe6-d5bc-49e5-ba83-808476b87bcb) + (property "Reference" "C17" (at 246.38 71.755 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "1u" (at 246.38 74.295 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 243.5352 76.2 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 242.57 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL10B105KP8NNNC" (at 242.57 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 6b153cc1-b2f8-4a53-9d48-5689b1c084eb)) + (pin "2" (uuid 39542967-46f6-4cd9-b39b-c564e60e7ff2)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "C17") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Reference_Voltage:MAX6106") (at 200.66 72.39 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 2721a4bf-a486-4e4a-95f3-7833d023f203) + (property "Reference" "U3" (at 194.31 71.755 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "MAX6106" (at 194.31 74.295 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 203.2 80.01 0) + (effects (font (size 1.27 1.27) italic) hide) + ) + (property "Datasheet" "http://datasheets.maximintegrated.com/en/ds/MAX6100-MAX6107.pdf" (at 203.2 81.28 0) + (effects (font (size 1.27 1.27) italic) hide) + ) + (property "Part Number" "MAX6106EUR+T" (at 200.66 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 14a2220b-3f94-4b6c-8253-0292c079e977)) + (pin "2" (uuid 6bec615b-28e8-4874-b9bd-ad456dde0db0)) + (pin "3" (uuid 16a57cde-52a3-4ad6-b3e2-482b1c3d1c91)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "U3") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 119.38 73.66 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 2c4be438-6cdd-4af1-896c-80967810d9d7) + (property "Reference" "#PWR038" (at 119.38 80.01 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 119.38 78.74 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 119.38 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 119.38 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid ce28dbda-92cb-422a-80d3-2d1509d298ec)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR038") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR060") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR027") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 77.47 151.13 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 3734b5dc-7757-4164-aaf4-0394d5a5e4e8) + (property "Reference" "#PWR014" (at 77.47 157.48 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 77.47 156.21 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 77.47 151.13 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 77.47 151.13 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 81690a4b-9ea5-43e4-9d13-527d1fb0c182)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR014") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR034") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR045") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 102.87 130.81 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 4928232b-2208-4ba3-94a3-4f551edb95e6) + (property "Reference" "R19" (at 105.41 130.175 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "174k" (at 105.41 132.715 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 103.886 131.064 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 102.87 130.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RMCF0603FT174K" (at 102.87 130.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 0b3d36cd-f02a-40eb-b4e2-ee8a34c11526)) + (pin "2" (uuid 4c42b571-51b2-40c3-917c-5c4dd2d5dfaa)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "R19") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 91.44 144.78 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 5a538b70-0a4a-472f-85a3-5d86c644f91a) + (property "Reference" "C21" (at 95.25 144.145 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "4.7u" (at 95.25 146.685 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 92.4052 148.59 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 91.44 144.78 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL10A475KP8NNNC" (at 91.44 144.78 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 8321bc94-c842-4d5b-a8c7-619af0ca5738)) + (pin "2" (uuid 35c8151c-4c66-420a-99e6-9b4f7bc6341f)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "C21") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VBUS") (at 96.52 66.04 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 63c1a517-0671-47d3-812d-286119ebbe57) + (property "Reference" "#PWR061" (at 96.52 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VBUS" (at 96.52 62.23 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 96.52 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 96.52 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 2af5903d-2193-42bc-bea6-926b80d80d0b)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR061") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR017") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VDDA") (at 222.25 134.62 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 69a0f71b-0607-484e-b263-de0bffc9a9b5) + (property "Reference" "#PWR013" (at 222.25 138.43 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VDDA" (at 222.25 129.54 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 222.25 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 222.25 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 28de77ff-87c7-4ee1-8a34-6eeb63355182)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR013") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR033") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR039") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector:TestPoint") (at 213.36 134.62 180) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 6c19d262-a0fe-4278-9e4c-98da07eea5c9) + (property "Reference" "TP2" (at 215.9 136.6519 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "TestPoint" (at 215.9 139.1919 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + (property "Footprint" "TestPoint:TestPoint_Pad_D1.0mm" (at 208.28 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 208.28 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 11ab48b4-00c1-4420-b776-913031772c78)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "TP2") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "TP2") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "TP2") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 130.81 135.89 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 75cccab0-1f63-406c-b256-08197905c2d8) + (property "Reference" "C19" (at 134.62 135.255 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "2.2u" (at 134.62 137.795 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 131.7752 139.7 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 130.81 135.89 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL10B225KP8NNNC" (at 130.81 135.89 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 12198c25-2660-4a1a-9ddc-8d1629dc760f)) + (pin "2" (uuid b09f302c-5356-4fb4-9ee6-d5ad6a3375f5)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "C19") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 80.01 71.12 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 7b324404-991b-4e7b-ac91-f04cb7cea286) + (property "Reference" "#PWR033" (at 80.01 74.93 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 80.01 66.04 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 80.01 71.12 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 80.01 71.12 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid b7bf0572-26a7-49cd-b90d-2da89242ab16)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR033") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR045") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR023") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 96.52 73.66 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 7bb6ce0d-1d2f-41b2-b395-b56ba1cc97b4) + (property "Reference" "#PWR038" (at 96.52 80.01 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 96.52 78.74 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 96.52 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 96.52 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 97b7c62d-a150-4314-8c2b-3c8d7b5e80bb)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR038") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR058") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR025") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 229.87 68.58 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 85dd6cb0-3ec6-4fd3-a7f3-5c00d59ddd52) + (property "Reference" "#PWR011" (at 229.87 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 229.87 63.5 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 229.87 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 229.87 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid f700b420-c6dc-403d-b658-a9646ac6db33)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR011") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR030") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR020") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 55.88 133.35 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 8e04a020-c831-4020-a547-acddae80ca1b) + (property "Reference" "R20" (at 55.88 128.27 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "0" (at 55.88 130.81 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 56.134 132.334 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 55.88 133.35 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RMCF0603ZT0R00" (at 55.88 133.35 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 6d436e5c-547e-41ff-86fc-7de02c55160f)) + (pin "2" (uuid 7305b306-ad5b-4a93-b739-b99626eb6e8b)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "R20") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 118.11 132.08 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 8e6ccf1c-f269-42c1-9cb6-a06e667980bd) + (property "Reference" "#PWR011" (at 118.11 135.89 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 118.11 127 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 118.11 132.08 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 118.11 132.08 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 0851bb54-ee23-4a4b-a81c-ef250286d779)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR011") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR030") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR034") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 229.87 72.39 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 8f35c64f-1632-4c1b-b8fa-42e58819b677) + (property "Reference" "C16" (at 233.68 71.755 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "4.7u" (at 233.68 74.295 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 230.8352 76.2 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 229.87 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL10A475KP8NNNC" (at 229.87 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 645d0c68-e6c9-493f-88d7-69007e5f25ee)) + (pin "2" (uuid 945e9a39-9c28-4800-a167-a87858c16bbc)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "C16") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VDDA") (at 212.09 72.39 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 8f3f4cc2-fe28-4d27-a2cc-01741fec1dff) + (property "Reference" "#PWR013" (at 212.09 76.2 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VDDA" (at 212.09 67.31 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 212.09 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 212.09 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 3eee085b-c189-432c-897c-8563c3779154)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR013") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR033") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR024") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Connector:TestPoint") (at 222.25 134.62 180) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 9563d063-75b0-44ce-b3ce-3dcaef0a8a7b) + (property "Reference" "TP3" (at 224.79 136.6519 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "TestPoint" (at 224.79 139.1919 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + (property "Footprint" "TestPoint:TestPoint_Pad_D1.0mm" (at 217.17 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 217.17 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid c28177d7-0d6f-42f8-9859-669225cfd629)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "TP3") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "TP3") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "TP3") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VBUS") (at 59.69 71.12 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid 980e1d26-93bc-4d43-9367-6ac9398bd11f) + (property "Reference" "#PWR022" (at 59.69 74.93 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VBUS" (at 59.69 66.04 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 59.69 71.12 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 59.69 71.12 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 95a97132-2d2e-42de-810e-996d6d2d517c)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR022") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 119.38 69.85 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 98f2b9b9-6327-4bc8-b876-121d7ad6905e) + (property "Reference" "C15" (at 123.19 69.215 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "4.7u" (at 123.19 71.755 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 120.3452 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 119.38 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL10A475KP8NNNC" (at 119.38 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 4f07604e-e771-44a6-967e-9aed9515d3f5)) + (pin "2" (uuid 93c96f5c-4843-4ac7-8da8-ad1f21690ddf)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "C15") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "C15") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 102.87 140.97 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid a1ea9e3c-6800-4e35-b5e2-cc7438c29b4e) + (property "Reference" "R21" (at 105.41 140.335 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "56k" (at 105.41 142.875 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 103.886 141.224 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 102.87 140.97 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RMCF0603FT56K0" (at 102.87 140.97 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 11a0ad8e-f178-4da7-9911-1f0675d8445a)) + (pin "2" (uuid 4eb73d7c-564b-4629-bd8e-f7c360497562)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "R21") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 107.95 69.85 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid a3e00720-9b71-4fec-8b36-e7a5cdc4ca07) + (property "Reference" "C14" (at 111.76 69.215 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "100n" (at 111.76 71.755 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 108.9152 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 107.95 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CL10B104KB8NNWC" (at 107.95 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 5ed47f8c-e7db-4bae-941d-46f4c03222e6)) + (pin "2" (uuid 9fe98691-dd94-43c3-8cbb-a358b32112fa)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "C14") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "C14") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Regulator_SwitchedCapacitor:LM27761") (at 77.47 138.43 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid ab5ba760-1b9a-48fc-8a36-c943d7f45f9f) + (property "Reference" "U4" (at 77.47 124.46 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "LM27761" (at 77.47 127 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Package_SON:WSON-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mm" (at 81.28 151.13 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + (property "Datasheet" "http://www.ti.com/lit/ds/symlink/lm27761.pdf" (at 140.97 148.59 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "LM27761DSGR" (at 77.47 138.43 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 21545055-5b80-4ed0-9ac9-2935855f79d1)) + (pin "2" (uuid 72213785-c384-447a-b2f7-3dce8f3a8ff4)) + (pin "3" (uuid 8a7b92d4-9dd9-4f6a-8d34-b0348a67ba66)) + (pin "4" (uuid 546e6335-ed48-4c12-bf5c-107851086860)) + (pin "5" (uuid 30d73505-7266-43ea-b473-c8efc129d173)) + (pin "6" (uuid 898c90d9-2d6f-49b9-afa3-0c2d7b7d5086)) + (pin "7" (uuid 2294023e-d221-41a5-9169-7c17fe4f596e)) + (pin "8" (uuid 8cbc5d5b-0e83-4f83-9cb4-c0c29c762dda)) + (pin "9" (uuid a4fc70c8-4d07-4810-8975-be14e976391e)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "U4") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:-5V") (at 130.81 132.08 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid ace022e9-6578-4042-b901-b11d04f4ab5f) + (property "Reference" "#PWR012" (at 130.81 129.54 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "-5V" (at 130.81 127 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 130.81 132.08 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 130.81 132.08 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 30cd4546-33d5-4a5a-89cc-e513583d5aa3)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR012") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR032") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR035") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 119.38 66.04 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid b0636f3a-4271-4dba-9f14-192c19f32b8a) + (property "Reference" "#PWR033" (at 119.38 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 119.38 60.96 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 119.38 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 119.38 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 42d0f091-2f24-49c7-9bda-875a505d02b5)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR033") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR063") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR019") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 91.44 148.59 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid b20c9d7c-2a79-48cd-ab76-376a4e5f7ba1) + (property "Reference" "#PWR014" (at 91.44 154.94 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 91.44 153.67 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 91.44 148.59 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 91.44 148.59 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 601197e0-9832-4c3d-b1a7-2bd03987bf47)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR014") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR034") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR044") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 130.81 139.7 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid b4dcadca-f631-4d3b-b1fa-841604f4c562) + (property "Reference" "#PWR014" (at 130.81 146.05 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 130.81 144.78 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 130.81 139.7 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 130.81 139.7 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 228640c4-a133-4c5d-81e9-857b4dc26614)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR014") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR034") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR042") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 198.12 64.77 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid be093599-523e-4c2e-b272-abe5809dc134) + (property "Reference" "#PWR011" (at 198.12 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 198.12 59.69 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 198.12 64.77 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 198.12 64.77 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 937eebdd-5301-49e5-b841-531e6acd0fa8)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR011") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR030") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR016") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 198.12 80.01 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid c0a6ce2c-2abe-4806-9b33-6aad4b43fed8) + (property "Reference" "#PWR014" (at 198.12 86.36 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 198.12 85.09 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 198.12 80.01 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 198.12 80.01 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 49c43164-09dd-4dfc-bd48-fa37f6aa7f2c)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR014") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR034") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR030") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 204.47 134.62 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid c9bf1559-a362-435c-9b54-e97ab8f624e0) + (property "Reference" "#PWR011" (at 204.47 138.43 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 204.47 129.54 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 204.47 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 204.47 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid ca17ace4-2639-4fd3-89bf-252e20ca7191)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR011") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR030") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR037") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 102.87 144.78 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid d150fb34-ff0f-4fb8-9bd5-5ac333ff1158) + (property "Reference" "#PWR014" (at 102.87 151.13 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 102.87 149.86 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 102.87 144.78 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 102.87 144.78 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 4650ff88-aff8-4a30-b27d-5975c17453e8)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR014") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR034") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR043") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 118.11 139.7 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid d493e9eb-0593-4b90-9c8f-2a800dff4a27) + (property "Reference" "#PWR014" (at 118.11 146.05 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 118.11 144.78 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 118.11 139.7 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 118.11 139.7 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid f217387a-3b05-4051-a8ff-9644a4c1b9a3)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR014") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR034") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR041") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 242.57 76.2 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid e1d27700-2b11-401d-86e1-e30a724dc96b) + (property "Reference" "#PWR014" (at 242.57 82.55 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 242.57 81.28 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 242.57 76.2 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 242.57 76.2 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 9df71c6c-f1d2-4978-9fb0-0de42b2d1cc7)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR014") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR034") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR029") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:L") (at 69.85 72.39 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid e1dbf950-0e9a-4d00-a47a-b30cf1090893) + (property "Reference" "L1" (at 69.85 68.58 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "33@100MHz" (at 69.85 73.66 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Inductor_SMD:L_0603_1608Metric" (at 69.85 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 69.85 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "BLM18PG330SN1D" (at 69.85 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 6dd83468-e806-4464-8c39-cb81c509c81e)) + (pin "2" (uuid 603c57a9-3abe-4b53-87cf-8b24f5f5440a)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "L1") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "L1") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VDDA") (at 242.57 68.58 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid e8f88fa3-a7ad-45e2-9e3b-660c8ab36936) + (property "Reference" "#PWR013" (at 242.57 72.39 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VDDA" (at 242.57 63.5 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 242.57 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 242.57 68.58 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid ba62c885-7793-4bef-9fbd-126a83cdb25f)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR013") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR033") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR021") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:-5V") (at 91.44 130.81 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid ea02a04a-7e35-43d1-b94b-f59b5022f4ac) + (property "Reference" "#PWR012" (at 91.44 128.27 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "-5V" (at 91.44 125.73 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 91.44 130.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 91.44 130.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 203ec968-cb96-4dba-a4f6-d28f29187f97)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR012") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR032") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR033") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:+5V") (at 107.95 66.04 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid ed2e49b0-c494-4ae8-83e5-7979b9638228) + (property "Reference" "#PWR033" (at 107.95 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "+5V" (at 107.95 60.96 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 107.95 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 107.95 66.04 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 8ddada4c-8473-4576-af2a-46b6ec6af1ce)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR033") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR062") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR018") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:C") (at 96.52 69.85 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid f2d797f3-24bb-4aa5-ba81-171b8a49029e) + (property "Reference" "C13" (at 100.33 69.215 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Value" "10n" (at 100.33 71.755 0) + (effects (font (size 1.27 1.27)) (justify left)) + ) + (property "Footprint" "Capacitor_SMD:C_0603_1608Metric" (at 97.4852 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 96.52 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "CC0603KRX7R9BB103" (at 96.52 69.85 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 3889c5b5-ada8-466e-9da0-08b1be88f996)) + (pin "2" (uuid 5b82a078-7e33-472d-912b-078f7710f2c6)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "C13") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "C13") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:-5V") (at 213.36 134.62 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid f352ed29-9dc0-4d41-90d6-e4145d389395) + (property "Reference" "#PWR012" (at 213.36 132.08 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "-5V" (at 213.36 129.54 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 213.36 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 213.36 134.62 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 850323b0-c815-47aa-939f-03c7add6b113)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR012") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR032") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR038") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 229.87 76.2 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid f3b53079-fa57-432c-82e9-af900d77ad7d) + (property "Reference" "#PWR014" (at 229.87 82.55 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 229.87 81.28 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 229.87 76.2 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 229.87 76.2 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 8a97012a-5db7-42be-b21c-f1397422a5e3)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR014") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR034") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR028") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 107.95 73.66 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid fc312680-4e84-43d8-abad-8d9ca7cd36c6) + (property "Reference" "#PWR038" (at 107.95 80.01 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 107.95 78.74 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 107.95 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 107.95 73.66 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 759805d4-114e-490e-9113-f8a3c4e71b42)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR038") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR059") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/97fc232a-dbc7-49da-a6a0-e33e9aacbabd" + (reference "#PWR026") (unit 1) + ) + ) + ) + ) +) diff --git a/hardware/user_io.kicad_sch b/hardware/user_io.kicad_sch new file mode 100755 index 0000000..f0e3e60 --- /dev/null +++ b/hardware/user_io.kicad_sch @@ -0,0 +1,1030 @@ +(kicad_sch (version 20230121) (generator eeschema) + + (uuid 0edcf05c-5355-4e2c-8fe9-25fab7c199bc) + + (paper "A4") + + (title_block + (title "User I/O") + (date "2023-08-08") + (company "bitgloo") + (comment 1 "Released under the CERN Open Hardware Licence Version 2 - Strongly Reciprocal") + ) + + (lib_symbols + (symbol "Device:LED_RAGB" (pin_names (offset 0) hide) (in_bom yes) (on_board yes) + (property "Reference" "D" (at 0 9.398 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "LED_RAGB" (at 0 -8.89 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 -1.27 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 -1.27 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "LED RGB diode" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "RGB LED, red/anode/green/blue" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "LED* LED_SMD:* LED_THT:*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "LED_RAGB_0_0" + (text "B" (at -1.905 -6.35 0) + (effects (font (size 1.27 1.27))) + ) + (text "G" (at -1.905 -1.27 0) + (effects (font (size 1.27 1.27))) + ) + (text "R" (at -1.905 3.81 0) + (effects (font (size 1.27 1.27))) + ) + ) + (symbol "LED_RAGB_0_1" + (polyline + (pts + (xy -1.27 -5.08) + (xy -2.54 -5.08) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 -5.08) + (xy 1.27 -5.08) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 -3.81) + (xy -1.27 -6.35) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 0) + (xy -2.54 0) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 1.27) + (xy -1.27 -1.27) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 5.08) + (xy -2.54 5.08) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 5.08) + (xy 1.27 5.08) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 6.35) + (xy -1.27 3.81) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 1.27 0) + (xy -1.27 0) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 1.27 0) + (xy 2.54 0) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 1.27) + (xy -1.27 -1.27) + (xy -1.27 -1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.27 6.35) + (xy -1.27 3.81) + (xy -1.27 3.81) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 1.27 -5.08) + (xy 2.032 -5.08) + (xy 2.032 5.08) + (xy 1.27 5.08) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 1.27 -3.81) + (xy 1.27 -6.35) + (xy -1.27 -5.08) + (xy 1.27 -3.81) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 1.27 1.27) + (xy 1.27 -1.27) + (xy -1.27 0) + (xy 1.27 1.27) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 1.27 6.35) + (xy 1.27 3.81) + (xy -1.27 5.08) + (xy 1.27 6.35) + ) + (stroke (width 0.254) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.016 -3.81) + (xy 0.508 -2.286) + (xy -0.254 -2.286) + (xy 0.508 -2.286) + (xy 0.508 -3.048) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.016 1.27) + (xy 0.508 2.794) + (xy -0.254 2.794) + (xy 0.508 2.794) + (xy 0.508 2.032) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy -1.016 6.35) + (xy 0.508 7.874) + (xy -0.254 7.874) + (xy 0.508 7.874) + (xy 0.508 7.112) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 -3.81) + (xy 1.524 -2.286) + (xy 0.762 -2.286) + (xy 1.524 -2.286) + (xy 1.524 -3.048) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 1.27) + (xy 1.524 2.794) + (xy 0.762 2.794) + (xy 1.524 2.794) + (xy 1.524 2.032) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 6.35) + (xy 1.524 7.874) + (xy 0.762 7.874) + (xy 1.524 7.874) + (xy 1.524 7.112) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (rectangle (start 1.27 -1.27) (end 1.27 1.27) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (rectangle (start 1.27 1.27) (end 1.27 1.27) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (rectangle (start 1.27 3.81) (end 1.27 6.35) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (rectangle (start 1.27 6.35) (end 1.27 6.35) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (circle (center 2.032 0) (radius 0.254) + (stroke (width 0) (type default)) + (fill (type outline)) + ) + (rectangle (start 2.794 8.382) (end -2.794 -7.62) + (stroke (width 0.254) (type default)) + (fill (type background)) + ) + ) + (symbol "LED_RAGB_1_1" + (pin passive line (at -5.08 5.08 0) (length 2.54) + (name "RK" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 5.08 0 180) (length 2.54) + (name "A" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 0 0) (length 2.54) + (name "GK" (effects (font (size 1.27 1.27)))) + (number "3" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at -5.08 -5.08 0) (length 2.54) + (name "BK" (effects (font (size 1.27 1.27)))) + (number "4" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Device:R_Potentiometer_US" (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes) + (property "Reference" "RV" (at -4.445 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "R_Potentiometer_US" (at -2.54 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "resistor variable" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Potentiometer, US symbol" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "Potentiometer*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "R_Potentiometer_US_0_1" + (polyline + (pts + (xy 0 -2.286) + (xy 0 -2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0 2.286) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 2.54 0) + (xy 1.524 0) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 1.143 0) + (xy 2.286 0.508) + (xy 2.286 -0.508) + (xy 1.143 0) + ) + (stroke (width 0) (type default)) + (fill (type outline)) + ) + (polyline + (pts + (xy 0 -0.762) + (xy 1.016 -1.143) + (xy 0 -1.524) + (xy -1.016 -1.905) + (xy 0 -2.286) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0.762) + (xy 1.016 0.381) + (xy 0 0) + (xy -1.016 -0.381) + (xy 0 -0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.286) + (xy 1.016 1.905) + (xy 0 1.524) + (xy -1.016 1.143) + (xy 0 0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "R_Potentiometer_US_1_1" + (pin passive line (at 0 3.81 270) (length 1.27) + (name "1" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 3.81 0 180) (length 1.27) + (name "2" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 0 -3.81 90) (length 1.27) + (name "3" (effects (font (size 1.27 1.27)))) + (number "3" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "Device:R_US" (pin_numbers hide) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "R" (at 2.54 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "R_US" (at -2.54 0 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 1.016 -0.254 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "R res resistor" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Resistor, US symbol" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_fp_filters" "R_*" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "R_US_0_1" + (polyline + (pts + (xy 0 -2.286) + (xy 0 -2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.286) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 -0.762) + (xy 1.016 -1.143) + (xy 0 -1.524) + (xy -1.016 -1.905) + (xy 0 -2.286) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0.762) + (xy 1.016 0.381) + (xy 0 0) + (xy -1.016 -0.381) + (xy 0 -0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.286) + (xy 1.016 1.905) + (xy 0 1.524) + (xy -1.016 1.143) + (xy 0 0.762) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "R_US_1_1" + (pin passive line (at 0 3.81 270) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + (pin passive line (at 0 -3.81 90) (length 1.27) + (name "~" (effects (font (size 1.27 1.27)))) + (number "2" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:GND" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -6.35 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 0 -3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"GND\" , ground" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "GND_0_1" + (polyline + (pts + (xy 0 0) + (xy 0 -1.27) + (xy 1.27 -1.27) + (xy 0 -2.54) + (xy -1.27 -1.27) + (xy 0 -1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "GND_1_1" + (pin power_in line (at 0 0 270) (length 0) hide + (name "GND" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + (symbol "power:VCC" (power) (pin_names (offset 0)) (in_bom yes) (on_board yes) + (property "Reference" "#PWR" (at 0 -3.81 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VCC" (at 0 3.81 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_keywords" "global power" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "ki_description" "Power symbol creates a global label with name \"VCC\"" (at 0 0 0) + (effects (font (size 1.27 1.27)) hide) + ) + (symbol "VCC_0_1" + (polyline + (pts + (xy -0.762 1.27) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 0) + (xy 0 2.54) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + (polyline + (pts + (xy 0 2.54) + (xy 0.762 1.27) + ) + (stroke (width 0) (type default)) + (fill (type none)) + ) + ) + (symbol "VCC_1_1" + (pin power_in line (at 0 0 90) (length 0) hide + (name "VCC" (effects (font (size 1.27 1.27)))) + (number "1" (effects (font (size 1.27 1.27)))) + ) + ) + ) + ) + + + (wire (pts (xy 96.52 106.68) (xy 100.33 106.68)) + (stroke (width 0) (type default)) + (uuid 222aa4be-b44f-43d8-9f1d-36f978346489) + ) + (wire (pts (xy 96.52 111.76) (xy 100.33 111.76)) + (stroke (width 0) (type default)) + (uuid 36caa1f7-82cf-4e39-998d-7cccd6c68c00) + ) + (wire (pts (xy 110.49 106.68) (xy 114.3 106.68)) + (stroke (width 0) (type default)) + (uuid b3676852-c578-405f-a793-f6668e22af7a) + ) + (wire (pts (xy 96.52 115.57) (xy 96.52 111.76)) + (stroke (width 0) (type default)) + (uuid cfee4500-40f6-4487-b611-6717f3037bb0) + ) + (wire (pts (xy 96.52 97.79) (xy 96.52 101.6)) + (stroke (width 0) (type default)) + (uuid d26e9002-6368-445c-9889-91050d5d6bde) + ) + (wire (pts (xy 96.52 101.6) (xy 100.33 101.6)) + (stroke (width 0) (type default)) + (uuid e9c734d6-1417-42bf-93f2-87e45d7558bc) + ) + + (text "Status LEDs and parameter knobs" (at 115.57 69.85 0) + (effects (font (size 2.54 2.54) (thickness 0.254) bold) (justify left bottom)) + (uuid c13dc8fd-4ee1-4031-b224-1a84272505b9) + ) + + (global_label "PC0{slash}POT1" (shape input) (at 153.67 106.68 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 00398924-6e31-4c1f-8993-22b891a1f27b) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 165.9407 106.6006 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "PC12{slash}LED_B" (shape input) (at 88.9 115.57 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid 0fd3b223-092e-4a18-9e3b-460e3e4605d7) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 74.5126 115.4906 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "PC10{slash}LED_R" (shape input) (at 88.9 97.79 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid 2074dbb5-c735-483e-a108-ecde670d15b4) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 74.5126 97.7106 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + (global_label "PC1{slash}POT2" (shape input) (at 196.85 106.68 0) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify left)) + (uuid 85823cba-5162-4cff-9c65-741e34b8bc70) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 209.1207 106.6006 0) + (effects (font (size 1.27 1.27)) (justify left) hide) + ) + ) + (global_label "PC11{slash}LED_G" (shape input) (at 88.9 106.68 180) (fields_autoplaced) + (effects (font (size 1.27 1.27)) (justify right)) + (uuid cdea714e-c064-473d-a6c3-973f5beb0d4e) + (property "Intersheetrefs" "${INTERSHEET_REFS}" (at 74.5126 106.6006 0) + (effects (font (size 1.27 1.27)) (justify right) hide) + ) + ) + + (symbol (lib_id "Device:R_Potentiometer_US") (at 193.04 106.68 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 04ebdf1c-ac9d-479f-992a-1ea0aeec5c23) + (property "Reference" "RV2" (at 190.5 105.4099 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "10K" (at 190.5 107.9499 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Potentiometer_THT:Potentiometer_Bourns_3386P_Vertical" (at 193.04 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 193.04 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "3386P-1-103TLF" (at 193.04 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 5468099e-cb95-4972-9078-30e43b094d04)) + (pin "2" (uuid 0de265c9-fa60-41cd-b5c8-3b2982f1e4cf)) + (pin "3" (uuid 8d22e474-522c-442d-84f9-4d3795fa75e1)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "RV2") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "RV2") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "RV2") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VCC") (at 193.04 102.87 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 0b7ce666-6cbf-4100-957e-48b86848c1c6) + (property "Reference" "#PWR056" (at 193.04 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VCC" (at 193.04 97.79 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 193.04 102.87 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 193.04 102.87 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 4d67f819-24dd-4ed0-ae73-b63ed362a7b4)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR056") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR027") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "#PWR068") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 92.71 106.68 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 29f7e662-f721-4c3d-848d-61fc5171ba42) + (property "Reference" "R18" (at 92.71 100.33 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "240" (at 92.71 102.87 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 92.964 105.664 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 92.71 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RC0603JR-07240RL" (at 92.71 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid bc61001a-9375-4494-bd53-b146b8cbbfcd)) + (pin "2" (uuid 0608467e-09dc-44ae-a62b-e571005c919b)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "R18") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "R16") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "R24") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 149.86 110.49 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 33bbd370-c8f7-49bf-97f1-713e8b674cb2) + (property "Reference" "#PWR058" (at 149.86 116.84 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 149.86 115.57 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 149.86 110.49 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 149.86 110.49 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid a8bd6d9a-853c-4922-aefa-69fd558f0efa)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR058") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR024") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "#PWR070") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:GND") (at 193.04 110.49 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 50eee7b6-f7e8-49f5-a03a-3e57c0517f9c) + (property "Reference" "#PWR059" (at 193.04 116.84 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "GND" (at 193.04 115.57 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 193.04 110.49 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 193.04 110.49 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 3b179701-3be9-44fd-b148-1cca65b5261f)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR059") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR028") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "#PWR071") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 92.71 97.79 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 63c4f82c-3aee-47eb-aaf9-4ff013fc8a40) + (property "Reference" "R17" (at 92.71 91.44 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "560" (at 92.71 93.98 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 92.964 96.774 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 92.71 97.79 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RC0603JR-07560RL" (at 92.71 97.79 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 261550e6-b14d-4948-b24c-2c241f5f4547)) + (pin "2" (uuid dd48f3e0-3f5d-46bd-85da-f4476fc2bdae)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "R17") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "R15") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "R23") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VCC") (at 149.86 102.87 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 881d1958-8c2a-4d5a-827d-7379482ba809) + (property "Reference" "#PWR055" (at 149.86 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VCC" (at 149.86 97.79 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 149.86 102.87 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 149.86 102.87 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 3f92816b-1cb9-4f48-9c32-7731fb5014e6)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR055") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR023") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "#PWR067") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:LED_RAGB") (at 105.41 106.68 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid 9ec9653f-c3a4-41f7-9b1c-80cc24251ffe) + (property "Reference" "D7" (at 105.41 93.98 0) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "LED_RAGB" (at 105.41 96.52 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "LED_SMD:LED_Kingbright_AAA3528ESGCT" (at 105.41 107.95 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "~" (at 105.41 107.95 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "AAA3528SEEZGKQBKS" (at 105.41 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 363fad31-16fa-4be8-b5d2-c004f7616847)) + (pin "2" (uuid c958bf86-e891-47cb-9056-d1b81e2b51c9)) + (pin "3" (uuid 42dd1fb6-acbd-4b4d-9b66-616c7b1fcb01)) + (pin "4" (uuid 0998c988-3a4a-4a56-b61e-668bef55cafd)) + (instances + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "D7") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_US") (at 92.71 115.57 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid d04657bd-c6dc-4346-b2bd-fdac6c2c8be6) + (property "Reference" "R19" (at 92.71 109.22 90) + (effects (font (size 1.27 1.27))) + ) + (property "Value" "240" (at 92.71 111.76 90) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "Resistor_SMD:R_0603_1608Metric" (at 92.964 114.554 90) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 92.71 115.57 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "RC0603JR-07240RL" (at 92.71 115.57 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 58518da9-c923-45a5-928d-33b164e619f0)) + (pin "2" (uuid 55ad7eab-6366-4c1f-aa56-1782827f3e8e)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "R19") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "R17") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "R25") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "power:VCC") (at 114.3 106.68 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid f28364df-0228-4487-bd82-798aa123dfd6) + (property "Reference" "#PWR057" (at 114.3 110.49 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Value" "VCC" (at 114.3 101.6 0) + (effects (font (size 1.27 1.27))) + ) + (property "Footprint" "" (at 114.3 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 114.3 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid e5e3bf25-e96c-47aa-b8ea-b90319a51b17)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "#PWR057") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "#PWR019") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "#PWR069") (unit 1) + ) + ) + ) + ) + + (symbol (lib_id "Device:R_Potentiometer_US") (at 149.86 106.68 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) (fields_autoplaced) + (uuid f4a975b9-7021-410d-9761-44f0c502022e) + (property "Reference" "RV1" (at 147.32 105.4099 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Value" "10K" (at 147.32 107.9499 0) + (effects (font (size 1.27 1.27)) (justify right)) + ) + (property "Footprint" "Potentiometer_THT:Potentiometer_Bourns_3386P_Vertical" (at 149.86 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Datasheet" "" (at 149.86 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (property "Part Number" "3386P-1-103TLF" (at 149.86 106.68 0) + (effects (font (size 1.27 1.27)) hide) + ) + (pin "1" (uuid 1a649be3-376f-4b5d-81c4-a51773e11622)) + (pin "2" (uuid 2642011f-a119-4c97-a567-49296afdd169)) + (pin "3" (uuid 402bf8e9-23dc-4da7-aabf-504b3b356586)) + (instances + (project "stmdsp_rev3" + (path "/975c3983-57e7-4e06-a697-831e5209dd80" + (reference "RV1") (unit 1) + ) + ) + (project "DSP PAW add-on board" + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/270d19d2-3af2-41db-ad1c-33373417ec82" + (reference "RV1") (unit 1) + ) + (path "/c291319b-d76e-4fda-91cc-061acff65f9f/7798c5d5-f9b1-4b2e-811c-a15abcd34bfa" + (reference "RV1") (unit 1) + ) + ) + ) + ) +)