diff --git a/font16.vlw b/font16.vlw new file mode 100644 index 0000000..020cb71 Binary files /dev/null and b/font16.vlw differ diff --git a/font16_chs.vlw b/font16_chs.vlw new file mode 100644 index 0000000..1839597 Binary files /dev/null and b/font16_chs.vlw differ diff --git a/font28.vlw b/font28.vlw new file mode 100644 index 0000000..0ad96f1 Binary files /dev/null and b/font28.vlw differ diff --git a/font28_chs.vlw b/font28_chs.vlw new file mode 100644 index 0000000..b15917e Binary files /dev/null and b/font28_chs.vlw differ diff --git a/font48.vlw b/font48.vlw new file mode 100644 index 0000000..3cc31b3 Binary files /dev/null and b/font48.vlw differ diff --git a/include/globals.h b/include/globals.h index 2ae26cf..65d6e03 100644 --- a/include/globals.h +++ b/include/globals.h @@ -346,14 +346,12 @@ extern mem presets[EE_PRESETS_CNT]; extern TEF6686 radio; extern TFT_eSprite FrequencySprite; -extern TFT_eSprite RDSSprite; extern TFT_eSprite SquelchSprite; extern TFT_eSprite FullLineSprite; extern TFT_eSprite OneBigLineSprite; extern TFT_eSprite SignalSprite; extern TFT_eSprite PSSprite; -extern TFT_eSprite PTYSprite; -extern TFT_eSprite CTSprite; +extern TFT_eSprite GeneralTextSprite; extern WiFiConnect wc; extern WiFiServer Server; diff --git a/include/scrolling_text.h b/include/scrolling_text.h index b66e3b2..1cb4d39 100644 --- a/include/scrolling_text.h +++ b/include/scrolling_text.h @@ -14,14 +14,16 @@ private: unsigned long holdTick; bool isScrolling; std::function postDrawCallback; + int usedW; + int usedH; static const unsigned long SCROLL_INTERVAL = 5; static const unsigned long HOLD_DURATION = 2000; + static const int SCROLL_GAP = 10; public: - ScrollingTextDisplay(TFT_eSprite* spr, int y, int maxW) - : sprite(spr), yPos(y), maxWidth(maxW), - xPos(0), textWidth(0), lastTick(0), holdTick(0), isScrolling(false), postDrawCallback(nullptr) {} + ScrollingTextDisplay(TFT_eSprite* spr, int y, int maxW, int inuseW = -1, int inuseH = -1 ) : + sprite(spr), yPos(y), maxWidth(maxW), xPos(0), textWidth(0), lastTick(0), holdTick(0), isScrolling(false), postDrawCallback(nullptr), usedW(inuseW), usedH(inuseH) {} void setPostDrawCallback(std::function callback) { postDrawCallback = callback; @@ -35,9 +37,10 @@ public: isScrolling = false; drawText(text, status, activeColor, activeSmooth, dropoutColor, dropoutSmooth, backgroundColor); } else { + if(!isScrolling) holdTick = millis(); isScrolling = true; if(millis() - lastTick >= SCROLL_INTERVAL) { - if(xPos < -textWidth) xPos = 0; + if(xPos <= -(textWidth + SCROLL_GAP)) xPos = 0; if(xPos == 0) { if(millis() - holdTick >= HOLD_DURATION) { @@ -71,12 +74,29 @@ public: private: void drawText(const String& text, bool status, uint16_t activeColor, uint16_t activeSmooth, uint16_t dropoutColor, uint16_t dropoutSmooth, uint16_t backgroundColor) { - sprite->fillSprite(backgroundColor); - if(status) sprite->setTextColor(activeColor, activeSmooth, false); - else sprite->setTextColor(dropoutColor, dropoutSmooth, false); - sprite->drawString(text, xPos, 0); - if(isScrolling) sprite->drawString(text, xPos + textWidth, 0); + if(usedW > 0 && usedH > 0) { + sprite->fillSprite(TFT_TRANSPARENT); + sprite->fillRect(0, 0, usedW, usedH, backgroundColor); + + sprite->setViewport(0, 0, usedW, usedH); + + if(status) sprite->setTextColor(activeColor, activeSmooth, false); + else sprite->setTextColor(dropoutColor, dropoutSmooth, false); + sprite->drawString(text, xPos, 0); + if(isScrolling) sprite->drawString(text, xPos + textWidth + SCROLL_GAP, 0); + + sprite->resetViewport(); + } else { + sprite->fillSprite(backgroundColor); + if(status) sprite->setTextColor(activeColor, activeSmooth, false); + else sprite->setTextColor(dropoutColor, dropoutSmooth, false); + sprite->drawString(text, xPos, 0); + if(isScrolling) sprite->drawString(text, xPos + textWidth + SCROLL_GAP, 0); + } + + sprite->fillRect(0, sprite->fontHeight(), sprite->width(), sprite->height() - sprite->fontHeight(), TFT_TRANSPARENT); + if(postDrawCallback) postDrawCallback(sprite, false); - sprite->pushSprite(35, yPos); + sprite->pushSprite(35, yPos, TFT_TRANSPARENT); } }; \ No newline at end of file diff --git a/lib/RX8010SJ/LICENSE b/lib/RX8010SJ/LICENSE new file mode 100644 index 0000000..e72bfdd --- /dev/null +++ b/lib/RX8010SJ/LICENSE @@ -0,0 +1,674 @@ + 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. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/lib/TFT_eSPI/TFT_eSPI.cpp b/lib/TFT_eSPI/TFT_eSPI.cpp index 837db3a..2176d1d 100644 --- a/lib/TFT_eSPI/TFT_eSPI.cpp +++ b/lib/TFT_eSPI/TFT_eSPI.cpp @@ -2,151 +2,17 @@ #include #include -#if !defined (TFT_PARALLEL_8_BIT) - #ifdef CONFIG_IDF_TARGET_ESP32 - SPIClass spi = SPIClass(VSPI); - #else - SPIClass& spi = SPI; - #endif -#endif +SPIClass spi = SPIClass(VSPI); -#ifdef ESP32_DMA - // DMA SPA handle - spi_device_handle_t dmaHAL; - #ifdef CONFIG_IDF_TARGET_ESP32 - #define DMA_CHANNEL 1 - #ifdef USE_HSPI_PORT - spi_host_device_t spi_host = HSPI_HOST; - #elif defined(USE_FSPI_PORT) - spi_host_device_t spi_host = SPI_HOST; - #else // use VSPI port - spi_host_device_t spi_host = VSPI_HOST; - #endif - #else - #ifdef USE_HSPI_PORT - #define DMA_CHANNEL SPI_DMA_CH_AUTO - spi_host_device_t spi_host = (spi_host_device_t) SPI3_HOST; // Draws once then freezes - #else // use FSPI port - #define DMA_CHANNEL SPI_DMA_CH_AUTO - spi_host_device_t spi_host = (spi_host_device_t) SPI2_HOST; // Draws once then freezes - #endif - #endif -#endif +spi_device_handle_t dmaHAL; +spi_host_device_t spi_host = VSPI_HOST; -#if !defined (TFT_PARALLEL_8_BIT) - // Volatile for register reads: - volatile uint32_t* _spi_cmd = (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT)); - volatile uint32_t* _spi_user = (volatile uint32_t*)(SPI_USER_REG(SPI_PORT)); - // Register writes only: - volatile uint32_t* _spi_mosi_dlen = (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT)); - volatile uint32_t* _spi_w = (volatile uint32_t*)(SPI_W0_REG(SPI_PORT)); -#endif +volatile uint32_t* _spi_cmd = (volatile uint32_t*)(SPI_CMD_REG(SPI_PORT)); +volatile uint32_t* _spi_user = (volatile uint32_t*)(SPI_USER_REG(SPI_PORT)); +volatile uint32_t* _spi_mosi_dlen = (volatile uint32_t*)(SPI_MOSI_DLEN_REG(SPI_PORT)); +volatile uint32_t* _spi_w = (volatile uint32_t*)(SPI_W0_REG(SPI_PORT)); -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_SDA_READ) -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: beginSDA - VSPI port only, FPSI port only for S2 -** Description: Detach MOSI and attach MISO to SDA for reads -***************************************************************************************/ -void TFT_eSPI::begin_SDA_Read(void) -{ - gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_INPUT); - #ifdef CONFIG_IDF_TARGET_ESP32 - pinMatrixInAttach(TFT_MOSI, VSPIQ_IN_IDX, false); - #else // S2 - pinMatrixInAttach(TFT_MOSI, FSPIQ_IN_IDX, false); - #endif - SET_BUS_READ_MODE; -} - -/*************************************************************************************** -** Function name: endSDA - VSPI port only, FPSI port only for S2 -** Description: Attach MOSI to SDA and detach MISO for writes -***************************************************************************************/ -void TFT_eSPI::end_SDA_Read(void) -{ - gpio_set_direction((gpio_num_t)TFT_MOSI, GPIO_MODE_OUTPUT); - #ifdef CONFIG_IDF_TARGET_ESP32 - pinMatrixOutAttach(TFT_MOSI, VSPID_OUT_IDX, false, false); - #else // S2 - pinMatrixOutAttach(TFT_MOSI, FSPID_OUT_IDX, false, false); - #endif - SET_BUS_WRITE_MODE; -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // #if defined (TFT_SDA_READ) -//////////////////////////////////////////////////////////////////////////////////////// - - -/*************************************************************************************** -** Function name: read byte - supports class functions -** Description: Read a byte from ESP32 8-bit data port -***************************************************************************************/ -// Parallel bus MUST be set to input before calling this function! -uint8_t TFT_eSPI::readByte(void) -{ - uint8_t b = 0xAA; - return b; -} - -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: pushBlock - for ESP32 -** Description: Write a block of pixels of the same colour -***************************************************************************************/ -/* -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ - - uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); - bool empty = true; - volatile uint32_t* spi_w = (volatile uint32_t*)_spi_w; - if (len > 31) - { - *_spi_mosi_dlen = 511; - spi_w[0] = color32; - spi_w[1] = color32; - spi_w[2] = color32; - spi_w[3] = color32; - spi_w[4] = color32; - spi_w[5] = color32; - spi_w[6] = color32; - spi_w[7] = color32; - spi_w[8] = color32; - spi_w[9] = color32; - spi_w[10] = color32; - spi_w[11] = color32; - spi_w[12] = color32; - spi_w[13] = color32; - spi_w[14] = color32; - spi_w[15] = color32; - while(len>31) - { - while ((*_spi_cmd)&SPI_USR); - *_spi_cmd = SPI_USR; - len -= 32; - } - empty = false; - } - - if (len) - { - if(empty) { - for (uint32_t i=0; i <= len; i+=2) *spi_w++ = color32; - } - len = (len << 4) - 1; - while (*_spi_cmd&SPI_USR); - *_spi_mosi_dlen = len; - *_spi_cmd = SPI_USR; - } - while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully? -} -//*/ -//* -void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) { volatile uint32_t* spi_w = _spi_w; uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8); @@ -154,14 +20,12 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ uint32_t rem = len & 0x1F; len = len - rem; - // Start with partial buffer pixels - if (rem) - { + if (rem) { while (*_spi_cmd&SPI_USR); for (i=0; i < rem; i+=2) *spi_w++ = color32; *_spi_mosi_dlen = (rem << 4) - 1; *_spi_cmd = SPI_USR; - if (!len) return; //{while (*_spi_cmd&SPI_USR); return; } + if (!len) return; i = i>>1; while(i++<16) *spi_w++ = color32; } @@ -169,35 +33,22 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ if (!rem) while (i++<16) *spi_w++ = color32; *_spi_mosi_dlen = 511; - // End with full buffer to maximise useful time for downstream code - while(len) - { + while(len) { while (*_spi_cmd&SPI_USR); *_spi_cmd = SPI_USR; len -= 32; } - - // Do not wait here - //while (*_spi_cmd&SPI_USR); } -//*/ -/*************************************************************************************** -** Function name: pushSwapBytePixels - for ESP32 -** Description: Write a sequence of pixels with swapped bytes -***************************************************************************************/ -void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ +void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len) { uint8_t* data = (uint8_t*)data_in; uint32_t color[16]; - if (len > 31) - { + if (len > 31) { WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511); - while(len>31) - { + while(len>31) { uint32_t i = 0; - while(i<16) - { + while(i<16) { color[i++] = DAT8TO32(data); data+=4; } @@ -258,10 +109,6 @@ void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ } -/*************************************************************************************** -** Function name: pushPixels - for ESP32 -** Description: Write a sequence of pixels -***************************************************************************************/ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ if(_swapBytes) { @@ -271,11 +118,9 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ uint32_t *data = (uint32_t*)data_in; - if (len > 31) - { + if (len > 31) { WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), 511); - while(len>31) - { + while(len>31) { while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), *data++); WRITE_PERI_REG(SPI_W1_REG(SPI_PORT), *data++); @@ -298,8 +143,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ } } - if (len) - { + if (len) { while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), (len << 4) - 1); for (uint32_t i=0; i <= (len<<1); i+=4) WRITE_PERI_REG((SPI_W0_REG(SPI_PORT) + i), *data++); @@ -307,17 +151,7 @@ void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ } while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR); } -//////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////////// - -/*************************************************************************************** -** Function name: dmaBusy -** Description: Check if DMA is busy -***************************************************************************************/ bool TFT_eSPI::dmaBusy(void) { if (!DMA_Enabled || !spiBusyCheck) return false; @@ -331,35 +165,22 @@ bool TFT_eSPI::dmaBusy(void) if (ret == ESP_OK) spiBusyCheck--; } - //Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck); if (spiBusyCheck ==0) return false; return true; } - -/*************************************************************************************** -** Function name: dmaWait -** Description: Wait until DMA is over (blocking!) -***************************************************************************************/ void TFT_eSPI::dmaWait(void) { if (!DMA_Enabled || !spiBusyCheck) return; spi_transaction_t *rtrans; esp_err_t ret; - for (int i = 0; i < spiBusyCheck; ++i) - { + for (int i = 0; i < spiBusyCheck; ++i) { ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY); assert(ret == ESP_OK); } spiBusyCheck = 0; } - -/*************************************************************************************** -** Function name: pushPixelsDMA -** Description: Push pixels to TFT (len must be less than 32767) -***************************************************************************************/ -// This will byte swap the original image if setSwapBytes(true) was called by sketch. void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) { if ((len == 0) || (!DMA_Enabled)) return; @@ -386,123 +207,6 @@ void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) spiBusyCheck++; } - -/*************************************************************************************** -** Function name: pushImageDMA -** Description: Push image to a window (w*h must be less than 65536) -***************************************************************************************/ -// Fixed const data assumed, will NOT clip or swap bytes -void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t const* image) -{ - if ((w == 0) || (h == 0) || (!DMA_Enabled)) return; - - uint32_t len = w*h; - - dmaWait(); - - setAddrWindow(x, y, w, h); - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = image; //Data pointer - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - - -/*************************************************************************************** -** Function name: pushImageDMA -** Description: Push image to a window (w*h must be less than 65536) -***************************************************************************************/ -// This will clip and also swap bytes if setSwapBytes(true) was called by sketch -void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer) -{ - if ((x >= _vpW) || (y >= _vpH) || (!DMA_Enabled)) return; - - int32_t dx = 0; - int32_t dy = 0; - int32_t dw = w; - int32_t dh = h; - - if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } - if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } - - if ((x + dw) > _vpW ) dw = _vpW - x; - if ((y + dh) > _vpH ) dh = _vpH - y; - - if (dw < 1 || dh < 1) return; - - uint32_t len = dw*dh; - - if (buffer == nullptr) { - buffer = image; - dmaWait(); - } - - // If image is clipped, copy pixels into a contiguous block - if ( (dw != w) || (dh != h) ) { - if(_swapBytes) { - for (int32_t yb = 0; yb < dh; yb++) { - for (int32_t xb = 0; xb < dw; xb++) { - uint32_t src = xb + dx + w * (yb + dy); - (buffer[xb + yb * dw] = image[src] << 8 | image[src] >> 8); - } - } - } - else { - for (int32_t yb = 0; yb < dh; yb++) { - memcpy((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1); - } - } - } - // else, if a buffer pointer has been provided copy whole image to the buffer - else if (buffer != image || _swapBytes) { - if(_swapBytes) { - for (uint32_t i = 0; i < len; i++) (buffer[i] = image[i] << 8 | image[i] >> 8); - } - else { - memcpy(buffer, image, len*2); - } - } - - if (spiBusyCheck) dmaWait(); // In case we did not wait earlier - - setAddrWindow(x, y, dw, dh); - - esp_err_t ret; - static spi_transaction_t trans; - - memset(&trans, 0, sizeof(spi_transaction_t)); - - trans.user = (void *)1; - trans.tx_buffer = buffer; //finally send the line data - trans.length = len * 16; //Data length, in bits - trans.flags = 0; //SPI_TRANS_USE_TXDATA flag - - ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY); - assert(ret == ESP_OK); - - spiBusyCheck++; -} - -//////////////////////////////////////////////////////////////////////////////////////// -// Processor specific DMA initialisation -//////////////////////////////////////////////////////////////////////////////////////// - -// The DMA functions here work with SPI only (not parallel) -/*************************************************************************************** -** Function name: dc_callback -** Description: Toggles DC line during transaction -***************************************************************************************/ extern "C" void dc_callback(); void IRAM_ATTR dc_callback(spi_transaction_t *spi_tx) @@ -511,10 +215,6 @@ void IRAM_ATTR dc_callback(spi_transaction_t *spi_tx) else {DC_C;} } -/*************************************************************************************** -** Function name: dma_end_callback -** Description: Clear DMA run flag to stop retransmission loop -***************************************************************************************/ extern "C" void dma_end_callback(); void IRAM_ATTR dma_end_callback(spi_transaction_t *spi_tx) @@ -522,10 +222,6 @@ void IRAM_ATTR dma_end_callback(spi_transaction_t *spi_tx) WRITE_PERI_REG(SPI_DMA_CONF_REG(spi_host), 0); } -/*************************************************************************************** -** Function name: initDMA -** Description: Initialise the DMA engine - returns true if init OK -***************************************************************************************/ bool TFT_eSPI::initDMA(bool ctrl_cs) { if (DMA_Enabled) return false; @@ -563,13 +259,9 @@ bool TFT_eSPI::initDMA(bool ctrl_cs) .flags = SPI_DEVICE_NO_DUMMY, //0, .queue_size = 1, .pre_cb = 0, //dc_callback, //Callback to handle D/C line - #ifdef CONFIG_IDF_TARGET_ESP32 - .post_cb = 0 - #else - .post_cb = dma_end_callback - #endif + .post_cb = 0 }; - ret = spi_bus_initialize(spi_host, &buscfg, DMA_CHANNEL); + ret = spi_bus_initialize(spi_host, &buscfg, 1); ESP_ERROR_CHECK(ret); ret = spi_bus_add_device(spi_host, &devcfg, &dmaHAL); ESP_ERROR_CHECK(ret); @@ -579,26 +271,6 @@ bool TFT_eSPI::initDMA(bool ctrl_cs) return true; } -/*************************************************************************************** -** Function name: deInitDMA -** Description: Disconnect the DMA engine from SPI -***************************************************************************************/ -void TFT_eSPI::deInitDMA(void) -{ - if (!DMA_Enabled) return; - spi_bus_remove_device(dmaHAL); - spi_bus_free(spi_host); - DMA_Enabled = false; -} - -//////////////////////////////////////////////////////////////////////////////////////// -#endif // End of DMA FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////////// - -#ifndef SPI_BUSY_CHECK - #define SPI_BUSY_CHECK -#endif - // Clipping macro for pushImage #define PI_CLIP \ if (_vpOoB) return; \ @@ -766,72 +438,6 @@ void TFT_eSPI::resetViewport() { _vpH = _yHeight = height(); } -int32_t TFT_eSPI::getViewportX() { - return _xDatum; -} - -int32_t TFT_eSPI::getViewportY() { - return _yDatum; -} - -int32_t TFT_eSPI::getViewportWidth() { - return _xWidth; -} - -int32_t TFT_eSPI::getViewportHeight() { - return _yHeight; -} - -bool TFT_eSPI::getViewportDatum() { - return _vpDatum; -} - -void TFT_eSPI::frameViewport(uint16_t color, int32_t w) -{ - // Save datum position - bool _dT = _vpDatum; - - // If w is positive the frame is drawn inside the viewport - // a large positive width will clear the screen inside the viewport - if (w>0) { - // Set vpDatum true to simplify coordinate derivation - _vpDatum = true; - fillRect(0, 0, _vpW - _vpX, w, color); // Top - fillRect(0, w, w, _vpH - _vpY - w - w, color); // Left - fillRect(_xWidth - w, w, w, _yHeight - w - w, color); // Right - fillRect(0, _yHeight - w, _xWidth, w, color); // Bottom - } - else { - w = -w; - - // Save old values - int32_t _xT = _vpX; _vpX = 0; - int32_t _yT = _vpY; _vpY = 0; - int32_t _wT = _vpW; - int32_t _hT = _vpH; - - // Set vpDatum false so frame can be drawn outside window - _vpDatum = false; // When false the full width and height is accessed - _vpH = height(); - _vpW = width(); - - // Draw frame - fillRect(_xT - w - _xDatum, _yT - w - _yDatum, _wT - _xT + w + w, w, color); // Top - fillRect(_xT - w - _xDatum, _yT - _yDatum, w, _hT - _yT, color); // Left - fillRect(_wT - _xDatum, _yT - _yDatum, w, _hT - _yT, color); // Right - fillRect(_xT - w - _xDatum, _hT - _yDatum, _wT - _xT + w + w, w, color); // Bottom - - // Restore old values - _vpX = _xT; - _vpY = _yT; - _vpW = _wT; - _vpH = _hT; - } - - // Restore vpDatum - _vpDatum = _dT; -} - bool TFT_eSPI::clipAddrWindow(int32_t *x, int32_t *y, int32_t *w, int32_t *h) { if (_vpOoB) return false; // Area is outside of viewport @@ -884,7 +490,8 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) rotation = padX = 0; cursor_y = cursor_x = last_cursor_x = bg_cursor_x = 0; - textfont = textsize = 1; + textfont = 0; + textsize = 1; textcolor = bitmap_fg = 0xFFFF; textbgcolor = bitmap_bg = 0x0000; @@ -903,19 +510,12 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h) _cp437 = false; _utf8 = true; - fs_font = true; - addr_row = 0xFFFF; addr_col = 0xFFFF; _xPivot = 0; _yPivot = 0; - cspinmask = 0; - dcpinmask = 0; - wrpinmask = 0; - sclkpinmask = 0; - fontsloaded = 0x0002; // Bit 1 set fontsloaded |= 0x8000; // Bit 15 set } @@ -934,13 +534,6 @@ if (TOUCH_CS >= 0) { digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive) } -#if defined (TFT_WR) - if (TFT_WR >= 0) { - pinMode(TFT_WR, OUTPUT); - digitalWrite(TFT_WR, HIGH); // Set write strobe high (inactive) - } -#endif - #ifdef TFT_DC if (TFT_DC >= 0) { pinMode(TFT_DC, OUTPUT); @@ -1060,25 +653,6 @@ void TFT_eSPI::setRotation(uint8_t m) { resetViewport(); } -uint8_t TFT_eSPI::getRotation() { - return rotation; -} - -void TFT_eSPI::setOrigin(int32_t x, int32_t y) -{ - _xDatum = x; - _yDatum = y; -} - -int32_t TFT_eSPI::getOriginX() { - return _xDatum; -} - -int32_t TFT_eSPI::getOriginY() { - return _yDatum; -} - - void TFT_eSPI::commandList (const uint8_t *addr) { uint8_t numCommands = pgm_read_byte(addr++), numArgs, ms; @@ -1231,61 +805,6 @@ void TFT_eSPI::setCallback(getColorCallback getCol) { getColor = getCol; } -void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) -{ - PI_CLIP ; - - // This function can get called after a begin_tft_write - // so a transaction may be in progress - bool wasInTransaction = inTransaction; - if (inTransaction) { inTransaction= false; end_tft_write();} - - uint16_t color = 0; - - begin_tft_read(); - - readAddrWindow(x, y, dw, dh); - - data += dx + dy * w; - - #ifdef TFT_SDA_READ - begin_SDA_Read(); - #endif - - // Dummy read to throw away don't care value - tft_Read_8(); - - // Read window pixel 24-bit RGB values - while (dh--) { - int32_t lw = dw; - uint16_t* line = data; - while (lw--) { - - // Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte - // as the TFT stores colours as 18 bits - uint8_t r = tft_Read_8(); - uint8_t g = tft_Read_8(); - uint8_t b = tft_Read_8(); - color = color565(r, g, b); - - // Swapped colour byte order for compatibility with pushRect() - *line++ = color << 8 | color >> 8; - } - data += w; - } - - //CS_H; - - #ifdef TFT_SDA_READ - end_SDA_Read(); - #endif - - end_tft_read(); - - // Reinstate the transaction if one was in progress - if(wasInTransaction) { begin_tft_write(); inTransaction = true; } -} - void TFT_eSPI::pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data) { bool swap = _swapBytes; _swapBytes = false; @@ -1898,92 +1417,6 @@ void TFT_eSPI::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *da end_tft_write(); } -/*************************************************************************************** -** Function name: pushMaskedImage -** Description: Render a 16-bit colour image to TFT with a 1bpp mask -***************************************************************************************/ -// Can be used with a 16bpp sprite and a 1bpp sprite for the mask -void TFT_eSPI::pushMaskedImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *img, uint8_t *mask) -{ - if (_vpOoB || w < 1 || h < 1) return; - - // To simplify mask handling the window clipping is done by the pushImage function - // Each mask image line assumed to be padded to an integer number of bytes & padding bits are 0 - - begin_tft_write(); - inTransaction = true; - - uint8_t *mptr = mask; - uint8_t *eptr = mask + ((w + 7) >> 3); - uint16_t *iptr = img; - uint32_t setCount = 0; - - // For each line in the image - while (h--) { - uint32_t xp = 0; - uint32_t clearCount = 0; - uint8_t mbyte= *mptr++; - uint32_t bits = 8; - // Scan through each byte of the bitmap and determine run lengths - do { - setCount = 0; - - //Get run length for clear bits to determine x offset - while ((mbyte & 0x80) == 0x00) { - // Check if remaining bits in byte are clear (reduce shifts) - if (mbyte == 0) { - clearCount += bits; // bits not always 8 here - if (mptr >= eptr) break; // end of line - mbyte = *mptr++; - bits = 8; - continue; - } - mbyte = mbyte << 1; // 0's shifted in - clearCount ++; - if (--bits) continue;; - if (mptr >= eptr) break; - mbyte = *mptr++; - bits = 8; - } - - //Get run length for set bits to determine render width - while ((mbyte & 0x80) == 0x80) { - // Check if all bits are set (reduces shifts) - if (mbyte == 0xFF) { - setCount += bits; - if (mptr >= eptr) break; - mbyte = *mptr++; - //bits = 8; // NR, bits always 8 here unless 1's shifted in - continue; - } - mbyte = mbyte << 1; //or mbyte += mbyte + 1 to shift in 1's - setCount ++; - if (--bits) continue; - if (mptr >= eptr) break; - mbyte = *mptr++; - bits = 8; - } - - // A mask boundary or mask end has been found, so render the pixel line - if (setCount) { - xp += clearCount; - clearCount = 0; - pushImage(x + xp, y, setCount, 1, iptr + xp); // pushImage handles clipping - if (mptr >= eptr) break; - xp += setCount; - } - } while (setCount || mptr < eptr); - - y++; - iptr += w; - eptr += ((w + 7) >> 3); - } - - inTransaction = lockTransaction; - end_tft_write(); -} - - /*************************************************************************************** ** Function name: setSwapBytes ** Description: Used by 16-bit pushImage() to swap byte order in colours @@ -2047,80 +1480,6 @@ void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_ end_tft_read(); } - -/*************************************************************************************** -** Function name: drawCircle -** Description: Draw a circle outline -***************************************************************************************/ -// Optimised midpoint circle algorithm -void TFT_eSPI::drawCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color) -{ - if ( r <= 0 ) return; - - //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() - inTransaction = true; - - int32_t f = 1 - r; - int32_t ddF_y = -2 * r; - int32_t ddF_x = 1; - int32_t xs = -1; - int32_t xe = 0; - int32_t len = 0; - - bool first = true; - do { - while (f < 0) { - ++xe; - f += (ddF_x += 2); - } - f += (ddF_y += 2); - - if (xe-xs>1) { - if (first) { - len = 2*(xe - xs)-1; - drawFastHLine(x0 - xe, y0 + r, len, color); - drawFastHLine(x0 - xe, y0 - r, len, color); - drawFastVLine(x0 + r, y0 - xe, len, color); - drawFastVLine(x0 - r, y0 - xe, len, color); - first = false; - } - else { - len = xe - xs++; - drawFastHLine(x0 - xe, y0 + r, len, color); - drawFastHLine(x0 - xe, y0 - r, len, color); - drawFastHLine(x0 + xs, y0 - r, len, color); - drawFastHLine(x0 + xs, y0 + r, len, color); - - drawFastVLine(x0 + r, y0 + xs, len, color); - drawFastVLine(x0 + r, y0 - xe, len, color); - drawFastVLine(x0 - r, y0 - xe, len, color); - drawFastVLine(x0 - r, y0 + xs, len, color); - } - } - else { - ++xs; - drawPixel(x0 - xe, y0 + r, color); - drawPixel(x0 - xe, y0 - r, color); - drawPixel(x0 + xs, y0 - r, color); - drawPixel(x0 + xs, y0 + r, color); - - drawPixel(x0 + r, y0 + xs, color); - drawPixel(x0 + r, y0 - xe, color); - drawPixel(x0 - r, y0 - xe, color); - drawPixel(x0 - r, y0 + xs, color); - } - xs = xe; - } while (xe < --r); - - inTransaction = lockTransaction; - end_tft_write(); // Does nothing if Sprite class uses this function -} - - -/*************************************************************************************** -** Function name: drawCircleHelper -** Description: Support function for drawRoundRect() -***************************************************************************************/ void TFT_eSPI::drawCircleHelper( int32_t x0, int32_t y0, int32_t rr, uint8_t cornername, uint32_t color) { if (rr <= 0) return; @@ -2436,25 +1795,6 @@ void TFT_eSPI::fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t } -/*************************************************************************************** -** Function name: drawTriangle -** Description: Draw a triangle outline using 3 arbitrary points -***************************************************************************************/ -// Draw a triangle -void TFT_eSPI::drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) -{ - //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() - inTransaction = true; - - drawLine(x0, y0, x1, y1, color); - drawLine(x1, y1, x2, y2, color); - drawLine(x2, y2, x0, y0, color); - - inTransaction = lockTransaction; - end_tft_write(); // Does nothing if Sprite class uses this function -} - - /*************************************************************************************** ** Function name: fillTriangle ** Description: Draw a filled triangle using 3 arbitrary points @@ -2653,26 +1993,6 @@ void TFT_eSPI::setCursor(int16_t x, int16_t y, uint8_t font) cursor_y = y; } - -/*************************************************************************************** -** Function name: getCursorX -** Description: Get the text cursor x position -***************************************************************************************/ -int16_t TFT_eSPI::getCursorX(void) -{ - return cursor_x; -} - -/*************************************************************************************** -** Function name: getCursorY -** Description: Get the text cursor y position -***************************************************************************************/ -int16_t TFT_eSPI::getCursorY(void) -{ - return cursor_y; -} - - /*************************************************************************************** ** Function name: setTextSize ** Description: Set the text size multiplier @@ -2721,27 +2041,6 @@ void TFT_eSPI::setPivot(int16_t x, int16_t y) _yPivot = y; } - -/*************************************************************************************** -** Function name: getPivotX -** Description: Get the x pivot position -***************************************************************************************/ -int16_t TFT_eSPI::getPivotX(void) -{ - return _xPivot; -} - - -/*************************************************************************************** -** Function name: getPivotY -** Description: Get the y pivot position -***************************************************************************************/ -int16_t TFT_eSPI::getPivotY(void) -{ - return _yPivot; -} - - /*************************************************************************************** ** Function name: setBitmapColor ** Description: Set the foreground foreground and background colour @@ -2784,52 +2083,18 @@ void TFT_eSPI::setTextPadding(uint16_t x_width) padX = x_width; } -/*************************************************************************************** -** Function name: setTextPadding -** Description: Define padding width (aids erasing old text and numbers) -***************************************************************************************/ -uint16_t TFT_eSPI::getTextPadding(void) -{ - return padX; -} - -/*************************************************************************************** -** Function name: getTextDatum -** Description: Return the text datum value (as used by setTextDatum()) -***************************************************************************************/ -uint8_t TFT_eSPI::getTextDatum(void) -{ - return textdatum; -} - - -/*************************************************************************************** -** Function name: width -** Description: Return the pixel width of display (per current rotation) -***************************************************************************************/ -// Return the size of the display (per current rotation) int16_t TFT_eSPI::width(void) { if (_vpDatum) return _xWidth; return _width; } - -/*************************************************************************************** -** Function name: height -** Description: Return the pixel height of display (per current rotation) -***************************************************************************************/ int16_t TFT_eSPI::height(void) { if (_vpDatum) return _yHeight; return _height; } - -/*************************************************************************************** -** Function name: textWidth -** Description: Return the width in pixels of a string in a given font -***************************************************************************************/ int16_t TFT_eSPI::textWidth(const String& string) { int16_t len = string.length() + 2; @@ -2846,78 +2111,42 @@ int16_t TFT_eSPI::textWidth(const String& string, uint8_t font) return textWidth(buffer, font); } -int16_t TFT_eSPI::textWidth(const char *string) -{ +int16_t TFT_eSPI::textWidth(const char *string) { return textWidth(string, textfont); } -int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) -{ +int16_t TFT_eSPI::textWidth(const char *string, uint8_t font) { int32_t str_width = 0; - uint16_t uniCode = 0; + uint16_t uniCode = 0; - if(fontLoaded) { - while (*string) { - uniCode = decodeUTF8(*string++); - if (uniCode) { - if (uniCode == 0x20) str_width += gFont.spaceWidth; - else { - uint16_t gNum = 0; - bool found = getUnicodeIndex(uniCode, &gNum); - if (found) { - if(str_width == 0 && gdX[gNum] < 0) str_width -= gdX[gNum]; - if (*string || isDigits) str_width += gxAdvance[gNum]; - else str_width += (gdX[gNum] + gWidth[gNum]); - } - else str_width += gFont.spaceWidth + 1; + while (*string) { + uniCode = decodeUTF8(*string++); + if (uniCode) { + if (uniCode == 0x20) str_width += gFonts[font].spaceWidth; + else { + uint16_t gNum = 0; + bool found = getUnicodeIndex(uniCode, &gNum, font); + if (found) { + if(str_width == 0 && gdX[font][gNum] < 0) str_width -= gdX[font][gNum]; + if (*string || isDigits) str_width += gxAdvance[font][gNum]; + else str_width += (gdX[font][gNum] + gWidth[font][gNum]); } + else str_width += gFonts[font].spaceWidth + 1; } } - isDigits = false; - return str_width; - } - - if (font>1 && font<9) { - char *widthtable = (char *)pgm_read_dword( &(fontdata[font].widthtbl ) ) - 32; //subtract the 32 outside the loop - - while (*string) { - uniCode = *(string++); - if (uniCode > 31 && uniCode < 128) - str_width += pgm_read_byte( widthtable + uniCode); // Normally we need to subtract 32 from uniCode - else str_width += pgm_read_byte( widthtable + 32); // Set illegal character = space width - } - - } - else { - while (*string++) str_width += 6; } isDigits = false; - return str_width * textsize; + return str_width; } - -/*************************************************************************************** -** Function name: fontsLoaded -** Description: return an encoded 16-bit value showing the fonts loaded -***************************************************************************************/ -// Returns a value showing which fonts are loaded (bit N set = Font N loaded) -uint16_t TFT_eSPI::fontsLoaded(void) -{ +uint16_t TFT_eSPI::fontsLoaded() { return fontsloaded; } - -/*************************************************************************************** -** Function name: fontHeight -** Description: return the height of a font (yAdvance for free fonts) -***************************************************************************************/ -int16_t TFT_eSPI::fontHeight(uint8_t font) -{ +int16_t TFT_eSPI::fontHeight(uint8_t font) { if (font > 8) return 0; - if(fontLoaded) return gFont.yAdvance; - - return pgm_read_byte( &fontdata[font].height ) * textsize; + return gFonts[font].yAdvance; } int16_t TFT_eSPI::fontHeight(void) @@ -2925,80 +2154,6 @@ int16_t TFT_eSPI::fontHeight(void) return fontHeight(textfont); } -/*************************************************************************************** -** Function name: drawChar -** Description: draw a single character in the GLCD or GFXFF font -***************************************************************************************/ -void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size) -{ - if (_vpOoB) return; - - int32_t xd = x + _xDatum; - int32_t yd = y + _yDatum; - - if ((xd >= _vpW) || // Clip right - ( yd >= _vpH) || // Clip bottom - ((xd + 6 * size - 1) < _vpX) || // Clip left - ((yd + 8 * size - 1) < _vpY)) // Clip top - return; - - if (c > 255) return; - if (!_cp437 && c > 175) c++; - - bool fillbg = (bg != color); - bool clip = xd < _vpX || xd + 6 * textsize >= _vpW || yd < _vpY || yd + 8 * textsize >= _vpH; - - if ((size==1) && fillbg && !clip) { - uint8_t column[6]; - uint8_t mask = 0x1; - begin_tft_write(); - - setWindow(xd, yd, xd+5, yd+7); - - for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(&font[0] + (c * 5) + i); - column[5] = 0; - - for (int8_t j = 0; j < 8; j++) { - for (int8_t k = 0; k < 5; k++ ) { - if (column[k] & mask) {tft_Write_16(color);} - else {tft_Write_16(bg);} - } - mask <<= 1; - tft_Write_16(bg); - } - - end_tft_write(); - } - else { - //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() - inTransaction = true; - - for (int8_t i = 0; i < 6; i++ ) { - uint8_t line; - if (i == 5) - line = 0x0; - else - line = pgm_read_byte(&font[0] + (c * 5) + i); - - if (size == 1 && !fillbg) { // default size - for (int8_t j = 0; j < 8; j++) { - if (line & 0x1) drawPixel(x + i, y + j, color); - line >>= 1; - } - } - else { // big size or clipped - for (int8_t j = 0; j < 8; j++) { - if (line & 0x1) fillRect(x + (i * size), y + (j * size), size, size, color); - else if (fillbg) fillRect(x + i * size, y + j * size, size, size, bg); - line >>= 1; - } - } - } - inTransaction = lockTransaction; - end_tft_write(); // Does nothing if Sprite class uses this function - } -} - /*************************************************************************************** ** Function name: setAddrWindow @@ -3026,13 +2181,6 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) addr_row = 0xFFFF; addr_col = 0xFFFF; - #ifdef CGRAM_OFFSET - x0+=colstart; - x1+=colstart; - y0+=rowstart; - y1+=rowstart; - #endif - SPI_BUSY_CHECK; DC_C; tft_Write_8(TFT_CASET); DC_D; tft_Write_32C(x0, x1); @@ -3057,13 +2205,6 @@ void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h) addr_col = 0xFFFF; addr_row = 0xFFFF; -#ifdef CGRAM_OFFSET - xs += colstart; - xe += colstart; - ys += rowstart; - ye += rowstart; -#endif - // Column addr set DC_C; tft_Write_8(TFT_CASET); DC_D; tft_Write_32C(xs, xe); @@ -3095,12 +2236,7 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color) // Range checking if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return; -#ifdef CGRAM_OFFSET - x+=colstart; - y+=rowstart; -#endif - -#if (defined (MULTI_TFT_SUPPORT) || defined (GC9A01_DRIVER)) && !defined (ILI9225_DRIVER) +#if defined (MULTI_TFT_SUPPORT) addr_row = 0xFFFF; addr_col = 0xFFFF; #endif @@ -3168,10 +2304,6 @@ void TFT_eSPI::startWrite(void) inTransaction = true; } -/*************************************************************************************** -** Function name: endWrite -** Description: end transaction with CS high -***************************************************************************************/ void TFT_eSPI::endWrite(void) { lockTransaction = false; // Release sketch induced transaction lock @@ -3180,35 +2312,10 @@ void TFT_eSPI::endWrite(void) end_tft_write(); // Release SPI bus } -/*************************************************************************************** -** Function name: writeColor (use startWrite() and endWrite() before & after) -** Description: raw write of "len" pixels avoiding transaction check -***************************************************************************************/ -void TFT_eSPI::writeColor(uint16_t color, uint32_t len) -{ +void TFT_eSPI::writeColor(uint16_t color, uint32_t len) { pushBlock(color, len); } -/*************************************************************************************** -** Function name: pushColors -** Description: push an array of pixels for 16-bit raw image drawing -***************************************************************************************/ -// Assumed that setAddrWindow() has previously been called -// len is number of bytes, not pixels -void TFT_eSPI::pushColors(uint8_t *data, uint32_t len) -{ - begin_tft_write(); - - pushPixels(data, len>>1); - - end_tft_write(); -} - - -/*************************************************************************************** -** Function name: pushColors -** Description: push an array of pixels, for image drawing -***************************************************************************************/ void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap) { begin_tft_write(); @@ -3220,13 +2327,6 @@ void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap) end_tft_write(); } - -/*************************************************************************************** -** Function name: drawLine -** Description: draw a line between 2 arbitrary points -***************************************************************************************/ -// Bresenham's algorithm - thx Wikipedia - speed enhanced by Bodmer to use -// an efficient FastH/V Line draw routine for line segments of 2 pixels or more void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) { if (_vpOoB) return; @@ -3234,9 +2334,6 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t //begin_tft_write(); // Sprite class can use this function, avoiding begin_tft_write() inTransaction = true; - //x+= _xDatum; // Not added here, added by drawPixel & drawFastXLine - //y+= _yDatum; - bool steep = abs(y1 - y0) > abs(x1 - x0); if (steep) { transpose(x0, y0); @@ -3268,9 +2365,7 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t } } if (dlen) drawFastVLine(y0, xs, dlen, color); - } - else - { + } else { for (; x0 <= x1; x0++) { dlen++; err -= dy; @@ -3289,19 +2384,11 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t end_tft_write(); } - -/*************************************************************************************** -** Description: Constants for anti-aliased line drawing on TFT and in Sprites -***************************************************************************************/ constexpr float PixelAlphaGain = 255.0; constexpr float LoAlphaTheshold = 1.0/32.0; constexpr float HiAlphaTheshold = 1.0 - LoAlphaTheshold; constexpr float deg2rad = 3.14159265359/180.0; -/*************************************************************************************** -** Function name: drawPixel (alpha blended) -** Description: Draw a pixel blended with the screen or bg pixel colour -***************************************************************************************/ uint16_t TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha, uint32_t bg_color) { if (bg_color == 0x00FFFFFF) bg_color = readPixel(x, y); @@ -3310,73 +2397,6 @@ uint16_t TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha return color; } - -/*************************************************************************************** -** Function name: drawSmoothArc -** Description: Draw a smooth arc clockwise from 6 o'clock -***************************************************************************************/ -void TFT_eSPI::drawSmoothArc(int32_t x, int32_t y, int32_t r, int32_t ir, uint32_t startAngle, uint32_t endAngle, uint32_t fg_color, uint32_t bg_color, bool roundEnds) -// Centre at x,y -// r = arc outer radius, ir = arc inner radius. Inclusive so arc thickness = r - ir + 1 -// Angles in range 0-360 -// Arc foreground colour anti-aliased with background colour at edges -// anti-aliased roundEnd is optional, default is anti-aliased straight end -// Note: rounded ends extend the arc angle so can overlap, user sketch to manage this. -{ - inTransaction = true; - - if (endAngle != startAngle && (startAngle != 0 || endAngle != 360)) - { - float sx = -sinf(startAngle * deg2rad); - float sy = +cosf(startAngle * deg2rad); - float ex = -sinf( endAngle * deg2rad); - float ey = +cosf( endAngle * deg2rad); - - if (roundEnds) - { // Round ends - sx = sx * (r + ir)/2.0 + x; - sy = sy * (r + ir)/2.0 + y; - drawSpot(sx, sy, (r - ir)/2.0, fg_color, bg_color); - - ex = ex * (r + ir)/2.0 + x; - ey = ey * (r + ir)/2.0 + y; - drawSpot(ex, ey, (r - ir)/2.0, fg_color, bg_color); - } - else - { // Square ends - float asx = sx * ir + x; - float asy = sy * ir + y; - float aex = sx * r + x; - float aey = sy * r + y; - drawWedgeLine(asx, asy, aex, aey, 0.3, 0.3, fg_color, bg_color); - - asx = ex * ir + x; - asy = ey * ir + y; - aex = ex * r + x; - aey = ey * r + y; - drawWedgeLine(asx, asy, aex, aey, 0.3, 0.3, fg_color, bg_color); - } - - // Draw arc - drawArc(x, y, r, ir, startAngle, endAngle, fg_color, bg_color); - - } - else // Draw full 360 - { - drawArc(x, y, r, ir, 0, 360, fg_color, bg_color); - } - - inTransaction = lockTransaction; - end_tft_write(); -} - -/*************************************************************************************** -** Function name: sqrt_fraction (private function) -** Description: Smooth graphics support function for alpha derivation -***************************************************************************************/ -// Compute the fixed point square root of an integer and -// return the 8 MS bits of fractional part. -// Quicker than sqrt() for processors that do not have an FPU (e.g. RP2040) inline uint8_t TFT_eSPI::sqrt_fraction(uint32_t num) { if (num > (0x40000000)) return 0; uint32_t bsh = 0x00004000; @@ -3399,21 +2419,7 @@ inline uint8_t TFT_eSPI::sqrt_fraction(uint32_t num) { return fpr>>osh; } -/*************************************************************************************** -** Function name: drawArc -** Description: Draw an arc clockwise from 6 o'clock position -***************************************************************************************/ -// Centre at x,y -// r = arc outer radius, ir = arc inner radius. Inclusive, so arc thickness = r-ir+1 -// Angles MUST be in range 0-360 -// Arc foreground fg_color anti-aliased with background colour along sides -// smooth is optional, default is true, smooth=false means no antialiasing -// Note: Arc ends are not anti-aliased (use drawSmoothArc instead for that) -void TFT_eSPI::drawArc(int32_t x, int32_t y, int32_t r, int32_t ir, - uint32_t startAngle, uint32_t endAngle, - uint32_t fg_color, uint32_t bg_color, - bool smooth) -{ +void TFT_eSPI::drawArc(int32_t x, int32_t y, int32_t r, int32_t ir, uint32_t startAngle, uint32_t endAngle, uint32_t fg_color, uint32_t bg_color, bool smooth) { if (endAngle > 360) endAngle = 360; if (startAngle > 360) startAngle = 360; if (_vpOoB || startAngle == endAngle) return; @@ -3459,43 +2465,34 @@ void TFT_eSPI::drawArc(int32_t x, int32_t y, int32_t r, int32_t ir, // Update slope table, add slope for arc start if (startAngle <= 90) { startSlope[0] = slope; - } - else if (startAngle <= 180) { + } else if (startAngle <= 180) { startSlope[1] = slope; - } - else if (startAngle <= 270) { + } else if (startAngle <= 270) { startSlope[1] = 0xFFFFFFFF; startSlope[2] = slope; - } - else { + } else { startSlope[1] = 0xFFFFFFFF; startSlope[2] = 0; startSlope[3] = slope; } // Fill in end slope table and empty quadrants - fabscos = fabsf(cosf(endAngle * deg2rad)); - fabssin = fabsf(sinf(endAngle * deg2rad)); + fabscos = fabsf(cosf(endAngle * deg2rad)); + fabssin = fabsf(sinf(endAngle * deg2rad)); // U16.16 slope of arc end - slope = (uint32_t)((fabscos/(fabssin + minDivisor)) * (float)(1UL<<16)); + slope = (uint32_t)((fabscos/(fabssin + minDivisor)) * (float)(1UL<<16)); // Work out which quadrants will need to be drawn and add slope for arc end if (endAngle <= 90) { endSlope[0] = slope; endSlope[1] = 0; startSlope[2] = 0; - } - else if (endAngle <= 180) { + } else if (endAngle <= 180) { endSlope[1] = slope; startSlope[2] = 0; - } - else if (endAngle <= 270) { - endSlope[2] = slope; - } - else { - endSlope[3] = slope; - } + } else if (endAngle <= 270) endSlope[2] = slope; + else endSlope[3] = slope; // Scan quadrant for (int32_t cy = r - 1; cy > 0; cy--) @@ -3575,22 +2572,11 @@ void TFT_eSPI::drawArc(int32_t x, int32_t y, int32_t r, int32_t ir, end_tft_write(); } -/*************************************************************************************** -** Function name: drawSmoothCircle -** Description: Draw a smooth circle -***************************************************************************************/ -// To have effective anti-aliasing the circle will be 3 pixels thick -void TFT_eSPI::drawSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t fg_color, uint32_t bg_color) -{ +void TFT_eSPI::drawSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t fg_color, uint32_t bg_color) { drawSmoothRoundRect(x-r, y-r, r, r-1, 0, 0, fg_color, bg_color); } -/*************************************************************************************** -** Function name: fillSmoothCircle -** Description: Draw a filled anti-aliased circle -***************************************************************************************/ -void TFT_eSPI::fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color) -{ +void TFT_eSPI::fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color) { if (r <= 0) return; inTransaction = true; @@ -3637,21 +2623,6 @@ void TFT_eSPI::fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, end_tft_write(); } - -/*************************************************************************************** -** Function name: drawSmoothRoundRect -** Description: Draw a rounded rectangle -***************************************************************************************/ -// x,y is top left corner of bounding box for a complete rounded rectangle -// r = arc outer corner radius, ir = arc inner radius. Arc thickness = r-ir+1 -// w and h are width and height of the bounding rectangle -// If w and h are < radius (e.g. 0,0) a circle will be drawn with centre at x+r,y+r -// Arc foreground fg_color anti-aliased with background colour at edges -// A subset of corners can be drawn by specifying a quadrants mask. A bit set in the -// mask means draw that quadrant (all are drawn if parameter missing): -// 0x1 | 0x2 -// ---¦--- Arc quadrant mask select bits (as in drawCircleHelper fn) -// 0x8 | 0x4 void TFT_eSPI::drawSmoothRoundRect(int32_t x, int32_t y, int32_t r, int32_t ir, int32_t w, int32_t h, uint32_t fg_color, uint32_t bg_color, uint8_t quadrants) { if (_vpOoB) return; @@ -3741,10 +2712,6 @@ void TFT_eSPI::drawSmoothRoundRect(int32_t x, int32_t y, int32_t r, int32_t ir, end_tft_write(); } -/*************************************************************************************** -** Function name: fillSmoothRoundRect -** Description: Draw a filled anti-aliased rounded corner rectangle -***************************************************************************************/ void TFT_eSPI::fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color, uint32_t bg_color) { inTransaction = true; @@ -3769,11 +2736,9 @@ void TFT_eSPI::fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, i r++; int32_t r2 = r * r; - for (int32_t cy = r - 1; cy > 0; cy--) - { + for (int32_t cy = r - 1; cy > 0; cy--) { int32_t dy2 = (r - cy) * (r - cy); - for (cx = xs; cx < r; cx++) - { + for (cx = xs; cx < r; cx++) { int32_t hyp2 = (r - cx) * (r - cx) + dy2; if (hyp2 <= r1) break; if (hyp2 >= r2) continue; @@ -3795,10 +2760,6 @@ void TFT_eSPI::fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, i end_tft_write(); } -/*************************************************************************************** -** Function name: drawSpot - maths intensive, so for small filled circles -** Description: Draw an anti-aliased filled circle at ax,ay with radius r -***************************************************************************************/ // Coordinates are floating point to achieve sub-pixel positioning void TFT_eSPI::drawSpot(float ax, float ay, float r, uint32_t fg_color, uint32_t bg_color) { @@ -3806,19 +2767,6 @@ void TFT_eSPI::drawSpot(float ax, float ay, float r, uint32_t fg_color, uint32_t drawWedgeLine( ax, ay, ax, ay, r, r, fg_color, bg_color); } -/*************************************************************************************** -** Function name: drawWideLine - background colour specified or pixel read -** Description: draw an anti-aliased line with rounded ends, width wd -***************************************************************************************/ -void TFT_eSPI::drawWideLine(float ax, float ay, float bx, float by, float wd, uint32_t fg_color, uint32_t bg_color) -{ - drawWedgeLine( ax, ay, bx, by, wd/2.0, wd/2.0, fg_color, bg_color); -} - -/*************************************************************************************** -** Function name: drawWedgeLine - background colour specified or pixel read -** Description: draw an anti-aliased line with different width radiused ends -***************************************************************************************/ void TFT_eSPI::drawWedgeLine(float ax, float ay, float bx, float by, float ar, float br, uint32_t fg_color, uint32_t bg_color) { if ( (ar < 0.0) || (br < 0.0) )return; @@ -3860,26 +2808,16 @@ void TFT_eSPI::drawWedgeLine(float ax, float ay, float bx, float by, float ar, f // Track edge to minimise calculations if (!endX) { endX = true; xs = xp; } if (alpha > HiAlphaTheshold) { - #ifdef GC9A01_DRIVER - drawPixel(xp, yp, fg_color); - #else - if (swin) { setWindow(xp, yp, x1, yp); swin = false; } - pushColor(fg_color); - #endif + if (swin) { setWindow(xp, yp, x1, yp); swin = false; } + pushColor(fg_color); continue; } //Blend color with background and plot if (bg_color == 0x00FFFFFF) { bg = readPixel(xp, yp); swin = true; } - #ifdef GC9A01_DRIVER - uint16_t pcol = fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg); - drawPixel(xp, yp, pcol); - swin = swin; - #else - if (swin) { setWindow(xp, yp, x1, yp); swin = false; } - pushColor(fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg)); - #endif + if (swin) { setWindow(xp, yp, x1, yp); swin = false; } + pushColor(fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg)); } } @@ -3898,26 +2836,15 @@ void TFT_eSPI::drawWedgeLine(float ax, float ay, float bx, float by, float ar, f // Track line boundary if (!endX) { endX = true; xs = xp; } if (alpha > HiAlphaTheshold) { - #ifdef GC9A01_DRIVER - drawPixel(xp, yp, fg_color); - #else - if (swin) { setWindow(xp, yp, x1, yp); swin = false; } - pushColor(fg_color); - #endif + if (swin) { setWindow(xp, yp, x1, yp); swin = false; } + pushColor(fg_color); continue; } - //Blend colour with background and plot if (bg_color == 0x00FFFFFF) { bg = readPixel(xp, yp); swin = true; } - #ifdef GC9A01_DRIVER - uint16_t pcol = fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg); - drawPixel(xp, yp, pcol); - swin = swin; - #else - if (swin) { setWindow(xp, yp, x1, yp); swin = false; } - pushColor(fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg)); - #endif + if (swin) { setWindow(xp, yp, x1, yp); swin = false; } + pushColor(fastBlend((uint8_t)(alpha * PixelAlphaGain), fg_color, bg)); } } @@ -3925,11 +2852,6 @@ void TFT_eSPI::drawWedgeLine(float ax, float ay, float bx, float by, float ar, f end_nin_write(); } - -/*************************************************************************************** -** Function name: lineDistance - private helper function for drawWedgeLine -** Description: returns distance of px,py to closest part of a to b wedge -***************************************************************************************/ inline float TFT_eSPI::wedgeLineDistance(float xpax, float ypay, float bax, float bay, float dr) { float h = fmaxf(fminf((xpax * bax + ypay * bay) / (bax * bax + bay * bay), 1.0f), 0.0f); @@ -3937,11 +2859,6 @@ inline float TFT_eSPI::wedgeLineDistance(float xpax, float ypay, float bax, floa return sqrtf(dx * dx + dy * dy) + h * dr; } - -/*************************************************************************************** -** Function name: drawFastVLine -** Description: draw a vertical line -***************************************************************************************/ void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) { if (_vpOoB) return; @@ -3967,11 +2884,6 @@ void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) end_tft_write(); } - -/*************************************************************************************** -** Function name: drawFastHLine -** Description: draw a horizontal line -***************************************************************************************/ void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) { if (_vpOoB) return; @@ -3997,11 +2909,6 @@ void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) end_tft_write(); } - -/*************************************************************************************** -** Function name: fillRect -** Description: draw a filled rectangle -***************************************************************************************/ void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) { if (_vpOoB) return; @@ -4020,15 +2927,6 @@ void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t col if ((w < 1) || (h < 1)) return; - //Serial.print(" _xDatum=");Serial.print( _xDatum);Serial.print(", _yDatum=");Serial.print( _yDatum); - //Serial.print(", _xWidth=");Serial.print(_xWidth);Serial.print(", _yHeight=");Serial.println(_yHeight); - - //Serial.print(" _vpX=");Serial.print( _vpX);Serial.print(", _vpY=");Serial.print( _vpY); - //Serial.print(", _vpW=");Serial.print(_vpW);Serial.print(", _vpH=");Serial.println(_vpH); - - //Serial.print(" x=");Serial.print( y);Serial.print(", y=");Serial.print( y); - //Serial.print(", w=");Serial.print(w);Serial.print(", h=");Serial.println(h); - begin_tft_write(); setWindow(x, y, x + w - 1, y + h - 1); @@ -4038,228 +2936,36 @@ void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t col end_tft_write(); } - -/*************************************************************************************** -** Function name: fillRectVGradient -** Description: draw a filled rectangle with a vertical colour gradient -***************************************************************************************/ -void TFT_eSPI::fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2) -{ - if (_vpOoB) return; - - x+= _xDatum; - y+= _yDatum; - - // Clipping - if ((x >= _vpW) || (y >= _vpH)) return; - - if (x < _vpX) { w += x - _vpX; x = _vpX; } - if (y < _vpY) { h += y - _vpY; y = _vpY; } - - if ((x + w) > _vpW) w = _vpW - x; - if ((y + h) > _vpH) h = _vpH - y; - - if ((w < 1) || (h < 1)) return; - - begin_nin_write(); - - float delta = -255.0/h; - float alpha = 255.0; - uint32_t color = color1; - - while (h--) { - drawFastHLine(x, y++, w, color); - alpha += delta; - color = fastBlend((uint8_t)alpha, color1, color2); - } - - end_nin_write(); -} - - -/*************************************************************************************** -** Function name: fillRectHGradient -** Description: draw a filled rectangle with a horizontal colour gradient -***************************************************************************************/ -void TFT_eSPI::fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2) -{ - if (_vpOoB) return; - - x+= _xDatum; - y+= _yDatum; - - // Clipping - if ((x >= _vpW) || (y >= _vpH)) return; - - if (x < _vpX) { w += x - _vpX; x = _vpX; } - if (y < _vpY) { h += y - _vpY; y = _vpY; } - - if ((x + w) > _vpW) w = _vpW - x; - if ((y + h) > _vpH) h = _vpH - y; - - if ((w < 1) || (h < 1)) return; - - begin_nin_write(); - - float delta = -255.0/w; - float alpha = 255.0; - uint32_t color = color1; - - while (w--) { - drawFastVLine(x++, y, h, color); - alpha += delta; - color = fastBlend((uint8_t)alpha, color1, color2); - } - - end_nin_write(); -} - - -/*************************************************************************************** -** Function name: color565 -** Description: convert three 8-bit RGB levels to a 16-bit colour value -***************************************************************************************/ -uint16_t TFT_eSPI::color565(uint8_t r, uint8_t g, uint8_t b) -{ +uint16_t TFT_eSPI::color565(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } - -/*************************************************************************************** -** Function name: color16to8 -** Description: convert 16-bit colour to an 8-bit 332 RGB colour value -***************************************************************************************/ -uint8_t TFT_eSPI::color16to8(uint16_t c) -{ - return ((c & 0xE000)>>8) | ((c & 0x0700)>>6) | ((c & 0x0018)>>3); -} - - -/*************************************************************************************** -** Function name: color8to16 -** Description: convert 8-bit colour to a 16-bit 565 colour value -***************************************************************************************/ -uint16_t TFT_eSPI::color8to16(uint8_t color) -{ - uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5-bit colour lookup table - uint16_t color16 = 0; - - // =====Green===== ===============Red============== - color16 = (color & 0x1C)<<6 | (color & 0xC0)<<5 | (color & 0xE0)<<8; - // =====Green===== =======Blue====== - color16 |= (color & 0x1C)<<3 | blue[color & 0x03]; - - return color16; -} - -/*************************************************************************************** -** Function name: color16to24 -** Description: convert 16-bit colour to a 24-bit 888 colour value -***************************************************************************************/ -uint32_t TFT_eSPI::color16to24(uint16_t color565) -{ - uint8_t r = (color565 >> 8) & 0xF8; r |= (r >> 5); - uint8_t g = (color565 >> 3) & 0xFC; g |= (g >> 6); - uint8_t b = (color565 << 3) & 0xF8; b |= (b >> 5); - - return ((uint32_t)r << 16) | ((uint32_t)g << 8) | ((uint32_t)b << 0); -} - -/*************************************************************************************** -** Function name: color24to16 -** Description: convert 24-bit colour to a 16-bit 565 colour value -***************************************************************************************/ -uint32_t TFT_eSPI::color24to16(uint32_t color888) -{ - uint16_t r = (color888 >> 8) & 0xF800; - uint16_t g = (color888 >> 5) & 0x07E0; - uint16_t b = (color888 >> 3) & 0x001F; - - return (r | g | b); -} - -/*************************************************************************************** -** Function name: invertDisplay -** Description: invert the display colours i = 1 invert, i = 0 normal -***************************************************************************************/ -void TFT_eSPI::invertDisplay(bool i) -{ +void TFT_eSPI::invertDisplay(bool i) { begin_tft_write(); - // Send the command twice as otherwise it does not always work! writecommand(i ? TFT_INVON : TFT_INVOFF); writecommand(i ? TFT_INVON : TFT_INVOFF); end_tft_write(); } - -/************************************************************************** -** Function name: setAttribute -** Description: Sets a control parameter of an attribute -**************************************************************************/ -void TFT_eSPI::setAttribute(uint8_t attr_id, uint8_t param) { - switch (attr_id) { - break; - case CP437_SWITCH: - _cp437 = param; - break; - case UTF8_SWITCH: - _utf8 = param; - decoderState = 0; - break; - //case 4: // TBD future feature control - // _tbd = param; - // break; - } -} - - -/************************************************************************** -** Function name: getAttribute -** Description: Get value of an attribute (control parameter) -**************************************************************************/ -uint8_t TFT_eSPI::getAttribute(uint8_t attr_id) { - switch (attr_id) { - case CP437_SWITCH: // ON/OFF control of full CP437 character set - return _cp437; - case UTF8_SWITCH: // ON/OFF control of UTF-8 decoding - return _utf8; - //case 3: // TBD future feature control - // return _tbd; - // break; - } - - return false; -} - -/*************************************************************************************** -** Function name: decodeUTF8 -** Description: Serial UTF-8 decoder with fall-back to extended ASCII -*************************************************************************************x*/ -uint16_t TFT_eSPI::decodeUTF8(uint8_t c) -{ +uint16_t TFT_eSPI::decodeUTF8(uint8_t c) { if (!_utf8) return c; - // 7-bit Unicode Code Point if ((c & 0x80) == 0x00) { decoderState = 0; return c; } if (decoderState == 0) { - // 11-bit Unicode Code Point if ((c & 0xE0) == 0xC0) { decoderBuffer = ((c & 0x1F)<<6); decoderState = 1; return 0; } - // 16-bit Unicode Code Point if ((c & 0xF0) == 0xE0) { decoderBuffer = ((c & 0x0F)<<12); decoderState = 2; return 0; } - // 21-bit Unicode Code Point not supported so fall-back to extended ASCII - // if ((c & 0xF8) == 0xF0) return c; } else { if (decoderState == 2) { @@ -4279,45 +2985,25 @@ uint16_t TFT_eSPI::decodeUTF8(uint8_t c) return c; // fall-back to extended ASCII } - -/*************************************************************************************** -** Function name: decodeUTF8 -** Description: Line buffer UTF-8 decoder with fall-back to extended ASCII -*************************************************************************************x*/ uint16_t TFT_eSPI::decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining) { uint16_t c = buf[(*index)++]; - //Serial.print("Byte from string = 0x"); Serial.println(c, HEX); if (!_utf8) return c; - // 7-bit Unicode if ((c & 0x80) == 0x00) return c; - // 11-bit Unicode if (((c & 0xE0) == 0xC0) && (remaining > 1)) return ((c & 0x1F)<<6) | (buf[(*index)++]&0x3F); - // 16-bit Unicode if (((c & 0xF0) == 0xE0) && (remaining > 2)) { c = ((c & 0x0F)<<12) | ((buf[(*index)++]&0x3F)<<6); return c | ((buf[(*index)++]&0x3F)); } - // 21-bit Unicode not supported so fall-back to extended ASCII - // if (((c & 0xF8) == 0xF0) && (remaining > 3)) { - // c = ((c & 0x07) << 18) | ((buf[(*index)++] & 0x03F) << 12); - // c |= ((buf[(*index)++] & 0x3F) << 6); - // return c | ((buf[(*index)++] & 0x3F)); - return c; // fall-back to extended ASCII } - -/*************************************************************************************** -** Function name: alphaBlend -** Description: Blend 16bit foreground and background -*************************************************************************************x*/ uint16_t TFT_eSPI::alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc) { // Split out and blend 5-bit red and blue channels @@ -4330,10 +3016,6 @@ uint16_t TFT_eSPI::alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc) return (rxb & 0xF81F) | (xgx & 0x07E0); } -/*************************************************************************************** -** Function name: alphaBlend -** Description: Blend 16bit foreground and background with dither -*************************************************************************************x*/ uint16_t TFT_eSPI::alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc, uint8_t dither) { if (dither) { @@ -4346,10 +3028,6 @@ uint16_t TFT_eSPI::alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc, uint8_t return alphaBlend(alpha, fgc, bgc); } -/*************************************************************************************** -** Function name: alphaBlend -** Description: Blend 24bit foreground and background with optional dither -*************************************************************************************x*/ uint32_t TFT_eSPI::alphaBlend24(uint8_t alpha, uint32_t fgc, uint32_t bgc, uint8_t dither) { @@ -4369,91 +3047,15 @@ uint32_t TFT_eSPI::alphaBlend24(uint8_t alpha, uint32_t fgc, uint32_t bgc, uint8 return (rxx & 0xFF0000) | (xgx & 0x00FF00) | (xxb & 0x0000FF); } -/*************************************************************************************** -** Function name: write -** Description: draw characters piped through serial stream -***************************************************************************************/ -/* // Not all processors support buffered write -#ifndef ARDUINO_ARCH_ESP8266 // Avoid ESP8266 board package bug -size_t TFT_eSPI::write(const uint8_t *buf, size_t len) -{ - inTransaction = true; - - uint8_t *lbuf = (uint8_t *)buf; - while(*lbuf !=0 && len--) write(*lbuf++); - - inTransaction = lockTransaction; - end_tft_write(); - return 1; -} -#endif -*/ -/*************************************************************************************** -** Function name: write -** Description: draw characters piped through serial stream -***************************************************************************************/ -size_t TFT_eSPI::write(uint8_t utf8) -{ - if (_vpOoB) return 1; - - uint16_t uniCode = decodeUTF8(utf8); - - if (!uniCode) return 1; - - if (utf8 == '\r') return 1; - - if(fontLoaded) { - if (uniCode < 32 && utf8 != '\n') return 1; - drawGlyph(uniCode); - return 1; - } - - if (uniCode == '\n') uniCode+=22; // Make it a valid space character to stop errors - - uint16_t cwidth = 0; - uint16_t cheight = 0; - - if (textfont==1) { - cwidth = 6; - cheight = 8; - } - - cheight = cheight * textsize; - - if (utf8 == '\n') { - cursor_y += cheight; - cursor_x = 0; - } - else { - if (textwrapX && (cursor_x + cwidth * textsize > width())) { - cursor_y += cheight; - cursor_x = 0; - } - if (textwrapY && (cursor_y >= (int32_t) height())) cursor_y = 0; - cursor_x += drawChar(uniCode, cursor_x, cursor_y, textfont); - } - - return 1; -} - - -/*************************************************************************************** -** Function name: drawChar -** Description: draw a Unicode glyph onto the screen -***************************************************************************************/ - // TODO: Rationalise with TFT_eSprite - // Any UTF-8 decoding must be done before calling drawChar() -int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y) -{ +int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y) { return drawChar(uniCode, x, y, textfont); } - // Any UTF-8 decoding must be done before calling drawChar() int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) { if (_vpOoB || !uniCode) return 0; - if (font==1) return 0; + if (font == 1) return 0; if ((font>1) && (font<9) && ((uniCode < 32) || (uniCode > 127))) return 0; int32_t width = 0; @@ -4467,12 +3069,11 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) if ((xd + width * textsize < _vpX || xd >= _vpW) && (yd + height * textsize < _vpY || yd >= _vpH)) return width * textsize ; int32_t w = width; - int32_t pX = 0; - int32_t pY = y; + int32_t pX = 0; + int32_t pY = y; uint8_t line = 0; bool clip = xd < _vpX || xd + width * textsize >= _vpW || yd < _vpY || yd + height * textsize >= _vpH; - // Stop warnings flash_address = flash_address; w = w; pX = pX; @@ -4480,15 +3081,9 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) line = line; clip = clip; - return width * textsize; // x + + return width * textsize; } - -/*************************************************************************************** -** Function name: drawString (with or without user defined font) -** Description : draw string with padding if it is defined -***************************************************************************************/ -// Without font number, uses font set by setTextFont() int16_t TFT_eSPI::drawString(const String& string, int32_t poX, int32_t poY) { int16_t len = string.length() + 2; @@ -4496,7 +3091,7 @@ int16_t TFT_eSPI::drawString(const String& string, int32_t poX, int32_t poY) string.toCharArray(buffer, len); return drawString(buffer, poX, poY, textfont); } -// With font number + int16_t TFT_eSPI::drawString(const String& string, int32_t poX, int32_t poY, uint8_t font) { int16_t len = string.length() + 2; @@ -4505,15 +3100,11 @@ int16_t TFT_eSPI::drawString(const String& string, int32_t poX, int32_t poY, uin return drawString(buffer, poX, poY, font); } -// Without font number, uses font set by setTextFont() -int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY) -{ +int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY) { return drawString(string, poX, poY, textfont); } -// With font number. Note: font number is over-ridden if a smooth font is loaded -int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8_t font) -{ +int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8_t font) { if (font > 8) return 0; int16_t sumX = 0; @@ -4521,16 +3112,10 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 uint16_t cwidth = textWidth(string, font); // Find the pixel width of the string in the font uint16_t cheight = 8 * textsize; - if(fontLoaded) { - baseline = gFont.maxAscent; - cheight = fontHeight(); - } else if (font!=1) { - baseline = pgm_read_byte( &fontdata[font].baseline ) * textsize; - cheight = fontHeight(font); - } + baseline = gFonts[font].maxAscent; + cheight = fontHeight(font); if (textdatum || padX) { - switch(textdatum) { case TC_DATUM: poX -= cwidth/2; @@ -4542,7 +3127,6 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 break; case ML_DATUM: poY -= cheight/2; - //padding += 0; break; case MC_DATUM: poX -= cwidth/2; @@ -4556,7 +3140,6 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 break; case BL_DATUM: poY -= cheight; - //padding += 0; break; case BC_DATUM: poX -= cwidth/2; @@ -4570,7 +3153,6 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 break; case L_BASELINE: poY -= baseline; - //padding += 0; break; case C_BASELINE: poX -= cwidth/2; @@ -4591,32 +3173,18 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 uint16_t len = strlen(string); uint16_t n = 0; - if(fontLoaded) { - setCursor(poX, poY); + setCursor(poX, poY); - bool fillbg = _fillbg; - // If padding is requested then fill the text background - if (padX && !_fillbg) _fillbg = true; + bool fillbg = _fillbg; + // If padding is requested then fill the text background + if (padX && !_fillbg) _fillbg = true; - while (n < len) { - uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n); - drawGlyph(uniCode); - } - _fillbg = fillbg; // restore state - sumX += cwidth; - } else { - while (n < len) { - uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n); - sumX += drawChar(uniCode, poX+sumX, poY, font); - } + while (n < len) { + uint16_t uniCode = decodeUTF8((uint8_t*)string, &n, len - n); + drawGlyph(uniCode, font); } - -//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv -// Switch on debugging for the padding areas -//#define PADDING_DEBUG - -#ifndef PADDING_DEBUG -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + _fillbg = fillbg; // restore state + sumX += cwidth; if((padX>cwidth) && (textcolor!=textbgcolor)) { int16_t padXc = poX+cwidth+xo; @@ -4636,42 +3204,9 @@ int16_t TFT_eSPI::drawString(const char *string, int32_t poX, int32_t poY, uint8 } } - -#else - -//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv -// This is debug code to show text (green box) and blanked (white box) areas -// It shows that the padding areas are being correctly sized and positioned - - if((padX>sumX) && (textcolor!=textbgcolor)) { - int16_t padXc = poX+sumX; // Maximum left side padding - drawRect(poX,poY,sumX,cheight, TFT_GREEN); - switch(padding) { - case 1: - drawRect(padXc,poY,padX-sumX,cheight, TFT_WHITE); - break; - case 2: - drawRect(padXc,poY,(padX-sumX)>>1, cheight, TFT_WHITE); - padXc = (padX-sumX)>>1; - drawRect(poX - padXc,poY,(padX-sumX)>>1,cheight, TFT_WHITE); - break; - case 3: - if (padXc>padX) padXc = padX; - drawRect(poX + sumX - padXc,poY,padXc-sumX,cheight, TFT_WHITE); - break; - } - } -#endif -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -return sumX; + return sumX; } - -/*************************************************************************************** -** Function name: drawNumber -** Description: draw a long integer -***************************************************************************************/ int16_t TFT_eSPI::drawNumber(long long_num, int32_t poX, int32_t poY) { isDigits = true; // Eliminate jiggle in monospaced fonts @@ -4688,13 +3223,6 @@ int16_t TFT_eSPI::drawNumber(long long_num, int32_t poX, int32_t poY, uint8_t fo return drawString(str, poX, poY, font); } - -/*************************************************************************************** -** Function name: drawFloat -** Descriptions: drawFloat, prints 7 non zero digits maximum -***************************************************************************************/ -// Assemble and print a string, this permits alignment relative to a datum -// looks complicated but much more compact and actually faster than using print class int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t poY) { return drawFloat(floatNumber, dp, poX, poY, textfont); @@ -4709,40 +3237,34 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t float rounding = 0.5; // Round up down delta bool negative = false; - if (dp > 7) dp = 7; // Limit the size of decimal portion + if (dp > 7) dp = 7; - // Adjust the rounding value for (uint8_t i = 0; i < dp; ++i) rounding /= 10.0; - if (floatNumber < -rounding) { // add sign, avoid adding - sign to 0.0! - str[ptr++] = '-'; // Negative number - str[ptr] = 0; // Put a null in the array as a precaution - digits = 0; // Set digits to 0 to compensate so pointer value can be used later - floatNumber = -floatNumber; // Make positive + if (floatNumber < -rounding) { + str[ptr++] = '-'; + str[ptr] = 0; + digits = 0; + floatNumber = -floatNumber; negative = true; } - floatNumber += rounding; // Round up or down + floatNumber += rounding; if (dp == 0) { if (negative) floatNumber = -floatNumber; return drawNumber((long)floatNumber, poX, poY, font); } - // For error put ... in string and return (all TFT_eSPI library fonts contain . character) if (floatNumber >= 2147483647) { strcpy(str, "..."); return drawString(str, poX, poY, font); } - // No chance of overflow from here on - // Get integer part uint32_t temp = (uint32_t)floatNumber; - // Put integer part into array ltoa(temp, str + ptr, 10); - // Find out where the null is to get the digit count loaded while ((uint8_t)str[ptr] != 0) ptr++; // Move the pointer along digits += ptr; // Count the digits @@ -4750,11 +3272,8 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t str[ptr] = '0'; // Add a dummy zero str[ptr + 1] = 0; // Add a null but don't increment pointer so it can be overwritten - // Get the decimal portion floatNumber = floatNumber - temp; - // Get decimal digits one by one and put in array - // Limit digit count so we don't get a false sense of resolution uint8_t i = 0; while ((i < dp) && (digits < 9)) { // while (i < dp) for no limit but array size must be increased i++; @@ -4765,346 +3284,65 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t floatNumber -= temp; // Remove that digit } - // Finally we can plot the string and return pixel length return drawString(str, poX, poY, font); } - -/*************************************************************************************** -** Function name: setFreeFont -** Descriptions: Sets the GFX free font to use -***************************************************************************************/ - -// Alternative to setTextFont() so we don't need two different named functions -void TFT_eSPI::setFreeFont(uint8_t font) -{ - setTextFont(font); -} - - -/*************************************************************************************** -** Function name: setTextFont -** Description: Set the font for the print stream -***************************************************************************************/ void TFT_eSPI::setTextFont(uint8_t f) { - textfont = (f > 0) ? f : 1; // Don't allow font 0 textfont = (f > 8) ? 1 : f; // Don't allow font > 8 } -/*************************************************************************************** -** Function name: getSPIinstance -** Description: Get the instance of the SPI class -***************************************************************************************/ -SPIClass& TFT_eSPI::getSPIinstance(void) +SPIClass& TFT_eSPI::getSPIinstance() { return spi; } - -/*************************************************************************************** -** Function name: verifySetupID -** Description: Compare the ID if USER_SETUP_ID defined in user setup file -***************************************************************************************/ -bool TFT_eSPI::verifySetupID(uint32_t id) -{ -#if defined (USER_SETUP_ID) - if (USER_SETUP_ID == id) return true; -#else - id = id; // Avoid warning -#endif - return false; -} - -/*************************************************************************************** -** Function name: getSetup -** Description: Get the setup details for diagnostic and sketch access -***************************************************************************************/ -void TFT_eSPI::getSetup(setup_t &tft_settings) -{ -// tft_settings.version is set in header file - -#if defined (USER_SETUP_INFO) - tft_settings.setup_info = USER_SETUP_INFO; -#else - tft_settings.setup_info = "NA"; -#endif - -#if defined (USER_SETUP_ID) - tft_settings.setup_id = USER_SETUP_ID; -#else - tft_settings.setup_id = 0; -#endif - -#if defined (PROCESSOR_ID) - tft_settings.esp = PROCESSOR_ID; -#else - tft_settings.esp = -1; -#endif - - tft_settings.trans = true; - -tft_settings.serial = true; -tft_settings.tft_spi_freq = spi_write_speed * 1000000/100000; -#ifdef SPI_READ_FREQUENCY - tft_settings.tft_rd_freq = SPI_READ_FREQUENCY/100000; -#endif -#ifndef GENERIC_PROCESSOR - #ifdef TFT_SPI_PORT - tft_settings.port = TFT_SPI_PORT; - #else - tft_settings.port = 255; - #endif -#endif -#ifdef RP2040_PIO_SPI - tft_settings.interface = 0x10; -#else - tft_settings.interface = 0x0; -#endif - -#if defined(TFT_SPI_OVERLAP) - tft_settings.overlap = true; -#else - tft_settings.overlap = false; -#endif - - tft_settings.tft_driver = TFT_DRIVER; - tft_settings.tft_width = _init_width; - tft_settings.tft_height = _init_height; - -#ifdef CGRAM_OFFSET - tft_settings.r0_x_offset = colstart; - tft_settings.r0_y_offset = rowstart; - tft_settings.r1_x_offset = 0; - tft_settings.r1_y_offset = 0; - tft_settings.r2_x_offset = 0; - tft_settings.r2_y_offset = 0; - tft_settings.r3_x_offset = 0; - tft_settings.r3_y_offset = 0; -#else - tft_settings.r0_x_offset = 0; - tft_settings.r0_y_offset = 0; - tft_settings.r1_x_offset = 0; - tft_settings.r1_y_offset = 0; - tft_settings.r2_x_offset = 0; - tft_settings.r2_y_offset = 0; - tft_settings.r3_x_offset = 0; - tft_settings.r3_y_offset = 0; -#endif - -#if defined (TFT_MOSI) - tft_settings.pin_tft_mosi = TFT_MOSI; -#else - tft_settings.pin_tft_mosi = -1; -#endif - -#if defined (TFT_MISO) - tft_settings.pin_tft_miso = TFT_MISO; -#else - tft_settings.pin_tft_miso = -1; -#endif - -#if defined (TFT_SCLK) - tft_settings.pin_tft_clk = TFT_SCLK; -#else - tft_settings.pin_tft_clk = -1; -#endif - -#if defined (TFT_CS) - tft_settings.pin_tft_cs = TFT_CS; -#else - tft_settings.pin_tft_cs = -1; -#endif - -#if defined (TFT_DC) - tft_settings.pin_tft_dc = TFT_DC; -#else - tft_settings.pin_tft_dc = -1; -#endif - -#if defined (TFT_RD) - tft_settings.pin_tft_rd = TFT_RD; -#else - tft_settings.pin_tft_rd = -1; -#endif - -#if defined (TFT_WR) - tft_settings.pin_tft_wr = TFT_WR; -#else - tft_settings.pin_tft_wr = -1; -#endif - -#if defined (TFT_RST) - tft_settings.pin_tft_rst = TFT_RST; -#else - tft_settings.pin_tft_rst = -1; -#endif - -#if defined (TFT_BL) - tft_settings.pin_tft_led = TFT_BL; -#endif - -#if defined (TFT_BACKLIGHT_ON) - tft_settings.pin_tft_led_on = TFT_BACKLIGHT_ON; -#endif - - tft_settings.pin_tch_cs = TOUCH_CS; - tft_settings.tch_spi_freq = SPI_TOUCH_FREQUENCY/100000; -} - -void TFT_eSPI::loadFont(const uint8_t array[]) +void TFT_eSPI::loadFont(const uint8_t array[], uint8_t font) { if (array == nullptr) return; - fontPtr = (uint8_t*) array; - loadFont("", false); + fontPtr = (uint8_t*)array; + unloadFont(font); + + gFonts[font].gArray = (const uint8_t*)fontPtr; + gFonts[font].gCount = (uint16_t)readInt32(); // glyph count in file + readInt32(); // vlw encoder version - discard + gFonts[font].yAdvance = (uint16_t)readInt32(); // Font size in points, not pixels + readInt32(); + gFonts[font].ascent = (uint16_t)readInt32(); // top of "d" + gFonts[font].descent = (uint16_t)readInt32(); // bottom of "p" + + gFonts[font].maxAscent = gFonts[font].ascent; + gFonts[font].maxDescent = gFonts[font].descent; + gFonts[font].yAdvance = gFonts[font].ascent + gFonts[font].descent; + gFonts[font].spaceWidth = gFonts[font].yAdvance / 4; + + loadMetrics(font); } -void TFT_eSPI::loadFont(String fontName, fs::FS &ffs) -{ - fontFS = ffs; - loadFont(fontName, false); -} - -void TFT_eSPI::loadFont(String fontName, bool flash) -{ - /* - The vlw font format does not appear to be documented anywhere, so some reverse - engineering has been applied! - - Header of vlw file comprises 6 uint32_t parameters (24 bytes total): - 1. The gCount (number of character glyphs) - 2. A version number (0xB = 11 for the one I am using) - 3. The font size (in points, not pixels) - 4. Deprecated mboxY parameter (typically set to 0) - 5. Ascent in pixels from baseline to top of "d" - 6. Descent in pixels from baseline to bottom of "p" - - Next are gCount sets of values for each glyph, each set comprises 7 int32t parameters (28 bytes): - 1. Glyph Unicode stored as a 32-bit value - 2. Height of bitmap bounding box - 3. Width of bitmap bounding box - 4. gxAdvance for cursor (setWidth in Processing) - 5. dY = distance from cursor baseline to top of glyph bitmap (signed value +ve = up) - 6. dX = distance from cursor to left side of glyph bitmap (signed value -ve = left) - 7. padding value, typically 0 - - The bitmaps start next at 24 + (28 * gCount) bytes from the start of the file. - Each pixel is 1 byte, an 8-bit Alpha value which represents the transparency from - 0xFF foreground colour, 0x00 background. The library uses a linear interpolation - between the foreground and background RGB component colours. e.g. - pixelRed = ((fgRed * alpha) + (bgRed * (255 - alpha))/255 - To gain a performance advantage fixed point arithmetic is used with rounding and - division by 256 (shift right 8 bits is faster). - - After the bitmaps is: - 1 byte for font name string length (excludes null) - a zero terminated character string giving the font name - 1 byte for Postscript name string length - a zero/one terminated character string giving the font name - last byte is 0 for non-anti-aliased and 1 for anti-aliased (smoothed) - - - Glyph bitmap example is: - // Cursor coordinate positions for this and next character are marked by 'C' - // C<------- gxAdvance ------->C gxAdvance is how far to move cursor for next glyph cursor position - // | | - // | | ascent is top of "d", descent is bottom of "p" - // +-- gdX --+ ascent - // | +-- gWidth--+ | gdX is offset to left edge of glyph bitmap - // | + x@.........@x + | gdX may be negative e.g. italic "y" tail extending to left of - // | | @@.........@@ | | cursor position, plot top left corner of bitmap at (cursorX + gdX) - // | | @@.........@@ gdY | gWidth and gHeight are glyph bitmap dimensions - // | | .@@@.....@@@@ | | - // | gHeight ....@@@@@..@@ + + <-- baseline - // | | ...........@@ | - // | | ...........@@ | gdY is the offset to the top edge of the bitmap - // | | .@@.......@@. descent plot top edge of bitmap at (cursorY + ascent - gdY) - // | + x..@@@@@@@..x | x marks the corner pixels of the bitmap - // | | - // +---------------------------+ yAdvance is y delta for the next line, font size or (ascent + descent) - // some fonts can overlay in y direction so may need a user adjust value - - */ - - if (fontLoaded) unloadFont(); - - if (fontName == "") fs_font = false; - else { fontPtr = nullptr; fs_font = true; } - - if (fs_font) { - spiffs = flash; // true if font is in SPIFFS - - if(spiffs) fontFS = SPIFFS; - - // Avoid a crash on the ESP32 if the file does not exist - if (fontFS.exists("/" + fontName + ".vlw") == false) { - Serial.println("Font file " + fontName + " not found!"); - return; - } - - fontFile = fontFS.open( "/" + fontName + ".vlw", "r"); - - if(!fontFile) return; - - fontFile.seek(0, fs::SeekSet); - } - - gFont.gArray = (const uint8_t*)fontPtr; - - gFont.gCount = (uint16_t)readInt32(); // glyph count in file - readInt32(); // vlw encoder version - discard - gFont.yAdvance = (uint16_t)readInt32(); // Font size in points, not pixels - readInt32(); // discard - gFont.ascent = (uint16_t)readInt32(); // top of "d" - gFont.descent = (uint16_t)readInt32(); // bottom of "p" - - // These next gFont values might be updated when the Metrics are fetched - gFont.maxAscent = gFont.ascent; // Determined from metrics - gFont.maxDescent = gFont.descent; // Determined from metrics - gFont.yAdvance = gFont.ascent + gFont.descent; - gFont.spaceWidth = gFont.yAdvance / 4; // Guess at space width - - fontLoaded = true; - - // Fetch the metrics for each glyph - loadMetrics(); -} - - -void TFT_eSPI::loadMetrics(void) +void TFT_eSPI::loadMetrics(uint8_t font) { uint32_t headerPtr = 24; - uint32_t bitmapPtr = headerPtr + gFont.gCount * 28; + uint32_t bitmapPtr = headerPtr + gFonts[font].gCount * 28; - { - gUnicode = (uint16_t*)malloc( gFont.gCount * 2); // Unicode 16-bit Basic Multilingual Plane (0-FFFF) - gHeight = (uint8_t*)malloc( gFont.gCount ); // Height of glyph - gWidth = (uint8_t*)malloc( gFont.gCount ); // Width of glyph - gxAdvance = (uint8_t*)malloc( gFont.gCount ); // xAdvance - to move x cursor - gdY = (int16_t*)malloc( gFont.gCount * 2); // offset from bitmap top edge from lowest point in any character - gdX = (int8_t*)malloc( gFont.gCount ); // offset for bitmap left edge relative to cursor X - gBitmap = (uint32_t*)malloc( gFont.gCount * 4); // seek pointer to glyph bitmap in the file - } - - if (fs_font) fontFile.seek(headerPtr, fs::SeekSet); + gUnicode[font] = (uint16_t*)malloc( gFonts[font].gCount * 2); // Unicode 16-bit Basic Multilingual Plane (0-FFFF) + gHeight[font] = (uint8_t*)malloc( gFonts[font].gCount ); // Height of glyph + gWidth[font] = (uint8_t*)malloc( gFonts[font].gCount ); // Width of glyph + gxAdvance[font] = (uint8_t*)malloc( gFonts[font].gCount ); // xAdvance - to move x cursor + gdY[font] = (int16_t*)malloc( gFonts[font].gCount * 2); // offset from bitmap top edge from lowest point in any character + gdX[font] = (int8_t*)malloc( gFonts[font].gCount ); // offset for bitmap left edge relative to cursor X + gBitmap[font] = (uint32_t*)malloc( gFonts[font].gCount * 4); // seek pointer to glyph bitmap in the file uint16_t gNum = 0; - while (gNum < gFont.gCount) - { - gUnicode[gNum] = (uint16_t)readInt32(); // Unicode code point value - gHeight[gNum] = (uint8_t)readInt32(); // Height of glyph - gWidth[gNum] = (uint8_t)readInt32(); // Width of glyph - gxAdvance[gNum] = (uint8_t)readInt32(); // xAdvance - to move x cursor - gdY[gNum] = (int16_t)readInt32(); // y delta from baseline - gdX[gNum] = (int8_t)readInt32(); // x delta from cursor + while (gNum < gFonts[font].gCount) { + gUnicode[font][gNum] = (uint16_t)readInt32(); // Unicode code point value + gHeight[font][gNum] = (uint8_t)readInt32(); // Height of glyph + gWidth[font][gNum] = (uint8_t)readInt32(); // Width of glyph + gxAdvance[font][gNum] = (uint8_t)readInt32(); // xAdvance - to move x cursor + gdY[font][gNum] = (int16_t)readInt32(); // y delta from baseline + gdX[font][gNum] = (int8_t)readInt32(); // x delta from cursor readInt32(); // ignored - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gHeight = "); Serial.println(gHeight[gNum]); - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gWidth = "); Serial.println(gWidth[gNum]); - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gxAdvance = "); Serial.println(gxAdvance[gNum]); - //Serial.print("Unicode = 0x"); Serial.print(gUnicode[gNum], HEX); Serial.print(", gdY = "); Serial.println(gdY[gNum]); - // Different glyph sets have different ascent values not always based on "d", so we could get // the maximum glyph ascent by checking all characters. BUT this method can generate bad values // for non-existent glyphs, so we will reply on processing for the value and disable this code for now... @@ -5123,115 +3361,91 @@ void TFT_eSPI::loadMetrics(void) */ // Different glyph sets have different descent values not always based on "p", so get maximum glyph descent - if (((int16_t)gHeight[gNum] - (int16_t)gdY[gNum]) > gFont.maxDescent) + if (((int16_t)gHeight[font][gNum] - (int16_t)gdY[font][gNum]) > gFonts[font].maxDescent) { // Avoid UTF coding values and characters that tend to give duff values - if (((gUnicode[gNum] > 0x20) && (gUnicode[gNum] < 0xA0) && (gUnicode[gNum] != 0x7F)) || (gUnicode[gNum] > 0xFF)) + if (((gUnicode[font][gNum] > 0x20) && (gUnicode[font][gNum] < 0xA0) && (gUnicode[font][gNum] != 0x7F)) || (gUnicode[font][gNum] > 0xFF)) { - gFont.maxDescent = gHeight[gNum] - gdY[gNum]; + gFonts[font].maxDescent = gHeight[font][gNum] - gdY[font][gNum]; } } - gBitmap[gNum] = bitmapPtr; + gBitmap[font][gNum] = bitmapPtr; - bitmapPtr += gWidth[gNum] * gHeight[gNum]; + bitmapPtr += gWidth[font][gNum] * gHeight[font][gNum]; gNum++; yield(); } - gFont.yAdvance = gFont.maxAscent + gFont.maxDescent; + gFonts[font].yAdvance = gFonts[font].maxAscent + gFonts[font].maxDescent; - gFont.spaceWidth = (gFont.ascent + gFont.descent) * 2/7; // Guess at space width + gFonts[font].spaceWidth = (gFonts[font].ascent + gFonts[font].descent) * 2/7; // Guess at space width } - -/*************************************************************************************** -** Function name: deleteMetrics -** Description: Delete the old glyph metrics and free up the memory -*************************************************************************************x*/ -void TFT_eSPI::unloadFont( void ) +void TFT_eSPI::unloadFont(uint8_t font) { - if (gUnicode) - { - free(gUnicode); - gUnicode = NULL; + if (gUnicode[font]) { + free(gUnicode[font]); + gUnicode[font] = NULL; } - if (gHeight) + if (gHeight[font]) { - free(gHeight); - gHeight = NULL; + free(gHeight[font]); + gHeight[font] = NULL; } - if (gWidth) + if (gWidth[font]) { - free(gWidth); - gWidth = NULL; + free(gWidth[font]); + gWidth[font] = NULL; } - if (gxAdvance) + if (gxAdvance[font]) { - free(gxAdvance); - gxAdvance = NULL; + free(gxAdvance[font]); + gxAdvance[font] = NULL; } - if (gdY) + if (gdY[font]) { - free(gdY); - gdY = NULL; + free(gdY[font]); + gdY[font] = NULL; } - if (gdX) + if (gdX[font]) { - free(gdX); - gdX = NULL; + free(gdX[font]); + gdX[font] = NULL; } - if (gBitmap) + if (gBitmap[font]) { - free(gBitmap); - gBitmap = NULL; + free(gBitmap[font]); + gBitmap[font] = NULL; } - gFont.gArray = nullptr; - - if (fs_font && fontFile) fontFile.close(); - - fontLoaded = false; + gFonts[font].gArray = nullptr; } - -/*************************************************************************************** -** Function name: readInt32 -** Description: Get a 32-bit integer from the font file -*************************************************************************************x*/ uint32_t TFT_eSPI::readInt32(void) { uint32_t val = 0; - if (fs_font) { - val = (uint32_t)fontFile.read() << 24; - val |= (uint32_t)fontFile.read() << 16; - val |= (uint32_t)fontFile.read() << 8; - val |= (uint32_t)fontFile.read(); - } - else - { - val = (uint32_t)pgm_read_byte(fontPtr++) << 24; - val |= (uint32_t)pgm_read_byte(fontPtr++) << 16; - val |= (uint32_t)pgm_read_byte(fontPtr++) << 8; - val |= (uint32_t)pgm_read_byte(fontPtr++); - } + val = (uint32_t)pgm_read_byte(fontPtr++) << 24; + val |= (uint32_t)pgm_read_byte(fontPtr++) << 16; + val |= (uint32_t)pgm_read_byte(fontPtr++) << 8; + val |= (uint32_t)pgm_read_byte(fontPtr++); return val; } -bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index) +bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index, uint16_t font) { - for (uint16_t i = 0; i < gFont.gCount; i++) + for (uint16_t i = 0; i < gFonts[font].gCount; i++) { - if (gUnicode[i] == unicode) + if (gUnicode[font][i] == unicode) { *index = i; return true; @@ -5240,7 +3454,7 @@ bool TFT_eSPI::getUnicodeIndex(uint16_t unicode, uint16_t *index) return false; } -void TFT_eSPI::drawGlyph(uint16_t code) +void TFT_eSPI::drawGlyph(uint16_t code, uint16_t font) { uint16_t fg = textcolor; uint16_t bg = textbgcolor; @@ -5255,8 +3469,8 @@ void TFT_eSPI::drawGlyph(uint16_t code) if (code < 0x21) { if (code == 0x20) { - if (_fillbg) fillRect(bg_cursor_x, cursor_y, (cursor_x + gFont.spaceWidth) - bg_cursor_x, gFont.yAdvance, bg); - cursor_x += gFont.spaceWidth; + if (_fillbg) fillRect(bg_cursor_x, cursor_y, (cursor_x + gFonts[font].spaceWidth) - bg_cursor_x, gFonts[font].yAdvance, bg); + cursor_x += gFonts[font].spaceWidth; bg_cursor_x = cursor_x; last_cursor_x = cursor_x; return; @@ -5266,38 +3480,32 @@ void TFT_eSPI::drawGlyph(uint16_t code) cursor_x = 0; bg_cursor_x = 0; last_cursor_x = 0; - cursor_y += gFont.yAdvance; + cursor_y += gFonts[font].yAdvance; if (textwrapY && (cursor_y >= height())) cursor_y = 0; return; } } uint16_t gNum = 0; - bool found = getUnicodeIndex(code, &gNum); - + bool found = getUnicodeIndex(code, &gNum, font); + if (found) { - if (textwrapX && (cursor_x + gWidth[gNum] + gdX[gNum] > width())) + if (textwrapX && (cursor_x + gWidth[font][gNum] + gdX[font][gNum] > width())) { - cursor_y += gFont.yAdvance; + cursor_y += gFonts[font].yAdvance; cursor_x = 0; bg_cursor_x = 0; } - if (textwrapY && ((cursor_y + gFont.yAdvance) >= height())) cursor_y = 0; - if (cursor_x == 0) cursor_x -= gdX[gNum]; + if (textwrapY && ((cursor_y + gFonts[font].yAdvance) >= height())) cursor_y = 0; + if (cursor_x == 0) cursor_x -= gdX[font][gNum]; uint8_t* pbuffer = nullptr; - const uint8_t* gPtr = (const uint8_t*) gFont.gArray; + const uint8_t* gPtr = (const uint8_t*) gFonts[font].gArray; - if (fs_font) - { - fontFile.seek(gBitmap[gNum], fs::SeekSet); - pbuffer = (uint8_t*)malloc(gWidth[gNum]); - } - - int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; - int16_t cx = cursor_x + gdX[gNum]; + int16_t cy = cursor_y + gFonts[font].maxAscent - gdY[font][gNum]; + int16_t cx = cursor_x + gdX[font][gNum]; // if (cx > width() && bg_cursor_x > width()) return; // if (cursor_y > height()) return; @@ -5316,9 +3524,9 @@ void TFT_eSPI::drawGlyph(uint16_t code) // Fill area above glyph if (_fillbg) { - fillwidth = (cursor_x + gxAdvance[gNum]) - bg_cursor_x; + fillwidth = (cursor_x + gxAdvance[font][gNum]) - bg_cursor_x; if (fillwidth > 0) { - fillheight = gFont.maxAscent - gdY[gNum]; + fillheight = gFonts[font].maxAscent - gdY[font][gNum]; // Could be negative if (fillheight > 0) { fillRect(bg_cursor_x, cursor_y, fillwidth, fillheight, textbgcolor); @@ -5329,38 +3537,21 @@ void TFT_eSPI::drawGlyph(uint16_t code) fillwidth = 0; } - // Fill any area to left of glyph - if (bg_cursor_x < cx) fillRect(bg_cursor_x, cy, cx - bg_cursor_x, gHeight[gNum], textbgcolor); + // Fill any area to left of glyph + if (bg_cursor_x < cx) fillRect(bg_cursor_x, cy, cx - bg_cursor_x, gHeight[font][gNum], textbgcolor); // Set x position in glyph area where background starts if (bg_cursor_x > cx) bx = bg_cursor_x - cx; // Fill any area to right of glyph if (cx + gWidth[gNum] < cursor_x + gxAdvance[gNum]) { - fillRect(cx + gWidth[gNum], cy, (cursor_x + gxAdvance[gNum]) - (cx + gWidth[gNum]), gHeight[gNum], textbgcolor); + fillRect(cx + gWidth[font][gNum], cy, (cursor_x + gxAdvance[gNum]) - (cx + gWidth[gNum]), gHeight[font][gNum], textbgcolor); } } - for (int32_t y = 0; y < gHeight[gNum]; y++) + for (int32_t y = 0; y < gHeight[font][gNum]; y++) { - if (fs_font) { - if (spiffs) - { - fontFile.read(pbuffer, gWidth[gNum]); - //Serial.println("SPIFFS"); - } - else - { - endWrite(); // Release SPI for SD card transaction - fontFile.read(pbuffer, gWidth[gNum]); - startWrite(); // Re-start SPI for TFT transaction - //Serial.println("Not SPIFFS"); - } - } - - for (int32_t x = 0; x < gWidth[gNum]; x++) + for (int32_t x = 0; x < gWidth[font][gNum]; x++) { - if (fs_font) pixel = pbuffer[x]; - else - pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y); + pixel = pgm_read_byte(gPtr + gBitmap[font][gNum] + x + gWidth[font][gNum] * y); if (pixel) { @@ -5398,85 +3589,30 @@ void TFT_eSPI::drawGlyph(uint16_t code) // Fill area below glyph if (fillwidth > 0) { - fillheight = (cursor_y + gFont.yAdvance) - (cy + gHeight[gNum]); + fillheight = (cursor_y + gFonts[font].yAdvance) - (cy + gHeight[font][gNum]); if (fillheight > 0) { - fillRect(bg_cursor_x, cy + gHeight[gNum], fillwidth, fillheight, textbgcolor); + fillRect(bg_cursor_x, cy + gHeight[font][gNum], fillwidth, fillheight, textbgcolor); } } if (pbuffer) free(pbuffer); - cursor_x += gxAdvance[gNum]; + cursor_x += gxAdvance[font][gNum]; endWrite(); } else { // Point code not in font so draw a rectangle and move on cursor - drawRect(cursor_x, cursor_y + gFont.maxAscent - gFont.ascent, gFont.spaceWidth, gFont.ascent, fg); - cursor_x += gFont.spaceWidth + 1; + drawRect(cursor_x, cursor_y + gFonts[font].maxAscent - gFonts[font].ascent, gFonts[font].spaceWidth, gFonts[font].ascent, fg); + cursor_x += gFonts[font].spaceWidth + 1; } bg_cursor_x = cursor_x; last_cursor_x = cursor_x; } -/*************************************************************************************** -** Function name: showFont -** Description: Page through all characters in font, td ms between screens -*************************************************************************************x*/ -void TFT_eSPI::showFont(uint32_t td) -{ - if(!fontLoaded) return; - - int16_t cursorX = width(); // Force start of new page to initialise cursor - int16_t cursorY = height();// for the first character - uint32_t timeDelay = 0; // No delay before first page - - fillScreen(textbgcolor); - - for (uint16_t i = 0; i < gFont.gCount; i++) { - // Check if this will need a new screen - if (cursorX + gdX[i] + gWidth[i] >= width()) { - cursorX = -gdX[i]; - - cursorY += gFont.yAdvance; - if (cursorY + gFont.maxAscent + gFont.descent >= height()) { - cursorX = -gdX[i]; - cursorY = 0; - delay(timeDelay); - timeDelay = td; - fillScreen(textbgcolor); - } - } - - setCursor(cursorX, cursorY); - drawGlyph(gUnicode[i]); - cursorX += gxAdvance[i]; - yield(); - } - - delay(timeDelay); - fillScreen(textbgcolor); -} - -// The following touch screen support code by maxpautsch was merged 1/10/17 -// https://github.com/maxpautsch - -// A demo is provided in examples Generic folder - -// Additions by Bodmer to double sample, use Z value to improve detection reliability -// and to correct rotation handling - -// See license in root directory. - -// Define a default pressure threshold #ifndef Z_THRESHOLD #define Z_THRESHOLD 350 // Touch pressure threshold for validating touches #endif -/*************************************************************************************** -** Function name: begin_touch_read_write - was spi_begin_touch -** Description: Start transaction and select touch controller -***************************************************************************************/ -// The touch controller has a low SPI clock rate inline void TFT_eSPI::begin_touch_read_write(void){ dmaWait(); CS_H; // Just in case it has been left low @@ -5485,39 +3621,23 @@ inline void TFT_eSPI::begin_touch_read_write(void){ digitalWrite(TOUCH_CS, LOW); } -/*************************************************************************************** -** Function name: end_touch_read_write - was spi_end_touch -** Description: End transaction and deselect touch controller -***************************************************************************************/ inline void TFT_eSPI::end_touch_read_write(void){ digitalWrite(TOUCH_CS, HIGH); if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}} } -/*************************************************************************************** -** Function name: Legacy - deprecated -** Description: Start/end transaction -***************************************************************************************/ -void TFT_eSPI::spi_begin_touch() {begin_touch_read_write();} -void TFT_eSPI::spi_end_touch() { end_touch_read_write();} - -/*************************************************************************************** -** Function name: getTouchRaw -** Description: read raw touch position. Always returns true. -***************************************************************************************/ uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){ uint16_t tmp; begin_touch_read_write(); - - // Start YP sample request for x position, read 4 times and keep last sample - spi.transfer(0xd0); // Start new YP conversion - spi.transfer(0); // Read first 8 bits - spi.transfer(0xd0); // Read last 8 bits and start new YP conversion - spi.transfer(0); // Read first 8 bits - spi.transfer(0xd0); // Read last 8 bits and start new YP conversion - spi.transfer(0); // Read first 8 bits - spi.transfer(0xd0); // Read last 8 bits and start new YP conversion + + spi.transfer(0xd0); + spi.transfer(0); + spi.transfer(0xd0); + spi.transfer(0); + spi.transfer(0xd0); + spi.transfer(0); + spi.transfer(0xd0); tmp = spi.transfer(0); // Read first 8 bits tmp = tmp <<5; @@ -5546,7 +3666,7 @@ uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){ /*************************************************************************************** ** Function name: getTouchRawZ -** Description: read raw pressure on touchpad and return Z value. +** Description: read raw pressure on touchpad and return Z value. ***************************************************************************************/ uint16_t TFT_eSPI::getTouchRawZ(void){ @@ -5567,7 +3687,7 @@ uint16_t TFT_eSPI::getTouchRawZ(void){ /*************************************************************************************** ** Function name: validTouch -** Description: read validated position. Return false if not pressed. +** Description: read validated position. Return false if not pressed. ***************************************************************************************/ #define _RAWERR 20 // Deadband error allowed in successive position samples uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ @@ -5586,7 +3706,7 @@ uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ // Serial.print("Z = ");Serial.println(z1); if (z1 <= threshold) return false; - + getTouchRaw(&x_tmp,&y_tmp); // Serial.print("Sample 1 x,y = "); Serial.print(x_tmp);Serial.print(",");Serial.print(y_tmp); @@ -5597,26 +3717,26 @@ uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ delay(2); // Small delay to the next sample getTouchRaw(&x_tmp2,&y_tmp2); - + // Serial.print("Sample 2 x,y = "); Serial.print(x_tmp2);Serial.print(",");Serial.println(y_tmp2); // Serial.print("Sample difference = ");Serial.print(abs(x_tmp - x_tmp2));Serial.print(",");Serial.println(abs(y_tmp - y_tmp2)); if (abs(x_tmp - x_tmp2) > _RAWERR) return false; if (abs(y_tmp - y_tmp2) > _RAWERR) return false; - + *x = x_tmp; *y = y_tmp; - + return true; } - + /*************************************************************************************** ** Function name: getTouch -** Description: read callibrated position. Return false if not pressed. +** Description: read callibrated position. Return false if not pressed. ***************************************************************************************/ uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ uint16_t x_tmp, y_tmp; - + if (threshold<20) threshold = 20; if (_pressTime > millis()) threshold=20; @@ -5628,23 +3748,21 @@ uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ } if (valid<1) { _pressTime = 0; return false; } - + _pressTime = millis() + 50; convertRawXY(&x_tmp, &y_tmp); if (x_tmp >= _width || y_tmp >= _height) return false; - _pressX = x_tmp; - _pressY = y_tmp; - *x = _pressX; - *y = _pressY; + *x = x_tmp; + *y = y_tmp; return valid; } /*************************************************************************************** ** Function name: convertRawXY -** Description: convert raw touch x,y values to screen coordinates +** Description: convert raw touch x,y values to screen coordinates ***************************************************************************************/ void TFT_eSPI::convertRawXY(uint16_t *x, uint16_t *y) { @@ -5671,7 +3789,7 @@ void TFT_eSPI::convertRawXY(uint16_t *x, uint16_t *y) /*************************************************************************************** ** Function name: calibrateTouch -** Description: generates calibration parameters for touchscreen. +** Description: generates calibration parameters for touchscreen. ***************************************************************************************/ void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t color_bg, uint8_t size){ int16_t values[] = {0,0,0,0,0,0,0,0}; @@ -5686,7 +3804,7 @@ void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t fillRect(_width-size-1, _height-size-1, size+1, size+1, color_bg); if (i == 5) break; // used to clear the arrows - + switch (i) { case 0: // up left drawLine(0, 0, 0, size, color_fg); @@ -5724,7 +3842,7 @@ void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t } - // from case 0 to case 1, the y value changed. + // from case 0 to case 1, the y value changed. // If the measured delta of the touch x axis is bigger than the delta of the y axis, the touch and TFT axes are switched. touchCalibration_rotate = false; if(abs(values[0]-values[2]) > abs(values[1]-values[3])){ @@ -5776,10 +3894,6 @@ void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t } -/*************************************************************************************** -** Function name: setTouch -** Description: imports calibration parameters for touchscreen. -***************************************************************************************/ void TFT_eSPI::setTouch(uint16_t *parameters){ touchCalibration_x0 = parameters[0]; touchCalibration_x1 = parameters[1]; @@ -5796,8 +3910,7 @@ void TFT_eSPI::setTouch(uint16_t *parameters){ touchCalibration_invert_y = parameters[4] & 0x04; } -TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) -{ +TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) { _tft = tft; // Pointer to tft class so we can call member functions _iwidth = 0; // Initialise width and height to 0 (it does not exist yet) @@ -5817,7 +3930,7 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) _yptr = 0; _colorMap = nullptr; - + // Ensure end_tft_write() does nothing in inherited functions. lockTransaction = true; } @@ -5828,8 +3941,7 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft) ** Description: Create a sprite (bitmap) of defined width and height ***************************************************************************************/ // cast returned value to (uint8_t*) for 8-bit or (uint16_t*) for 16-bit colours -void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) -{ +void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) { if ( _created ) return _img8_1; @@ -5841,7 +3953,6 @@ void* TFT_eSprite::createSprite(int16_t w, int16_t h, uint8_t frames) cursor_x = 0; cursor_y = 0; - // Default scroll rectangle and gap fill colour _sx = 0; _sy = 0; _sw = w; @@ -5918,7 +4029,7 @@ bool TFT_eSprite::created(void) TFT_eSprite::~TFT_eSprite(void) { deleteSprite(); - if(fontLoaded) unloadFont(); + for(int i = 0; i < 2; i++) unloadFont(i); } @@ -6027,33 +4138,6 @@ void TFT_eSprite::createPalette(const uint16_t colorMap[], uint8_t colors) } } - -/*************************************************************************************** -** Function name: frameBuffer -** Description: For 1 bpp Sprites, select the frame used for graphics -***************************************************************************************/ -// Frames are numbered 1 and 2 -void* TFT_eSprite::frameBuffer(int8_t f) -{ - if (!_created) return nullptr; - - if ( f == 2 ) _img8 = _img8_2; - else _img8 = _img8_1; - - if (_bpp == 16) _img = (uint16_t*)_img8; - - //if (_bpp == 8) _img8 = _img8; - - if (_bpp == 4) _img4 = _img8; - - return _img8; -} - - -/*************************************************************************************** -** Function name: setColorDepth -** Description: Set bits per pixel for colour (1, 8 or 16) -***************************************************************************************/ void* TFT_eSprite::setColorDepth(int8_t b) { // Do not re-create the sprite if the colour depth does not change @@ -6074,11 +4158,6 @@ void* TFT_eSprite::setColorDepth(int8_t b) return nullptr; } - -/*************************************************************************************** -** Function name: getColorDepth -** Description: Get bits per pixel for colour (1, 8 or 16) -***************************************************************************************/ int8_t TFT_eSprite::getColorDepth(void) { if (_created) return _bpp; @@ -6139,279 +4218,10 @@ void TFT_eSprite::deleteSprite(void) free(_img8_1); _img8 = nullptr; _created = false; - _vpOoB = true; // TFT_eSPI class write() uses this to check for valid sprite + _vpOoB = true; } } - -/*************************************************************************************** -** Function name: pushRotated - Fast fixed point integer maths version -** Description: Push rotated Sprite to TFT screen -***************************************************************************************/ -#define FP_SCALE 10 -bool TFT_eSprite::pushRotated(int16_t angle, uint32_t transp) -{ - if ( !_created || _tft->_vpOoB) return false; - - // Bounding box parameters - int16_t min_x; - int16_t min_y; - int16_t max_x; - int16_t max_y; - - // Get the bounding box of this rotated source Sprite relative to Sprite pivot - if ( !getRotatedBounds(angle, &min_x, &min_y, &max_x, &max_y) ) return false; - - uint16_t sline_buffer[max_x - min_x + 1]; - - int32_t xt = min_x - _tft->_xPivot; - int32_t yt = min_y - _tft->_yPivot; - uint32_t xe = _dwidth << FP_SCALE; - uint32_t ye = _dheight << FP_SCALE; - uint16_t tpcolor = (uint16_t)transp; - - if (transp != 0x00FFFFFF) { - if (_bpp == 4) tpcolor = _colorMap[transp & 0x0F]; - tpcolor = tpcolor>>8 | tpcolor<<8; // Working with swapped color bytes - } - _tft->startWrite(); // Avoid transaction overhead for every tft pixel - - // Scan destination bounding box and fetch transformed pixels from source Sprite - for (int32_t y = min_y; y <= max_y; y++, yt++) { - int32_t x = min_x; - uint32_t xs = (_cosra * xt - (_sinra * yt - (_xPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); - uint32_t ys = (_sinra * xt + (_cosra * yt + (_yPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); - - while ((xs >= xe || ys >= ye) && x < max_x) { x++; xs += _cosra; ys += _sinra; } - if (x == max_x) continue; - - uint32_t pixel_count = 0; - do { - uint32_t rp; - int32_t xp = xs >> FP_SCALE; - int32_t yp = ys >> FP_SCALE; - if (_bpp == 16) {rp = _img[xp + yp * _iwidth]; } - else { rp = readPixel(xp, yp); rp = (uint16_t)(rp>>8 | rp<<8); } - if (transp != 0x00FFFFFF && tpcolor == rp) { - if (pixel_count) { - // TFT window is already clipped, so this is faster than pushImage() - _tft->setWindow(x - pixel_count, y, x - 1, y); - _tft->pushPixels(sline_buffer, pixel_count); - pixel_count = 0; - } - } - else { - sline_buffer[pixel_count++] = rp; - } - } while (++x < max_x && (xs += _cosra) < xe && (ys += _sinra) < ye); - if (pixel_count) { - // TFT window is already clipped, so this is faster than pushImage() - _tft->setWindow(x - pixel_count, y, x - 1, y); - _tft->pushPixels(sline_buffer, pixel_count); - } - } - - _tft->endWrite(); // End transaction - - return true; -} - - -/*************************************************************************************** -** Function name: pushRotated - Fast fixed point integer maths version -** Description: Push a rotated copy of the Sprite to another Sprite -***************************************************************************************/ -// Not compatible with 4bpp -bool TFT_eSprite::pushRotated(TFT_eSprite *spr, int16_t angle, uint32_t transp) -{ - if ( !_created || _bpp == 4) return false; // Check this Sprite is created - if ( !spr->_created || spr->_bpp == 4) return false; // Ckeck destination Sprite is created - - // Bounding box parameters - int16_t min_x; - int16_t min_y; - int16_t max_x; - int16_t max_y; - - // Get the bounding box of this rotated source Sprite - if ( !getRotatedBounds(spr, angle, &min_x, &min_y, &max_x, &max_y) ) return false; - - uint16_t sline_buffer[max_x - min_x + 1]; - - int32_t xt = min_x - spr->_xPivot; - int32_t yt = min_y - spr->_yPivot; - uint32_t xe = _dwidth << FP_SCALE; - uint32_t ye = _dheight << FP_SCALE; - uint16_t tpcolor = (uint16_t)transp; - - if (transp != 0x00FFFFFF) { - if (_bpp == 4) tpcolor = _colorMap[transp & 0x0F]; - tpcolor = tpcolor>>8 | tpcolor<<8; // Working with swapped color bytes - } - - bool oldSwapBytes = spr->getSwapBytes(); - spr->setSwapBytes(false); - - // Scan destination bounding box and fetch transformed pixels from source Sprite - for (int32_t y = min_y; y <= max_y; y++, yt++) { - int32_t x = min_x; - uint32_t xs = (_cosra * xt - (_sinra * yt - (_xPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); - uint32_t ys = (_sinra * xt + (_cosra * yt + (_yPivot << FP_SCALE)) + (1 << (FP_SCALE - 1))); - - while ((xs >= xe || ys >= ye) && x < max_x) { x++; xs += _cosra; ys += _sinra; } - if (x == max_x) continue; - - uint32_t pixel_count = 0; - do { - uint32_t rp; - int32_t xp = xs >> FP_SCALE; - int32_t yp = ys >> FP_SCALE; - if (_bpp == 16) rp = _img[xp + yp * _iwidth]; - else { rp = readPixel(xp, yp); rp = (uint16_t)(rp>>8 | rp<<8); } - if (transp != 0x00FFFFFF && tpcolor == rp) { - if (pixel_count) { - spr->pushImage(x - pixel_count, y, pixel_count, 1, sline_buffer); - pixel_count = 0; - } - } - else { - sline_buffer[pixel_count++] = rp; - } - } while (++x < max_x && (xs += _cosra) < xe && (ys += _sinra) < ye); - if (pixel_count) spr->pushImage(x - pixel_count, y, pixel_count, 1, sline_buffer); - } - spr->setSwapBytes(oldSwapBytes); - return true; -} - - -/*************************************************************************************** -** Function name: getRotatedBounds -** Description: Get TFT bounding box of a rotated Sprite wrt pivot -***************************************************************************************/ -bool TFT_eSprite::getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, - int16_t *max_x, int16_t *max_y) -{ - // Get the bounding box of this rotated source Sprite relative to Sprite pivot - getRotatedBounds(angle, width(), height(), _xPivot, _yPivot, min_x, min_y, max_x, max_y); - - // Move bounding box so source Sprite pivot coincides with TFT pivot - *min_x += _tft->_xPivot; - *max_x += _tft->_xPivot; - *min_y += _tft->_yPivot; - *max_y += _tft->_yPivot; - - // Return if bounding box is outside of TFT viewport - if (*min_x > _tft->_vpW) return false; - if (*min_y > _tft->_vpH) return false; - if (*max_x < _tft->_vpX) return false; - if (*max_y < _tft->_vpY) return false; - - // Clip bounding box to be within TFT viewport - if (*min_x < _tft->_vpX) *min_x = _tft->_vpX; - if (*min_y < _tft->_vpY) *min_y = _tft->_vpY; - if (*max_x > _tft->_vpW) *max_x = _tft->_vpW; - if (*max_y > _tft->_vpH) *max_y = _tft->_vpH; - - return true; -} - - -/*************************************************************************************** -** Function name: getRotatedBounds -** Description: Get destination Sprite bounding box of a rotated Sprite wrt pivot -***************************************************************************************/ -bool TFT_eSprite::getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y, - int16_t *max_x, int16_t *max_y) -{ - // Get the bounding box of this rotated source Sprite relative to Sprite pivot - getRotatedBounds(angle, width(), height(), _xPivot, _yPivot, min_x, min_y, max_x, max_y); - - // Move bounding box so source Sprite pivot coincides with destination Sprite pivot - *min_x += spr->_xPivot; - *max_x += spr->_xPivot; - *min_y += spr->_yPivot; - *max_y += spr->_yPivot; - - // Test only to show bounding box - // spr->fillSprite(TFT_BLACK); - // spr->drawRect(min_x, min_y, max_x - min_x + 1, max_y - min_y + 1, TFT_GREEN); - - // Return if bounding box is completely outside of destination Sprite - if (*min_x > spr->width()) return true; - if (*min_y > spr->height()) return true; - if (*max_x < 0) return true; - if (*max_y < 0) return true; - - // Clip bounding box to Sprite boundaries - // Clipping to a viewport will be done by destination Sprite pushImage function - if (*min_x < 0) min_x = 0; - if (*min_y < 0) min_y = 0; - if (*max_x > spr->width()) *max_x = spr->width(); - if (*max_y > spr->height()) *max_y = spr->height(); - - return true; -} - - -/*************************************************************************************** -** Function name: rotatedBounds -** Description: Get bounding box of a rotated Sprite wrt pivot -***************************************************************************************/ -void TFT_eSprite::getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp, - int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y) -{ - // Trig values for the rotation - float radAngle = -angle * 0.0174532925; // Convert degrees to radians - float sina = sin(radAngle); - float cosa = cos(radAngle); - - w -= xp; // w is now right edge coordinate relative to xp - h -= yp; // h is now bottom edge coordinate relative to yp - - // Calculate new corner coordinates - int16_t x0 = -xp * cosa - yp * sina; - int16_t y0 = xp * sina - yp * cosa; - - int16_t x1 = w * cosa - yp * sina; - int16_t y1 = -w * sina - yp * cosa; - - int16_t x2 = h * sina + w * cosa; - int16_t y2 = h * cosa - w * sina; - - int16_t x3 = h * sina - xp * cosa; - int16_t y3 = h * cosa + xp * sina; - - // Find bounding box extremes, enlarge box to accomodate rounding errors - *min_x = x0-2; - if (x1 < *min_x) *min_x = x1-2; - if (x2 < *min_x) *min_x = x2-2; - if (x3 < *min_x) *min_x = x3-2; - - *max_x = x0+2; - if (x1 > *max_x) *max_x = x1+2; - if (x2 > *max_x) *max_x = x2+2; - if (x3 > *max_x) *max_x = x3+2; - - *min_y = y0-2; - if (y1 < *min_y) *min_y = y1-2; - if (y2 < *min_y) *min_y = y2-2; - if (y3 < *min_y) *min_y = y3-2; - - *max_y = y0+2; - if (y1 > *max_y) *max_y = y1+2; - if (y2 > *max_y) *max_y = y2+2; - if (y3 > *max_y) *max_y = y3+2; - - _sinra = round(sina * (1<pushImage(x, y, _dwidth, _dheight, _img8, (bool)(_bpp == 8)); } - -/*************************************************************************************** -** Function name: pushSprite -** Description: Push the sprite to the TFT at x, y with transparent colour -***************************************************************************************/ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) { if (!_created) return; @@ -6458,19 +4263,6 @@ void TFT_eSprite::pushSprite(int32_t x, int32_t y, uint16_t transp) else _tft->pushImage(x, y, _dwidth, _dheight, _img8, 0, (bool)false); } - -/*************************************************************************************** -** Function name: pushToSprite -** Description: Push the sprite to another sprite at x, y -***************************************************************************************/ -// Note: The following sprite to sprite colour depths are currently supported: -// Source Destination -// 16bpp -> 16bpp -// 16bpp -> 8bpp -// 8bpp -> 8bpp -// 4bpp -> 4bpp (note: color translation depends on the 2 sprites palette colors) -// 1bpp -> 1bpp (note: color translation depends on the 2 sprites bitmap colors) - bool TFT_eSprite::pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y) { if (!_created) return false; @@ -6779,11 +4571,6 @@ uint16_t TFT_eSprite::readPixel(int32_t x, int32_t y) else return _tft->bitmap_bg; } - -/*************************************************************************************** -** Function name: pushImage -** Description: push image into a defined area of a sprite -***************************************************************************************/ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint8_t sbpp) { if (data == nullptr || !_created) return; @@ -6918,99 +4705,15 @@ void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_ } } - -/*************************************************************************************** -** Function name: pushImage -** Description: push 565 colour FLASH (PROGMEM) image into a defined area -***************************************************************************************/ -void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) -{ -#ifdef ESP32 +void TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) { pushImage(x, y, w, h, (uint16_t*) data); -#else - // Partitioned memory FLASH processor - if (data == nullptr || !_created) return; - - PI_CLIP; - - if (_bpp == 16) // Plot a 16 bpp image into a 16 bpp Sprite - { - for (int32_t yp = dy; yp < dy + dh; yp++) - { - int32_t ox = x; - for (int32_t xp = dx; xp < dx + dw; xp++) - { - uint16_t color = pgm_read_word(data + xp + yp * w); - if(_swapBytes) color = color<<8 | color>>8; - _img[ox + y * _iwidth] = color; - ox++; - } - y++; - } - } - - else if (_bpp == 8) // Plot a 16 bpp image into a 8 bpp Sprite - { - for (int32_t yp = dy; yp < dy + dh; yp++) - { - int32_t ox = x; - for (int32_t xp = dx; xp < dx + dw; xp++) - { - uint16_t color = pgm_read_word(data + xp + yp * w); - if(_swapBytes) color = color<<8 | color>>8; - _img8[ox + y * _iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); - ox++; - } - y++; - } - } - - else if (_bpp == 4) - { - #ifdef TFT_eSPI_DEBUG - Serial.println("TFT_eSprite::pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data) not implemented"); - #endif - return; - } - - else // Plot a 1bpp image into a 1bpp Sprite - { - x-= _xDatum; // Remove offsets, drawPixel will add - y-= _yDatum; - uint16_t bsw = (w+7) >> 3; // Width in bytes of source image line - uint8_t *ptr = ((uint8_t*)data) + dy * bsw; - - while (dh--) { - int32_t odx = dx; - int32_t ox = x; - while (odx < dx + dw) { - uint8_t pbyte = pgm_read_byte(ptr + (odx>>3)); - uint8_t mask = 0x80 >> (odx & 7); - while (mask) { - uint8_t p = pbyte & mask; - mask = mask >> 1; - drawPixel(ox++, y, p); - odx++; - } - } - ptr += bsw; - y++; - } - } -#endif // if ESP32 check } - -/*************************************************************************************** -** Function name: setWindow -** Description: Set the bounds of a window in the sprite -***************************************************************************************/ -// Intentionally not constrained to viewport area, does not manage 1bpp rotations void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { if (x0 > x1) transpose(x0, x1); if (y0 > y1) transpose(y0, y1); - + int32_t w = width(); int32_t h = height(); @@ -7038,11 +4741,6 @@ void TFT_eSprite::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) _yptr = _ys; } - -/*************************************************************************************** -** Function name: pushColor -** Description: Send a new pixel to the set window -***************************************************************************************/ void TFT_eSprite::pushColor(uint16_t color) { if (!_created ) return; @@ -7080,11 +4778,6 @@ void TFT_eSprite::pushColor(uint16_t color) } - -/*************************************************************************************** -** Function name: pushColor -** Description: Send a "len" new pixels to the set window -***************************************************************************************/ void TFT_eSprite::pushColor(uint16_t color, uint32_t len) { if (!_created ) return; @@ -7102,11 +4795,6 @@ void TFT_eSprite::pushColor(uint16_t color, uint32_t len) while(len--) writeColor(pixelColor); } - -/*************************************************************************************** -** Function name: writeColor -** Description: Write a pixel with pre-formatted colour to the set window -***************************************************************************************/ void TFT_eSprite::writeColor(uint16_t color) { if (!_created ) return; @@ -7140,135 +4828,6 @@ void TFT_eSprite::writeColor(uint16_t color) } } - -/*************************************************************************************** -** Function name: setScrollRect -** Description: Set scroll area within the sprite and the gap fill colour -***************************************************************************************/ -// Intentionally not constrained to viewport area -void TFT_eSprite::setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color) -{ - if ((x >= _iwidth) || (y >= _iheight) || !_created ) return; - - if (x < 0) { w += x; x = 0; } - if (y < 0) { h += y; y = 0; } - - if ((x + w) > _iwidth ) w = _iwidth - x; - if ((y + h) > _iheight) h = _iheight - y; - - if ( w < 1 || h < 1) return; - - _sx = x; - _sy = y; - _sw = w; - _sh = h; - - _scolor = color; -} - - -/*************************************************************************************** -** Function name: scroll -** Description: Scroll dx,dy pixels, positive right,down, negative left,up -***************************************************************************************/ -void TFT_eSprite::scroll(int16_t dx, int16_t dy) -{ - if (abs(dx) >= _sw || abs(dy) >= _sh) - { - fillRect (_sx, _sy, _sw, _sh, _scolor); - return; - } - - // Fetch the scroll area width and height set by setScrollRect() - uint32_t w = _sw - abs(dx); // line width to copy - uint32_t h = _sh - abs(dy); // lines to copy - int32_t iw = _iwidth; // rounded up width of sprite - - // Fetch the x,y origin set by setScrollRect() - uint32_t tx = _sx; // to x - uint32_t fx = _sx; // from x - uint32_t ty = _sy; // to y - uint32_t fy = _sy; // from y - - // Adjust for x delta - if (dx <= 0) fx -= dx; - else tx += dx; - - // Adjust for y delta - if (dy <= 0) fy -= dy; - else - { // Scrolling down so start copy from bottom - ty = ty + _sh - 1; // "To" pointer - iw = -iw; // Pointer moves backwards - fy = ty - dy; // "From" pointer - } - - // Calculate "from y" and "to y" pointers in RAM - uint32_t fyp = fx + fy * _iwidth; - uint32_t typ = tx + ty * _iwidth; - - // Now move the pixels in RAM - if (_bpp == 16) - { - while (h--) - { // move pixel lines (to, from, byte count) - memmove( _img + typ, _img + fyp, w<<1); - typ += iw; - fyp += iw; - } - } - else if (_bpp == 8) - { - while (h--) - { // move pixel lines (to, from, byte count) - memmove( _img8 + typ, _img8 + fyp, w); - typ += iw; - fyp += iw; - } - } - else if (_bpp == 4) - { - // could optimize for scrolling by even # pixels using memove (later) - if (dx > 0) { tx += w; fx += w; } // Start from right edge - while (h--) - { // move pixels one by one - for (uint16_t xp = 0; xp < w; xp++) - { - if (dx <= 0) drawPixel(tx + xp, ty, readPixelValue(fx + xp, fy)); - if (dx > 0) drawPixel(tx - xp, ty, readPixelValue(fx - xp, fy)); - } - if (dy <= 0) { ty++; fy++; } - else { ty--; fy--; } - } - } - else if (_bpp == 1 ) - { - if (dx > 0) { tx += w; fx += w; } // Start from right edge - while (h--) - { // move pixels one by one - for (uint16_t xp = 0; xp < w; xp++) - { - if (dx <= 0) drawPixel(tx + xp, ty, readPixelValue(fx + xp, fy)); - if (dx > 0) drawPixel(tx - xp, ty, readPixelValue(fx - xp, fy)); - } - if (dy <= 0) { ty++; fy++; } - else { ty--; fy--; } - } - } - else return; // Not 1, 4, 8 or 16 bpp - - // Fill the gap left by the scrolling - if (dx > 0) fillRect(_sx, _sy, dx, _sh, _scolor); - if (dx < 0) fillRect(_sx + _sw + dx, _sy, -dx, _sh, _scolor); - if (dy > 0) fillRect(_sx, _sy, _sw, dy, _scolor); - if (dy < 0) fillRect(_sx, _sy + _sh + dy, _sw, -dy, _scolor); -} - - -/*************************************************************************************** -** Function name: fillSprite -** Description: Fill the whole sprite with defined colour -***************************************************************************************/ void TFT_eSprite::fillSprite(uint32_t color) { if (!_created || _vpOoB) return; @@ -7301,12 +4860,6 @@ void TFT_eSprite::fillSprite(uint32_t color) else fillRect(_vpX - _xDatum, _vpY - _yDatum, _xWidth, _yHeight, color); } - -/*************************************************************************************** -** Function name: width -** Description: Return the width of sprite -***************************************************************************************/ -// Return the size of the sprite int16_t TFT_eSprite::width(void) { if (!_created ) return 0; @@ -7325,11 +4878,6 @@ int16_t TFT_eSprite::width(void) return _dwidth; } - -/*************************************************************************************** -** Function name: height -** Description: Return the height of sprite -***************************************************************************************/ int16_t TFT_eSprite::height(void) { if (!_created ) return 0; @@ -7348,41 +4896,6 @@ int16_t TFT_eSprite::height(void) return _dheight; } - -/*************************************************************************************** -** Function name: setRotation -** Description: Rotate coordinate frame for 1bpp sprite -***************************************************************************************/ -// Does nothing for 4, 8 and 16 bpp sprites. -void TFT_eSprite::setRotation(uint8_t r) -{ - if (_bpp != 1) return; - - rotation = r; - - if (rotation&1) { - resetViewport(); - } - else { - resetViewport(); - } -} - - -/*************************************************************************************** -** Function name: getRotation -** Description: Get rotation for 1bpp sprite -***************************************************************************************/ -uint8_t TFT_eSprite::getRotation(void) -{ - return rotation; -} - - -/*************************************************************************************** -** Function name: drawPixel -** Description: push a single pixel at an arbitrary position -***************************************************************************************/ void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color) { if (!_created || _vpOoB) return; @@ -7393,41 +4906,24 @@ void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color) // Range checking if ((x < _vpX) || (y < _vpY) ||(x >= _vpW) || (y >= _vpH)) return; - if (_bpp == 16) - { + if (_bpp == 16) { color = (color >> 8) | (color << 8); _img[x+y*_iwidth] = (uint16_t) color; - } - else if (_bpp == 8) - { - _img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); - } - else if (_bpp == 4) - { + } else if (_bpp == 8) _img8[x+y*_iwidth] = (uint8_t)((color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3); + else if (_bpp == 4) { uint8_t c = color & 0x0F; int index = (x+y*_iwidth)>>1;; - if ((x & 0x01) == 0) { - _img4[index] = (uint8_t)((c << 4) | (_img4[index] & 0x0F)); - } - else { - _img4[index] = (uint8_t)(c | (_img4[index] & 0xF0)); - } - } - else // 1 bpp - { - if (rotation == 1) - { + if ((x & 0x01) == 0) _img4[index] = (uint8_t)((c << 4) | (_img4[index] & 0x0F)); + else _img4[index] = (uint8_t)(c | (_img4[index] & 0xF0)); + } else { + if (rotation == 1) { uint16_t tx = x; x = _dwidth - y - 1; y = tx; - } - else if (rotation == 2) - { + } else if (rotation == 2) { x = _dwidth - x - 1; y = _dheight - y - 1; - } - else if (rotation == 3) - { + } else if (rotation == 3) { uint16_t tx = x; x = y; y = _dheight - tx - 1; @@ -7438,11 +4934,6 @@ void TFT_eSprite::drawPixel(int32_t x, int32_t y, uint32_t color) } } - -/*************************************************************************************** -** Function name: drawLine -** Description: draw a line between 2 arbitrary points -***************************************************************************************/ void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) { if (!_created || _vpOoB) return; @@ -7496,11 +4987,6 @@ void TFT_eSprite::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint3 } } - -/*************************************************************************************** -** Function name: drawFastVLine -** Description: draw a vertical line -***************************************************************************************/ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) { if (!_created || _vpOoB) return; @@ -7517,43 +5003,31 @@ void TFT_eSprite::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color) if (h < 1) return; - if (_bpp == 16) - { + if (_bpp == 16) { color = (color >> 8) | (color << 8); int32_t yp = x + _iwidth * y; while (h--) {_img[yp] = (uint16_t) color; yp += _iwidth;} - } - else if (_bpp == 8) - { + } else if (_bpp == 8) { color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; while (h--) _img8[x + _iwidth * y++] = (uint8_t) color; - } - else if (_bpp == 4) - { - if ((x & 0x01) == 0) - { + } else if (_bpp == 4) { + if ((x & 0x01) == 0) { uint8_t c = (uint8_t) (color & 0xF) << 4; while (h--) { _img4[(x + _iwidth * y)>>1] = (uint8_t) (c | (_img4[(x + _iwidth * y)>>1] & 0x0F)); y++; } - } - else { + } else { uint8_t c = (uint8_t)color & 0xF; while (h--) { _img4[(x + _iwidth * y)>>1] = (uint8_t) (c | (_img4[(x + _iwidth * y)>>1] & 0xF0)); // x is odd; new color goes into the low bits. y++; } } - } - else - { + } else { x -= _xDatum; // Remove any offset as it will be added by drawPixel y -= _yDatum; - while (h--) - { - drawPixel(x, y++, color); - } + while (h--) drawPixel(x, y++, color); } } @@ -7578,53 +5052,37 @@ void TFT_eSprite::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color) if (w < 1) return; - if (_bpp == 16) - { + if (_bpp == 16) { color = (color >> 8) | (color << 8); while (w--) _img[_iwidth * y + x++] = (uint16_t) color; - } - else if (_bpp == 8) - { + } else if (_bpp == 8) { color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; memset(_img8+_iwidth * y + x, (uint8_t)color, w); - } - else if (_bpp == 4) - { + } else if (_bpp == 4) { uint8_t c = (uint8_t)color & 0x0F; uint8_t c2 = (c | ((c << 4) & 0xF0)); if ((x & 0x01) == 1) { drawPixel(x - _xDatum, y - _yDatum, color); x++; w--; - if (w < 1) - return; + if (w < 1) return; } - if (((w + x) & 0x01) == 1) - { + if (((w + x) & 0x01) == 1) { // handle the extra one at the other end drawPixel(x - _xDatum + w - 1, y - _yDatum, color); w--; if (w < 1) return; } memset(_img4 + ((_iwidth * y + x) >> 1), c2, (w >> 1)); - } - else { + } else { x -= _xDatum; // Remove any offset as it will be added by drawPixel y -= _yDatum; - while (w--) - { - drawPixel(x++, y, color); - } + while (w--) drawPixel(x++, y, color); } } - -/*************************************************************************************** -** Function name: fillRect -** Description: draw a filled rectangle -***************************************************************************************/ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color) { if (!_created || _vpOoB) return; @@ -7645,85 +5103,62 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t int32_t yp = _iwidth * y + x; - if (_bpp == 16) - { + if (_bpp == 16) { color = (color >> 8) | (color << 8); uint32_t iw = w; int32_t ys = yp; if(h--) {while (iw--) _img[yp++] = (uint16_t) color;} yp = ys; - while (h--) - { + while (h--) { yp += _iwidth; memcpy( _img+yp, _img+ys, w<<1); } - } - else if (_bpp == 8) - { + } else if (_bpp == 8) { color = (color & 0xE000)>>8 | (color & 0x0700)>>6 | (color & 0x0018)>>3; - while (h--) - { + while (h--) { memset(_img8 + yp, (uint8_t)color, w); yp += _iwidth; } - } - else if (_bpp == 4) - { + } else if (_bpp == 4) { uint8_t c1 = (uint8_t)color & 0x0F; uint8_t c2 = c1 | ((c1 << 4) & 0xF0); - if ((x & 0x01) == 0 && (w & 0x01) == 0) - { + if ((x & 0x01) == 0 && (w & 0x01) == 0) { yp = (yp >> 1); - while (h--) - { + while (h--) { memset(_img4 + yp, c2, (w>>1)); yp += (_iwidth >> 1); } - } - else if ((x & 0x01) == 0) - { - + } else if ((x & 0x01) == 0) { // same as above but you have a hangover on the right. yp = (yp >> 1); - while (h--) - { + while (h--) { if (w > 1) memset(_img4 + yp, c2, (w-1)>>1); // handle the rightmost pixel by calling drawPixel drawPixel(x+w-1-_xDatum, y+h-_yDatum, c1); yp += (_iwidth >> 1); } - } - else if ((w & 0x01) == 1) - { + } else if ((w & 0x01) == 1) { yp = (yp + 1) >> 1; while (h--) { drawPixel(x-_xDatum, y+h-_yDatum, color & 0x0F); - if (w > 1) - memset(_img4 + yp, c2, (w-1)>>1); + if (w > 1) memset(_img4 + yp, c2, (w-1)>>1); // same as above but you have a hangover on the left instead yp += (_iwidth >> 1); } - } - else - { + } else { yp = (yp + 1) >> 1; while (h--) { drawPixel(x-_xDatum, y+h-_yDatum, color & 0x0F); if (w > 1) drawPixel(x+w-1-_xDatum, y+h-_yDatum, color & 0x0F); - if (w > 2) - memset(_img4 + yp, c2, (w-2)>>1); - // maximal hacking, single pixels on left and right. + if (w > 2) memset(_img4 + yp, c2, (w-2)>>1); yp += (_iwidth >> 1); } } - } - else - { + } else { x -= _xDatum; y -= _yDatum; - while (h--) - { + while (h--) { int32_t ww = w; int32_t xx = x; while (ww--) drawPixel(xx++, y, color); @@ -7732,79 +5167,6 @@ void TFT_eSprite::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t } } - -/*************************************************************************************** -** Function name: drawChar -** Description: draw a single character in the Adafruit GLCD or freefont -***************************************************************************************/ -void TFT_eSprite::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size) -{ - if ( _vpOoB || !_created ) return; - - if (c < 32) return; - if ((x >= _vpW - _xDatum) || // Clip right - (y >= _vpH - _yDatum)) // Clip bottom - return; - - if (((x + 6 * size - 1) < (_vpX - _xDatum)) || // Clip left - ((y + 8 * size - 1) < (_vpY - _yDatum))) // Clip top - return; - - if (c > 255) return; - if (!_cp437 && c > 175) c++; - - bool fillbg = (bg != color); - - if ((size==1) && fillbg) - { - uint8_t column[6]; - uint8_t mask = 0x1; - - for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i); - column[5] = 0; - - int8_t j, k; - for (j = 0; j < 8; j++) { - for (k = 0; k < 5; k++ ) { - if (column[k] & mask) { - drawPixel(x + k, y + j, color); - } - else { - drawPixel(x + k, y + j, bg); - } - } - - mask <<= 1; - - drawPixel(x + k, y + j, bg); - } - } - else - { - for (int8_t i = 0; i < 6; i++ ) { - uint8_t line; - if (i == 5) - line = 0x0; - else - line = pgm_read_byte(font + (c * 5) + i); - - if (size == 1) // default size - { - for (int8_t j = 0; j < 8; j++) { - if (line & 0x1) drawPixel(x + i, y + j, color); - line >>= 1; - } - } else { // big size - for (int8_t j = 0; j < 8; j++) { - if (line & 0x1) fillRect(x + (i * size), y + (j * size), size, size, color); - else if (fillbg) fillRect(x + i * size, y + j * size, size, size, bg); - line >>= 1; - } - } - } - } -} - int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y) { return drawChar(uniCode, x, y, textfont); } @@ -7842,7 +5204,7 @@ int16_t TFT_eSprite::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t fo return width * textsize; // x + } -void TFT_eSprite::drawGlyph(uint16_t code) +void TFT_eSprite::drawGlyph(uint16_t code, uint16_t font) { uint16_t fg = textcolor; uint16_t bg = textbgcolor; @@ -7857,8 +5219,8 @@ void TFT_eSprite::drawGlyph(uint16_t code) if (code < 0x21) { if (code == 0x20) { - if (_fillbg) fillRect(bg_cursor_x, cursor_y, (cursor_x + gFont.spaceWidth) - bg_cursor_x, gFont.yAdvance, bg); - cursor_x += gFont.spaceWidth; + if (_fillbg) fillRect(bg_cursor_x, cursor_y, (cursor_x + gFonts[font].spaceWidth) - bg_cursor_x, gFonts[font].yAdvance, bg); + cursor_x += gFonts[font].spaceWidth; bg_cursor_x = cursor_x; last_cursor_x = cursor_x; return; @@ -7868,46 +5230,41 @@ void TFT_eSprite::drawGlyph(uint16_t code) cursor_x = 0; bg_cursor_x = 0; last_cursor_x = 0; - cursor_y += gFont.yAdvance; + cursor_y += gFonts[font].yAdvance; if (textwrapY && (cursor_y >= height())) cursor_y = 0; return; } } uint16_t gNum = 0; - bool found = getUnicodeIndex(code, &gNum); + bool found = getUnicodeIndex(code, &gNum, font); if (found) { bool newSprite = !_created; if (newSprite) { - createSprite(gWidth[gNum], gFont.yAdvance); + createSprite(gWidth[font][gNum], gFonts[font].yAdvance); if(fg != bg) fillSprite(bg); - cursor_x = -gdX[gNum]; + cursor_x = -gdX[font][gNum]; bg_cursor_x = cursor_x; last_cursor_x = cursor_x; cursor_y = 0; } else { - if( textwrapX && ((cursor_x + gWidth[gNum] + gdX[gNum]) > width())) { - cursor_y += gFont.yAdvance; + if( textwrapX && ((cursor_x + gWidth[font][gNum] + gdX[font][gNum]) > width())) { + cursor_y += gFonts[font].yAdvance; cursor_x = 0; bg_cursor_x = 0; last_cursor_x = 0; } - if( textwrapY && ((cursor_y + gFont.yAdvance) > height())) cursor_y = 0; - if ( cursor_x == 0) cursor_x -= gdX[gNum]; + if( textwrapY && ((cursor_y + gFonts[font].yAdvance) > height())) cursor_y = 0; + if ( cursor_x == 0) cursor_x -= gdX[font][gNum]; } uint8_t* pbuffer = nullptr; - const uint8_t* gPtr = (const uint8_t*) gFont.gArray; + const uint8_t* gPtr = (const uint8_t*) gFonts[font].gArray; - if (fs_font) { - fontFile.seek(gBitmap[gNum], fs::SeekSet); - pbuffer = (uint8_t*)malloc(gWidth[gNum]); - } - - int16_t cy = cursor_y + gFont.maxAscent - gdY[gNum]; - int16_t cx = cursor_x + gdX[gNum]; + int16_t cy = cursor_y + gFonts[font].maxAscent - gdY[font][gNum]; + int16_t cx = cursor_x + gdX[font][gNum]; int16_t fxs = cx; uint32_t fl = 0; @@ -7921,27 +5278,24 @@ void TFT_eSprite::drawGlyph(uint16_t code) // Fill area above glyph if (_fillbg) { - fillwidth = (cursor_x + gxAdvance[gNum]) - bg_cursor_x; + fillwidth = (cursor_x + gxAdvance[font][gNum]) - bg_cursor_x; if (fillwidth > 0) { - fillheight = gFont.maxAscent - gdY[gNum]; + fillheight = gFonts[font].maxAscent - gdY[font][gNum]; if (fillheight > 0) fillRect(bg_cursor_x, cursor_y, fillwidth, fillheight, textbgcolor); } else fillwidth = 0; - // Fill any area to left of glyph - if (bg_cursor_x < cx) fillRect(bg_cursor_x, cy, cx - bg_cursor_x, gHeight[gNum], textbgcolor); + // Fill any area to left of glyph + if (bg_cursor_x < cx) fillRect(bg_cursor_x, cy, cx - bg_cursor_x, gHeight[font][gNum], textbgcolor); // Set x position in glyph area where background starts if (bg_cursor_x > cx) bx = bg_cursor_x - cx; // Fill any area to right of glyph - if (cx + gWidth[gNum] < cursor_x + gxAdvance[gNum]) fillRect(cx + gWidth[gNum], cy, (cursor_x + gxAdvance[gNum]) - (cx + gWidth[gNum]), gHeight[gNum], textbgcolor); + if (cx + gWidth[gNum] < cursor_x + gxAdvance[gNum]) fillRect(cx + gWidth[font][gNum], cy, (cursor_x + gxAdvance[gNum]) - (cx + gWidth[gNum]), gHeight[font][gNum], textbgcolor); } - for (int32_t y = 0; y < gHeight[gNum]; y++) { - if (fs_font) fontFile.read(pbuffer, gWidth[gNum]); - - for (int32_t x = 0; x < gWidth[gNum]; x++) { - if (fs_font) pixel = pbuffer[x]; - else pixel = pgm_read_byte(gPtr + gBitmap[gNum] + x + gWidth[gNum] * y); + for (int32_t y = 0; y < gHeight[font][gNum]; y++) { + for (int32_t x = 0; x < gWidth[font][gNum]; x++) { + pixel = pgm_read_byte(gPtr + gBitmap[font][gNum] + x + gWidth[font][gNum] * y); if (pixel) { if (bl) { drawFastHLine( bxs, y + cy, bl, bg); bl = 0; } @@ -7974,12 +5328,12 @@ void TFT_eSprite::drawGlyph(uint16_t code) // Fill area below glyph if (fillwidth > 0) { - fillheight = (cursor_y + gFont.yAdvance) - (cy + gHeight[gNum]); - if (fillheight > 0) fillRect(bg_cursor_x, cy + gHeight[gNum], fillwidth, fillheight, textbgcolor); + fillheight = (cursor_y + gFonts[font].yAdvance) - (cy + gHeight[font][gNum]); + if (fillheight > 0) fillRect(bg_cursor_x, cy + gHeight[font][gNum], fillwidth, fillheight, textbgcolor); } if (pbuffer) free(pbuffer); - cursor_x += gxAdvance[gNum]; + cursor_x += gxAdvance[font][gNum]; if (newSprite) { pushSprite(cx, cursor_y); @@ -7987,76 +5341,9 @@ void TFT_eSprite::drawGlyph(uint16_t code) } } else { - drawRect(cursor_x, cursor_y + gFont.maxAscent - gFont.ascent, gFont.spaceWidth, gFont.ascent, fg); - cursor_x += gFont.spaceWidth + 1; + drawRect(cursor_x, cursor_y + gFonts[font].maxAscent - gFonts[font].ascent, gFonts[font].spaceWidth, gFonts[font].ascent, fg); + cursor_x += gFonts[font].spaceWidth + 1; } bg_cursor_x = cursor_x; last_cursor_x = cursor_x; -} - -void TFT_eSprite::printToSprite(String string) -{ - if(!fontLoaded) return; - printToSprite((char*)string.c_str(), string.length()); -} - -void TFT_eSprite::printToSprite(char *cbuffer, uint16_t len) //String string) -{ - if(!fontLoaded) return; - - uint16_t n = 0; - bool newSprite = !_created; - int16_t cursorX = _tft->cursor_x; - - if (newSprite) { - int16_t sWidth = 0; - uint16_t index = 0; - bool first = true; - while (n < len) { - uint16_t unicode = decodeUTF8((uint8_t*)cbuffer, &n, len - n); - if (getUnicodeIndex(unicode, &index)) { - if (first) { - first = false; - sWidth -= gdX[index]; - cursorX += gdX[index]; - } - if (n == len) sWidth += ( gWidth[index] + gdX[index]); - else sWidth += gxAdvance[index]; - } - else sWidth += gFont.spaceWidth + 1; - } - - createSprite(sWidth, gFont.yAdvance); - - if (textcolor != textbgcolor) fillSprite(textbgcolor); - } - - n = 0; - - while(n < len) drawGlyph(decodeUTF8((uint8_t*)cbuffer, &n, len - n)); - - if (newSprite) { - pushSprite(cursorX, _tft->cursor_y); - deleteSprite(); - } -} - -int16_t TFT_eSprite::printToSprite(int16_t x, int16_t y, uint16_t index) { - bool newSprite = !_created; - int16_t sWidth = gWidth[index]; - - if (newSprite) { - createSprite(sWidth, gFont.yAdvance); - - if (textcolor != textbgcolor) fillSprite(textbgcolor); - - drawGlyph(gUnicode[index]); - - pushSprite(x + gdX[index], y, textbgcolor); - deleteSprite(); - } - - else drawGlyph(gUnicode[index]); - - return gxAdvance[index]; -} +} \ No newline at end of file diff --git a/lib/TFT_eSPI/TFT_eSPI.h b/lib/TFT_eSPI/TFT_eSPI.h index ebc9b89..fb2fc3e 100644 --- a/lib/TFT_eSPI/TFT_eSPI.h +++ b/lib/TFT_eSPI/TFT_eSPI.h @@ -10,130 +10,29 @@ #include -// Processor ID reported by getSetup() #define PROCESSOR_ID 0x32 - -#ifdef USE_HSPI_PORT - #ifdef CONFIG_IDF_TARGET_ESP32 - #define SPI_PORT HSPI //HSPI is port 2 on ESP32 - #else - #define SPI_PORT 3 //HSPI is port 3 on ESP32 S2 - #endif -#elif defined(USE_FSPI_PORT) - #define SPI_PORT 2 //FSPI(ESP32 S2) -#else - #ifdef CONFIG_IDF_TARGET_ESP32 - #define SPI_PORT VSPI - #else - #define SPI_PORT 2 //FSPI(ESP32 S2) - #endif -#endif - -// Include processor specific header +#define SPI_PORT VSPI #include "soc/spi_reg.h" #include "driver/spi_master.h" #include "hal/gpio_ll.h" -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32) - #define CONFIG_IDF_TARGET_ESP32 -#endif - -#if (TFT_SPI_MODE == SPI_MODE1) || (TFT_SPI_MODE == SPI_MODE2) - #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI | SPI_CK_OUT_EDGE - #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN | SPI_CK_OUT_EDGE -#else - #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI - #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN -#endif - -#define ESP32_DMA +#define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI +#define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN #define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR) -// If smooth font is used then it is likely SPIFFS will be needed -// Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts #define FS_NO_GLOBALS #include #include "SPIFFS.h" // ESP32 only -#ifndef TFT_DC - #define DC_C // No macro allocated so it generates no code - #define DC_D // No macro allocated so it generates no code -#else - #if (TFT_DC >= 32) - #ifdef RPI_DISPLAY_TYPE // RPi displays need a slower DC change - #define DC_C GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)); \ - GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) - #define DC_D GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)); \ - GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) - #else - #define DC_C GPIO.out1_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1tc.val = (1 << (TFT_DC - 32)) - #define DC_D GPIO.out1_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_DC - 32)) - #endif - #elif (TFT_DC >= 0) - #if defined (RPI_DISPLAY_TYPE) - #if defined (ILI9486_DRIVER) - // RPi ILI9486 display needs a slower DC change - #define DC_C GPIO.out_w1tc = (1 << TFT_DC); \ - GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ - GPIO.out_w1ts = (1 << TFT_DC) - #else - // Other RPi displays need a slower C->D change - #define DC_C GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1tc = (1 << TFT_DC); \ - GPIO.out_w1ts = (1 << TFT_DC) - #endif - #else - #define DC_C GPIO.out_w1tc = (1 << TFT_DC)//;GPIO.out_w1tc = (1 << TFT_DC) - #define DC_D GPIO.out_w1ts = (1 << TFT_DC)//;GPIO.out_w1ts = (1 << TFT_DC) - #endif - #else - #define DC_C - #define DC_D - #endif -#endif +#define DC_C GPIO.out_w1tc = (1 << TFT_DC)//;GPIO.out_w1tc = (1 << TFT_DC) +#define DC_D GPIO.out_w1ts = (1 << TFT_DC)//;GPIO.out_w1ts = (1 << TFT_DC) -//////////////////////////////////////////////////////////////////////////////////////// -// Define the CS (TFT chip select) pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#ifndef TFT_CS - #define TFT_CS -1 // Keep DMA code happy - #define CS_L // No macro allocated so it generates no code - #define CS_H // No macro allocated so it generates no code -#else - #if (TFT_CS >= 32) - #define CS_L GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out1_w1tc.val = (1 << (TFT_CS - 32)) - #define CS_H GPIO.out1_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out1_w1ts.val = (1 << (TFT_CS - 32)) - #elif (TFT_CS >= 0) - #define CS_L GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) - #define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (1 << TFT_CS) - #else - #define CS_L - #define CS_H - #endif -#endif +#define CS_L GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) +#define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (1 << TFT_CS) -//////////////////////////////////////////////////////////////////////////////////////// -// Define the WR (TFT Write) pin drive code -//////////////////////////////////////////////////////////////////////////////////////// -#if defined (TFT_WR) - #if (TFT_WR >= 32) - // Note: it will be ~1.25x faster if the TFT_WR pin uses a GPIO pin lower than 32 - #define WR_L GPIO.out1_w1tc.val = (1 << (TFT_WR - 32)) - #define WR_H GPIO.out1_w1ts.val = (1 << (TFT_WR - 32)) - #elif (TFT_WR >= 0) - // TFT_WR, for best performance, should be in range 0-31 for single register parallel write - #define WR_L GPIO.out_w1tc = (1 << TFT_WR) - #define WR_H GPIO.out_w1ts = (1 << TFT_WR) - #else - #define WR_L - #define WR_H - #endif -#else - #define WR_L - #define WR_H -#endif +#define WR_L +#define WR_H #ifndef TFT_MISO #define TFT_MISO -1 @@ -142,18 +41,10 @@ #ifndef TFT_MOSI #define TFT_MOSI 23 #endif -#if (TFT_MOSI == -1) - #undef TFT_MOSI - #define TFT_MOSI 23 -#endif #ifndef TFT_SCLK #define TFT_SCLK 18 #endif -#if (TFT_SCLK == -1) - #undef TFT_SCLK - #define TFT_SCLK 18 -#endif #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ *_spi_w = D; \ @@ -196,292 +87,6 @@ #define TFT_SPI_MODE SPI_MODE0 #endif -static const unsigned char font[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, - 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, - 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, - 0x18, 0x3C, 0x7E, 0x3C, 0x18, - 0x1C, 0x57, 0x7D, 0x57, 0x1C, - 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, - 0x00, 0x18, 0x3C, 0x18, 0x00, - 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, - 0x00, 0x18, 0x24, 0x18, 0x00, - 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, - 0x30, 0x48, 0x3A, 0x06, 0x0E, - 0x26, 0x29, 0x79, 0x29, 0x26, - 0x40, 0x7F, 0x05, 0x05, 0x07, - 0x40, 0x7F, 0x05, 0x25, 0x3F, - 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, - 0x7F, 0x3E, 0x1C, 0x1C, 0x08, - 0x08, 0x1C, 0x1C, 0x3E, 0x7F, - 0x14, 0x22, 0x7F, 0x22, 0x14, - 0x5F, 0x5F, 0x00, 0x5F, 0x5F, - 0x06, 0x09, 0x7F, 0x01, 0x7F, - 0x00, 0x66, 0x89, 0x95, 0x6A, - 0x60, 0x60, 0x60, 0x60, 0x60, - 0x94, 0xA2, 0xFF, 0xA2, 0x94, - 0x08, 0x04, 0x7E, 0x04, 0x08, - 0x10, 0x20, 0x7E, 0x20, 0x10, - 0x08, 0x08, 0x2A, 0x1C, 0x08, - 0x08, 0x1C, 0x2A, 0x08, 0x08, - 0x1E, 0x10, 0x10, 0x10, 0x10, - 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, - 0x30, 0x38, 0x3E, 0x38, 0x30, - 0x06, 0x0E, 0x3E, 0x0E, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x5F, 0x00, 0x00, - 0x00, 0x07, 0x00, 0x07, 0x00, - 0x14, 0x7F, 0x14, 0x7F, 0x14, - 0x24, 0x2A, 0x7F, 0x2A, 0x12, - 0x23, 0x13, 0x08, 0x64, 0x62, - 0x36, 0x49, 0x56, 0x20, 0x50, - 0x00, 0x08, 0x07, 0x03, 0x00, - 0x00, 0x1C, 0x22, 0x41, 0x00, - 0x00, 0x41, 0x22, 0x1C, 0x00, - 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, - 0x08, 0x08, 0x3E, 0x08, 0x08, - 0x00, 0x80, 0x70, 0x30, 0x00, - 0x08, 0x08, 0x08, 0x08, 0x08, - 0x00, 0x00, 0x60, 0x60, 0x00, - 0x20, 0x10, 0x08, 0x04, 0x02, - 0x3E, 0x51, 0x49, 0x45, 0x3E, - 0x00, 0x42, 0x7F, 0x40, 0x00, - 0x72, 0x49, 0x49, 0x49, 0x46, - 0x21, 0x41, 0x49, 0x4D, 0x33, - 0x18, 0x14, 0x12, 0x7F, 0x10, - 0x27, 0x45, 0x45, 0x45, 0x39, - 0x3C, 0x4A, 0x49, 0x49, 0x31, - 0x41, 0x21, 0x11, 0x09, 0x07, - 0x36, 0x49, 0x49, 0x49, 0x36, - 0x46, 0x49, 0x49, 0x29, 0x1E, - 0x00, 0x00, 0x14, 0x00, 0x00, - 0x00, 0x40, 0x34, 0x00, 0x00, - 0x00, 0x08, 0x14, 0x22, 0x41, - 0x14, 0x14, 0x14, 0x14, 0x14, - 0x00, 0x41, 0x22, 0x14, 0x08, - 0x02, 0x01, 0x59, 0x09, 0x06, - 0x3E, 0x41, 0x5D, 0x59, 0x4E, - 0x7C, 0x12, 0x11, 0x12, 0x7C, - 0x7F, 0x49, 0x49, 0x49, 0x36, - 0x3E, 0x41, 0x41, 0x41, 0x22, - 0x7F, 0x41, 0x41, 0x41, 0x3E, - 0x7F, 0x49, 0x49, 0x49, 0x41, - 0x7F, 0x09, 0x09, 0x09, 0x01, - 0x3E, 0x41, 0x41, 0x51, 0x73, - 0x7F, 0x08, 0x08, 0x08, 0x7F, - 0x00, 0x41, 0x7F, 0x41, 0x00, - 0x20, 0x40, 0x41, 0x3F, 0x01, - 0x7F, 0x08, 0x14, 0x22, 0x41, - 0x7F, 0x40, 0x40, 0x40, 0x40, - 0x7F, 0x02, 0x1C, 0x02, 0x7F, - 0x7F, 0x04, 0x08, 0x10, 0x7F, - 0x3E, 0x41, 0x41, 0x41, 0x3E, - 0x7F, 0x09, 0x09, 0x09, 0x06, - 0x3E, 0x41, 0x51, 0x21, 0x5E, - 0x7F, 0x09, 0x19, 0x29, 0x46, - 0x26, 0x49, 0x49, 0x49, 0x32, - 0x03, 0x01, 0x7F, 0x01, 0x03, - 0x3F, 0x40, 0x40, 0x40, 0x3F, - 0x1F, 0x20, 0x40, 0x20, 0x1F, - 0x3F, 0x40, 0x38, 0x40, 0x3F, - 0x63, 0x14, 0x08, 0x14, 0x63, - 0x03, 0x04, 0x78, 0x04, 0x03, - 0x61, 0x59, 0x49, 0x4D, 0x43, - 0x00, 0x7F, 0x41, 0x41, 0x41, - 0x02, 0x04, 0x08, 0x10, 0x20, - 0x00, 0x41, 0x41, 0x41, 0x7F, - 0x04, 0x02, 0x01, 0x02, 0x04, - 0x40, 0x40, 0x40, 0x40, 0x40, - 0x00, 0x03, 0x07, 0x08, 0x00, - 0x20, 0x54, 0x54, 0x78, 0x40, - 0x7F, 0x28, 0x44, 0x44, 0x38, - 0x38, 0x44, 0x44, 0x44, 0x28, - 0x38, 0x44, 0x44, 0x28, 0x7F, - 0x38, 0x54, 0x54, 0x54, 0x18, - 0x00, 0x08, 0x7E, 0x09, 0x02, - 0x18, 0xA4, 0xA4, 0x9C, 0x78, - 0x7F, 0x08, 0x04, 0x04, 0x78, - 0x00, 0x44, 0x7D, 0x40, 0x00, - 0x20, 0x40, 0x40, 0x3D, 0x00, - 0x7F, 0x10, 0x28, 0x44, 0x00, - 0x00, 0x41, 0x7F, 0x40, 0x00, - 0x7C, 0x04, 0x78, 0x04, 0x78, - 0x7C, 0x08, 0x04, 0x04, 0x78, - 0x38, 0x44, 0x44, 0x44, 0x38, - 0xFC, 0x18, 0x24, 0x24, 0x18, - 0x18, 0x24, 0x24, 0x18, 0xFC, - 0x7C, 0x08, 0x04, 0x04, 0x08, - 0x48, 0x54, 0x54, 0x54, 0x24, - 0x04, 0x04, 0x3F, 0x44, 0x24, - 0x3C, 0x40, 0x40, 0x20, 0x7C, - 0x1C, 0x20, 0x40, 0x20, 0x1C, - 0x3C, 0x40, 0x30, 0x40, 0x3C, - 0x44, 0x28, 0x10, 0x28, 0x44, - 0x4C, 0x90, 0x90, 0x90, 0x7C, - 0x44, 0x64, 0x54, 0x4C, 0x44, - 0x00, 0x08, 0x36, 0x41, 0x00, - 0x00, 0x00, 0x77, 0x00, 0x00, - 0x00, 0x41, 0x36, 0x08, 0x00, - 0x02, 0x01, 0x02, 0x04, 0x02, - 0x3C, 0x26, 0x23, 0x26, 0x3C, - 0x1E, 0xA1, 0xA1, 0x61, 0x12, - 0x3A, 0x40, 0x40, 0x20, 0x7A, - 0x38, 0x54, 0x54, 0x55, 0x59, - 0x21, 0x55, 0x55, 0x79, 0x41, - 0x21, 0x54, 0x54, 0x78, 0x41, - 0x21, 0x55, 0x54, 0x78, 0x40, - 0x20, 0x54, 0x55, 0x79, 0x40, - 0x0C, 0x1E, 0x52, 0x72, 0x12, - 0x39, 0x55, 0x55, 0x55, 0x59, - 0x39, 0x54, 0x54, 0x54, 0x59, - 0x39, 0x55, 0x54, 0x54, 0x58, - 0x00, 0x00, 0x45, 0x7C, 0x41, - 0x00, 0x02, 0x45, 0x7D, 0x42, - 0x00, 0x01, 0x45, 0x7C, 0x40, - 0xF0, 0x29, 0x24, 0x29, 0xF0, - 0xF0, 0x28, 0x25, 0x28, 0xF0, - 0x7C, 0x54, 0x55, 0x45, 0x00, - 0x20, 0x54, 0x54, 0x7C, 0x54, - 0x7C, 0x0A, 0x09, 0x7F, 0x49, - 0x32, 0x49, 0x49, 0x49, 0x32, - 0x32, 0x48, 0x48, 0x48, 0x32, - 0x32, 0x4A, 0x48, 0x48, 0x30, - 0x3A, 0x41, 0x41, 0x21, 0x7A, - 0x3A, 0x42, 0x40, 0x20, 0x78, - 0x00, 0x9D, 0xA0, 0xA0, 0x7D, - 0x39, 0x44, 0x44, 0x44, 0x39, - 0x3D, 0x40, 0x40, 0x40, 0x3D, - 0x3C, 0x24, 0xFF, 0x24, 0x24, - 0x48, 0x7E, 0x49, 0x43, 0x66, - 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, - 0xFF, 0x09, 0x29, 0xF6, 0x20, - 0xC0, 0x88, 0x7E, 0x09, 0x03, - 0x20, 0x54, 0x54, 0x79, 0x41, - 0x00, 0x00, 0x44, 0x7D, 0x41, - 0x30, 0x48, 0x48, 0x4A, 0x32, - 0x38, 0x40, 0x40, 0x22, 0x7A, - 0x00, 0x7A, 0x0A, 0x0A, 0x72, - 0x7D, 0x0D, 0x19, 0x31, 0x7D, - 0x26, 0x29, 0x29, 0x2F, 0x28, - 0x26, 0x29, 0x29, 0x29, 0x26, - 0x30, 0x48, 0x4D, 0x40, 0x20, - 0x38, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x38, - 0x2F, 0x10, 0xC8, 0xAC, 0xBA, - 0x2F, 0x10, 0x28, 0x34, 0xFA, - 0x00, 0x00, 0x7B, 0x00, 0x00, - 0x08, 0x14, 0x2A, 0x14, 0x22, - 0x22, 0x14, 0x2A, 0x14, 0x08, - 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code - 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block - 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block - 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x10, 0x10, 0x10, 0xFF, 0x00, - 0x14, 0x14, 0x14, 0xFF, 0x00, - 0x10, 0x10, 0xFF, 0x00, 0xFF, - 0x10, 0x10, 0xF0, 0x10, 0xF0, - 0x14, 0x14, 0x14, 0xFC, 0x00, - 0x14, 0x14, 0xF7, 0x00, 0xFF, - 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x14, 0x14, 0xF4, 0x04, 0xFC, - 0x14, 0x14, 0x17, 0x10, 0x1F, - 0x10, 0x10, 0x1F, 0x10, 0x1F, - 0x14, 0x14, 0x14, 0x1F, 0x00, - 0x10, 0x10, 0x10, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x1F, 0x10, - 0x10, 0x10, 0x10, 0x1F, 0x10, - 0x10, 0x10, 0x10, 0xF0, 0x10, - 0x00, 0x00, 0x00, 0xFF, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0xFF, 0x10, - 0x00, 0x00, 0x00, 0xFF, 0x14, - 0x00, 0x00, 0xFF, 0x00, 0xFF, - 0x00, 0x00, 0x1F, 0x10, 0x17, - 0x00, 0x00, 0xFC, 0x04, 0xF4, - 0x14, 0x14, 0x17, 0x10, 0x17, - 0x14, 0x14, 0xF4, 0x04, 0xF4, - 0x00, 0x00, 0xFF, 0x00, 0xF7, - 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0xF7, 0x00, 0xF7, - 0x14, 0x14, 0x14, 0x17, 0x14, - 0x10, 0x10, 0x1F, 0x10, 0x1F, - 0x14, 0x14, 0x14, 0xF4, 0x14, - 0x10, 0x10, 0xF0, 0x10, 0xF0, - 0x00, 0x00, 0x1F, 0x10, 0x1F, - 0x00, 0x00, 0x00, 0x1F, 0x14, - 0x00, 0x00, 0x00, 0xFC, 0x14, - 0x00, 0x00, 0xF0, 0x10, 0xF0, - 0x10, 0x10, 0xFF, 0x10, 0xFF, - 0x14, 0x14, 0x14, 0xFF, 0x14, - 0x10, 0x10, 0x10, 0x1F, 0x00, - 0x00, 0x00, 0x00, 0xF0, 0x10, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, - 0x38, 0x44, 0x44, 0x38, 0x44, - 0x7C, 0x2A, 0x2A, 0x3E, 0x14, - 0x7E, 0x02, 0x02, 0x06, 0x06, - 0x02, 0x7E, 0x02, 0x7E, 0x02, - 0x63, 0x55, 0x49, 0x41, 0x63, - 0x38, 0x44, 0x44, 0x3C, 0x04, - 0x40, 0x7E, 0x20, 0x1E, 0x20, - 0x06, 0x02, 0x7E, 0x02, 0x02, - 0x99, 0xA5, 0xE7, 0xA5, 0x99, - 0x1C, 0x2A, 0x49, 0x2A, 0x1C, - 0x4C, 0x72, 0x01, 0x72, 0x4C, - 0x30, 0x4A, 0x4D, 0x4D, 0x30, - 0x30, 0x48, 0x78, 0x48, 0x30, - 0xBC, 0x62, 0x5A, 0x46, 0x3D, - 0x3E, 0x49, 0x49, 0x49, 0x00, - 0x7E, 0x01, 0x01, 0x01, 0x7E, - 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, - 0x44, 0x44, 0x5F, 0x44, 0x44, - 0x40, 0x51, 0x4A, 0x44, 0x40, - 0x40, 0x44, 0x4A, 0x51, 0x40, - 0x00, 0x00, 0xFF, 0x01, 0x03, - 0xE0, 0x80, 0xFF, 0x00, 0x00, - 0x08, 0x08, 0x6B, 0x6B, 0x08, - 0x36, 0x12, 0x36, 0x24, 0x36, - 0x06, 0x0F, 0x09, 0x0F, 0x06, - 0x00, 0x00, 0x18, 0x18, 0x00, - 0x00, 0x00, 0x10, 0x10, 0x00, - 0x30, 0x40, 0xFF, 0x01, 0x01, - 0x00, 0x1F, 0x01, 0x01, 0x1E, - 0x00, 0x19, 0x1D, 0x17, 0x12, - 0x00, 0x3C, 0x3C, 0x3C, 0x3C, - 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// Create a null default font in case some fonts not used (to prevent crash) -const uint8_t widtbl_null[1] = {0}; -PROGMEM const uint8_t chr_null[1] = {0}; -PROGMEM const uint8_t* const chrtbl_null[1] = {chr_null}; - -// This is a structure to conveniently hold information on the default fonts -// Stores pointer to font character image address table, width table and height -typedef struct { - const uint8_t *chartbl; - const uint8_t *widthtbl; - uint8_t height; - uint8_t baseline; -} fontinfo; - -// Now fill the structure -const PROGMEM fontinfo fontdata [] = { - { (const uint8_t *)font, widtbl_null, 0, 0 }, - { (const uint8_t *)chrtbl_null, widtbl_null, 8, 7 }, - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 }, - { (const uint8_t *)chrtbl_null, widtbl_null, 0, 0 } -}; - //These enumerate the text plotting alignment (reference datum point) #define TL_DATUM 0 // Top left (default) #define TC_DATUM 1 // Top centre @@ -553,71 +158,16 @@ static const uint16_t default_4bit_palette[] PROGMEM = { TFT_PINK // 15 }; -typedef struct -{ - String version = TFT_ESPI_VERSION; - String setup_info; // Setup reference name available to use in a user setup - uint32_t setup_id; // ID available to use in a user setup - int32_t esp; // Processor code - uint8_t trans; // SPI transaction support - uint8_t serial; // Serial (SPI) - #ifndef GENERIC_PROCESSOR - uint8_t port; // SPI port - #endif - uint8_t overlap; // ESP8266 overlap mode - uint8_t interface; // Interface type - - uint16_t tft_driver; // Hexadecimal code - uint16_t tft_width; // Rotation 0 width and height - uint16_t tft_height; - - uint8_t r0_x_offset; // Display offsets, not all used yet - uint8_t r0_y_offset; - uint8_t r1_x_offset; - uint8_t r1_y_offset; - uint8_t r2_x_offset; - uint8_t r2_y_offset; - uint8_t r3_x_offset; - uint8_t r3_y_offset; - - int8_t pin_tft_mosi; // SPI pins - int8_t pin_tft_miso; - int8_t pin_tft_clk; - int8_t pin_tft_cs; - - int8_t pin_tft_dc; // Control pins - int8_t pin_tft_rd; - int8_t pin_tft_wr; - int8_t pin_tft_rst; - - int8_t pin_tft_led; - int8_t pin_tft_led_on; - - int8_t pin_tch_cs; // Touch chip select pin - - int16_t tft_spi_freq;// TFT write SPI frequency - int16_t tft_rd_freq; // TFT read SPI frequency - int16_t tch_spi_freq;// Touch controller read/write SPI frequency -} setup_t; - -/*************************************************************************************** -** Section 8: Class member and support functions -***************************************************************************************/ - -// Callback prototype for smooth font pixel colour read typedef uint16_t (*getColorCallback)(uint16_t x, uint16_t y); -// Class functions and variables -class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has access to protected members +class TFT_eSPI { friend class TFT_eSprite; - //--------------------------------------- public ------------------------------------// public: void setSPISpeed(uint8_t speed_Mhz); TFT_eSPI(int16_t _W = TFT_WIDTH, int16_t _H = TFT_HEIGHT); void init(); virtual void drawPixel(int32_t x, int32_t y, uint32_t color), - drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size), drawLine(int32_t xs, int32_t ys, int32_t xe, int32_t ye, uint32_t color), drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color), drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color), @@ -625,110 +175,43 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac virtual int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font), drawChar(uint16_t uniCode, int32_t x, int32_t y), - height(void), - width(void); + height(), + width(); virtual uint16_t readPixel(int32_t x, int32_t y); - virtual void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); - virtual void pushColor(uint16_t color); - virtual void begin_nin_write(); - virtual void end_nin_write(); + virtual void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); + virtual void pushColor(uint16_t color); + virtual void begin_nin_write(); + virtual void end_nin_write(); - void setRotation(uint8_t r); - uint8_t getRotation(); - void setOrigin(int32_t x, int32_t y); - int32_t getOriginX(); - int32_t getOriginY(); - void invertDisplay(bool i); - void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); // Note: start coordinates + width and height - void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true); - bool checkViewport(int32_t x, int32_t y, int32_t w, int32_t h); - int32_t getViewportX(); - int32_t getViewportY(); - int32_t getViewportWidth(); - int32_t getViewportHeight(); - bool getViewportDatum(); - void frameViewport(uint16_t color, int32_t w); - void resetViewport(); - bool clipAddrWindow(int32_t* x, int32_t* y, int32_t* w, int32_t* h); - bool clipWindow(int32_t* xs, int32_t* ys, int32_t* xe, int32_t* ye); - void pushColor(uint16_t color, uint32_t len), // Deprecated, use pushBlock() - pushColors(uint16_t *data, uint32_t len, bool swap = true), // With byte swap option - pushColors(uint8_t *data, uint32_t len); // Deprecated, use pushPixels() - void pushBlock(uint16_t color, uint32_t len); - void pushPixels(const void * data_in, uint32_t len); - - // Support for half duplex (bi-directional SDA) SPI bus where MOSI must be switched to input - #ifdef TFT_SDA_READ - #if defined (TFT_eSPI_ENABLE_8_BIT_READ) - uint8_t tft_Read_8(void); // Read 8-bit value from TFT command register - #endif - void begin_SDA_Read(void); // Begin a read on a half duplex (bi-directional SDA) SPI bus - sets MOSI to input - void end_SDA_Read(void); // Restore MOSI to output - #endif - - - // Graphics drawing - void fillScreen(uint32_t color), + void setRotation(uint8_t r); + void invertDisplay(bool i); + void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); + void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true); + bool checkViewport(int32_t x, int32_t y, int32_t w, int32_t h); + void resetViewport(); + bool clipAddrWindow(int32_t* x, int32_t* y, int32_t* w, int32_t* h); + bool clipWindow(int32_t* xs, int32_t* ys, int32_t* xe, int32_t* ye); + void pushColor(uint16_t color, uint32_t len); + void pushColors(uint16_t *data, uint32_t len, bool swap = true); + void pushBlock(uint16_t color, uint32_t len); + void pushPixels(const void * data_in, uint32_t len); + void fillScreen(uint32_t color), drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color), drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color), fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color); - - void fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2); - void fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2); - - void drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color), - drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color), + void drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color), fillCircle(int32_t x, int32_t y, int32_t r, uint32_t color), fillCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, int32_t delta, uint32_t color), - drawEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color), fillEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color), - - // Corner 1 Corner 2 Corner 3 - drawTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color), fillTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color); - - - // Smooth (anti-aliased) graphics drawing - // Draw a pixel blended with the background pixel colour (bg_color) specified, return blended colour - // If the bg_color is not specified, the background pixel colour will be read from TFT or sprite uint16_t drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha, uint32_t bg_color = 0x00FFFFFF); - - // Draw an anti-aliased (smooth) arc between start and end angles. Arc ends are anti-aliased. - // By default the arc is drawn with square ends unless the "roundEnds" parameter is included and set true - // Angle = 0 is at 6 o'clock position, 90 at 9 o'clock etc. The angles must be in range 0-360 or they will be clipped to these limits - // The start angle may be larger than the end angle. Arcs are always drawn clockwise from the start angle. - void drawSmoothArc(int32_t x, int32_t y, int32_t r, int32_t ir, uint32_t startAngle, uint32_t endAngle, uint32_t fg_color, uint32_t bg_color, bool roundEnds = false); - - // As per "drawSmoothArc" except the ends of the arc are NOT anti-aliased, this facilitates dynamic arc length changes with - // arc segments and ensures clean segment joints. - // The sides of the arc are anti-aliased by default. If smoothArc is false sides will NOT be anti-aliased void drawArc(int32_t x, int32_t y, int32_t r, int32_t ir, uint32_t startAngle, uint32_t endAngle, uint32_t fg_color, uint32_t bg_color, bool smoothArc = true); - - // Draw an anti-aliased filled circle at x, y with radius r - // Note: The thickness of line is 3 pixels to reduce the visible "braiding" effect of anti-aliasing narrow lines - // this means the inner anti-alias zone is always at r-1 and the outer zone at r+1 void drawSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t fg_color, uint32_t bg_color); - - // Draw an anti-aliased filled circle at x, y with radius r - // If bg_color is not included the background pixel colour will be read from TFT or sprite void fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color = 0x00FFFFFF); - - // Draw a rounded rectangle that has a line thickness of r-ir+1 and bounding box defined by x,y and w,h - // The outer corner radius is r, inner corner radius is ir - // The inside and outside of the border are anti-aliased void drawSmoothRoundRect(int32_t x, int32_t y, int32_t r, int32_t ir, int32_t w, int32_t h, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF, uint8_t quadrants = 0xF); - - // Draw a filled rounded rectangle , corner radius r and bounding box defined by x,y and w,h void fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color, uint32_t bg_color = 0x00FFFFFF); - - // Draw a small anti-aliased filled circle at ax,ay with radius r (uses drawWideLine) - // If bg_color is not included the background pixel colour will be read from TFT or sprite void drawSpot(float ax, float ay, float r, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF); - - // Draw an anti-aliased wide line from ax,ay to bx,by width wd with radiused ends (radius is wd/2) - // If bg_color is not included the background pixel colour will be read from TFT or sprite - void drawWideLine(float ax, float ay, float bx, float by, float wd, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF); void drawWedgeLine(float ax, float ay, float bx, float by, float aw, float bw, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF); void setSwapBytes(bool swap); bool getSwapBytes(); @@ -736,38 +219,16 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac drawBitmap( int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor), drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor), drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor), - setBitmapColor(uint16_t fgcolor, uint16_t bgcolor); // Define the 2 colours for 1bpp sprites - + setBitmapColor(uint16_t fgcolor, uint16_t bgcolor); void setPivot(int16_t x, int16_t y); - int16_t getPivotX(), // Get pivot x - getPivotY(); // Get pivot y - - void readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); - // Write a block of pixels to the screen which have been read by readRect() void pushRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); - - // These are used to render images or sprites stored in RAM arrays (used by Sprite class for 16bpp Sprites) void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint16_t transparent); - - // These are used to render images stored in FLASH (PROGMEM) void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transparent); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data); - - // These are used by Sprite class pushSprite() member function for 1, 4 and 8 bits per pixel (bpp) colours - // They are not intended to be used with user sketches (but could be) - // Set bpp8 true for 8bpp sprites, false otherwise. The cmap pointer must be specified for 4bpp void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, bool bpp8 = true, uint16_t *cmap = nullptr); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, uint8_t transparent, bool bpp8 = true, uint16_t *cmap = nullptr); - // FLASH version void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t *data, bool bpp8, uint16_t *cmap = nullptr); - - // Render a 16-bit colour image with a 1bpp mask - void pushMaskedImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *img, uint8_t *mask); - - // This next function has been used successfully to dump the TFT screen to a PC for documentation purposes - // It reads a screen area and returns the 3 RGB 8-bit colour values of each pixel in the buffer - // Set w and h to 1 to read 1 pixel's colour. The data buffer must be at least w * h * 3 bytes void readRectRGB(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data); @@ -791,9 +252,6 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac void setCursor(int16_t x, int16_t y), // Set cursor for tft.print() setCursor(int16_t x, int16_t y, uint8_t font); // Set cursor and font number for tft.print() - int16_t getCursorX(void), // Read current cursor x position (moves with tft.print()) - getCursorY(void); // Read current cursor y position - void setTextColor(uint16_t color), // Set character (glyph) color only (background not over-written) setTextColor(uint16_t fgcolor, uint16_t bgcolor, bool bgfill = false), // Set character (glyph) foreground and background colour, optional background fill for smooth fonts setTextSize(uint8_t size); // Set character size multiplier (this increases pixel size) @@ -801,35 +259,27 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac void setTextWrap(bool wrapX, bool wrapY = false); // Turn on/off wrapping of text in TFT width and/or height void setTextDatum(uint8_t datum); // Set text datum position (default is top left), see Section 5 above - uint8_t getTextDatum(void); - void setTextPadding(uint16_t x_width); // Set text padding (background blanking/over-write) width in pixels - uint16_t getTextPadding(void); // Get text padding + void setTextPadding(uint16_t x_width); // Set text padding (background blanking) width in pixels - void setFreeFont(uint8_t font), // Not used, historical fix to prevent an error - setTextFont(uint8_t font); // Set the font number to use in future + void setTextFont(uint8_t font); // Set the font number to use in future int16_t textWidth(const char *string, uint8_t font), // Returns pixel width of string in specified font textWidth(const char *string), // Returns pixel width of string in current font textWidth(const String& string, uint8_t font), // As above for String types textWidth(const String& string), fontHeight(uint8_t font), // Returns pixel height of specified font - fontHeight(void); // Returns pixel height of current font + fontHeight(); // Returns pixel height of current font // Used by library and Smooth font class to extract Unicode point codes from a UTF8 encoded string uint16_t decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining), decodeUTF8(uint8_t c); - // Support function to UTF8 decode and draw characters piped through print stream - size_t write(uint8_t); - // size_t write(const uint8_t *buf, size_t len); - // Used by Smooth font class to fetch a pixel colour for the anti-aliasing void setCallback(getColorCallback getCol); uint16_t fontsLoaded(void); // Each bit in returned value represents a font type that is loaded - used for debug/error handling only - // Low level read/write void spiwrite(uint8_t); // legacy support only void writecommand(uint8_t c); // Send an 8-bit command, function resets DC/RS high ready for data void writedata(uint8_t d); // Send data with DC/RS set high @@ -845,15 +295,6 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac // Convert 8-bit red, green and blue to 16 bits uint16_t color565(uint8_t red, uint8_t green, uint8_t blue); - // Convert 8-bit colour to 16 bits - uint16_t color8to16(uint8_t color332); - // Convert 16-bit colour to 8 bits - uint8_t color16to8(uint16_t color565); - - // Convert 16-bit colour to/from 24-bit, R+G+B concatenated into LS 24 bits - uint32_t color16to24(uint16_t color565); - uint32_t color24to16(uint32_t color888); - // Alpha blend 2 colours, see generic "alphaBlend_Test" example // alpha = 0 = 100% background colour // alpha = 255 = 100% foreground colour @@ -864,61 +305,13 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac // 24-bit colour alphaBlend with optional alpha dither uint32_t alphaBlend24(uint8_t alpha, uint32_t fgc, uint32_t bgc, uint8_t dither = 0); - // Direct Memory Access (DMA) support functions - // These can be used for SPI writes when using the ESP32 (original) or STM32 processors. - // DMA also works on a RP2040 processor with PIO based SPI interfaces - // Bear in mind DMA will only be of benefit in particular circumstances and can be tricky - // to manage by noobs. The functions have however been designed to be noob friendly and - // avoid a few DMA behaviour "gotchas". - // - // At best you will get a 2x TFT rendering performance improvement when using DMA because - // this library handles the SPI bus so efficiently during normal (non DMA) transfers. The best - // performance improvement scenario is the DMA transfer time is exactly the same as the time it - // takes for the processor to prepare the next image buffer and initiate another DMA transfer. - // - // DMA transfer to the TFT is done while the processor moves on to handle other tasks. Bear - // this in mind and watch out for "gotchas" like the image buffer going out of scope as the - // processor leaves a function or its content being changed while the DMA engine is reading it. - // - // The compiler MAY change the implied scope of a buffer which has been set aside by creating - // an array. For example a buffer defined before a "for-next" loop may get de-allocated when - // the loop ends. To avoid this use, for example, malloc() and free() to take control of when - // the buffer space is available and ensure it is not released until DMA is complete. - // - // Clearly you should not modify a buffer that is being DMA'ed to the TFT until the DMA is over. - // Use the dmaBusy() function to check this. Use tft.startWrite() before invoking DMA so the - // TFT chip select stays low. If you use tft.endWrite() before DMA is complete then the endWrite - // function will wait for the DMA to complete, so this may defeat any DMA performance benefit. - // - bool initDMA(bool ctrl_cs = false); // Initialise the DMA engine and attach to SPI bus - typically used in setup() - // Parameter "true" enables DMA engine control of TFT chip select (ESP32 only) - // For ESP32 only, TFT reads will not work if parameter is true - void deInitDMA(void); // De-initialise the DMA engine and detach from SPI bus - typically not used - - // Push an image to the TFT using DMA, buffer is optional and grabs (double buffers) a copy of the image - // Use the buffer if the image data will get over-written or destroyed while DMA is in progress - // - // Note 1: If swapping colour bytes is defined, and the double buffer option is NOT used, then the bytes - // in the original image buffer content will be byte swapped by the function before DMA is initiated. - // - // Note 2: If part of the image will be off screen or outside of a set viewport, then the the original - // image buffer content will be altered to a correctly clipped image before DMA is initiated. - // - // The function will wait for the last DMA to complete if it is called while a previous DMA is still - // in progress, this simplifies the sketch and helps avoid "gotchas". - void pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* data, uint16_t* buffer = nullptr); - -#if defined (ESP32) // ESP32 only at the moment - // For case where pointer is a const and the image data must not be modified (clipped or byte swapped) - void pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t const* data); -#endif // Push a block of pixels into a window set up using setAddrWindow() void pushPixelsDMA(uint16_t* image, uint32_t len); // Check if the DMA is complete - use while(tft.dmaBusy); for a blocking wait - bool dmaBusy(void); // returns true if DMA is still in progress - void dmaWait(void); // wait until DMA is complete + bool dmaBusy(); // returns true if DMA is still in progress + void dmaWait(); // wait until DMA is complete bool DMA_Enabled = false; // Flag for DMA enabled state uint8_t spiBusyCheck = 0; // Number of ESP32 transfer buffers to check @@ -928,20 +321,6 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac void writeColor(uint16_t color, uint32_t len); // Deprecated, use pushBlock() void endWrite(void); // End SPI transaction - // Set/get an arbitrary library configuration attribute or option - // Use to switch ON/OFF capabilities such as UTF8 decoding - each attribute has a unique ID - // id = 0: reserved - may be used in future to reset all attributes to a default state - // id = 1: Turn on (a=true) or off (a=false) GLCD cp437 font character error correction - // id = 2: Turn on (a=true) or off (a=false) UTF8 decoding - #define CP437_SWITCH 1 - #define UTF8_SWITCH 2 - void setAttribute(uint8_t id = 0, uint8_t a = 0); // Set attribute value - uint8_t getAttribute(uint8_t id = 0); // Get attribute value - - // Used for diagnostic sketch to see library setup adopted by compiler, see Section 7 above - void getSetup(setup_t& tft_settings); // Sketch provides the instance to populate - bool verifySetupID(uint32_t id); - // Global variables static SPIClass& getSPIinstance(void); // Get SPI class handle uint32_t textcolor, textbgcolor; // Text foreground and background colours @@ -956,15 +335,11 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac uint8_t decoderState = 0; // UTF8 decoder state - not for user access uint16_t decoderBuffer; // Unicode code-point buffer - not for user access - void loadFont(const uint8_t array[]); - void loadFont(String fontName, fs::FS &ffs); - void loadFont(String fontName, bool flash = true); - void unloadFont( void ); - bool getUnicodeIndex(uint16_t unicode, uint16_t *index); + void loadFont(const uint8_t array[], uint8_t font); + void unloadFont(uint8_t font); + bool getUnicodeIndex(uint16_t unicode, uint16_t *index, uint16_t font); - virtual void drawGlyph(uint16_t code); - - void showFont(uint32_t td); + virtual void drawGlyph(uint16_t code, uint16_t font); typedef struct { @@ -978,91 +353,71 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac uint16_t maxDescent; // Maximum descent found in font } fontMetrics; - fontMetrics gFont = { nullptr, 0, 0, 0, 0, 0, 0, 0 }; + fontMetrics gFonts[8] = { + { nullptr, 0, 0, 0, 0, 0, 0, 0 }, + { nullptr, 0, 0, 0, 0, 0, 0, 0 }, + { nullptr, 0, 0, 0, 0, 0, 0, 0 }, + { nullptr, 0, 0, 0, 0, 0, 0, 0 }, + { nullptr, 0, 0, 0, 0, 0, 0, 0 }, + { nullptr, 0, 0, 0, 0, 0, 0, 0 }, + { nullptr, 0, 0, 0, 0, 0, 0, 0 }, + { nullptr, 0, 0, 0, 0, 0, 0, 0 } + }; // These are for the metrics for each individual glyph (so we don't need to seek this in file and waste time) - uint16_t* gUnicode = NULL; //UTF-16 code, the codes are searched so do not need to be sequential - uint8_t* gHeight = NULL; //cheight - uint8_t* gWidth = NULL; //cwidth - uint8_t* gxAdvance = NULL; //setWidth - int16_t* gdY = NULL; //topExtent - int8_t* gdX = NULL; //leftExtent - uint32_t* gBitmap = NULL; //file pointer to greyscale bitmap + uint16_t* gUnicode[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //UTF-16 code, the codes are searched so do not need to be sequential + uint8_t* gHeight[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //cheight + uint8_t* gWidth[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //cwidth + uint8_t* gxAdvance[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //setWidth + int16_t* gdY[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //topExtent + int8_t* gdX[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //leftExtent + uint32_t* gBitmap[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //file pointer to greyscale bitmap - bool fontLoaded = false; // Flags when a anti-aliased font is loaded + uint8_t getTouchRaw(uint16_t *x, uint16_t *y); + uint16_t getTouchRawZ(void); + void convertRawXY(uint16_t *x, uint16_t *y); + uint8_t getTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600); - fs::File fontFile; - fs::FS &fontFS = SPIFFS; - bool spiffs = true; - bool fs_font = false; + void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size); + void setTouch(uint16_t *data); //--------------------------------------- private ------------------------------------// private: - // Legacy begin and end prototypes - deprecated TODO: delete - void spi_begin(); - void spi_end(); - - void spi_begin_read(); - void spi_end_read(); - - // New begin and end prototypes - // begin/end a TFT write transaction - // For SPI bus the transmit clock rate is set inline void begin_tft_write() __attribute__((always_inline)); inline void end_tft_write() __attribute__((always_inline)); - // begin/end a TFT read transaction - // For SPI bus: begin lowers SPI clock rate, end reinstates transmit clock rate inline void begin_tft_read() __attribute__((always_inline)); inline void end_tft_read() __attribute__((always_inline)); - // Initialise the data bus GPIO and hardware interfaces - void initBus(void); + void initBus(); - // Temporary library development function TODO: remove need for this - void pushSwapBytePixels(const void* data_in, uint32_t len); + void pushSwapBytePixels(const void* data_in, uint32_t len); - // Same as setAddrWindow but exits with CGRAM in read mode - void readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); + void readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); - // Byte read prototype - uint8_t readByte(void); + uint8_t readByte(); - // GPIO parallel bus input/output direction control - void busDir(uint32_t mask, uint8_t mode); + void busDir(uint32_t mask, uint8_t mode); - // Single GPIO input/output direction control - void gpioMode(uint8_t gpio, uint8_t mode); + void gpioMode(uint8_t gpio, uint8_t mode); - // Smooth graphics helper - uint8_t sqrt_fraction(uint32_t num); + uint8_t sqrt_fraction(uint32_t num); - // Helper function: calculate distance of a point from a finite length line between two points - float wedgeLineDistance(float pax, float pay, float bax, float bay, float dr); - - // Display variant settings - uint8_t tabcolor, // ST7735 screen protector "tab" colour (now invalid) - colstart = 0, rowstart = 0; // Screen display area to CGRAM area coordinate offsets - - // Port and pin masks for control signals (ESP826 only) - TODO: remove need for this - volatile uint32_t *dcport, *csport; - uint32_t cspinmask, dcpinmask, wrpinmask, sclkpinmask; - - //uint32_t lastColor = 0xFFFF; // Last colour - used to minimise bit shifting overhead + float wedgeLineDistance(float pax, float pay, float bax, float bay, float dr); getColorCallback getColor = nullptr; // Smooth font callback function pointer - bool locked, inTransaction, lockTransaction; // SPI transaction and mutex lock flags + bool locked, inTransaction, lockTransaction; // SPI transaction and mutex lock flags - void loadMetrics(void); - uint32_t readInt32(void); + void loadMetrics(uint8_t font); // Function of Fear, which is Unhandled Exception, writing to 0x000000000 + uint32_t readInt32(); uint8_t* fontPtr = nullptr; //-------------------------------------- protected ----------------------------------// protected: -uint8_t spi_write_speed; // SPI write speed +uint8_t spi_write_speed; //int32_t win_xe, win_ye; // Window end coords - not needed int32_t _init_width, _init_height; // Display w/h as input, used by setRotation() @@ -1081,219 +436,83 @@ uint8_t spi_write_speed; // SPI write speed bool _vpDatum; bool _vpOoB; - int32_t cursor_x, cursor_y, padX; // Text cursor x,y and padding setting - int32_t bg_cursor_x; // Background fill cursor - int32_t last_cursor_x; // Previous text cursor position when fill used + int32_t cursor_x, cursor_y, padX; + int32_t bg_cursor_x; + int32_t last_cursor_x; - uint32_t fontsloaded; // Bit field of fonts loaded + uint32_t fontsloaded; - uint8_t glyph_ab, // Smooth font glyph delta Y (height) above baseline - glyph_bb; // Smooth font glyph delta Y (height) below baseline + bool isDigits; + bool textwrapX, textwrapY; + bool _swapBytes; - bool isDigits; // adjust bounding box for numbers to reduce visual jiggling - bool textwrapX, textwrapY; // If set, 'wrap' text at right and optionally bottom edge of display - bool _swapBytes; // Swap the byte order for TFT pushImage() + bool _booted; - bool _booted; // init() or begin() has already run once + bool _cp437; + bool _utf8; - // User sketch manages these via set/getAttribute() - bool _cp437; // If set, use correct CP437 charset (default is OFF) - bool _utf8; // If set, use UTF-8 decoder in print stream 'write()' function (default ON) + uint32_t _lastColor; - uint32_t _lastColor; // Buffered value of last colour used - - bool _fillbg; // Fill background flag (just for for smooth fonts at the moment) - - public: - // Get raw x,y ADC values from touch controller - uint8_t getTouchRaw(uint16_t *x, uint16_t *y); - // Get raw z (i.e. pressure) ADC value from touch controller - uint16_t getTouchRawZ(void); - // Convert raw x,y values to calibrated and correctly rotated screen coordinates - void convertRawXY(uint16_t *x, uint16_t *y); - // Get the screen touch coordinates, returns true if screen has been touched - // if the touch coordinates are off screen then x and y are not updated - // The returned value can be treated as a bool type, false or 0 means touch not detected - // In future the function may return an 8-bit "quality" (jitter) value. - // The threshold value is optional, this must be higher than the bias level for z (pressure) - // reported by Test_Touch_Controller when the screen is NOT touched. When touched the z value - // must be higher than the threshold for a touch to be detected. - uint8_t getTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600); - - // Run screen calibration and test, report calibration values to the serial port - void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size); - // Set the screen calibration values - void setTouch(uint16_t *data); + bool _fillbg; private: - // Legacy support only - deprecated TODO: delete - void spi_begin_touch(); - void spi_end_touch(); - - // Handlers for the touch controller bus settings inline void begin_touch_read_write() __attribute__((always_inline)); inline void end_touch_read_write() __attribute__((always_inline)); - // Private function to validate a touch, allow settle time and reduce spurious coordinates uint8_t validTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600); - // Initialise with example calibration values so processor does not crash if setTouch() not called in setup() uint16_t touchCalibration_x0 = 300, touchCalibration_x1 = 3600, touchCalibration_y0 = 300, touchCalibration_y1 = 3600; uint8_t touchCalibration_rotate = 1, touchCalibration_invert_x = 2, touchCalibration_invert_y = 0; - uint32_t _pressTime; // Press and hold time-out - uint16_t _pressX, _pressY; // For future use (last sampled calibrated coordinates) + uint32_t _pressTime; }; class TFT_eSprite : public TFT_eSPI { public: explicit TFT_eSprite(TFT_eSPI *tft); ~TFT_eSprite(void); - - // Create a sprite of width x height pixels, return a pointer to the RAM area - // Sketch can cast returned value to (uint16_t*) for 16-bit depth if needed - // RAM required is: - // - 1 bit per pixel for 1 bit colour depth - // - 1 nibble per pixel for 4-bit colour (with palette table) - // - 1 byte per pixel for 8-bit colour (332 RGB format) - // - 2 bytes per pixel for 16-bit color depth (565 RGB format) - void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); - - // Returns a pointer to the sprite or nullptr if not created, user must cast to pointer type - void* getPointer(void); - - // Returns true if sprite has been created - bool created(void); - - // Delete the sprite to free up the RAM - void deleteSprite(void); - - // Select the frame buffer for graphics write (for 2 colour ePaper and DMA toggle buffer) - // Returns a pointer to the Sprite frame buffer - void* frameBuffer(int8_t f); - - // Set or get the colour depth to 1, 4, 8 or 16 bits. Can be used to change depth an existing - // sprite, but clears it to black, returns a new pointer if sprite is re-created. - void* setColorDepth(int8_t b); - int8_t getColorDepth(void); - - // Set the palette for a 4-bit depth sprite. Only the first 16 colours in the map are used. - void createPalette(uint16_t *palette = nullptr, uint8_t colors = 16); // Palette in RAM - void createPalette(const uint16_t *palette = nullptr, uint8_t colors = 16); // Palette in FLASH - - // Set a single palette index to the given color - void setPaletteColor(uint8_t index, uint16_t color); - - // Get the color at the given palette index + void* createSprite(int16_t width, int16_t height, uint8_t frames = 1); + void* getPointer(); + bool created(); + void deleteSprite(void); + void* setColorDepth(int8_t b); + int8_t getColorDepth(void); + void createPalette(uint16_t *palette = nullptr, uint8_t colors = 16); + void createPalette(const uint16_t *palette = nullptr, uint8_t colors = 16); + void setPaletteColor(uint8_t index, uint16_t color); uint16_t getPaletteColor(uint8_t index); - - // Set foreground and background colours for 1 bit per pixel Sprite - void setBitmapColor(uint16_t fg, uint16_t bg); - - // Draw a single pixel at x,y - void drawPixel(int32_t x, int32_t y, uint32_t color); - - // Draw a single character in the GLCD or GFXFF font - void drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size), - - // Fill Sprite with a colour - fillSprite(uint32_t color), - - // Define a window to push 16-bit colour pixels into in a raster order - // Colours are converted to the set Sprite colour bit depth + void setBitmapColor(uint16_t fg, uint16_t bg); + void drawPixel(int32_t x, int32_t y, uint32_t color); + void fillSprite(uint32_t color), setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1), - // Push a color (aka singe pixel) to the sprite's set window area pushColor(uint16_t color), - // Push len colors (pixels) to the sprite's set window area pushColor(uint16_t color, uint32_t len), - // Push a pixel pre-formatted as a 1, 4, 8 or 16-bit colour (avoids conversion overhead) writeColor(uint16_t color), - - // Set the scroll zone, top left corner at x,y with defined width and height - // The colour (optional, black is default) is used to fill the gap after the scroll - setScrollRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t color = TFT_BLACK), - // Scroll the defined zone dx,dy pixels. Negative values left,up, positive right,down - // dy is optional (default is 0, so no up/down scroll). - // The sprite coordinate frame does not move because pixels are moved - scroll(int16_t dx, int16_t dy = 0), - - // Draw lines drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color), drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color), drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color), - - // Fill a rectangular area with a color (aka draw a filled rectangle) fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color); - - // Set the coordinate rotation of the Sprite (for 1bpp Sprites only) - // Note: this uses coordinate rotation and is primarily for ePaper which does not support - // CGRAM rotation (like TFT drivers do) within the displays internal hardware - void setRotation(uint8_t rotation); - uint8_t getRotation(void); - - // Push a rotated copy of Sprite to TFT with optional transparent colour - bool pushRotated(int16_t angle, uint32_t transp = 0x00FFFFFF); - // Push a rotated copy of Sprite to another different Sprite with optional transparent colour - bool pushRotated(TFT_eSprite *spr, int16_t angle, uint32_t transp = 0x00FFFFFF); - - // Get the TFT bounding box for a rotated copy of this Sprite - bool getRotatedBounds(int16_t angle, int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y); - // Get the destination Sprite bounding box for a rotated copy of this Sprite - bool getRotatedBounds(TFT_eSprite *spr, int16_t angle, int16_t *min_x, int16_t *min_y, - int16_t *max_x, int16_t *max_y); - // Bounding box support function - void getRotatedBounds(int16_t angle, int16_t w, int16_t h, int16_t xp, int16_t yp, - int16_t *min_x, int16_t *min_y, int16_t *max_x, int16_t *max_y); - - // Read the colour of a pixel at x,y and return value in 565 format uint16_t readPixel(int32_t x0, int32_t y0); - - // return the numerical value of the pixel at x,y (used when scrolling) - // 16bpp = colour, 8bpp = byte, 4bpp = colour index, 1bpp = 1 or 0 uint16_t readPixelValue(int32_t x, int32_t y); - - // Write an image (colour bitmap) to the sprite. void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data, uint8_t sbpp = 0); void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data); - - // Push the sprite to the TFT screen, this fn calls pushImage() in the TFT class. - // Optionally a "transparent" colour can be defined, pixels of that colour will not be rendered void pushSprite(int32_t x, int32_t y); void pushSprite(int32_t x, int32_t y, uint16_t transparent); - - // Push a windowed area of the sprite to the TFT at tx, ty bool pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh); - - // Push the sprite to another sprite at x,y. This fn calls pushImage() in the destination sprite (dspr) class. bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y); bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y, uint16_t transparent); - - // Draw a single character in the selected font int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font), drawChar(uint16_t uniCode, int32_t x, int32_t y); - - // Return the width and height of the sprite int16_t width(void), height(void); - - // Functions associated with anti-aliased fonts - // Draw a single Unicode character using the loaded font - void drawGlyph(uint16_t code); - // Print string to sprite using loaded font at cursor position - void printToSprite(String string); - // Print char array to sprite using loaded font at cursor position - void printToSprite(char *cbuffer, uint16_t len); - // Print indexed glyph to sprite using loaded font at x,y - int16_t printToSprite(int16_t x, int16_t y, uint16_t index); + void drawGlyph(uint16_t code, uint16_t font); private: TFT_eSPI *_tft; - // Reserve memory for the Sprite and return a pointer void* callocSprite(int16_t width, int16_t height, uint8_t frames = 1); - // Override the non-inlined TFT_eSPI functions void begin_nin_write(void) { ; } void end_nin_write(void) { ; } @@ -1311,13 +530,12 @@ class TFT_eSprite : public TFT_eSPI { int32_t _sinra; // Sine of rotation angle in fixed point int32_t _cosra; // Cosine of rotation angle in fixed point - bool _created; // A Sprite has been created and memory reserved - bool _gFont = false; + bool _created; - int32_t _xs, _ys, _xe, _ye, _xptr, _yptr; // for setWindow - int32_t _sx, _sy; // x,y for scroll zone - uint32_t _sw, _sh; // w,h for scroll zone - uint32_t _scolor; // gap fill colour for scroll zone + int32_t _xs, _ys, _xe, _ye, _xptr, _yptr; + int32_t _sx, _sy; + uint32_t _sw, _sh; + uint32_t _scolor; int32_t _iwidth, _iheight; // Sprite memory image bit width and height (swapped during rotations) int32_t _dwidth, _dheight; // Real sprite width and height (for <8bpp Sprites) diff --git a/lib/TFT_eSPI/User_Setup_Select.h b/lib/TFT_eSPI/User_Setup_Select.h index 0cd4913..5a1fbeb 100644 --- a/lib/TFT_eSPI/User_Setup_Select.h +++ b/lib/TFT_eSPI/User_Setup_Select.h @@ -39,7 +39,7 @@ #define PIN_D9 3 // RXD0 #define PIN_D10 1 // TXD0 -#define PIN_MOSI 8 // SD1 FLASH and overlap mode +#define PIN_MOSI 8 // SD1 #define PIN_MISO 7 // SD0 #define PIN_SCLK 6 // CLK #define PIN_HWCS 0 // D3 diff --git a/src/TEF6686.cpp b/src/TEF6686.cpp index d721790..0192cdf 100644 --- a/src/TEF6686.cpp +++ b/src/TEF6686.cpp @@ -1209,7 +1209,6 @@ void TEF6686::readRDS(byte showrdserrors) { } } } break; - case RDS_GROUP_4A: { if (!rdsBerrorThreshold && !rdsCerrorThreshold && !rdsDerrorThreshold && rds.ctupdate && (rds.PICTlock == pi || rds.PICTlock == 0)) { auto rtc_time = rtc.getEpoch(); @@ -1254,10 +1253,12 @@ void TEF6686::readRDS(byte showrdserrors) { rtcset = true; time_t rds_utc_time = rdstime + timeoffset; - rds.clock_correction = rtc_time - rds_utc_time; + int32_t current_correction = rtc_time - rds_utc_time; + rds.clock_correction = current_correction; if (!NTPupdated) { - rtc.setTime(rds_utc_time); + time_t corrected_time = rds_utc_time - (current_correction / 2); + rtc.setTime(corrected_time); sync_to_rx_rtc(); } } else rds.hasCT = false; diff --git a/src/globals.cpp b/src/globals.cpp index bed6aba..5d0be74 100644 --- a/src/globals.cpp +++ b/src/globals.cpp @@ -332,16 +332,14 @@ mem presets[EE_PRESETS_CNT]; TEF6686 radio; // FrequencySprite.createSprite(200, 50); -// RDSSprite.createSprite(165, 19); // PSSprite.createSprite(150, 32); -// PTYSprite.createSprite(160, 19); +// GeneralTextSprite.createSprite(308, 28); // SquelchSprite.createSprite(27, 19); // FullLineSprite.createSprite(308, 19); // OneBigLineSprite.createSprite(270, 30); TFT_eSprite FrequencySprite = TFT_eSprite(&tft); -TFT_eSprite RDSSprite = TFT_eSprite(&tft); -TFT_eSprite PTYSprite = TFT_eSprite(&tft); +TFT_eSprite GeneralTextSprite = TFT_eSprite(&tft); TFT_eSprite SignalSprite = TFT_eSprite(&tft); TFT_eSprite SquelchSprite = TFT_eSprite(&tft); TFT_eSprite FullLineSprite = TFT_eSprite(&tft); @@ -354,7 +352,7 @@ WiFiClient RemoteClient; WiFiUDP Udp; WebServer webserver(80); -ScrollingTextDisplay rtplusDisplay(&RDSSprite, 147, 180); -ScrollingTextDisplay eonDisplay(&RDSSprite, 174, 180); +ScrollingTextDisplay rtplusDisplay(&GeneralTextSprite, 147, 180, 165, 19); +ScrollingTextDisplay eonDisplay(&GeneralTextSprite, 174, 180, 165, 19); ScrollingTextDisplay eccDisplay(&FullLineSprite, 198, 270); ScrollingTextDisplay rtDisplay(&FullLineSprite, 220, 270); \ No newline at end of file diff --git a/src/gui.cpp b/src/gui.cpp index 0c9120a..2274a8a 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -5538,6 +5538,7 @@ void DoMenu() { void Infoboxprint(const char* input) { int length = strlen(input); int newlineIndex = -1; + uint8_t font = (language == LANGUAGE_CHS) ? 6 : 7; // six seven for (int i = 0; i < length; i++) { if (input[i] == '\n') { @@ -5560,8 +5561,8 @@ void Infoboxprint(const char* input) { tftPrint(ACENTER, line1, 155, 40, ActiveColor, ActiveColorSmooth, 28); tftPrint(ACENTER, line2, 155, 70, ActiveColor, ActiveColorSmooth, 28); } else { - FrequencySprite.drawString(line1, 100, 5); - FrequencySprite.drawString(line2, 100, 25); + FrequencySprite.drawString(line1, 100, 5, font); + FrequencySprite.drawString(line2, 100, 25, font); } free(line1); free(line2); @@ -5570,9 +5571,7 @@ void Infoboxprint(const char* input) { tftPrint(ACENTER, input, 155, 78, ActiveColor, ActiveColorSmooth, 28); } else if (setupmode) { tftPrint(ACENTER, input, 155, 70, ActiveColor, ActiveColorSmooth, 28); - } else { - FrequencySprite.drawString(input, 100, 15); - } + } else FrequencySprite.drawString(input, 100, 15, font); } } diff --git a/src/main.cpp b/src/main.cpp index 2e20e3b..396b0c8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -207,7 +207,7 @@ void updateSWMIBand() { case SW_MI_BAND_90M: case SW_MI_BAND_120M: case SW_MI_BAND_160M: - FrequencySprite.drawString(SWMIBandstring + " ", 0, 0); + FrequencySprite.drawString(SWMIBandstring + " ", 0, 0, 6); beepresetstart = true; if (beepresetstop) { EdgeBeeper(); @@ -816,22 +816,12 @@ void TuneFreq(int temp) { } void ShowNum(int val) { - switch (freqfont) { - case 1: FrequencySprite.loadFont(FREQFONT1); break; - case 2: FrequencySprite.loadFont(FREQFONT2); break; - case 3: FrequencySprite.loadFont(FREQFONT3); break; - case 4: FrequencySprite.loadFont(FREQFONT4); break; - default: FrequencySprite.loadFont(FREQFONT0); break; - } - FrequencySprite.setTextDatum(TR_DATUM); FrequencySprite.fillSprite(BackgroundColor); FrequencySprite.setTextColor(SecondaryColor, SecondaryColorSmooth, false); - FrequencySprite.drawString(String(val) + " ", 218, -6); + FrequencySprite.drawString(String(val) + " ", 218, -6, freqfont); FrequencySprite.pushSprite(46, 46); - - FrequencySprite.unloadFont(); } byte numval[16] = {2, 3, 127, 5, 6, 0, 9, 13, 8, 7, 4, 1, 0, 0, 0, 0}; @@ -981,8 +971,7 @@ void NumpadProcess(int num) { if (spispeed == 7) tft.setSPISpeed(40); submenu = true; menu = true; - PSSprite.unloadFont(); - if (language == LANGUAGE_CHS) PSSprite.loadFont(FONT16_CHS); else PSSprite.loadFont(FONT16); + if (language == LANGUAGE_CHS) PSSprite.setTextFont(1); else PSSprite.setTextFont(0); BuildMenu(); } else if (num == 13) { if (freq_in != 0) { @@ -1068,8 +1057,7 @@ void endMenu() { if (USBmode) Serial.begin(19200); else Serial.begin(115200); leave = true; - PSSprite.unloadFont(); - if (language == LANGUAGE_CHS) PSSprite.loadFont(FONT28_CHS); else PSSprite.loadFont(FONT28); + if (language == LANGUAGE_CHS) PSSprite.setTextFont(3); else PSSprite.setTextFont(2); PSSprite.setTextDatum(TL_DATUM); BuildDisplay(); SelectBand(); @@ -1248,6 +1236,12 @@ void setup() { tft.init(); tft.initDMA(); + tft.loadFont(FONT16, 0); + tft.loadFont(FONT16_CHS, 1); + tft.loadFont(FONT28, 2); + tft.loadFont(FONT28_CHS, 3); + tft.loadFont(FONT48, 4); + doTheme(); if (displayflip == 0) { @@ -1289,26 +1283,47 @@ void setup() { FrequencySprite.createSprite(200, 50); FrequencySprite.setTextDatum(TR_DATUM); FrequencySprite.setSwapBytes(true); + FrequencySprite.loadFont(FREQFONT0, 0); + FrequencySprite.loadFont(FREQFONT1, 1); + FrequencySprite.loadFont(FREQFONT2, 2); + FrequencySprite.loadFont(FREQFONT3, 3); + FrequencySprite.loadFont(FREQFONT4, 4); + FrequencySprite.loadFont(FREQFONT5, 5); + FrequencySprite.loadFont(FONT16, 6); + FrequencySprite.loadFont(FONT16_CHS, 7); - RDSSprite.createSprite(165, 19); - RDSSprite.setSwapBytes(true); - - PTYSprite.createSprite(160, 19); - PTYSprite.setSwapBytes(true); + GeneralTextSprite.createSprite(308, 28); + GeneralTextSprite.setSwapBytes(true); + GeneralTextSprite.loadFont(FONT16, 0); + GeneralTextSprite.loadFont(FONT16_CHS, 1); + GeneralTextSprite.loadFont(FONT28, 2); + GeneralTextSprite.loadFont(FONT28_CHS, 3); + GeneralTextSprite.loadFont(FONT48, 4); PSSprite.createSprite(150, 32); PSSprite.setSwapBytes(true); + PSSprite.loadFont(FONT16, 0); + PSSprite.loadFont(FONT16_CHS, 1); + PSSprite.loadFont(FONT28, 2); + PSSprite.loadFont(FONT28_CHS, 3); SquelchSprite.createSprite(27, 19); SquelchSprite.setSwapBytes(true); + SquelchSprite.loadFont(FONT16, 0); + SquelchSprite.loadFont(FONT16_CHS, 1); FullLineSprite.createSprite(308, 19); FullLineSprite.setSwapBytes(true); + FullLineSprite.loadFont(FONT16, 0); + FullLineSprite.loadFont(FONT16_CHS, 0); OneBigLineSprite.createSprite(270, 30); OneBigLineSprite.setSwapBytes(true); + OneBigLineSprite.loadFont(FONT28, 0); + OneBigLineSprite.loadFont(FONT28_CHS, 0); SignalSprite.createSprite(80, 48); + SignalSprite.loadFont(FONT28, 0); SignalSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); SignalSprite.setSwapBytes(true); @@ -2421,8 +2436,7 @@ void ModeButtonPress() { menupage = INDEX; menuitem = 0; if (spispeed == 7) tft.setSPISpeed(40); - PSSprite.unloadFont(); - if (language == LANGUAGE_CHS) PSSprite.loadFont(FONT16_CHS); else PSSprite.loadFont(FONT16); + if (language == LANGUAGE_CHS) PSSprite.setTextFont(1); else PSSprite.setTextFont(0); BuildMenu(); freq_in = 0; menu = true; @@ -2465,8 +2479,7 @@ void ModeButtonPress() { menuoption = ITEM1; menupage = INDEX; menuitem = 0; - PSSprite.unloadFont(); - if (language == LANGUAGE_CHS) PSSprite.loadFont(FONT16_CHS); else PSSprite.loadFont(FONT16); + if (language == LANGUAGE_CHS) PSSprite.setTextFont(1); else PSSprite.setTextFont(0); BuildMenu(); freq_in = 0; } @@ -2881,30 +2894,17 @@ void ShowFreq(int mode) { if (!screenmute) { FrequencySprite.fillSprite(BackgroundColor); - - switch (freqfont) { - case 0: FrequencySprite.loadFont(FREQFONT0); break; - case 1: FrequencySprite.loadFont(FREQFONT1); break; - case 2: FrequencySprite.loadFont(FREQFONT2); break; - case 3: FrequencySprite.loadFont(FREQFONT3); break; - case 4: FrequencySprite.loadFont(FREQFONT4); break; - case 5: FrequencySprite.loadFont(FREQFONT5); break; - } - FrequencySprite.setTextDatum(TR_DATUM); FrequencySprite.setTextColor(FreqColor, FreqColorSmooth, false); - FrequencySprite.drawString(String(frequency_AM) + " ", 218, -6); - FrequencySprite.unloadFont(); + FrequencySprite.drawString(String(frequency_AM) + " ", 218, -6, freqfont); FrequencySprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); FrequencySprite.setTextDatum(TL_DATUM); - FrequencySprite.loadFont(FONT16); if (band == BAND_SW && showSWMIBand) { DivdeSWMIBand(); updateSWMIBand(); } - FrequencySprite.unloadFont(); FrequencySprite.pushSprite(46, 46); } @@ -2923,33 +2923,21 @@ void ShowFreq(int mode) { tftReplace(ARIGHT, String(freqold / 100) + "." + (freqold % 100 < 10 ? "0" : "") + String(freqold % 100) + " MHz", String(freq / 100) + "." + (freq % 100 < 10 ? "0" : "") + String(freq % 100), 290, 201, BWAutoColor, BWAutoColorSmooth, BackgroundColor, 16); freqold = freq; } else { - switch (freqfont) { - case 0: FrequencySprite.loadFont(FREQFONT0); break; - case 1: FrequencySprite.loadFont(FREQFONT1); break; - case 2: FrequencySprite.loadFont(FREQFONT2); break; - case 3: FrequencySprite.loadFont(FREQFONT3); break; - case 4: FrequencySprite.loadFont(FREQFONT4); break; - case 5: FrequencySprite.loadFont(FREQFONT5); break; - } - FrequencySprite.fillSprite(BackgroundColor); if (mode == 0) { FrequencySprite.setTextDatum(TR_DATUM); FrequencySprite.setTextColor(FreqColor, FreqColorSmooth, false); } else { - FrequencySprite.unloadFont(); FrequencySprite.setTextColor(ActiveColor, ActiveColorSmooth, false); FrequencySprite.setTextDatum(TC_DATUM); - if (language == LANGUAGE_CHS) FrequencySprite.loadFont(FONT16_CHS); else FrequencySprite.loadFont(FONT16); } switch (mode) { case 0: - FrequencySprite.drawString(String(freq / 100) + "." + (freq % 100 < 10 ? "0" : "") + String(freq % 100) + " ", 218, -6); + FrequencySprite.drawString(String(freq / 100) + "." + (freq % 100 < 10 ? "0" : "") + String(freq % 100) + " ", 218, -6, freqfont); freqold = freq; break; - case 1: Infoboxprint(textUI(34)); break; case 2: Infoboxprint(textUI(290)); break; case 3: Infoboxprint(textUI(291)); break; @@ -2958,7 +2946,6 @@ void ShowFreq(int mode) { } FrequencySprite.pushSprite(46, 46); - FrequencySprite.unloadFont(); if (mode == 5) delay(1000); } } @@ -2988,8 +2975,9 @@ void ShowFreq(int mode) { tft.fillCircle(314, 223, 2, GreyoutColor); tft.fillCircle(314, 234, 2, GreyoutColor); } else { - RDSSprite.fillSprite(BackgroundColor); - RDSSprite.pushSprite(36, 220); + GeneralTextSprite.fillSprite(TFT_TRANSPARENT); + GeneralTextSprite.fillRect(0, 0, 165, 19, BackgroundColor); + GeneralTextSprite.pushSprite(36, 220, TFT_TRANSPARENT); tft.fillCircle(314, 223, 2, GreyoutColor); tft.fillCircle(314, 234, 2, GreyoutColor); } @@ -3311,16 +3299,14 @@ void doSquelch() { } } } else { - if (language == LANGUAGE_CHS) SquelchSprite.loadFont(FONT16_CHS); else SquelchSprite.loadFont(FONT16); - if (!XDRGTKUSB && !XDRGTKTCP && usesquelch && (!scandxmode || (scandxmode && !scanmute))) { if (!screenmute && usesquelch && !advancedRDS && !afscreen && !rdsstatscreen) { if (!BWtune && !menu && (Squelch > Squelchold + 2 || Squelch < Squelchold - 2)) { SquelchSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); SquelchSprite.fillSprite(BackgroundColor); - if (Squelch == -100) SquelchSprite.drawString("--", 0, 0); - else if (Squelch == 920) SquelchSprite.drawString("ST", 0, 0); - else SquelchSprite.drawString(String(SquelchShow), 0, 0); + if (Squelch == -100) SquelchSprite.drawString("--", 0, 0, (language == LANGUAGE_CHS) ? 1 : 0); + else if (Squelch == 920) SquelchSprite.drawString("ST", 0, 0, (language == LANGUAGE_CHS) ? 1 : 0); + else SquelchSprite.drawString(String(SquelchShow), 0, 0, (language == LANGUAGE_CHS) ? 1 : 0); SquelchSprite.pushSprite(223, 147); Squelchold = Squelch; } @@ -3355,9 +3341,9 @@ void doSquelch() { SquelchSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); SquelchSprite.fillSprite(BackgroundColor); - if (Squelch == -1) SquelchSprite.drawString("ST", 0, 0); - else if (Squelch == 0) SquelchSprite.drawString("--", 0, 0); - else SquelchSprite.drawString(String(SquelchShow), 0, 0); + if (Squelch == -1) SquelchSprite.drawString("ST", 0, 0, (language == LANGUAGE_CHS) ? 1 : 0); + else if (Squelch == 0) SquelchSprite.drawString("--", 0, 0, (language == LANGUAGE_CHS) ? 1 : 0); + else SquelchSprite.drawString(String(SquelchShow), 0, 0, (language == LANGUAGE_CHS) ? 1 : 0); if (Squelch != Squelchold) SquelchSprite.pushSprite(223, 147); Squelchold = Squelch; } @@ -3387,7 +3373,6 @@ void doSquelch() { } } } - SquelchSprite.unloadFont(); } void doBW() { @@ -3860,17 +3845,16 @@ void read_encoder() { } void tftReplace(int8_t offset, const String & textold, const String & text, int16_t x, int16_t y, int color, int smoothcolor, int background, uint8_t fontsize) { - const uint8_t *selectedFont = nullptr; + uint8_t selectedFont = 0; if (language == LANGUAGE_CHS) { - if (fontsize == 16) selectedFont = FONT16_CHS; - else if (fontsize == 28) selectedFont = FONT28_CHS; + if (fontsize == 16) selectedFont = 1; + else if (fontsize == 28) selectedFont = 3; } else { - if (fontsize == 16) selectedFont = FONT16; - else if (fontsize == 28) selectedFont = FONT28; + if (fontsize == 16) selectedFont = 0; + else if (fontsize == 28) selectedFont = 2; } - if (fontsize == 48) selectedFont = FONT48; + if (fontsize == 48) selectedFont = 4; - tft.loadFont(selectedFont); tft.setTextColor(background, background, false); switch (offset) { @@ -3879,7 +3863,7 @@ void tftReplace(int8_t offset, const String & textold, const String & text, int1 case 1: tft.setTextDatum(TR_DATUM); break; } - tft.drawString(textold, x, y); + tft.drawString(textold, x, y, selectedFont); tft.setTextColor(color, smoothcolor, false); switch (offset) { @@ -3891,23 +3875,19 @@ void tftReplace(int8_t offset, const String & textold, const String & text, int1 String modifiedText = text; modifiedText.replace("\n", " "); - tft.drawString(modifiedText, x, y); - tft.unloadFont(); + tft.drawString(modifiedText, x, y, selectedFont); } void tftPrint(int8_t offset, const String & text, int16_t x, int16_t y, int color, int smoothcolor, uint8_t fontsize) { - const uint8_t *selectedFont = nullptr; + uint8_t selectedFont = 0; if (language == LANGUAGE_CHS) { - if (fontsize == 16) selectedFont = FONT16_CHS; - else if (fontsize == 28) selectedFont = FONT28_CHS; + if (fontsize == 16) selectedFont = 1; + else if (fontsize == 28) selectedFont = 3; } else { - if (fontsize == 16) selectedFont = FONT16; - else if (fontsize == 28) selectedFont = FONT28; + if (fontsize == 16) selectedFont = 0; + else if (fontsize == 28) selectedFont = 2; } - - if (fontsize == 48) selectedFont = FONT48; - - tft.loadFont(selectedFont); + if (fontsize == 48) selectedFont = 4; tft.setTextColor(color, smoothcolor, (fontsize == 52 ? true : false)); @@ -3920,40 +3900,24 @@ void tftPrint(int8_t offset, const String & text, int16_t x, int16_t y, int colo String modifiedText = text; modifiedText.replace("\n", " "); - tft.drawString(modifiedText, x, y, 1); - tft.unloadFont(); + tft.drawString(modifiedText, x, y, selectedFont); } void UpdateFonts(byte mode) { switch (mode) { case 0: - RDSSprite.unloadFont(); - PTYSprite.unloadFont(); - PSSprite.unloadFont(); - FullLineSprite.unloadFont(); - OneBigLineSprite.unloadFont(); - if (language == LANGUAGE_CHS) { - RDSSprite.loadFont(FONT16_CHS); - PTYSprite.loadFont(FONT16_CHS); - if (menu) PSSprite.loadFont(FONT16_CHS); else PSSprite.loadFont(FONT28_CHS); - FullLineSprite.loadFont(FONT16_CHS); - OneBigLineSprite.loadFont(FONT28_CHS); + if (menu) PSSprite.setTextFont(1); else PSSprite.setTextFont(3); + OneBigLineSprite.setTextFont(1); + GeneralTextSprite.setTextFont(1); + FullLineSprite.setTextFont(1); } else { - RDSSprite.loadFont(FONT16); - PTYSprite.loadFont(FONT16); - if (menu) PSSprite.loadFont(FONT16); else PSSprite.loadFont(FONT28); - FullLineSprite.loadFont(FONT16); - OneBigLineSprite.loadFont(FONT28); + if (menu) PSSprite.setTextFont(0); else PSSprite.setTextFont(2); + OneBigLineSprite.setTextFont(0); + GeneralTextSprite.setTextFont(0); + FullLineSprite.setTextFont(0); } break; - case 1: - FullLineSprite.unloadFont(); - OneBigLineSprite.unloadFont(); - RDSSprite.unloadFont(); - PTYSprite.unloadFont(); - PSSprite.unloadFont(); - break; } } @@ -4043,14 +4007,11 @@ uint8_t doAutoMemory(uint16_t startfreq, uint16_t stopfreq, uint8_t startmem, ui SignalSprite.setTextColor(SecondaryColor, SecondaryColorSmooth, false); SignalSprite.setTextDatum(TC_DATUM); - SignalSprite.loadFont(FONT28); SignalSprite.drawString(String(percent) + "%", 40, 0); - SignalSprite.unloadFont(); SignalSprite.pushSprite(120, 125); - if (language == LANGUAGE_CHS) SquelchSprite.loadFont(FONT16_CHS); else SquelchSprite.loadFont(FONT16); SquelchSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false); - SquelchSprite.drawString(String(counter), 0, 0); + SquelchSprite.drawString(String(counter), 0, 0, (language == LANGUAGE_CHS) ? 1 : 0); SquelchSprite.pushSprite(200, 155); tft.fillRect(60, 110, 2 * percent, 6, BarInsignificantColor); diff --git a/src/rds.cpp b/src/rds.cpp index f1c2d9d..d8709a1 100644 --- a/src/rds.cpp +++ b/src/rds.cpp @@ -406,14 +406,15 @@ void showPI() { void showPTY() { if(radio.rds.PTY.changed(0)) { String PTYString = String(radio.rds.PTY) + "/" + (radio.rds.region != 0 ? (radio.rds.region == 0 ? PTY_EU[radio.rds.PTY] : PTY_USA[radio.rds.PTY]) : textUI(228 + radio.rds.PTY)); - PTYSprite.fillSprite(BackgroundColor); - if(RDSstatus) PTYSprite.setTextColor(RDSColor, RDSColorSmooth, false); - else PTYSprite.setTextColor(RDSDropoutColor, RDSDropoutColorSmooth, false); - if(band < BAND_GAP) PTYSprite.drawString(PTYString, 0, 2); // only draw it on fm + GeneralTextSprite.fillSprite(TFT_TRANSPARENT); + GeneralTextSprite.fillRect(0, 0, 160, 19, BackgroundColor); + if(RDSstatus) GeneralTextSprite.setTextColor(RDSColor, RDSColorSmooth, false); + else GeneralTextSprite.setTextColor(RDSDropoutColor, RDSDropoutColorSmooth, false); + if(band < BAND_GAP) GeneralTextSprite.drawString(PTYString, 0, 2); // only draw it on fm if (!screenmute) { - if (advancedRDS) PTYSprite.pushSprite(35, 107); - else PTYSprite.pushSprite(35, 161); + if (advancedRDS) GeneralTextSprite.pushSprite(35, 107, TFT_TRANSPARENT); + else GeneralTextSprite.pushSprite(35, 161, TFT_TRANSPARENT); } if (wifi) { @@ -514,7 +515,7 @@ void showPS() { void showCT() { char timeStr[16]; char dateStr[9]; - time_t t = rtc.getEpoch() + (NTPupdated ? 0 : radio.rds.offset); + time_t t = rtc.getEpoch(); if (NTPupdated) { t += NTPoffset * 3600; // Convert offset from hours to seconds @@ -537,7 +538,7 @@ void showCT() { int hour = localtm->tm_hour; if (hour < 0 || hour > 23) hour = 0; - snprintf(timeStr, sizeof(timeStr), "%02d:%02d", hour, localtm->tm_min); + snprintf(timeStr, sizeof(timeStr), "%02d:%02d:%02d", hour, localtm->tm_min, localtm->tm_sec); } rds_clock = String(timeStr); @@ -547,26 +548,11 @@ void showCT() { rds_date = String(dateStr); if (!screenmute && showclock && (rds_clock != rds_clockold || rds_date != rds_dateold || radio.rds.hasCT.changed(0))) { - - if ((radio.rds.hasCT && RDSstatus) || NTPupdated) { - rtcset = true; - tftReplace(ACENTER, rds_clockold, rds_clock, 134, 1, RDSColor, RDSColorSmooth, BackgroundColor, 16); - tftReplace(ACENTER, rds_dateold, rds_date, 134, 15, RDSColor, RDSColorSmooth, BackgroundColor, 16); - } else { // Handle dropout scenarios - if (rtcset) { // Display dropout message if RTC was set - tftReplace(ACENTER, rds_clockold, rds_clock, 134, 1, RDSDropoutColor, RDSDropoutColorSmooth, BackgroundColor, 16); - tftReplace(ACENTER, rds_dateold, rds_date, 134, 15, RDSDropoutColor, RDSDropoutColorSmooth, BackgroundColor, 16); - } else { // Clear and reprint the clock and date - tftPrint(ACENTER, rds_clockold, 134, 1, BackgroundColor, BackgroundColor, 16); - tftPrint(ACENTER, rds_clock, 134, 1, BackgroundColor, BackgroundColor, 16); - tftPrint(ACENTER, rds_dateold, 134, 15, BackgroundColor, BackgroundColor, 16); - tftPrint(ACENTER, rds_date, 134, 15, BackgroundColor, BackgroundColor, 16); - } - } + tftReplace(ACENTER, rds_clockold, rds_clock, 134, 1, RDSColor, RDSColorSmooth, BackgroundColor, 16); + tftReplace(ACENTER, rds_dateold, rds_date, 134, 15, RDSColor, RDSColorSmooth, BackgroundColor, 16); + rds_clockold = rds_clock; + rds_dateold = rds_date; } - - rds_clockold = rds_clock; - rds_dateold = rds_date; } void showRadioText() {