diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk
index 95124cb00059..01c694205700 100644
--- a/builddefs/common_features.mk
+++ b/builddefs/common_features.mk
@@ -188,7 +188,7 @@ else
ifeq ($(PLATFORM),AVR)
# Automatically provided by avr-libc, nothing required
else ifeq ($(PLATFORM),CHIBIOS)
- ifneq ($(filter STM32F3xx_% STM32F1xx_% STM32F4xx_% STM32L4xx_% GD32VF103_% CM32M101A_% %_STM32F401xC %_STM32F401xE %_STM32F405xG %_STM32F411xE %_STM32F072xB %_STM32F042x6 %_GD32VF103xB %_GD32VF103x8 ,$(MCU_SERIES)_$(MCU_LDSCRIPT)),)
+ ifneq ($(filter STM32F3xx_% STM32F1xx_% STM32F4xx_% STM32L4xx_% GD32VF103_% %_STM32F401xC %_STM32F401xE %_STM32F405xG %_STM32F411xE %_STM32F072xB %_STM32F042x6 %_GD32VF103xB %_GD32VF103x8 ,$(MCU_SERIES)_$(MCU_LDSCRIPT)),)
# Emulated EEPROM
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_STM32_FLASH_EMULATED
COMMON_VPATH += $(DRIVER_PATH)/eeprom
diff --git a/keyboards/zhaqian/djinn/LICENSE b/keyboards/zhaqian/djinn/LICENSE
new file mode 100644
index 000000000000..f288702d2fa1
--- /dev/null
+++ b/keyboards/zhaqian/djinn/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
+.
diff --git a/keyboards/zhaqian/djinn/config.h b/keyboards/zhaqian/djinn/config.h
new file mode 100644
index 000000000000..b2725678dbfd
--- /dev/null
+++ b/keyboards/zhaqian/djinn/config.h
@@ -0,0 +1,157 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include "config_common.h"
+
+// USB Device parameters
+#define VENDOR_ID 0x1209
+#define PRODUCT_ID 0x4919
+#define DEVICE_VER 0x0001
+#define MANUFACTURER Tzarc
+#define PRODUCT Djinn
+
+// Matrix
+#define MATRIX_ROWS 12
+#define MATRIX_COLS 7
+#define DIODE_DIRECTION ROW2COL
+
+// Encoders -- right-side is reversed
+#define ENCODERS_PAD_A \
+ { C14 }
+#define ENCODERS_PAD_B \
+ { C15 }
+#define ENCODERS_PAD_A_RIGHT \
+ { C15 }
+#define ENCODERS_PAD_B_RIGHT \
+ { C14 }
+
+#ifndef ENCODER_RESOLUTION
+# define ENCODER_RESOLUTION 2
+#endif // ENCODER_RESOLUTION
+
+// Bootloader
+#define STM32_BOOTLOADER_DUAL_BANK TRUE
+#define STM32_BOOTLOADER_DUAL_BANK_GPIO B7
+
+// Peripheral power control pins
+#define LCD_POWER_ENABLE_PIN A6
+
+// Split configuration
+#define SPLIT_PLUG_DETECT_PIN B12
+#define SPLIT_TRANSACTION_IDS_KB RPC_ID_SYNC_STATE_KB
+#define SPLIT_TRANSPORT_MIRROR
+#define SPLIT_LAYER_STATE_ENABLE
+#define SPLIT_LED_STATE_ENABLE
+#define SPLIT_MODS_ENABLE
+#define SPLIT_WPM_ENABLE
+
+// SPI Configuration
+#define SPI_DRIVER SPID3
+#define SPI_SCK_PIN C10
+#define SPI_SCK_PAL_MODE 6
+#define SPI_MOSI_PIN C12
+#define SPI_MOSI_PAL_MODE 6
+#define SPI_MISO_PIN C11
+#define SPI_MISO_PAL_MODE 6
+
+// LCD Configuration
+#define ILI9XXX_PIXDATA_BUFSIZE 240
+#define LCD_RST_PIN B3
+#define LCD_CS_PIN D2
+#define LCD_DC_PIN A15
+#ifndef LCD_ACTIVITY_TIMEOUT
+# define LCD_ACTIVITY_TIMEOUT 30000
+#endif // LCD_ACTIVITY_TIMEOUT
+
+// Backlight driver (to control LCD backlight)
+#define BACKLIGHT_LEVELS 4
+#define BACKLIGHT_PIN A7
+#define BACKLIGHT_PWM_DRIVER PWMD17
+#define BACKLIGHT_PWM_CHANNEL 1
+#define BACKLIGHT_PAL_MODE 1
+
+// RGB configuration
+#define WS2812_EXTERNAL_PULLUP
+#define RGB_DI_PIN B2
+#ifdef RGB_MATRIX_ENABLE
+# define DRIVER_LED_TOTAL RGBLED_NUM
+# define RGB_MATRIX_SPLIT RGBLED_SPLIT
+#endif // RGB_MATRIX_ENABLE
+#define WS2812_PWM_DRIVER PWMD20
+#define WS2812_PWM_CHANNEL 1
+#define WS2812_PWM_PAL_MODE 3
+#define WS2812_DMA_STREAM STM32_DMA1_STREAM1
+#define WS2812_DMA_CHANNEL 1
+#define WS2812_DMAMUX_ID STM32_DMAMUX1_TIM20_UP
+
+// Audio configuration
+#define AUDIO_PIN A5
+#define AUDIO_PIN_ALT A4
+#define AUDIO_PIN_ALT_AS_NEGATIVE
+#define A5_AUDIO
+#ifndef STARTUP_SONG
+# define STARTUP_SONG SONG(STARTUP_SOUND)
+#endif // STARTUP_SONG
+
+/* disable these deprecated features by default */
+#define NO_ACTION_MACRO
+#define NO_ACTION_FUNCTION
+
+// RGB Effects
+#define ENABLE_RGB_MATRIX_ALPHAS_MODS
+#define ENABLE_RGB_MATRIX_GRADIENT_UP_DOWN
+#define ENABLE_RGB_MATRIX_GRADIENT_LEFT_RIGHT
+#define ENABLE_RGB_MATRIX_BREATHING
+#define ENABLE_RGB_MATRIX_BAND_SAT
+#define ENABLE_RGB_MATRIX_BAND_VAL
+#define ENABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
+#define ENABLE_RGB_MATRIX_BAND_PINWHEEL_VAL
+#define ENABLE_RGB_MATRIX_BAND_SPIRAL_SAT
+#define ENABLE_RGB_MATRIX_BAND_SPIRAL_VAL
+#define ENABLE_RGB_MATRIX_CYCLE_ALL
+#define ENABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
+#define ENABLE_RGB_MATRIX_CYCLE_UP_DOWN
+#define ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
+#define ENABLE_RGB_MATRIX_CYCLE_OUT_IN
+#define ENABLE_RGB_MATRIX_CYCLE_OUT_IN_DUAL
+#define ENABLE_RGB_MATRIX_CYCLE_PINWHEEL
+#define ENABLE_RGB_MATRIX_CYCLE_SPIRAL
+#define ENABLE_RGB_MATRIX_DUAL_BEACON
+#define ENABLE_RGB_MATRIX_RAINBOW_BEACON
+#define ENABLE_RGB_MATRIX_RAINBOW_PINWHEELS
+#define ENABLE_RGB_MATRIX_RAINDROPS
+#define ENABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
+#define ENABLE_RGB_MATRIX_HUE_BREATHING
+#define ENABLE_RGB_MATRIX_HUE_PENDULUM
+#define ENABLE_RGB_MATRIX_HUE_WAVE
+#define ENABLE_RGB_MATRIX_PIXEL_FRACTAL
+#define ENABLE_RGB_MATRIX_PIXEL_RAIN
+#define ENABLE_RGB_MATRIX_TYPING_HEATMAP
+#define ENABLE_RGB_MATRIX_DIGITAL_RAIN
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
+#define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
+#define ENABLE_RGB_MATRIX_SPLASH
+#define ENABLE_RGB_MATRIX_MULTISPLASH
+#define ENABLE_RGB_MATRIX_SOLID_SPLASH
+#define ENABLE_RGB_MATRIX_SOLID_MULTISPLASH
\ No newline at end of file
diff --git a/keyboards/zhaqian/djinn/djinn.c b/keyboards/zhaqian/djinn/djinn.c
new file mode 100644
index 000000000000..7269aa2ef58b
--- /dev/null
+++ b/keyboards/zhaqian/djinn/djinn.c
@@ -0,0 +1,371 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+
+#include "djinn.h"
+#include "serial.h"
+#include "split_util.h"
+
+#include "qp_ili9341.h"
+
+painter_device_t lcd;
+
+kb_runtime_config kb_state;
+uint32_t last_slave_sync_time = 0;
+
+void board_init(void) { usbpd_init(); }
+
+__attribute__((weak)) void draw_ui_user(void) {}
+
+const char* usbpd_str(usbpd_allowance_t allowance) {
+ switch (allowance) {
+ default:
+ case USBPD_500MA:
+ return "500mA";
+ case USBPD_1500MA:
+ return "1500mA";
+ case USBPD_3000MA:
+ return "3000mA";
+ }
+}
+
+void usbpd_update(void) {
+ static uint32_t last_read = 0;
+ if (timer_elapsed32(last_read) > 250) {
+ last_read = timer_read32();
+ switch (usbpd_get_allowance()) {
+ case USBPD_500MA:
+ if (kb_state.current_setting != USBPD_500MA) {
+ dprintf("Transitioning UCPD1 %s -> %s\n", usbpd_str(kb_state.current_setting), usbpd_str(USBPD_500MA));
+ kb_state.current_setting = USBPD_500MA;
+ }
+ break;
+ case USBPD_1500MA:
+ if (kb_state.current_setting != USBPD_1500MA) {
+ dprintf("Transitioning UCPD1 %s -> %s\n", usbpd_str(kb_state.current_setting), usbpd_str(USBPD_1500MA));
+ kb_state.current_setting = USBPD_1500MA;
+ }
+ break;
+ case USBPD_3000MA:
+ if (kb_state.current_setting != USBPD_3000MA) {
+ dprintf("Transitioning UCPD1 %s -> %s\n", usbpd_str(kb_state.current_setting), usbpd_str(USBPD_3000MA));
+ kb_state.current_setting = USBPD_3000MA;
+ }
+ break;
+ }
+ }
+}
+
+void kb_state_update(void) {
+ if (is_keyboard_master()) {
+ // Modify allowed current limits
+ usbpd_update();
+
+ // Turn off the LCD if there's been no matrix activity
+ kb_state.lcd_power = (last_input_activity_elapsed() < LCD_ACTIVITY_TIMEOUT) ? 1 : 0;
+ }
+}
+
+void kb_state_sync(void) {
+ if (!is_transport_connected()) return;
+
+ if (is_keyboard_master()) {
+ // Keep track of the last state, so that we can tell if we need to propagate to slave
+ static kb_runtime_config last_kb_state;
+ static uint32_t last_sync;
+ bool needs_sync = false;
+
+ // Check if the state values are different
+ if (memcmp(&kb_state, &last_kb_state, sizeof(kb_runtime_config))) {
+ needs_sync = true;
+ memcpy(&last_kb_state, &kb_state, sizeof(kb_runtime_config));
+ }
+
+ // Send to slave every 500ms regardless of state change
+ if (timer_elapsed32(last_sync) > 500) {
+ needs_sync = true;
+ }
+
+ // Perform the sync if requested
+ if (needs_sync) {
+ if (transaction_rpc_send(RPC_ID_SYNC_STATE_KB, sizeof(kb_runtime_config), &kb_state)) {
+ last_sync = timer_read32();
+ } else {
+ dprint("Failed to perform data transaction\n");
+ }
+ }
+ }
+}
+
+void kb_state_sync_slave(uint8_t initiator2target_buffer_size, const void* initiator2target_buffer, uint8_t target2initiator_buffer_size, void* target2initiator_buffer) {
+ if (initiator2target_buffer_size == sizeof(kb_runtime_config)) {
+ memcpy(&kb_state, initiator2target_buffer, sizeof(kb_runtime_config));
+ }
+}
+
+#define MATRIX_ROW_PINS \
+ { B13, B14, B15, C6, C7, C8 }
+#define MATRIX_COL_PINS \
+ { C0, C1, C2, C3, A0, A1, A2 }
+
+void housekeeping_task_kb(void) {
+ // Update kb_state so we can send to slave
+ kb_state_update();
+
+ // Data sync from master to slave
+ kb_state_sync();
+
+ // Work out if we've changed our current limit, update the limiter circuit switches
+ static uint8_t current_setting = USBPD_500MA;
+ if (current_setting != kb_state.current_setting) {
+ current_setting = kb_state.current_setting;
+ switch (current_setting) {
+ default:
+ case USBPD_500MA:
+ writePinLow(RGB_CURR_1500mA_OK_PIN);
+ writePinLow(RGB_CURR_3000mA_OK_PIN);
+ break;
+#ifdef DJINN_SUPPORTS_3A_FUSE
+ case USBPD_1500MA:
+ writePinHigh(RGB_CURR_1500mA_OK_PIN);
+ writePinLow(RGB_CURR_3000mA_OK_PIN);
+ break;
+ case USBPD_3000MA:
+ writePinHigh(RGB_CURR_1500mA_OK_PIN);
+ writePinHigh(RGB_CURR_3000mA_OK_PIN);
+ break;
+#else
+ case USBPD_1500MA:
+ case USBPD_3000MA:
+ writePinHigh(RGB_CURR_1500mA_OK_PIN);
+ writePinLow(RGB_CURR_3000mA_OK_PIN);
+ break;
+#endif
+ }
+
+ // Toggle rgblight on and off, if it's already on, to force a brightness update on all LEDs
+ if (is_keyboard_master() && rgblight_is_enabled()) {
+ rgblight_disable_noeeprom();
+ rgblight_enable_noeeprom();
+ }
+ }
+
+ // Turn on/off the LCD
+ static bool lcd_on = false;
+ if (lcd_on != (bool)kb_state.lcd_power) {
+ lcd_on = (bool)kb_state.lcd_power;
+ qp_power(lcd, lcd_on);
+ }
+
+ // Enable/disable RGB
+ if (lcd_on) {
+ // Enable EEPROM so that we've got some colour data already being transmitted, by the time we turn on the RGB_PWR line
+ if (rgblight_is_enabled() != lcd_on) {
+ rgblight_enable_noeeprom();
+ }
+ // Turn on RGB_PWR
+ writePinHigh(RGB_POWER_ENABLE_PIN);
+ } else {
+ // Turn off RGB_PWR
+ writePinLow(RGB_POWER_ENABLE_PIN);
+ // Disable the PWM output for the RGB
+ if (rgblight_is_enabled() != lcd_on) {
+ rgblight_disable_noeeprom();
+ }
+ }
+
+ // Match the backlight to the LCD state
+ if (is_keyboard_master() && is_backlight_enabled() != lcd_on) {
+ if (lcd_on)
+ backlight_enable();
+ else
+ backlight_disable();
+ }
+
+ // Draw the UI
+ if (kb_state.lcd_power) {
+ draw_ui_user();
+ }
+
+ // Go into low-scan interrupt-based mode if we haven't had any matrix activity in the last 5 seconds
+ if (last_input_activity_elapsed() > 5000) {
+ // ROW2COL
+ const pin_t row_pins[] = MATRIX_ROW_PINS;
+ const pin_t col_pins[] = MATRIX_COL_PINS;
+
+ // Set up row/col pins and attach callback
+ for (int i = 0; i < sizeof(col_pins) / sizeof(pin_t); ++i) {
+ setPinOutput(col_pins[i]);
+ writePinLow(col_pins[i]);
+ }
+ for (int i = 0; i < sizeof(row_pins) / sizeof(pin_t); ++i) {
+ setPinInputHigh(row_pins[i]);
+ palEnableLineEvent(row_pins[i], PAL_EVENT_MODE_BOTH_EDGES);
+ }
+
+ // Wait for an interrupt
+ __WFI();
+
+ // Now that the interrupt has woken us up, reset all the row/col pins back to defaults
+ for (int i = 0; i < sizeof(row_pins) / sizeof(pin_t); ++i) {
+ palDisableLineEvent(row_pins[i]);
+ writePinHigh(row_pins[i]);
+ setPinInputHigh(row_pins[i]);
+ }
+ for (int i = 0; i < sizeof(col_pins) / sizeof(pin_t); ++i) {
+ writePinHigh(col_pins[i]);
+ setPinInputHigh(col_pins[i]);
+ }
+ }
+}
+
+//----------------------------------------------------------
+// Initialisation
+
+void keyboard_post_init_kb(void) {
+ // Register keyboard state sync split transaction
+ transaction_register_rpc(RPC_ID_SYNC_STATE_KB, kb_state_sync_slave);
+
+ // Reset the initial shared data value between master and slave
+ memset(&kb_state, 0, sizeof(kb_state));
+
+ // Turn off increased current limits
+ setPinOutput(RGB_CURR_1500mA_OK_PIN);
+ writePinLow(RGB_CURR_1500mA_OK_PIN);
+ setPinOutput(RGB_CURR_3000mA_OK_PIN);
+ writePinLow(RGB_CURR_3000mA_OK_PIN);
+
+ // Turn on the RGB
+ setPinOutput(RGB_POWER_ENABLE_PIN);
+ writePinHigh(RGB_POWER_ENABLE_PIN);
+
+#ifdef EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN
+ setPinOutput(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN);
+ writePinHigh(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN);
+#endif // EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN
+
+ // Turn on the LCD
+ setPinOutput(LCD_POWER_ENABLE_PIN);
+ writePinHigh(LCD_POWER_ENABLE_PIN);
+
+ // Let the LCD get some power...
+ wait_ms(50);
+
+ // Initialise the LCD
+ lcd = qp_ili9341_make_spi_device(320, 240, LCD_CS_PIN, LCD_DC_PIN, LCD_RST_PIN, 4, 0);
+ qp_init(lcd, QP_ROTATION_0);
+
+ // Turn on the LCD and clear the display
+ kb_state.lcd_power = 1;
+ qp_power(lcd, true);
+ qp_rect(lcd, 0, 0, 239, 319, HSV_BLACK, true);
+
+ // Turn on the LCD backlight
+ backlight_enable();
+ backlight_level(BACKLIGHT_LEVELS);
+
+ // Allow for user post-init
+ keyboard_post_init_user();
+}
+
+//----------------------------------------------------------
+// QMK overrides
+
+// Read the ports in one go
+#define GPIOB_BITMASK (1 << 13 | 1 << 14 | 1 << 15) // B13, B14, B15
+#define GPIOB_OFFSET 13
+#define GPIOB_COUNT 3
+#define GPIOC_BITMASK (1 << 6 | 1 << 7 | 1 << 8) // C6, C7, C8
+#define GPIOC_OFFSET 6
+
+// Pin definitions
+static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
+
+void matrix_init_pins(void) {
+ for (int i = 0; i < MATRIX_ROWS; ++i) setPinInputHigh(row_pins[i]);
+ for (int i = 0; i < MATRIX_COLS; ++i) setPinInputHigh(col_pins[i]);
+}
+
+void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col, matrix_row_t row_shifter) {
+ // Setup the output column pin
+ setPinOutput(col_pins[current_col]);
+ writePinLow(col_pins[current_col]);
+ rtcnt_t start = chSysGetRealtimeCounterX();
+ rtcnt_t end = start + 500;
+ while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end))
+ if (readPin(col_pins[current_col]) == 0) break;
+
+ // Read the row ports
+ uint32_t gpio_b = palReadPort(GPIOB);
+ uint32_t gpio_c = palReadPort(GPIOC);
+
+ // Unselect the row pin
+ setPinInputHigh(col_pins[current_col]);
+
+ // Consutrct the packed bitmask for the pins
+ uint32_t readback = ~(((gpio_b & GPIOB_BITMASK) >> GPIOB_OFFSET) | (((gpio_c & GPIOC_BITMASK) >> GPIOC_OFFSET) << GPIOB_COUNT));
+
+ // Inject values into the matrix
+ for (int i = 0; i < MATRIX_ROWS; ++i) {
+ if (readback & (1 << i))
+ current_matrix[i] |= (1ul << current_col);
+ else
+ current_matrix[i] &= ~(1ul << current_col);
+ }
+
+ // Wait for readback of each port to go high -- unselecting the row would have been completed
+ start = chSysGetRealtimeCounterX();
+ end = start + 500;
+ while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end))
+ if ((palReadPort(GPIOB) & GPIOB_BITMASK) == GPIOB_BITMASK) break;
+ while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end))
+ if ((palReadPort(GPIOC) & GPIOC_BITMASK) == GPIOC_BITMASK) break;
+}
+
+#if defined(RGB_MATRIX_ENABLE)
+# define rgb_to_hsv_hook_func rgb_matrix_hsv_to_rgb
+#elif defined(RGBLIGHT_ENABLE)
+# define rgb_to_hsv_hook_func rgblight_hsv_to_rgb
+#endif
+RGB rgb_to_hsv_hook_func(HSV hsv) {
+ float scale;
+ switch (kb_state.current_setting) {
+ default:
+ case USBPD_500MA:
+ scale = 0.35f;
+ break;
+#ifdef DJINN_SUPPORTS_3A_FUSE
+ case USBPD_1500MA:
+ scale = 0.75f;
+ break;
+ case USBPD_3000MA:
+ scale = 1.0f;
+ break;
+#else
+ case USBPD_1500MA:
+ case USBPD_3000MA:
+ scale = 0.75f;
+ break;
+#endif
+ }
+
+ hsv.v = (uint8_t)(hsv.v * scale);
+ return hsv_to_rgb(hsv);
+}
diff --git a/keyboards/zhaqian/djinn/djinn.h b/keyboards/zhaqian/djinn/djinn.h
new file mode 100644
index 000000000000..9c563fb5c2fe
--- /dev/null
+++ b/keyboards/zhaqian/djinn/djinn.h
@@ -0,0 +1,74 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+
+//----------------------------------------------------------
+// Layout
+
+// clang-format off
+
+#define LAYOUT_all( \
+ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B, k0C, k0D, \
+ k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B, k1C, k1D, \
+ k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2A, k2B, k2C, k2D, \
+ k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k3A, k3B, k3C, k3D, \
+ k40, k41, k42, k43, k44, k45, k46, k47, \
+ k50, k51, \
+ k60, k61, \
+ k70, k71, k72, k73, k74, k75, \
+ k80, k81 \
+ ) \
+ { \
+ {k00, k01, k02, k03, k04, k05, k06}, \
+ {k10, k11, k12, k13, k14, k15, k16}, \
+ {k20, k21, k22, k23, k24, k25, k26}, \
+ {k30, k31, k32, k33, k34, k35, k36}, \
+ {KC_NO, KC_NO, KC_NO, k40, k41, k42, k43}, \
+ {KC_NO, k60, k70, k80, k72, k71, k50}, \
+ {k0D, k0C, k0B, k0A, k09, k08, k07}, \
+ {k1D, k1C, k1B, k1A, k19, k18, k17}, \
+ {k2D, k2C, k2B, k2A, k29, k28, k27}, \
+ {k3D, k3C, k3B, k3A, k39, k38, k37}, \
+ {KC_NO, KC_NO, KC_NO, k47, k46, k45, k44}, \
+ {KC_NO, k61, k73, k81, k75, k74, k51}, \
+ }
+
+// clang-format on
+
+//----------------------------------------------------------
+// Runtime data sync -- keyboard
+
+extern painter_device_t lcd;
+
+#pragma pack(push)
+#pragma pack(1)
+
+typedef struct kb_runtime_config {
+ unsigned lcd_power : 1;
+ usbpd_allowance_t current_setting : 2;
+} kb_runtime_config;
+
+#pragma pack(pop)
+
+_Static_assert(sizeof(kb_runtime_config) == 1, "Invalid data transfer size for keyboard sync data");
+
+extern kb_runtime_config kb_state;
+
+const char *usbpd_str(usbpd_allowance_t allowance);
diff --git a/keyboards/zhaqian/djinn/graphics/Thintel.ttf b/keyboards/zhaqian/djinn/graphics/Thintel.ttf
new file mode 100644
index 000000000000..e00633a57044
Binary files /dev/null and b/keyboards/zhaqian/djinn/graphics/Thintel.ttf differ
diff --git a/keyboards/zhaqian/djinn/graphics/src/djinn.qgf.c b/keyboards/zhaqian/djinn/graphics/src/djinn.qgf.c
new file mode 100644
index 000000000000..120f026eeff2
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/djinn.qgf.c
@@ -0,0 +1,246 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i djinn.png -f mono4`
+
+#include
+
+const uint32_t gfx_djinn_length = 3724;
+
+// clang-format off
+const uint8_t gfx_djinn[3724] QP_RESIDENT_FLASH = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x8C, 0x0E, 0x00, 0x00, 0x73, 0xF1, 0xFF,
+ 0xFF, 0x66, 0x00, 0x20, 0x01, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0x5C, 0x0E, 0x00,
+ 0x58, 0x00, 0x80, 0x90, 0x19, 0x00, 0x80, 0x2D, 0x18, 0x00, 0x81, 0xE0, 0x07, 0x18, 0x00, 0x81,
+ 0xFE, 0x01, 0x17, 0x00, 0x81, 0xF4, 0x2F, 0x17, 0x00, 0x82, 0x80, 0xFF, 0x07, 0x17, 0x00, 0x82,
+ 0xFD, 0xFF, 0x01, 0x16, 0x00, 0x82, 0xE0, 0xFF, 0x2F, 0x16, 0x00, 0x80, 0x80, 0x02, 0xFF, 0x80,
+ 0x03, 0x15, 0x00, 0x84, 0x40, 0xFE, 0xFF, 0x7F, 0x14, 0x15, 0x00, 0x80, 0xF9, 0x02, 0xFF, 0x81,
+ 0x4B, 0x1A, 0x14, 0x00, 0x80, 0xE4, 0x03, 0xFF, 0x81, 0xE0, 0x06, 0x13, 0x00, 0x80, 0xD0, 0x03,
+ 0xFF, 0x82, 0x0F, 0xBE, 0x01, 0x12, 0x00, 0x80, 0x80, 0x04, 0xFF, 0x81, 0xE0, 0x6F, 0x13, 0x00,
+ 0x80, 0xFE, 0x03, 0xFF, 0x82, 0x0F, 0xFE, 0x0B, 0x12, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x82, 0xE0,
+ 0xFF, 0x02, 0x11, 0x00, 0x80, 0xE0, 0x04, 0xFF, 0x82, 0x0F, 0xFE, 0xBF, 0x11, 0x00, 0x80, 0x80,
+ 0x04, 0xFF, 0x83, 0xBF, 0xF4, 0xFF, 0x1F, 0x11, 0x00, 0x80, 0xFE, 0x04, 0xFF, 0x80, 0x47, 0x02,
+ 0xFF, 0x80, 0x07, 0x10, 0x00, 0x80, 0xF4, 0x04, 0xFF, 0x83, 0x2F, 0xF8, 0xFF, 0xBF, 0x10, 0x00,
+ 0x80, 0xD0, 0x05, 0xFF, 0x80, 0xD1, 0x02, 0xFF, 0x80, 0x1F, 0x0F, 0x00, 0x81, 0x40, 0xFE, 0x04,
+ 0xFF, 0x81, 0x0B, 0xFE, 0x02, 0xFF, 0x80, 0x06, 0x0F, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x81, 0x2F,
+ 0xF4, 0x02, 0xFF, 0x80, 0xBF, 0x0F, 0x00, 0x80, 0xE0, 0x04, 0xFF, 0x81, 0xBF, 0xD0, 0x03, 0xFF,
+ 0x80, 0x1F, 0x0E, 0x00, 0x80, 0x40, 0x04, 0xFF, 0x81, 0xBF, 0x41, 0x04, 0xFF, 0x80, 0x06, 0x0E,
+ 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x81, 0x06, 0xFD, 0x03, 0xFF, 0x80, 0x7F, 0x0E, 0x00, 0x80, 0xE0,
+ 0x04, 0xFF, 0x81, 0x06, 0x90, 0x04, 0xFF, 0x80, 0x0B, 0x0D, 0x00, 0x80, 0x40, 0x04, 0xFF, 0x82,
+ 0x1B, 0x00, 0xE4, 0x04, 0xFF, 0x80, 0x01, 0x0D, 0x00, 0x80, 0xF8, 0x03, 0xFF, 0x80, 0x1B, 0x02,
+ 0x00, 0x80, 0xE4, 0x03, 0xFF, 0x80, 0x2F, 0x0D, 0x00, 0x80, 0xD0, 0x03, 0xFF, 0x80, 0x5B, 0x03,
+ 0x00, 0x80, 0xE4, 0x03, 0xFF, 0x80, 0x07, 0x0D, 0x00, 0x80, 0xFE, 0x02, 0xFF, 0x80, 0x6F, 0x04,
+ 0x00, 0x80, 0xF9, 0x02, 0xFF, 0x80, 0x7F, 0x0D, 0x00, 0x80, 0xE0, 0x02, 0xFF, 0x80, 0x7F, 0x05,
+ 0x00, 0x80, 0xFD, 0x02, 0xFF, 0x80, 0x0B, 0x0C, 0x00, 0x80, 0x40, 0x02, 0xFF, 0x81, 0xBF, 0x01,
+ 0x04, 0x00, 0x81, 0x40, 0xFE, 0x02, 0xFF, 0x0D, 0x00, 0x80, 0xF8, 0x02, 0xFF, 0x80, 0x02, 0x05,
+ 0x00, 0x80, 0x90, 0x02, 0xFF, 0x80, 0x0F, 0x0C, 0x00, 0x80, 0x80, 0x02, 0xFF, 0x80, 0x07, 0x06,
+ 0x00, 0x80, 0xF4, 0x02, 0xFF, 0x0D, 0x00, 0x82, 0xFD, 0xFF, 0x1F, 0x07, 0x00, 0x82, 0xFD, 0xFF,
+ 0x1F, 0x0C, 0x00, 0x82, 0xD0, 0xFF, 0x7F, 0x07, 0x00, 0x80, 0x80, 0x02, 0xFF, 0x80, 0x01, 0x0C,
+ 0x00, 0x82, 0xFD, 0xFF, 0x02, 0x07, 0x00, 0x82, 0xF4, 0xFF, 0x1F, 0x0C, 0x00, 0x82, 0xE0, 0xFF,
+ 0x0B, 0x08, 0x00, 0x82, 0xFE, 0xFF, 0x01, 0x0C, 0x00, 0x81, 0xFE, 0x7F, 0x08, 0x00, 0x82, 0xD0,
+ 0xFF, 0x1F, 0x0C, 0x00, 0x82, 0xE0, 0xFF, 0x02, 0x08, 0x00, 0x81, 0xF8, 0xFF, 0x0D, 0x00, 0x81,
+ 0xFE, 0x1F, 0x08, 0x00, 0x82, 0x40, 0xFF, 0x0F, 0x0C, 0x00, 0x82, 0xE0, 0xFF, 0x01, 0x08, 0x00,
+ 0x81, 0xF4, 0xFF, 0x0D, 0x00, 0x81, 0xFD, 0x0B, 0x09, 0x00, 0x81, 0xFE, 0x0B, 0x0C, 0x00, 0x81,
+ 0xD0, 0xBF, 0x09, 0x00, 0x81, 0xE0, 0xBF, 0x0D, 0x00, 0x81, 0xF9, 0x07, 0x09, 0x00, 0x81, 0xFD,
+ 0x07, 0x0C, 0x00, 0x81, 0x80, 0x7F, 0x09, 0x00, 0x81, 0xD0, 0x7F, 0x0D, 0x00, 0x81, 0xF8, 0x07,
+ 0x09, 0x00, 0x81, 0xF9, 0x03, 0x0C, 0x00, 0x81, 0x40, 0x7F, 0x09, 0x00, 0x81, 0x90, 0x2F, 0x0D,
+ 0x00, 0x81, 0xE0, 0x07, 0x09, 0x00, 0x81, 0xF8, 0x02, 0x0D, 0x00, 0x80, 0x7D, 0x09, 0x00, 0x81,
+ 0x80, 0x1F, 0x0D, 0x00, 0x81, 0x80, 0x07, 0x09, 0x00, 0x80, 0xB8, 0x0E, 0x00, 0x80, 0x74, 0x09,
+ 0x00, 0x81, 0x80, 0x0B, 0x0E, 0x00, 0x80, 0x0A, 0x03, 0x00, 0x80, 0x04, 0x05, 0x00, 0x80, 0x78,
+ 0x0E, 0x00, 0x80, 0x90, 0x03, 0x00, 0x83, 0xA4, 0x00, 0x80, 0x06, 0x02, 0x00, 0x81, 0x80, 0x02,
+ 0x0E, 0x00, 0x87, 0x04, 0x00, 0x40, 0xE9, 0x0B, 0x00, 0xF8, 0x5A, 0x02, 0x00, 0x80, 0x14, 0x10,
+ 0x00, 0x86, 0x40, 0xFA, 0xBF, 0x00, 0x40, 0xFF, 0x6B, 0x12, 0x00, 0x87, 0x90, 0xFE, 0xFF, 0x07,
+ 0x00, 0xE0, 0xFF, 0xAF, 0x11, 0x00, 0x80, 0x80, 0x02, 0xFF, 0x80, 0x1F, 0x02, 0x00, 0x82, 0xF9,
+ 0xFF, 0x2F, 0x11, 0x00, 0x82, 0xFE, 0xFF, 0x6F, 0x03, 0x00, 0x82, 0xFD, 0xFF, 0x0B, 0x10, 0x00,
+ 0x82, 0xF8, 0xFF, 0x7F, 0x03, 0x00, 0x82, 0x40, 0xFE, 0xFF, 0x10, 0x00, 0x83, 0xD0, 0xFF, 0xBF,
+ 0x01, 0x03, 0x00, 0x82, 0x80, 0xFF, 0x1F, 0x10, 0x00, 0x82, 0xFD, 0xFF, 0x02, 0x04, 0x00, 0x82,
+ 0xD0, 0xFF, 0x02, 0x0F, 0x00, 0x82, 0xE0, 0xFF, 0x0B, 0x05, 0x00, 0x81, 0xF8, 0x2F, 0x0F, 0x00,
+ 0x82, 0x40, 0xFF, 0x2F, 0x06, 0x00, 0x81, 0xFE, 0x02, 0x0F, 0x00, 0x89, 0xF4, 0xFF, 0x01, 0x00,
+ 0x50, 0x55, 0x05, 0x00, 0xD0, 0x7F, 0x0F, 0x00, 0x84, 0x40, 0xFF, 0x07, 0x00, 0xA4, 0x02, 0xAA,
+ 0x02, 0x00, 0x81, 0xF8, 0x07, 0x0F, 0x00, 0x81, 0xF4, 0x6F, 0x02, 0x00, 0x85, 0xFE, 0xFF, 0x07,
+ 0x00, 0x40, 0x7F, 0x0F, 0x00, 0x8A, 0x40, 0xFF, 0x81, 0x00, 0x80, 0xFF, 0x1F, 0x00, 0x40, 0xE0,
+ 0x0B, 0x0F, 0x00, 0x85, 0xF4, 0x1B, 0x1E, 0x00, 0xF0, 0xBF, 0x02, 0x00, 0x81, 0x19, 0xBD, 0x0F,
+ 0x00, 0x8B, 0x80, 0xBF, 0xF0, 0x02, 0x00, 0xFD, 0x07, 0x00, 0xE0, 0xC2, 0x0B, 0x05, 0x0E, 0x00,
+ 0x8A, 0xF8, 0x47, 0xBF, 0x00, 0x80, 0x2F, 0x00, 0x40, 0x7F, 0xB8, 0x61, 0x0E, 0x00, 0x8B, 0x40,
+ 0x6F, 0xF8, 0x1F, 0x00, 0xF4, 0x01, 0x00, 0xF9, 0x47, 0x1F, 0x1E, 0x0E, 0x00, 0x8B, 0xF4, 0x82,
+ 0xFF, 0x06, 0x00, 0x19, 0x00, 0xE4, 0xBF, 0xF0, 0xD1, 0x06, 0x0D, 0x00, 0x8C, 0x40, 0x1F, 0xFD,
+ 0xBF, 0x01, 0x40, 0x00, 0x90, 0xFF, 0x0B, 0x2E, 0xBD, 0x01, 0x0D, 0x00, 0x86, 0xF4, 0xE1, 0xFF,
+ 0xBF, 0x01, 0x00, 0x80, 0x02, 0xFF, 0x82, 0xE0, 0x92, 0x6F, 0x0D, 0x00, 0x8C, 0x45, 0x1B, 0xFE,
+ 0xFF, 0xBF, 0x05, 0x94, 0xFE, 0xFF, 0x1F, 0x2D, 0xF8, 0x1B, 0x0C, 0x00, 0x82, 0x74, 0xB4, 0xE0,
+ 0x07, 0xFF, 0x83, 0xD1, 0x86, 0xFF, 0x07, 0x0B, 0x00, 0x83, 0xD0, 0x47, 0x4B, 0xFE, 0x06, 0xFF,
+ 0x84, 0x2F, 0x7D, 0xF8, 0xFF, 0x06, 0x0A, 0x00, 0x83, 0x90, 0x7F, 0xB4, 0xF4, 0x07, 0xFF, 0x84,
+ 0xD2, 0x47, 0xFF, 0xBF, 0x01, 0x09, 0x00, 0x83, 0x90, 0xFF, 0x87, 0x47, 0x07, 0xFF, 0x85, 0x3F,
+ 0xB8, 0xF4, 0xFF, 0xBF, 0x05, 0x08, 0x00, 0x84, 0x95, 0xFF, 0x3F, 0x78, 0xF8, 0x07, 0xFF, 0x81,
+ 0x83, 0x4B, 0x03, 0xFF, 0x81, 0x56, 0x15, 0x04, 0x00, 0x82, 0x50, 0x55, 0xEA, 0x02, 0xFF, 0x81,
+ 0x82, 0x86, 0x07, 0xFF, 0x82, 0x7F, 0xB4, 0xE0, 0x03, 0xFF, 0x81, 0xAF, 0x6A, 0x03, 0x00, 0x81,
+ 0x90, 0xFA, 0x03, 0xFF, 0x82, 0x1F, 0x2D, 0xF8, 0x07, 0xFF, 0x82, 0x0B, 0x19, 0xFE, 0x04, 0xFF,
+ 0x80, 0x6F, 0x02, 0x00, 0x80, 0x40, 0x05, 0xFF, 0x02, 0xD1, 0x08, 0xFF, 0x81, 0x01, 0xE0, 0x05,
+ 0xFF, 0x80, 0x1B, 0x02, 0x00, 0x80, 0xFD, 0x04, 0xFF, 0x82, 0x0B, 0x0A, 0xFE, 0x07, 0xFF, 0x81,
+ 0xBF, 0x41, 0x06, 0xFF, 0x82, 0x02, 0x00, 0xE4, 0x04, 0xFF, 0x82, 0xBF, 0x10, 0xF4, 0x08, 0xFF,
+ 0x80, 0xBF, 0x06, 0xFF, 0x82, 0x7F, 0x00, 0x80, 0x05, 0xFF, 0x81, 0x1F, 0xD0, 0x08, 0xFF, 0x82,
+ 0xBF, 0x56, 0xF9, 0x05, 0xFF, 0x82, 0x1B, 0x00, 0xF9, 0x05, 0xFF, 0x80, 0x9B, 0x08, 0xFF, 0x80,
+ 0x5A, 0x02, 0x00, 0x80, 0xF4, 0x05, 0xFF, 0x81, 0x01, 0x90, 0x05, 0xFF, 0x81, 0xAB, 0x5A, 0x04,
+ 0x55, 0x80, 0xA9, 0x02, 0xAA, 0x84, 0x01, 0x40, 0x55, 0x05, 0xFD, 0x03, 0xFF, 0x84, 0xAA, 0x15,
+ 0x00, 0x94, 0xFA, 0x02, 0xFF, 0x81, 0xBF, 0x56, 0x09, 0x00, 0x87, 0x95, 0xFA, 0xFF, 0x81, 0xFF,
+ 0xAF, 0x6A, 0x15, 0x03, 0x00, 0x86, 0x40, 0xA5, 0xFA, 0xBF, 0x05, 0x50, 0x55, 0x03, 0xAA, 0x80,
+ 0x16, 0x02, 0x00, 0x92, 0x50, 0xE9, 0xFF, 0xBF, 0x2A, 0xA4, 0x56, 0x05, 0x00, 0x54, 0x65, 0x00,
+ 0x59, 0x01, 0x40, 0x55, 0x06, 0xA5, 0xFA, 0x02, 0xFF, 0x92, 0xBF, 0x5A, 0x01, 0x40, 0xA5, 0xFE,
+ 0xFF, 0x5A, 0x15, 0x00, 0x01, 0x00, 0x55, 0xAA, 0xFE, 0x07, 0xE0, 0xAF, 0x56, 0x02, 0x00, 0x80,
+ 0xE8, 0x03, 0xFF, 0x87, 0x6B, 0x05, 0x00, 0x95, 0xFA, 0xFF, 0xBF, 0x15, 0x03, 0x00, 0x81, 0x95,
+ 0xEA, 0x02, 0xFF, 0x86, 0xBF, 0x00, 0xFE, 0xFF, 0xAF, 0x1A, 0xE0, 0x02, 0xFF, 0x84, 0xAF, 0x05,
+ 0x00, 0x94, 0xFA, 0x02, 0xFF, 0x85, 0x6F, 0x01, 0x00, 0x54, 0xAA, 0xFE, 0x04, 0xFF, 0x81, 0x0B,
+ 0xE0, 0x03, 0xFF, 0x80, 0x82, 0x02, 0xFF, 0x83, 0x1B, 0x00, 0x50, 0xFA, 0x03, 0xFF, 0x83, 0x1B,
+ 0x00, 0x94, 0xFE, 0x06, 0xFF, 0x82, 0xBF, 0x00, 0xFE, 0x02, 0xFF, 0x85, 0x1F, 0xFD, 0xBF, 0x05,
+ 0x00, 0xE9, 0x04, 0xFF, 0x82, 0x06, 0x40, 0xFE, 0x08, 0xFF, 0x81, 0x0B, 0xE0, 0x03, 0xFF, 0x84,
+ 0xE1, 0xBF, 0x01, 0x94, 0xFE, 0x04, 0xFF, 0x81, 0x06, 0x90, 0x09, 0xFF, 0x82, 0xBF, 0x00, 0xFD,
+ 0x02, 0xFF, 0x83, 0x1F, 0xFE, 0x01, 0xE5, 0x04, 0xFF, 0x82, 0xBF, 0x06, 0xA4, 0x0A, 0xFF, 0x81,
+ 0x0B, 0xD0, 0x03, 0xFF, 0x82, 0xD1, 0x0B, 0xF9, 0x04, 0xFF, 0x82, 0xBF, 0x05, 0xE5, 0x0A, 0xFF,
+ 0x82, 0xBF, 0x00, 0xFD, 0x02, 0xFF, 0x82, 0x2F, 0x7C, 0xF4, 0x04, 0xFF, 0x82, 0xBF, 0x05, 0xE5,
+ 0x0B, 0xFF, 0x81, 0x07, 0x90, 0x03, 0xFF, 0x81, 0x42, 0x82, 0x04, 0xFF, 0x82, 0xBF, 0x05, 0xE9,
+ 0x0B, 0xFF, 0x82, 0x7F, 0x00, 0xF8, 0x02, 0xFF, 0x82, 0xBF, 0x10, 0xF9, 0x04, 0xFF, 0x81, 0x05,
+ 0xE9, 0x0C, 0xFF, 0x81, 0x06, 0x40, 0x03, 0xFF, 0x81, 0x1F, 0xD0, 0x04, 0xFF, 0x81, 0x06, 0xE0,
+ 0x0C, 0xFF, 0x82, 0x2F, 0x00, 0xF4, 0x03, 0xFF, 0x81, 0x47, 0xFE, 0x03, 0xFF, 0x82, 0x06, 0x00,
+ 0xE4, 0x0C, 0xFF, 0x82, 0x01, 0x00, 0xFE, 0x07, 0xFF, 0x83, 0x06, 0x90, 0x05, 0x90, 0x0B, 0xFF,
+ 0x82, 0x1B, 0x00, 0xD0, 0x07, 0xFF, 0x85, 0x0B, 0x90, 0xFF, 0x16, 0x40, 0xFA, 0x09, 0xFF, 0x80,
+ 0x7F, 0x02, 0x00, 0x80, 0xF9, 0x06, 0xFF, 0x81, 0x1B, 0x94, 0x02, 0xFF, 0x82, 0x5B, 0x00, 0xA5,
+ 0x09, 0xFF, 0x82, 0x02, 0x00, 0x40, 0x06, 0xFF, 0x81, 0x1B, 0xD4, 0x03, 0xFF, 0x83, 0x6F, 0x01,
+ 0x94, 0xFA, 0x07, 0xFF, 0x80, 0x1B, 0x02, 0x00, 0x80, 0xE0, 0x05, 0xFF, 0x81, 0x1B, 0x90, 0x04,
+ 0xFF, 0x84, 0xBF, 0x16, 0x40, 0xA5, 0xFE, 0x05, 0xFF, 0x80, 0x6F, 0x03, 0x00, 0x80, 0xF8, 0x04,
+ 0xFF, 0x81, 0x1B, 0x90, 0x06, 0xFF, 0x84, 0x6A, 0x01, 0x50, 0xA9, 0xFE, 0x03, 0xFF, 0x80, 0x6F,
+ 0x04, 0x00, 0x80, 0xFE, 0x03, 0xFF, 0x81, 0x1B, 0x90, 0x07, 0xFF, 0x84, 0xAF, 0x16, 0x00, 0x50,
+ 0x95, 0x02, 0xAA, 0x80, 0x56, 0x04, 0x00, 0x81, 0x40, 0xFE, 0x02, 0xFF, 0x81, 0x1B, 0x90, 0x09,
+ 0xFF, 0x81, 0xAB, 0x05, 0x09, 0x00, 0x84, 0x40, 0xFA, 0xBF, 0x05, 0x90, 0x0B, 0xFF, 0x81, 0xAF,
+ 0x55, 0x0B, 0x00, 0x80, 0x90, 0x0E, 0xFF, 0x80, 0xBF, 0x08, 0x00, 0x81, 0x40, 0xE5, 0x0F, 0xFF,
+ 0x80, 0x02, 0x07, 0x00, 0x81, 0x90, 0xFE, 0x0F, 0xFF, 0x80, 0x07, 0x08, 0x00, 0x80, 0xF9, 0x0F,
+ 0xFF, 0x80, 0x1F, 0x08, 0x00, 0x80, 0x40, 0x0F, 0xFF, 0x80, 0x7F, 0x09, 0x00, 0x80, 0xD0, 0x0F,
+ 0xFF, 0x80, 0x01, 0x09, 0x00, 0x80, 0xF8, 0x0E, 0xFF, 0x80, 0x0B, 0x0A, 0x00, 0x80, 0xFE, 0x0D,
+ 0xFF, 0x80, 0x2F, 0x0A, 0x00, 0x80, 0xD0, 0x0D, 0xFF, 0x81, 0xBF, 0x01, 0x0A, 0x00, 0x80, 0xF4,
+ 0x0D, 0xFF, 0x80, 0x06, 0x0B, 0x00, 0x80, 0xFD, 0x0C, 0xFF, 0x80, 0x1F, 0x0B, 0x00, 0x80, 0x80,
+ 0x0C, 0xFF, 0x80, 0xBF, 0x0C, 0x00, 0x80, 0xE4, 0x0C, 0xFF, 0x80, 0x02, 0x0C, 0x00, 0x80, 0xFD,
+ 0x0B, 0xFF, 0x80, 0x1F, 0x0C, 0x00, 0x80, 0x80, 0x0B, 0xFF, 0x80, 0xBF, 0x0D, 0x00, 0x80, 0xE0,
+ 0x0B, 0xFF, 0x80, 0x07, 0x0D, 0x00, 0x80, 0xFD, 0x0A, 0xFF, 0x80, 0x1F, 0x0D, 0x00, 0x80, 0x80,
+ 0x0A, 0xFF, 0x80, 0xBF, 0x0E, 0x00, 0x80, 0xE0, 0x0A, 0xFF, 0x80, 0x07, 0x0E, 0x00, 0x80, 0xFD,
+ 0x09, 0xFF, 0x80, 0x2F, 0x0E, 0x00, 0x80, 0x80, 0x0A, 0xFF, 0x80, 0x01, 0x0E, 0x00, 0x80, 0xE0,
+ 0x09, 0xFF, 0x80, 0x0B, 0x0F, 0x00, 0x80, 0xFD, 0x08, 0xFF, 0x80, 0x7F, 0x0F, 0x00, 0x80, 0x80,
+ 0x09, 0xFF, 0x80, 0x02, 0x0F, 0x00, 0x80, 0xF4, 0x08, 0xFF, 0x80, 0x1F, 0x10, 0x00, 0x80, 0xFE,
+ 0x07, 0xFF, 0x80, 0xBF, 0x10, 0x00, 0x80, 0x90, 0x08, 0xFF, 0x80, 0x07, 0x10, 0x00, 0x80, 0xF4,
+ 0x07, 0xFF, 0x80, 0x2F, 0x10, 0x00, 0x81, 0x40, 0xFE, 0x07, 0xFF, 0x80, 0x02, 0x10, 0x00, 0x80,
+ 0xD0, 0x07, 0xFF, 0x80, 0x1F, 0x11, 0x00, 0x80, 0xF8, 0x06, 0xFF, 0x80, 0xBF, 0x11, 0x00, 0x80,
+ 0x80, 0x07, 0xFF, 0x80, 0x07, 0x11, 0x00, 0x80, 0xF4, 0x06, 0xFF, 0x80, 0x3F, 0x12, 0x00, 0x80,
+ 0xFE, 0x06, 0xFF, 0x80, 0x02, 0x11, 0x00, 0x80, 0xD0, 0x06, 0xFF, 0x80, 0x1F, 0x12, 0x00, 0x80,
+ 0xFC, 0x05, 0xFF, 0x80, 0xBF, 0x12, 0x00, 0x80, 0x40, 0x06, 0xFF, 0x80, 0x07, 0x12, 0x00, 0x80,
+ 0xF4, 0x05, 0xFF, 0x80, 0x7F, 0x13, 0x00, 0x80, 0xFE, 0x05, 0xFF, 0x80, 0x02, 0x12, 0x00, 0x80,
+ 0xE0, 0x05, 0xFF, 0x80, 0x2F, 0x13, 0x00, 0x80, 0xFD, 0x05, 0xFF, 0x80, 0x01, 0x12, 0x00, 0x80,
+ 0xD0, 0x05, 0xFF, 0x80, 0x1B, 0x13, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0xBF, 0x13, 0x00, 0x80,
+ 0x80, 0x05, 0xFF, 0x80, 0x07, 0x13, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0x7F, 0x13, 0x00, 0x80,
+ 0x40, 0x05, 0xFF, 0x80, 0x02, 0x13, 0x00, 0x80, 0xF4, 0x04, 0xFF, 0x80, 0x2F, 0x13, 0x00, 0x80,
+ 0x40, 0x05, 0xFF, 0x80, 0x01, 0x13, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0x1B, 0x13, 0x00, 0x80,
+ 0x80, 0x04, 0xFF, 0x80, 0xBF, 0x14, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0x07, 0x13, 0x00, 0x80,
+ 0x80, 0x04, 0xFF, 0x80, 0x6F, 0x14, 0x00, 0x80, 0xF8, 0x04, 0xFF, 0x80, 0x02, 0x13, 0x00, 0x80,
+ 0x80, 0x04, 0xFF, 0x80, 0x2F, 0x14, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x01, 0x13, 0x00, 0x80,
+ 0xD0, 0x04, 0xFF, 0x80, 0x0B, 0x14, 0x00, 0x80, 0xFD, 0x03, 0xFF, 0x80, 0x7F, 0x14, 0x00, 0x80,
+ 0xD0, 0x04, 0xFF, 0x80, 0x02, 0x14, 0x00, 0x80, 0xFD, 0x03, 0xFF, 0x80, 0x1F, 0x14, 0x00, 0x80,
+ 0xE0, 0x04, 0xFF, 0x15, 0x00, 0x80, 0xFE, 0x03, 0xFF, 0x80, 0x0B, 0x14, 0x00, 0x80, 0xF0, 0x03,
+ 0xFF, 0x80, 0x7F, 0x15, 0x00, 0x04, 0xFF, 0x80, 0x02, 0x14, 0x00, 0x80, 0xF4, 0x03, 0xFF, 0x80,
+ 0x1F, 0x14, 0x00, 0x80, 0x40, 0x03, 0xFF, 0x80, 0xBF, 0x15, 0x00, 0x80, 0xF8, 0x03, 0xFF, 0x80,
+ 0x07, 0x14, 0x00, 0x80, 0x80, 0x03, 0xFF, 0x80, 0x1F, 0x15, 0x00, 0x80, 0xFC, 0x02, 0xFF, 0x81,
+ 0xBF, 0x01, 0x14, 0x00, 0x80, 0xD0, 0x03, 0xFF, 0x80, 0x07, 0x15, 0x00, 0x80, 0xFD, 0x02, 0xFF,
+ 0x80, 0x2F, 0x15, 0x00, 0x80, 0xE0, 0x02, 0xFF, 0x81, 0xBF, 0x01, 0x15, 0x00, 0x03, 0xFF, 0x80,
+ 0x07, 0x15, 0x00, 0x80, 0xF4, 0x02, 0xFF, 0x80, 0x2F, 0x15, 0x00, 0x80, 0x40, 0x02, 0xFF, 0x80,
+ 0xBF, 0x16, 0x00, 0x80, 0xF8, 0x02, 0xFF, 0x80, 0x07, 0x15, 0x00, 0x80, 0xD0, 0x02, 0xFF, 0x80,
+ 0x1F, 0x16, 0x00, 0x82, 0xFD, 0xFF, 0xBF, 0x16, 0x00, 0x80, 0xE0, 0x02, 0xFF, 0x80, 0x02, 0x15,
+ 0x00, 0x83, 0x40, 0xFE, 0xFF, 0x0B, 0x16, 0x00, 0x82, 0xF4, 0xFF, 0x6F, 0x16, 0x00, 0x83, 0x80,
+ 0xFF, 0xBF, 0x01, 0x16, 0x00, 0x82, 0xFD, 0xFF, 0x06, 0x16, 0x00, 0x82, 0xE0, 0xFF, 0x0B, 0x16,
+ 0x00, 0x82, 0x40, 0xFE, 0x2F, 0x17, 0x00, 0x81, 0xF8, 0xBF, 0x17, 0x00, 0x82, 0x90, 0xBF, 0x01,
+ 0x17, 0x00, 0x81, 0xFE, 0x06, 0x17, 0x00, 0x81, 0xF4, 0x1B, 0x17, 0x00, 0x81, 0x80, 0x1B, 0x18,
+ 0x00, 0x80, 0x2E, 0x18, 0x00, 0x80, 0x24, 0x18, 0x00, 0x80, 0x40, 0x7F, 0x00, 0x61, 0x00, 0x82,
+ 0x40, 0x55, 0x01, 0x04, 0x00, 0x83, 0xA9, 0x01, 0x50, 0x1A, 0x0F, 0x00, 0x82, 0xFD, 0xBF, 0x16,
+ 0x03, 0x00, 0x84, 0xF9, 0xBF, 0x40, 0xFF, 0x1B, 0x0E, 0x00, 0x83, 0xD0, 0xAA, 0xFA, 0x1B, 0x02,
+ 0x00, 0x85, 0xE0, 0x56, 0x1E, 0xB9, 0xE5, 0x06, 0x0E, 0x00, 0x8A, 0x1D, 0x40, 0xE5, 0x0B, 0x00,
+ 0x40, 0x1B, 0xD0, 0xE6, 0x02, 0x78, 0x0E, 0x00, 0x8B, 0xD0, 0x01, 0x00, 0xE5, 0x06, 0x00, 0x74,
+ 0x00, 0x78, 0x1E, 0x40, 0x0B, 0x0E, 0x00, 0x80, 0x1D, 0x02, 0x00, 0x87, 0xB9, 0x00, 0x40, 0x07,
+ 0x80, 0xA7, 0x01, 0xB4, 0x0E, 0x00, 0x8B, 0xD0, 0x01, 0x00, 0x40, 0x2E, 0x00, 0xB4, 0x00, 0x6D,
+ 0x1E, 0x40, 0x0B, 0x0E, 0x00, 0x80, 0x1D, 0x02, 0x00, 0x87, 0x90, 0x07, 0x40, 0x2E, 0xE4, 0xD2,
+ 0x07, 0x7D, 0x0E, 0x00, 0x81, 0xD0, 0x01, 0x02, 0x00, 0x87, 0xB4, 0x00, 0x90, 0xFF, 0x0B, 0xF8,
+ 0xFF, 0x01, 0x0E, 0x00, 0x8A, 0x1D, 0x00, 0x01, 0x00, 0x1E, 0x00, 0xA4, 0x1A, 0x00, 0xA9, 0x06,
+ 0x0E, 0x00, 0x85, 0xD0, 0x01, 0xA0, 0x01, 0xD0, 0x03, 0x14, 0x00, 0x84, 0x1D, 0x00, 0x6E, 0x00,
+ 0x78, 0x14, 0x00, 0x85, 0xD0, 0x01, 0xE0, 0x0B, 0x40, 0x0B, 0x14, 0x00, 0x85, 0x1D, 0x00, 0xFE,
+ 0x01, 0xE0, 0x01, 0x02, 0x55, 0x86, 0x41, 0x55, 0x15, 0x40, 0x06, 0x90, 0x5A, 0x02, 0x00, 0x82,
+ 0x16, 0x50, 0x5A, 0x05, 0x00, 0x94, 0xD0, 0x01, 0xE0, 0x2E, 0x00, 0x2E, 0xE0, 0xFF, 0x2F, 0xF9,
+ 0xFF, 0x06, 0xF8, 0x86, 0xFF, 0x1B, 0x00, 0xF8, 0x46, 0xFE, 0x1B, 0x05, 0x00, 0x94, 0x1D, 0x00,
+ 0xDE, 0x07, 0xD0, 0x02, 0xAE, 0xEA, 0xD2, 0xAA, 0x7E, 0xE0, 0xBA, 0x7E, 0xE5, 0x07, 0xE0, 0xBB,
+ 0xBE, 0xE5, 0x07, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0x79, 0x00, 0x3C, 0xE0, 0x01, 0x2D, 0x1D,
+ 0x80, 0x87, 0x4F, 0xBE, 0x01, 0xB4, 0x41, 0x1F, 0xFE, 0x01, 0xF4, 0x01, 0x04, 0x00, 0x94, 0x1D,
+ 0x00, 0x5E, 0x0B, 0x80, 0x07, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x3E, 0x90, 0x06, 0x00, 0x1E, 0x7D,
+ 0x80, 0x07, 0x00, 0x2D, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xB5, 0x00, 0xB4, 0xE0, 0x01, 0x2D,
+ 0x1D, 0x80, 0xFB, 0x01, 0x14, 0x00, 0xD0, 0xF6, 0x01, 0x14, 0x00, 0x90, 0x03, 0x04, 0x00, 0x94,
+ 0x1D, 0x00, 0x1E, 0x0B, 0x40, 0x0B, 0x1E, 0xD0, 0xD2, 0x01, 0xB8, 0x0B, 0x00, 0x14, 0x00, 0xA9,
+ 0x1F, 0x00, 0x14, 0x00, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xB1, 0x01, 0xB0, 0xE0, 0x01,
+ 0x2D, 0x1D, 0x80, 0xE7, 0x01, 0x90, 0x06, 0x80, 0xE7, 0x02, 0x90, 0x0B, 0x80, 0x07, 0x04, 0x00,
+ 0x94, 0x1D, 0x00, 0x1E, 0x1A, 0x00, 0x1F, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xFB, 0x01,
+ 0x78, 0x2D, 0x40, 0xEE, 0x01, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xE1, 0x01, 0xE0, 0xE1,
+ 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04,
+ 0x00, 0x81, 0x1D, 0x00, 0x02, 0x1E, 0x80, 0x00, 0x02, 0x1E, 0x8D, 0xD0, 0xD2, 0x01, 0x78, 0x2D,
+ 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xE1,
+ 0x01, 0xE0, 0xE1, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D,
+ 0x80, 0x07, 0x04, 0x00, 0x81, 0x1D, 0x00, 0x02, 0x1E, 0x80, 0x00, 0x02, 0x1E, 0x8D, 0xD0, 0xD2,
+ 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0,
+ 0x01, 0xE0, 0xD1, 0x01, 0xD0, 0xE2, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7,
+ 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1D, 0x00, 0x2D, 0x1E, 0xD0,
+ 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95,
+ 0xD0, 0x01, 0xE0, 0xD1, 0x01, 0xD0, 0xE2, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80,
+ 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1D, 0x00, 0x2D, 0x1E,
+ 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00,
+ 0x95, 0xD0, 0x01, 0xE0, 0xD1, 0x01, 0xD0, 0xE2, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E,
+ 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1D, 0x00, 0x2D,
+ 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04,
+ 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xD1, 0x01, 0xD0, 0xE2, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74,
+ 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1D, 0x00,
+ 0x1D, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78,
+ 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xD1, 0x01, 0xE0, 0xE1, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02,
+ 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x81, 0x1D, 0x00, 0x02, 0x1E,
+ 0x80, 0x00, 0x02, 0x1E, 0x8D, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40,
+ 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xE1, 0x01, 0xE0, 0xE1, 0x01, 0x2D, 0x1D,
+ 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x81, 0x1D,
+ 0x00, 0x02, 0x1E, 0x80, 0x00, 0x02, 0x1E, 0x8D, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01,
+ 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xE1, 0x01, 0xF0, 0xE1,
+ 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04,
+ 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x1A, 0x00, 0x0B, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7,
+ 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xA1, 0x01, 0xB4,
+ 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07,
+ 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x0B, 0x40, 0x0B, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40,
+ 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0xB5, 0x00,
+ 0x78, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80,
+ 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x5E, 0x0B, 0x80, 0x07, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D,
+ 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0, 0x79,
+ 0x00, 0x3C, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D,
+ 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0xDE, 0x02, 0xD0, 0x02, 0x1E, 0xD0, 0xD2, 0x01, 0x78,
+ 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0xE0,
+ 0x2E, 0x00, 0x1E, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4,
+ 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0xFE, 0x01, 0xE0, 0x00, 0x1E, 0xD0, 0xD2, 0x01,
+ 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01,
+ 0xE0, 0x07, 0x40, 0x0B, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03,
+ 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x1D, 0x00, 0x1E, 0x00, 0x78, 0x00, 0x1E, 0xD0, 0xD2,
+ 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0,
+ 0x01, 0x60, 0x00, 0xD0, 0x02, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7,
+ 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x80, 0x1D, 0x03, 0x00, 0x90, 0x1E, 0x00, 0x1E, 0xD0,
+ 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78, 0x04, 0x00, 0x81,
+ 0xD0, 0x01, 0x02, 0x00, 0x91, 0xB4, 0x00, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02, 0x74, 0x1E,
+ 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x80, 0x1D, 0x02, 0x00, 0x91, 0xD0, 0x07,
+ 0x00, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40, 0xDB, 0x02, 0x78,
+ 0x04, 0x00, 0x95, 0xD0, 0x01, 0x00, 0x40, 0x1F, 0x00, 0xE0, 0x01, 0x2D, 0x1D, 0x80, 0xD7, 0x02,
+ 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x80, 0x1D, 0x02, 0x00, 0x80,
+ 0x7D, 0x02, 0x00, 0x8E, 0x1E, 0xD0, 0xD2, 0x01, 0x78, 0x2D, 0x40, 0xE7, 0x01, 0x78, 0x3C, 0x40,
+ 0xDB, 0x02, 0x78, 0x04, 0x00, 0x95, 0xD0, 0x01, 0x40, 0xF9, 0x01, 0x00, 0xE0, 0x01, 0x2D, 0x1D,
+ 0x80, 0xD7, 0x02, 0x74, 0x1E, 0x80, 0xC7, 0x03, 0xB4, 0x2D, 0x80, 0x07, 0x04, 0x00, 0x94, 0x6D,
+ 0x95, 0xFA, 0x06, 0x00, 0x40, 0x1A, 0xD0, 0xD2, 0x56, 0x79, 0x6D, 0x95, 0xE7, 0x56, 0x79, 0x7C,
+ 0x95, 0xDB, 0x56, 0x79, 0x04, 0x00, 0x83, 0xD0, 0xFF, 0xBF, 0x06, 0x02, 0x00, 0x8F, 0xB8, 0x00,
+ 0x2D, 0xFD, 0xFF, 0xD7, 0xFF, 0x7F, 0xFE, 0xFF, 0xC7, 0xFF, 0xBF, 0xFD, 0xFF, 0x07, 0x04, 0x00,
+ 0x02, 0x55, 0x80, 0x05, 0x02, 0x00, 0x8F, 0xE4, 0x07, 0xD0, 0x52, 0x55, 0x15, 0x54, 0x55, 0x51,
+ 0x55, 0x15, 0x54, 0x55, 0x45, 0x55, 0x15, 0x09, 0x00, 0x83, 0x40, 0x1B, 0x00, 0x2D, 0x16, 0x00,
+ 0x83, 0xB4, 0x00, 0xE0, 0x01, 0x15, 0x00, 0x83, 0x40, 0x0B, 0x40, 0x0B, 0x16, 0x00, 0x82, 0xB4,
+ 0x00, 0x7D, 0x16, 0x00, 0x83, 0x40, 0x0B, 0xF5, 0x01, 0x16, 0x00, 0x82, 0xB4, 0xE5, 0x07, 0x16,
+ 0x00, 0x82, 0x40, 0xFF, 0x1B, 0x17, 0x00, 0x81, 0xA4, 0x16, 0x5D, 0x00,
+};
+// clang-format on
diff --git a/keyboards/zhaqian/djinn/graphics/src/djinn.qgf.h b/keyboards/zhaqian/djinn/graphics/src/djinn.qgf.h
new file mode 100644
index 000000000000..aedf00126b4b
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/djinn.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i djinn.png -f mono4`
+
+#pragma once
+
+#include
+
+extern const uint32_t gfx_djinn_length;
+extern const uint8_t gfx_djinn[3724] QP_RESIDENT_FLASH;
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-caps-OFF.qgf.c b/keyboards/zhaqian/djinn/graphics/src/lock-caps-OFF.qgf.c
new file mode 100644
index 000000000000..04783f57ee6b
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-caps-OFF.qgf.c
@@ -0,0 +1,31 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-caps-OFF.png -f mono4`
+
+#include
+
+const uint32_t gfx_lock_caps_OFF_length = 288;
+
+// clang-format off
+const uint8_t gfx_lock_caps_OFF[288] QP_RESIDENT_FLASH = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x20, 0x01, 0x00, 0x00, 0xDF, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xF0, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x80, 0xFC, 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x83, 0xF0,
+ 0x03, 0x00, 0x3C, 0x04, 0x00, 0x83, 0xC0, 0x0F, 0x00, 0x3C, 0x05, 0x00, 0x82, 0x3F, 0x00, 0x3C,
+ 0x02, 0x00, 0x85, 0xF0, 0x0F, 0x00, 0xFC, 0x00, 0x3C, 0x02, 0x00, 0x85, 0xF0, 0x0F, 0x00, 0xF0,
+ 0x03, 0x3C, 0x02, 0x00, 0x85, 0xFC, 0x0F, 0x00, 0xC0, 0x0F, 0x3C, 0x02, 0x00, 0x81, 0xFC, 0x3F,
+ 0x02, 0x00, 0x81, 0x3F, 0x3C, 0x02, 0x00, 0x81, 0xFC, 0x3F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00,
+ 0x81, 0xFC, 0x3F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xFC, 0x3F, 0x02, 0x00, 0x02, 0x3C,
+ 0x02, 0x00, 0x02, 0x3F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0x3F, 0xFC, 0x02, 0x00, 0x02,
+ 0x3C, 0x02, 0x00, 0x81, 0x3F, 0xFC, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0x3F, 0xFC, 0x02,
+ 0x00, 0x02, 0x3C, 0x81, 0x00, 0xC0, 0x02, 0xFF, 0x02, 0x00, 0x02, 0x3C, 0x81, 0x00, 0xC0, 0x02,
+ 0xFF, 0x81, 0x03, 0x00, 0x02, 0x3C, 0x81, 0x00, 0xC0, 0x02, 0xFF, 0x81, 0x03, 0x00, 0x02, 0x3C,
+ 0x85, 0x00, 0xC0, 0x0F, 0xF0, 0x03, 0x00, 0x02, 0x3C, 0x85, 0x00, 0xF0, 0x0F, 0xF0, 0x03, 0x00,
+ 0x02, 0x3C, 0x85, 0x00, 0xF0, 0x0F, 0xF0, 0x0F, 0x00, 0x02, 0x3C, 0x85, 0x00, 0xF0, 0x03, 0xF0,
+ 0x0F, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C,
+ 0x06, 0x00, 0x81, 0x3C, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-caps-OFF.qgf.h b/keyboards/zhaqian/djinn/graphics/src/lock-caps-OFF.qgf.h
new file mode 100644
index 000000000000..3f4c25239457
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-caps-OFF.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-caps-OFF.png -f mono4`
+
+#pragma once
+
+#include
+
+extern const uint32_t gfx_lock_caps_OFF_length;
+extern const uint8_t gfx_lock_caps_OFF[288] QP_RESIDENT_FLASH;
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-caps-ON.qgf.c b/keyboards/zhaqian/djinn/graphics/src/lock-caps-ON.qgf.c
new file mode 100644
index 000000000000..1b88898c2805
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-caps-ON.qgf.c
@@ -0,0 +1,32 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-caps-ON.png -f mono4`
+
+#include
+
+const uint32_t gfx_lock_caps_ON_length = 291;
+
+// clang-format off
+const uint8_t gfx_lock_caps_ON[291] QP_RESIDENT_FLASH = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x23, 0x01, 0x00, 0x00, 0xDC, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xF3, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x82, 0x03, 0x00, 0xFC,
+ 0x05, 0xFF, 0x82, 0x0F, 0x00, 0xFC, 0x05, 0xFF, 0x82, 0x3F, 0x00, 0xFC, 0x02, 0xFF, 0x81, 0x0F,
+ 0xF0, 0x02, 0xFF, 0x81, 0x00, 0xFC, 0x02, 0xFF, 0x81, 0x0F, 0xF0, 0x02, 0xFF, 0x81, 0x03, 0xFC,
+ 0x02, 0xFF, 0x81, 0x03, 0xF0, 0x02, 0xFF, 0x81, 0x0F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xC0, 0x02,
+ 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xC0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF,
+ 0x81, 0x03, 0xC0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xC0, 0x02, 0xFF, 0x81,
+ 0x3F, 0xFC, 0x02, 0xFF, 0x02, 0xC0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0xC0, 0x03,
+ 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0xC0, 0x03, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02,
+ 0xFF, 0x81, 0xC0, 0x03, 0x02, 0xFF, 0x83, 0x3F, 0xFC, 0xFF, 0x3F, 0x02, 0x00, 0x02, 0xFF, 0x83,
+ 0x3F, 0xFC, 0xFF, 0x3F, 0x02, 0x00, 0x85, 0xFC, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0x02, 0x00, 0xA3,
+ 0xFC, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0xF0, 0x0F, 0xFC, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F, 0xF0, 0x0F,
+ 0xFC, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F, 0xFC, 0x0F,
+ 0xF0, 0xFF, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x80,
+ 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-caps-ON.qgf.h b/keyboards/zhaqian/djinn/graphics/src/lock-caps-ON.qgf.h
new file mode 100644
index 000000000000..7ae68256d834
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-caps-ON.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-caps-ON.png -f mono4`
+
+#pragma once
+
+#include
+
+extern const uint32_t gfx_lock_caps_ON_length;
+extern const uint8_t gfx_lock_caps_ON[291] QP_RESIDENT_FLASH;
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-num-OFF.qgf.c b/keyboards/zhaqian/djinn/graphics/src/lock-num-OFF.qgf.c
new file mode 100644
index 000000000000..220042efc6f7
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-num-OFF.qgf.c
@@ -0,0 +1,31 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-num-OFF.png -f mono4`
+
+#include
+
+const uint32_t gfx_lock_num_OFF_length = 286;
+
+// clang-format off
+const uint8_t gfx_lock_num_OFF[286] QP_RESIDENT_FLASH = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x1E, 0x01, 0x00, 0x00, 0xE1, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xEE, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x80, 0xFC, 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x83, 0xF0,
+ 0x03, 0x00, 0x3C, 0x04, 0x00, 0x83, 0xC0, 0x0F, 0x00, 0x3C, 0x05, 0x00, 0x82, 0x3F, 0x00, 0x3C,
+ 0x02, 0x00, 0x85, 0xF0, 0x0F, 0x00, 0xFC, 0x00, 0x3C, 0x02, 0x00, 0x85, 0xFC, 0x0F, 0x00, 0xF0,
+ 0x03, 0x3C, 0x02, 0x00, 0x89, 0xFF, 0x0F, 0x00, 0xC0, 0x0F, 0x3C, 0x00, 0xC0, 0xFF, 0x0F, 0x02,
+ 0x00, 0x81, 0x3F, 0x3C, 0x02, 0x00, 0x81, 0xCF, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81,
+ 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02,
+ 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02,
+ 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02,
+ 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0,
+ 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00,
+ 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C,
+ 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x0F, 0x02, 0x00,
+ 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00,
+ 0x81, 0x3C, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-num-OFF.qgf.h b/keyboards/zhaqian/djinn/graphics/src/lock-num-OFF.qgf.h
new file mode 100644
index 000000000000..678334cce126
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-num-OFF.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-num-OFF.png -f mono4`
+
+#pragma once
+
+#include
+
+extern const uint32_t gfx_lock_num_OFF_length;
+extern const uint8_t gfx_lock_num_OFF[286] QP_RESIDENT_FLASH;
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-num-ON.qgf.c b/keyboards/zhaqian/djinn/graphics/src/lock-num-ON.qgf.c
new file mode 100644
index 000000000000..9468d5263ea6
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-num-ON.qgf.c
@@ -0,0 +1,32 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-num-ON.png -f mono4`
+
+#include
+
+const uint32_t gfx_lock_num_ON_length = 302;
+
+// clang-format off
+const uint8_t gfx_lock_num_ON[302] QP_RESIDENT_FLASH = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x2E, 0x01, 0x00, 0x00, 0xD1, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xFE, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x82, 0x03, 0x00, 0xFC,
+ 0x05, 0xFF, 0x82, 0x0F, 0x00, 0xFC, 0x05, 0xFF, 0x82, 0x3F, 0x00, 0xFC, 0x02, 0xFF, 0x81, 0x0F,
+ 0xF0, 0x02, 0xFF, 0x81, 0x00, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xF0, 0x02, 0xFF, 0x81, 0x03, 0xFC,
+ 0x02, 0xFF, 0x81, 0x00, 0xF0, 0x02, 0xFF, 0x85, 0x0F, 0xFC, 0xFF, 0x3F, 0x00, 0xF0, 0x02, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x30, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81,
+ 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F,
+ 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0,
+ 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02,
+ 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81,
+ 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F,
+ 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0,
+ 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xF0, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x06,
+ 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-num-ON.qgf.h b/keyboards/zhaqian/djinn/graphics/src/lock-num-ON.qgf.h
new file mode 100644
index 000000000000..df93da062af6
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-num-ON.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-num-ON.png -f mono4`
+
+#pragma once
+
+#include
+
+extern const uint32_t gfx_lock_num_ON_length;
+extern const uint8_t gfx_lock_num_ON[302] QP_RESIDENT_FLASH;
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-scrl-OFF.qgf.c b/keyboards/zhaqian/djinn/graphics/src/lock-scrl-OFF.qgf.c
new file mode 100644
index 000000000000..537103f47fb6
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-scrl-OFF.qgf.c
@@ -0,0 +1,32 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-scrl-OFF.png -f mono4`
+
+#include
+
+const uint32_t gfx_lock_scrl_OFF_length = 292;
+
+// clang-format off
+const uint8_t gfx_lock_scrl_OFF[292] QP_RESIDENT_FLASH = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x24, 0x01, 0x00, 0x00, 0xDB, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xF4, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x80, 0xFC, 0x02, 0x00, 0x80, 0x3C, 0x04, 0x00, 0x83, 0xF0,
+ 0x03, 0x00, 0x3C, 0x04, 0x00, 0x83, 0xC0, 0x0F, 0x00, 0x3C, 0x05, 0x00, 0x82, 0x3F, 0x00, 0x3C,
+ 0x05, 0x00, 0x82, 0xFC, 0x00, 0x3C, 0x02, 0x00, 0x85, 0xC0, 0x03, 0x00, 0xF0, 0x03, 0x3C, 0x02,
+ 0x00, 0x85, 0xC0, 0x03, 0x00, 0xC0, 0x0F, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x81,
+ 0x3F, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03,
+ 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81,
+ 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02,
+ 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xC0, 0x03, 0x02, 0x00, 0x02,
+ 0x3C, 0x80, 0x00, 0x02, 0xC0, 0x02, 0x03, 0x80, 0x00, 0x02, 0x3C, 0x81, 0x00, 0xF0, 0x02, 0xC3,
+ 0x81, 0x0F, 0x00, 0x02, 0x3C, 0x85, 0x00, 0xC0, 0xCF, 0xF3, 0x03, 0x00, 0x02, 0x3C, 0x02, 0x00,
+ 0x02, 0xFF, 0x02, 0x00, 0x02, 0x3C, 0x02, 0x00, 0x81, 0xFC, 0x3F, 0x02, 0x00, 0x02, 0x3C, 0x02,
+ 0x00, 0x81, 0xF0, 0x0F, 0x02, 0x00, 0x02, 0x3C, 0x81, 0x00, 0xF0, 0x02, 0xFF, 0x81, 0x0F, 0x00,
+ 0x02, 0x3C, 0x81, 0x00, 0xF0, 0x02, 0xFF, 0x81, 0x0F, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x02, 0x3C,
+ 0x06, 0x00, 0x02, 0x3C, 0x06, 0x00, 0x81, 0x3C, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF,
+ 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-scrl-OFF.qgf.h b/keyboards/zhaqian/djinn/graphics/src/lock-scrl-OFF.qgf.h
new file mode 100644
index 000000000000..7d0fbde66ffd
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-scrl-OFF.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-scrl-OFF.png -f mono4`
+
+#pragma once
+
+#include
+
+extern const uint32_t gfx_lock_scrl_OFF_length;
+extern const uint8_t gfx_lock_scrl_OFF[292] QP_RESIDENT_FLASH;
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-scrl-ON.qgf.c b/keyboards/zhaqian/djinn/graphics/src/lock-scrl-ON.qgf.c
new file mode 100644
index 000000000000..7fe05661a097
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-scrl-ON.qgf.c
@@ -0,0 +1,32 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-scrl-ON.png -f mono4`
+
+#include
+
+const uint32_t gfx_lock_scrl_ON_length = 296;
+
+// clang-format off
+const uint8_t gfx_lock_scrl_ON[296] QP_RESIDENT_FLASH = {
+ 0x00, 0xFF, 0x12, 0x00, 0x00, 0x51, 0x47, 0x46, 0x01, 0x28, 0x01, 0x00, 0x00, 0xD7, 0xFE, 0xFF,
+ 0xFF, 0x20, 0x00, 0x20, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x02, 0xFD, 0x06, 0x00, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xE8, 0x03, 0x05, 0xFA, 0xF8, 0x00, 0x00,
+ 0x08, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x0F, 0x02, 0x00, 0x80, 0xFC, 0x04, 0xFF, 0x80, 0x3F,
+ 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x02, 0x00, 0x80, 0xFC, 0x05, 0xFF, 0x82, 0x03, 0x00, 0xFC,
+ 0x05, 0xFF, 0x82, 0x0F, 0x00, 0xFC, 0x05, 0xFF, 0x82, 0x3F, 0x00, 0xFC, 0x06, 0xFF, 0x81, 0x00,
+ 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC,
+ 0x02, 0xFF, 0x81, 0x0F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02,
+ 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81,
+ 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F,
+ 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x3F, 0xFC,
+ 0x02, 0xFF, 0x82, 0x3F, 0xFC, 0xFF, 0x02, 0x3F, 0x02, 0xFC, 0x84, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F,
+ 0x02, 0x3C, 0x8B, 0xF0, 0xFF, 0x3F, 0xFC, 0xFF, 0x3F, 0x30, 0x0C, 0xFC, 0xFF, 0x3F, 0xFC, 0x02,
+ 0xFF, 0x02, 0x00, 0x02, 0xFF, 0x81, 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x03, 0xC0, 0x02, 0xFF, 0x81,
+ 0x3F, 0xFC, 0x02, 0xFF, 0x81, 0x0F, 0xF0, 0x02, 0xFF, 0x83, 0x3F, 0xFC, 0xFF, 0x0F, 0x02, 0x00,
+ 0x85, 0xF0, 0xFF, 0x3F, 0xFC, 0xFF, 0x0F, 0x02, 0x00, 0x83, 0xF0, 0xFF, 0x3F, 0xFC, 0x06, 0xFF,
+ 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81, 0x3F, 0xFC, 0x06, 0xFF, 0x81,
+ 0x3F, 0xFC, 0x06, 0xFF, 0x80, 0x3F, 0x08, 0x00,
+};
+// clang-format on
diff --git a/keyboards/zhaqian/djinn/graphics/src/lock-scrl-ON.qgf.h b/keyboards/zhaqian/djinn/graphics/src/lock-scrl-ON.qgf.h
new file mode 100644
index 000000000000..8eb48e4a1b6d
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/lock-scrl-ON.qgf.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, image retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-graphics -i lock-scrl-ON.png -f mono4`
+
+#pragma once
+
+#include
+
+extern const uint32_t gfx_lock_scrl_ON_length;
+extern const uint8_t gfx_lock_scrl_ON[296] QP_RESIDENT_FLASH;
diff --git a/keyboards/zhaqian/djinn/graphics/src/thintel15.qff.c b/keyboards/zhaqian/djinn/graphics/src/thintel15.qff.c
new file mode 100644
index 000000000000..19016be96ff9
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/thintel15.qff.c
@@ -0,0 +1,74 @@
+// Copyright 2022 QMK -- generated source code only, font retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-font-image -i thintel15.png -f mono2`
+
+#include
+
+const uint32_t font_thintel15_length = 966;
+
+// clang-format off
+const uint8_t font_thintel15[966] QP_RESIDENT_FLASH = {
+ 0x00, 0xFF, 0x14, 0x00, 0x00, 0x51, 0x46, 0x46, 0x01, 0xC6, 0x03, 0x00, 0x00, 0x39, 0xFC, 0xFF,
+ 0xFF, 0x0B, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x01, 0xFE, 0x1D, 0x01, 0x00, 0x02, 0x00,
+ 0x00, 0xC2, 0x00, 0x00, 0x84, 0x01, 0x00, 0x06, 0x03, 0x00, 0x46, 0x05, 0x00, 0x88, 0x07, 0x00,
+ 0x46, 0x0A, 0x00, 0x82, 0x0C, 0x00, 0x43, 0x0D, 0x00, 0x83, 0x0E, 0x00, 0xC4, 0x0F, 0x00, 0x46,
+ 0x11, 0x00, 0x83, 0x13, 0x00, 0xC5, 0x14, 0x00, 0x82, 0x16, 0x00, 0x44, 0x17, 0x00, 0xC5, 0x18,
+ 0x00, 0x84, 0x1A, 0x00, 0x05, 0x1C, 0x00, 0xC5, 0x1D, 0x00, 0x85, 0x1F, 0x00, 0x45, 0x21, 0x00,
+ 0x05, 0x23, 0x00, 0xC5, 0x24, 0x00, 0x85, 0x26, 0x00, 0x45, 0x28, 0x00, 0x02, 0x2A, 0x00, 0xC3,
+ 0x2A, 0x00, 0x05, 0x2C, 0x00, 0xC5, 0x2D, 0x00, 0x85, 0x2F, 0x00, 0x45, 0x31, 0x00, 0x08, 0x33,
+ 0x00, 0xC5, 0x35, 0x00, 0x85, 0x37, 0x00, 0x45, 0x39, 0x00, 0x05, 0x3B, 0x00, 0xC4, 0x3C, 0x00,
+ 0x44, 0x3E, 0x00, 0xC5, 0x3F, 0x00, 0x85, 0x41, 0x00, 0x44, 0x43, 0x00, 0xC5, 0x44, 0x00, 0x85,
+ 0x46, 0x00, 0x44, 0x48, 0x00, 0xC6, 0x49, 0x00, 0x06, 0x4C, 0x00, 0x45, 0x4E, 0x00, 0x05, 0x50,
+ 0x00, 0xC5, 0x51, 0x00, 0x85, 0x53, 0x00, 0x45, 0x55, 0x00, 0x06, 0x57, 0x00, 0x45, 0x59, 0x00,
+ 0x06, 0x5B, 0x00, 0x46, 0x5D, 0x00, 0x86, 0x5F, 0x00, 0xC6, 0x61, 0x00, 0x06, 0x64, 0x00, 0x44,
+ 0x66, 0x00, 0xC4, 0x67, 0x00, 0x44, 0x69, 0x00, 0xC6, 0x6A, 0x00, 0x05, 0x6D, 0x00, 0xC3, 0x6E,
+ 0x00, 0x05, 0x70, 0x00, 0xC5, 0x71, 0x00, 0x84, 0x73, 0x00, 0x05, 0x75, 0x00, 0xC5, 0x76, 0x00,
+ 0x84, 0x78, 0x00, 0x05, 0x7A, 0x00, 0xC5, 0x7B, 0x00, 0x82, 0x7D, 0x00, 0x43, 0x7E, 0x00, 0x85,
+ 0x7F, 0x00, 0x42, 0x81, 0x00, 0x06, 0x82, 0x00, 0x45, 0x84, 0x00, 0x05, 0x86, 0x00, 0xC5, 0x87,
+ 0x00, 0x85, 0x89, 0x00, 0x44, 0x8B, 0x00, 0xC5, 0x8C, 0x00, 0x83, 0x8E, 0x00, 0xC5, 0x8F, 0x00,
+ 0x86, 0x91, 0x00, 0xC6, 0x93, 0x00, 0x06, 0x96, 0x00, 0x45, 0x98, 0x00, 0x04, 0x9A, 0x00, 0x85,
+ 0x9B, 0x00, 0x42, 0x9D, 0x00, 0x05, 0x9E, 0x00, 0xC5, 0x9F, 0x00, 0x04, 0xFB, 0x86, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x54, 0x45, 0x00, 0x50, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xFD, 0xD2,
+ 0xAF, 0x28, 0x00, 0x00, 0x00, 0x84, 0x53, 0x15, 0x0E, 0x55, 0x39, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x12, 0x15, 0x0A, 0x28, 0x54, 0x24, 0x00, 0x00, 0x00, 0x80, 0x50, 0x14, 0x52, 0x95, 0x58, 0x00,
+ 0x00, 0x00, 0x14, 0x00, 0x00, 0x4A, 0x92, 0x24, 0x02, 0x00, 0x91, 0x24, 0x49, 0x01, 0x00, 0x20,
+ 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x1F, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x60, 0x0A, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x24, 0x22,
+ 0x11, 0x00, 0x00, 0xC0, 0xA4, 0x94, 0x52, 0x32, 0x00, 0x00, 0x20, 0x23, 0x22, 0x72, 0x00, 0x00,
+ 0xC0, 0x24, 0x44, 0x44, 0x78, 0x00, 0x00, 0xC0, 0x24, 0x44, 0x50, 0x32, 0x00, 0x00, 0x80, 0x29,
+ 0x95, 0x1E, 0x42, 0x00, 0x00, 0xE0, 0x85, 0x83, 0x50, 0x32, 0x00, 0x00, 0xC0, 0xA4, 0x70, 0x52,
+ 0x32, 0x00, 0x00, 0xE0, 0x21, 0x42, 0x84, 0x10, 0x00, 0x00, 0xC0, 0xA4, 0x64, 0x52, 0x32, 0x00,
+ 0x00, 0xC0, 0xA4, 0xE4, 0x50, 0x32, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x30, 0x60, 0x0A, 0x00,
+ 0x00, 0x11, 0x11, 0x04, 0x41, 0x00, 0x00, 0x00, 0x80, 0x07, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x08,
+ 0x82, 0x88, 0x08, 0x00, 0x00, 0xC0, 0x24, 0x64, 0x04, 0x10, 0x00, 0x00, 0x00, 0x1C, 0x22, 0x59,
+ 0x55, 0x2D, 0x02, 0x1C, 0x00, 0x00, 0x00, 0xC0, 0xA4, 0xF4, 0x52, 0x4A, 0x00, 0x00, 0xE0, 0xA4,
+ 0x74, 0x52, 0x3A, 0x00, 0x00, 0xC0, 0xA4, 0x10, 0x42, 0x32, 0x00, 0x00, 0xE0, 0xA4, 0x94, 0x52,
+ 0x3A, 0x00, 0x00, 0x70, 0x11, 0x17, 0x71, 0x00, 0x00, 0x70, 0x11, 0x17, 0x11, 0x00, 0x00, 0xC0,
+ 0xA4, 0xD0, 0x52, 0x32, 0x00, 0x00, 0x20, 0xA5, 0xF4, 0x52, 0x4A, 0x00, 0x00, 0x70, 0x22, 0x22,
+ 0x72, 0x00, 0x00, 0xC0, 0x21, 0x84, 0x50, 0x32, 0x00, 0x00, 0x20, 0xA5, 0x32, 0x4A, 0x4A, 0x00,
+ 0x00, 0x10, 0x11, 0x11, 0x71, 0x00, 0x00, 0x40, 0xB4, 0x55, 0x51, 0x14, 0x45, 0x00, 0x00, 0x00,
+ 0x40, 0x34, 0x55, 0x59, 0x14, 0x45, 0x00, 0x00, 0x00, 0xC0, 0xA4, 0x94, 0x52, 0x32, 0x00, 0x00,
+ 0xE0, 0xA4, 0x74, 0x42, 0x08, 0x00, 0x00, 0xC0, 0xA4, 0x94, 0x52, 0x51, 0x00, 0x00, 0xE0, 0xA4,
+ 0x74, 0x52, 0x4A, 0x00, 0x00, 0xC0, 0xA4, 0x60, 0x50, 0x32, 0x00, 0x00, 0xC0, 0x47, 0x10, 0x04,
+ 0x41, 0x10, 0x00, 0x00, 0x00, 0x20, 0xA5, 0x94, 0x52, 0x32, 0x00, 0x00, 0x40, 0x14, 0x45, 0x51,
+ 0xA4, 0x10, 0x00, 0x00, 0x00, 0x40, 0x14, 0x45, 0x51, 0xB5, 0x45, 0x00, 0x00, 0x00, 0x40, 0x14,
+ 0x29, 0x84, 0x12, 0x45, 0x00, 0x00, 0x00, 0x40, 0x14, 0x45, 0x0E, 0x41, 0x10, 0x00, 0x00, 0x00,
+ 0xC0, 0x07, 0x21, 0x84, 0x10, 0x7C, 0x00, 0x00, 0x00, 0x17, 0x11, 0x11, 0x11, 0x07, 0x00, 0x10,
+ 0x21, 0x22, 0x44, 0x00, 0x00, 0x47, 0x44, 0x44, 0x44, 0x07, 0x00, 0x84, 0x12, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x93, 0x5C, 0x72, 0x00, 0x00, 0x20, 0x84, 0x93, 0x52, 0x3A, 0x00, 0x00, 0x00, 0x60,
+ 0x11, 0x61, 0x00, 0x00, 0x00, 0x21, 0x97, 0x52, 0x72, 0x00, 0x00, 0x00, 0x00, 0x93, 0x5E, 0x70,
+ 0x00, 0x00, 0x60, 0x11, 0x13, 0x11, 0x00, 0x00, 0x00, 0x00, 0x97, 0x52, 0x72, 0x28, 0x19, 0x20,
+ 0x84, 0x93, 0x52, 0x4A, 0x00, 0x00, 0x10, 0x55, 0x00, 0x80, 0x20, 0x49, 0x0A, 0x00, 0x20, 0x84,
+ 0x94, 0x4E, 0x4A, 0x00, 0x00, 0x54, 0x55, 0x00, 0x00, 0x00, 0x2C, 0x55, 0x55, 0x55, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x93, 0x52, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x93, 0x52, 0x32, 0x00, 0x00, 0x00,
+ 0x80, 0x93, 0x52, 0x3A, 0x21, 0x00, 0x00, 0x00, 0x97, 0x52, 0x72, 0x08, 0x01, 0x00, 0x50, 0x13,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0C, 0x3A, 0x00, 0x00, 0x48, 0x96, 0x44, 0x00, 0x00, 0x00,
+ 0x80, 0x94, 0x52, 0x72, 0x00, 0x00, 0x00, 0x00, 0x44, 0x51, 0xA4, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x44, 0x51, 0x54, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x0A, 0xA1, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x94, 0x52, 0x72, 0x28, 0x19, 0x00, 0x70, 0x24, 0x71, 0x00, 0x00, 0x4C, 0x08,
+ 0x11, 0x84, 0x10, 0x0C, 0x00, 0x55, 0x55, 0x01, 0x83, 0x10, 0x82, 0x08, 0x21, 0x03, 0x00, 0x00,
+ 0x00, 0xB0, 0x1A, 0x00, 0x00, 0x00,
+};
+// clang-format on
diff --git a/keyboards/zhaqian/djinn/graphics/src/thintel15.qff.h b/keyboards/zhaqian/djinn/graphics/src/thintel15.qff.h
new file mode 100644
index 000000000000..ddcc718d5d7e
--- /dev/null
+++ b/keyboards/zhaqian/djinn/graphics/src/thintel15.qff.h
@@ -0,0 +1,11 @@
+// Copyright 2022 QMK -- generated source code only, font retains original copyright
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file was auto-generated by `qmk painter-convert-font-image -i thintel15.png -f mono2`
+
+#pragma once
+
+#include
+
+extern const uint32_t font_thintel15_length;
+extern const uint8_t font_thintel15[966] QP_RESIDENT_FLASH;
diff --git a/keyboards/zhaqian/djinn/halconf.h b/keyboards/zhaqian/djinn/halconf.h
new file mode 100644
index 000000000000..eb6c740f16b3
--- /dev/null
+++ b/keyboards/zhaqian/djinn/halconf.h
@@ -0,0 +1,38 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#define HAL_USE_GPT TRUE
+#define HAL_USE_PWM TRUE
+#define HAL_USE_SPI TRUE
+
+#define SERIAL_BUFFERS_SIZE 256
+
+// This enables interrupt-driven moe
+#define PAL_USE_WAIT TRUE
+
+#if defined(SERIAL_DRIVER_USART) || defined(SERIAL_DRIVER_USART_DUPLEX_ALT)
+#define HAL_USE_SERIAL TRUE
+#endif // defined(SERIAL_DRIVER_USART) || defined(SERIAL_DRIVER_USART_DUPLEX_ALT)
+
+#if defined(SERIAL_DRIVER_USART_DUPLEX)
+#define HAL_USE_UART TRUE
+#define UART_USE_WAIT TRUE
+#endif // defined(SERIAL_DRIVER_USART_DUPLEX)
+
+#include_next
+
diff --git a/keyboards/zhaqian/djinn/keymaps/default/config.h b/keyboards/zhaqian/djinn/keymaps/default/config.h
new file mode 100644
index 000000000000..1616bfca0cbf
--- /dev/null
+++ b/keyboards/zhaqian/djinn/keymaps/default/config.h
@@ -0,0 +1,34 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+// 1000Hz poll rate
+#define USB_POLLING_INTERVAL_MS 1
+
+// Encoder settings
+#define ENCODER_RESOLUTION 2
+
+// LCD blanking period
+#define LCD_ACTIVITY_TIMEOUT 30000
+
+// RGB settings
+#define RGBLIGHT_ANIMATIONS
+#define RGB_MATRIX_KEYPRESSES
+#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
+
+// Allow for an extra sync command over the split
+#define SPLIT_TRANSACTION_IDS_USER USER_DATA_SYNC
diff --git a/keyboards/zhaqian/djinn/keymaps/default/keymap.c b/keyboards/zhaqian/djinn/keymaps/default/keymap.c
new file mode 100644
index 000000000000..0651935754de
--- /dev/null
+++ b/keyboards/zhaqian/djinn/keymaps/default/keymap.c
@@ -0,0 +1,252 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include QMK_KEYBOARD_H
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MEDIA_KEY_DELAY 5
+
+// Layer definitions
+enum { _QWERTY, _LOWER, _RAISE, _ADJUST };
+
+#define KC_LWR MO(_LOWER)
+#define KC_RSE MO(_RAISE)
+
+// clang-format off
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [_QWERTY] = LAYOUT_all(
+ KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_GRV, KC_DEL, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_LBRC, KC_RBRC, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLS,
+ KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_HOME, KC_PGUP, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_END, KC_PGDN, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT,
+ KC_LGUI, KC_LWR, KC_SPC, KC_NO, KC_NO, KC_SPC, KC_RSE, KC_LALT,
+ RGB_RMOD, RGB_MOD,
+ KC_UP, KC_UP,
+ KC_LEFT, _______, KC_RIGHT, KC_LEFT, _______, KC_RIGHT,
+ KC_DOWN, KC_DOWN
+ ),
+ [_LOWER] = LAYOUT_all(
+ KC_F12, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, _______, _______, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
+ _______, _______, KC_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, KC_LEFT, KC_DOWN, KC_RIGHT,_______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______,
+ BL_DEC, BL_INC,
+ _______, _______,
+ _______, _______, _______, _______, _______, _______,
+ _______, _______
+ ),
+ [_RAISE] = LAYOUT_all(
+ KC_F12, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, _______, _______, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
+ _______,_______, KC_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______,KC_LEFT, KC_DOWN, KC_RIGHT, _______, KC_UNDS, KC_NO, KC_NO, KC_EQL, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, KC_MINS, KC_NO, KC_NO, KC_PLUS, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______,
+ _______, _______,
+ _______, _______, _______, _______, _______, _______,
+ _______, _______
+ ),
+ [_ADJUST] = LAYOUT_all(
+ _______, KC_CLCK, KC_NLCK, KC_SLCK, _______, _______, _______, _______, _______, _______, _______, DEBUG, EEP_RST, RESET,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______,
+ _______, _______,
+ _______, _______, _______, _______, _______, _______,
+ _______, _______
+ )
+};
+// clang-format on
+
+layer_state_t layer_state_set_user(layer_state_t state) {
+ // Default handler for lower/raise/adjust
+ return update_tri_layer_state(state, _LOWER, _RAISE, _ADJUST);
+}
+
+#ifdef ENCODER_MAP_ENABLE
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
+ [_QWERTY] = {ENCODER_CCW_CW(KC_MS_WH_UP, KC_MS_WH_DOWN), ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
+ [_LOWER] = {ENCODER_CCW_CW(RGB_HUD, RGB_HUI), ENCODER_CCW_CW(RGB_SAD, RGB_SAI)},
+ [_RAISE] = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI), ENCODER_CCW_CW(RGB_SPD, RGB_SPI)},
+ [_ADJUST] = {ENCODER_CCW_CW(RGB_RMOD, RGB_MOD), ENCODER_CCW_CW(KC_LEFT, KC_RIGHT)},
+};
+#else
+bool encoder_update_user(uint8_t index, bool clockwise) {
+ uint8_t temp_mod = get_mods();
+ uint8_t temp_osm = get_oneshot_mods();
+ bool is_ctrl = (temp_mod | temp_osm) & MOD_MASK_CTRL;
+ bool is_shift = (temp_mod | temp_osm) & MOD_MASK_SHIFT;
+
+ if (is_shift) {
+ if (index == 0) { /* First encoder */
+ if (clockwise) {
+ rgblight_increase_hue();
+ } else {
+ rgblight_decrease_hue();
+ }
+ } else if (index == 1) { /* Second encoder */
+ if (clockwise) {
+ rgblight_decrease_sat();
+ } else {
+ rgblight_increase_sat();
+ }
+ }
+ } else if (is_ctrl) {
+ if (index == 0) { /* First encoder */
+ if (clockwise) {
+ rgblight_increase_val();
+ } else {
+ rgblight_decrease_val();
+ }
+ } else if (index == 1) { /* Second encoder */
+ if (clockwise) {
+ rgblight_increase_speed();
+ } else {
+ rgblight_decrease_speed();
+ }
+ }
+ } else {
+ if (index == 0) { /* First encoder */
+ if (clockwise) {
+ tap_code16(KC_MS_WH_DOWN);
+ } else {
+ tap_code16(KC_MS_WH_UP);
+ }
+ } else if (index == 1) { /* Second encoder */
+ if (clockwise) {
+ tap_code_delay(KC_VOLU, MEDIA_KEY_DELAY);
+ } else {
+ tap_code_delay(KC_VOLD, MEDIA_KEY_DELAY);
+ }
+ }
+ }
+ return false;
+}
+#endif
+
+// clang-format off
+#ifdef SWAP_HANDS_ENABLE
+const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
+ { { 6, 6 }, { 5, 6 }, { 4, 6 }, { 3, 6 }, { 2, 6 }, { 1, 6 }, { 0, 6 } },
+ { { 6, 7 }, { 5, 7 }, { 4, 7 }, { 3, 7 }, { 2, 7 }, { 1, 7 }, { 0, 7 } },
+ { { 6, 8 }, { 5, 8 }, { 4, 8 }, { 3, 8 }, { 2, 8 }, { 1, 8 }, { 0, 8 } },
+ { { 6, 9 }, { 5, 9 }, { 4, 9 }, { 3, 9 }, { 2, 9 }, { 1, 9 }, { 0, 9 } },
+ { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 6, 10 }, { 5, 10 }, { 4, 10 }, { 3, 10 } },
+ { { 0, 0 }, { 6, 11 }, { 5, 11 }, { 4, 11 }, { 3, 11 }, { 2, 11 }, { 1, 11 } },
+
+ { { 6, 0 }, { 5, 0 }, { 4, 0 }, { 3, 0 }, { 2, 0 }, { 1, 0 }, { 0, 0 } },
+ { { 6, 1 }, { 5, 1 }, { 4, 1 }, { 3, 1 }, { 2, 1 }, { 1, 1 }, { 0, 1 } },
+ { { 6, 2 }, { 5, 2 }, { 4, 2 }, { 3, 2 }, { 2, 2 }, { 1, 2 }, { 0, 2 } },
+ { { 6, 3 }, { 5, 3 }, { 4, 3 }, { 3, 3 }, { 2, 3 }, { 1, 3 }, { 0, 3 } },
+ { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 6, 4 }, { 5, 4 }, { 4, 4 }, { 3, 4 } },
+ { { 0, 0 }, { 6, 5 }, { 5, 5 }, { 4, 5 }, { 3, 5 }, { 2, 5 }, { 1, 5 } },
+};
+# ifdef ENCODER_MAP_ENABLE
+const uint8_t PROGMEM encoder_hand_swap_config[NUM_ENCODERS] = { 1, 0 };
+# endif
+#endif
+// clang-format on
+
+//----------------------------------------------------------
+// Sync
+#pragma pack(push)
+#pragma pack(1)
+
+typedef struct user_runtime_config {
+ uint32_t scan_rate;
+} user_runtime_config;
+
+#pragma pack(pop)
+
+_Static_assert(sizeof(user_runtime_config) == 4, "Invalid data transfer size for user sync data");
+
+user_runtime_config user_state;
+
+void rpc_user_sync_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
+ if (initiator2target_buffer_size == sizeof(user_state)) {
+ memcpy(&user_state, initiator2target_buffer, sizeof(user_runtime_config));
+ }
+}
+
+void keyboard_post_init_user(void) {
+ // Register keyboard state sync split transaction
+ transaction_register_rpc(USER_DATA_SYNC, rpc_user_sync_callback);
+
+ // Reset the initial shared data value between master and slave
+ memset(&user_state, 0, sizeof(user_state));
+
+ void keyboard_post_init_display(void);
+ keyboard_post_init_display();
+}
+
+void user_state_update(void) {
+ if (is_keyboard_master()) {
+ // Keep the scan rate in sync
+ user_state.scan_rate = get_matrix_scan_rate();
+ }
+}
+
+void user_state_sync(void) {
+ if (!is_transport_connected()) return;
+
+ if (is_keyboard_master()) {
+ // Keep track of the last state, so that we can tell if we need to propagate to slave
+ static user_runtime_config last_user_state;
+ static uint32_t last_sync;
+ bool needs_sync = false;
+
+ // Check if the state values are different
+ if (memcmp(&user_state, &last_user_state, sizeof(user_runtime_config))) {
+ needs_sync = true;
+ memcpy(&last_user_state, &user_state, sizeof(user_runtime_config));
+ }
+
+ // Send to slave every 125ms regardless of state change
+ if (timer_elapsed32(last_sync) > 125) {
+ needs_sync = true;
+ }
+
+ // Perform the sync if requested
+ if (needs_sync) {
+ if (transaction_rpc_send(USER_DATA_SYNC, sizeof(user_runtime_config), &user_state)) {
+ last_sync = timer_read32();
+ }
+ }
+ }
+}
+
+void housekeeping_task_user(void) {
+ // Update kb_state so we can send to slave
+ user_state_update();
+
+ // Data sync from master to slave
+ user_state_sync();
+}
+
+//----------------------------------------------------------
+// Display
+#include "theme_djinn.inl.c"
+//#include "theme_hf.inl.c"
diff --git a/keyboards/zhaqian/djinn/keymaps/default/rules.mk b/keyboards/zhaqian/djinn/keymaps/default/rules.mk
new file mode 100644
index 000000000000..9938915589d9
--- /dev/null
+++ b/keyboards/zhaqian/djinn/keymaps/default/rules.mk
@@ -0,0 +1 @@
+DEBUG_MATRIX_SCAN_RATE_ENABLE ?= api
diff --git a/keyboards/zhaqian/djinn/keymaps/default/theme_djinn.inl.c b/keyboards/zhaqian/djinn/keymaps/default/theme_djinn.inl.c
new file mode 100644
index 000000000000..117d0e23c836
--- /dev/null
+++ b/keyboards/zhaqian/djinn/keymaps/default/theme_djinn.inl.c
@@ -0,0 +1,256 @@
+#include "graphics/src/djinn.qgf.c"
+#include "graphics/src/lock-caps-ON.qgf.c"
+#include "graphics/src/lock-scrl-ON.qgf.c"
+#include "graphics/src/lock-num-ON.qgf.c"
+#include "graphics/src/lock-caps-OFF.qgf.c"
+#include "graphics/src/lock-scrl-OFF.qgf.c"
+#include "graphics/src/lock-num-OFF.qgf.c"
+#include "graphics/src/thintel15.qff.c"
+
+static painter_image_handle_t djinn_logo;
+static painter_image_handle_t lock_caps_on;
+static painter_image_handle_t lock_caps_off;
+static painter_image_handle_t lock_num_on;
+static painter_image_handle_t lock_num_off;
+static painter_image_handle_t lock_scrl_on;
+static painter_image_handle_t lock_scrl_off;
+static painter_font_handle_t thintel;
+
+//----------------------------------------------------------
+// RGB Matrix naming
+#include
+
+#if defined(RGB_MATRIX_EFFECT)
+# undef RGB_MATRIX_EFFECT
+#endif // defined(RGB_MATRIX_EFFECT)
+
+#define RGB_MATRIX_EFFECT(x) RGB_MATRIX_EFFECT_##x,
+enum {
+ RGB_MATRIX_EFFECT_NONE,
+#include "rgb_matrix_effects.inc"
+#undef RGB_MATRIX_EFFECT
+#ifdef RGB_MATRIX_CUSTOM_KB
+# include "rgb_matrix_kb.inc"
+#endif
+#ifdef RGB_MATRIX_CUSTOM_USER
+# include "rgb_matrix_user.inc"
+#endif
+};
+
+#define RGB_MATRIX_EFFECT(x) \
+ case RGB_MATRIX_EFFECT_##x: \
+ return #x;
+const char *rgb_matrix_name(uint8_t effect) {
+ switch (effect) {
+ case RGB_MATRIX_EFFECT_NONE:
+ return "NONE";
+#include "rgb_matrix_effects.inc"
+#undef RGB_MATRIX_EFFECT
+#ifdef RGB_MATRIX_CUSTOM_KB
+# include "rgb_matrix_kb.inc"
+#endif
+#ifdef RGB_MATRIX_CUSTOM_USER
+# include "rgb_matrix_user.inc"
+#endif
+ default:
+ return "UNKNOWN";
+ }
+}
+
+//----------------------------------------------------------
+// UI Initialisation
+void keyboard_post_init_display(void) {
+ djinn_logo = qp_load_image_mem(gfx_djinn);
+ lock_caps_on = qp_load_image_mem(gfx_lock_caps_ON);
+ lock_caps_off = qp_load_image_mem(gfx_lock_caps_OFF);
+ lock_num_on = qp_load_image_mem(gfx_lock_num_ON);
+ lock_num_off = qp_load_image_mem(gfx_lock_num_OFF);
+ lock_scrl_on = qp_load_image_mem(gfx_lock_scrl_ON);
+ lock_scrl_off = qp_load_image_mem(gfx_lock_scrl_OFF);
+ thintel = qp_load_font_mem(font_thintel15);
+}
+
+//----------------------------------------------------------
+// UI Drawing
+void draw_ui_user(void) {
+ bool hue_redraw = false;
+ static uint16_t last_hue = 0xFFFF;
+ uint8_t curr_hue = rgblight_get_hue();
+ if (last_hue != curr_hue) {
+ last_hue = curr_hue;
+ hue_redraw = true;
+ }
+
+ bool layer_state_redraw = false;
+ static uint32_t last_layer_state = 0;
+ if (last_layer_state != layer_state) {
+ last_layer_state = layer_state;
+ layer_state_redraw = true;
+ }
+
+ bool power_state_redraw = false;
+ static usbpd_allowance_t last_current_state = (usbpd_allowance_t)(~0);
+ if (last_current_state != kb_state.current_setting) {
+ last_current_state = kb_state.current_setting;
+ power_state_redraw = true;
+ }
+
+ bool scan_redraw = false;
+ static uint32_t last_scan_update = 0;
+ if (timer_elapsed32(last_scan_update) > 125) {
+ last_scan_update = timer_read32();
+ scan_redraw = true;
+ }
+
+ bool wpm_redraw = false;
+ static uint32_t last_wpm_update = 0;
+ if (timer_elapsed32(last_wpm_update) > 125) {
+ last_wpm_update = timer_read32();
+ wpm_redraw = true;
+ }
+
+#if defined(RGB_MATRIX_ENABLE)
+ bool rgb_effect_redraw = false;
+ static uint16_t last_effect = 0xFFFF;
+ uint8_t curr_effect = rgb_matrix_config.mode;
+ if (last_effect != curr_effect) {
+ last_effect = curr_effect;
+ rgb_effect_redraw = true;
+ }
+#endif // defined(RGB_MATRIX_ENABLE)
+
+ // Show the Djinn logo and two vertical bars on both sides
+ if (hue_redraw) {
+ qp_drawimage_recolor(lcd, 120 - djinn_logo->width / 2, 32, djinn_logo, curr_hue, 255, 255, curr_hue, 255, 0);
+ qp_rect(lcd, 0, 0, 8, 319, curr_hue, 255, 255, true);
+ qp_rect(lcd, 231, 0, 239, 319, curr_hue, 255, 255, true);
+ }
+
+ int ypos = 4;
+
+ // Show layer info on the left side
+ if (is_keyboard_left()) {
+ char buf[32] = {0};
+ int xpos = 16;
+
+#if defined(RGB_MATRIX_ENABLE)
+ if (hue_redraw || rgb_effect_redraw) {
+ static int max_rgb_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "rgb: %s", rgb_matrix_name(curr_effect));
+
+ for (int i = 5; i < sizeof(buf); ++i) {
+ if (buf[i] == 0)
+ break;
+ else if (buf[i] == '_')
+ buf[i] = ' ';
+ else if (buf[i - 1] == ' ')
+ buf[i] = toupper(buf[i]);
+ else if (buf[i - 1] != ' ')
+ buf[i] = tolower(buf[i]);
+ }
+
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_rgb_xpos < xpos) {
+ max_rgb_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_rgb_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+#endif // defined(RGB_MATRIX_ENABLE)
+
+ if (hue_redraw || layer_state_redraw) {
+ const char *layer_name = "unknown";
+ switch (get_highest_layer(layer_state)) {
+ case _QWERTY:
+ layer_name = "qwerty";
+ break;
+ case _LOWER:
+ layer_name = "lower";
+ break;
+ case _RAISE:
+ layer_name = "raise";
+ break;
+ case _ADJUST:
+ layer_name = "adjust";
+ break;
+ }
+
+ static int max_layer_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "layer: %s", layer_name);
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_layer_xpos < xpos) {
+ max_layer_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_layer_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+
+ if (hue_redraw || power_state_redraw) {
+ static int max_power_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "power: %s", usbpd_str(kb_state.current_setting));
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_power_xpos < xpos) {
+ max_power_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_power_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+
+ if (hue_redraw || scan_redraw) {
+ static int max_scans_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "scans: %d", (int)user_state.scan_rate);
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_scans_xpos < xpos) {
+ max_scans_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_scans_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+
+ if (hue_redraw || wpm_redraw) {
+ static int max_wpm_xpos = 0;
+ xpos = 16;
+ snprintf_(buf, sizeof(buf), "wpm: %d", (int)get_current_wpm());
+ xpos += qp_drawtext_recolor(lcd, xpos, ypos, thintel, buf, curr_hue, 255, 255, curr_hue, 255, 0);
+ if (max_wpm_xpos < xpos) {
+ max_wpm_xpos = xpos;
+ }
+ qp_rect(lcd, xpos, ypos, max_wpm_xpos, ypos + thintel->line_height, 0, 0, 0, true);
+ }
+
+ ypos += thintel->line_height + 4;
+ }
+
+ // Show LED lock indicators on the right side
+ if (!is_keyboard_left()) {
+ static led_t last_led_state = {0};
+ if (hue_redraw || last_led_state.raw != host_keyboard_led_state().raw) {
+ last_led_state.raw = host_keyboard_led_state().raw;
+ qp_drawimage_recolor(lcd, 239 - 12 - (32 * 3), 0, last_led_state.caps_lock ? lock_caps_on : lock_caps_off, curr_hue, 255, last_led_state.caps_lock ? 255 : 32, curr_hue, 255, 0);
+ qp_drawimage_recolor(lcd, 239 - 12 - (32 * 2), 0, last_led_state.num_lock ? lock_num_on : lock_num_off, curr_hue, 255, last_led_state.num_lock ? 255 : 32, curr_hue, 255, 0);
+ qp_drawimage_recolor(lcd, 239 - 12 - (32 * 1), 0, last_led_state.scroll_lock ? lock_scrl_on : lock_scrl_off, curr_hue, 255, last_led_state.scroll_lock ? 255 : 32, curr_hue, 255, 0);
+ }
+ }
+
+#if 0
+ // Test code
+ if (redraw_required) {
+ qp_line(lcd, 8, 0, 32, 319, curr_hue, 255, 255);
+ qp_line(lcd, 32, 0, 8, 319, curr_hue, 255, 255);
+ for (int i = 0; i < 8; ++i) qp_circle(lcd, 20, (i * 40) + 20, 10, curr_hue, 255, 255, (i % 2) == 0);
+ qp_drawtext(lcd, 0, 0, font_noto16, "So this is a test of font rendering");
+ qp_drawtext_recolor(lcd, 0, font_noto16->line_height, font_noto16, "with Quantum Painter...", 0, 255, 255, 0, 255, 0);
+ qp_drawtext_recolor(lcd, 0, 2 * font_noto16->line_height, font_noto16, "Perhaps a different background?", 43, 255, 255, 169, 255, 255);
+ qp_drawtext(lcd, 0, 3 * font_noto16->line_height, font_noto28, "Unicode: ĄȽɂɻɣɈʣ");
+ qp_drawtext(lcd, 0, 3 * font_noto16->line_height + font_noto28->line_height, thintel, "And here we are, with another font!");
+ }
+#endif
+}
\ No newline at end of file
diff --git a/keyboards/zhaqian/djinn/mcuconf.h b/keyboards/zhaqian/djinn/mcuconf.h
new file mode 100644
index 000000000000..3732d09e6ca2
--- /dev/null
+++ b/keyboards/zhaqian/djinn/mcuconf.h
@@ -0,0 +1,53 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include_next
+
+// Used for audio
+#undef STM32_PWM_USE_TIM1
+#undef STM32_GPT_USE_TIM6
+#undef STM32_GPT_USE_TIM7
+#undef STM32_GPT_USE_TIM8
+#define STM32_PWM_USE_TIM1 TRUE
+#define STM32_GPT_USE_TIM6 TRUE
+#define STM32_GPT_USE_TIM7 TRUE
+#define STM32_GPT_USE_TIM8 TRUE
+
+// Used for backlight
+#undef STM32_PWM_USE_TIM17
+#define STM32_PWM_USE_TIM17 TRUE
+
+// Used for SK6812 chain
+#undef STM32_PWM_USE_TIM20
+#define STM32_PWM_USE_TIM20 TRUE
+
+// Used for split comms
+#if defined(SERIAL_DRIVER_USART) || defined(SERIAL_DRIVER_USART_DUPLEX_ALT)
+#undef STM32_SERIAL_USE_USART3
+#define STM32_SERIAL_USE_USART3 TRUE
+#endif // defined(SERIAL_DRIVER_USART) || defined(SERIAL_DRIVER_USART_DUPLEX_ALT)
+
+#if defined(SERIAL_DRIVER_USART_DUPLEX)
+#undef STM32_UART_USE_USART3
+#define STM32_UART_USE_USART3 TRUE
+#endif // defined(SERIAL_DRIVER_USART_DUPLEX)
+
+// Used for EEPROM
+#undef STM32_SPI_USE_SPI3
+#define STM32_SPI_USE_SPI3 TRUE
+
diff --git a/keyboards/zhaqian/djinn/post_rules.mk b/keyboards/zhaqian/djinn/post_rules.mk
new file mode 100644
index 000000000000..14d30d47c926
--- /dev/null
+++ b/keyboards/zhaqian/djinn/post_rules.mk
@@ -0,0 +1,5 @@
+ifeq ($(strip $(DEBUG_BUILD)), yes)
+ LTO_ENABLE = no
+ OPT = g
+ OPT_DEFS += -g
+endif
diff --git a/keyboards/zhaqian/djinn/rev1/config.h b/keyboards/zhaqian/djinn/rev1/config.h
new file mode 100644
index 000000000000..92bcd4f2d48b
--- /dev/null
+++ b/keyboards/zhaqian/djinn/rev1/config.h
@@ -0,0 +1,38 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+// Split configuration
+#define SERIAL_USART_DRIVER SD3
+#define SERIAL_USART_TX_PAL_MODE 7
+#define SOFT_SERIAL_PIN B9
+#define SERIAL_USART_SPEED 640000
+#define SPLIT_HAND_PIN B11
+
+// RGB configuration
+#define RGB_POWER_ENABLE_PIN B1
+#define RGB_CURR_1500mA_OK_PIN B0
+#define RGB_CURR_3000mA_OK_PIN C5
+#define RGBLED_NUM 84
+#define RGBLED_SPLIT \
+ { 42, 42 }
+
+// EEPROM configuration
+#define EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN B5
+#define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR 32
+#define EXTERNAL_EEPROM_BYTE_COUNT 4096
+#define EXTERNAL_EEPROM_PAGE_SIZE 64
diff --git a/keyboards/zhaqian/djinn/rev1/rev1.c b/keyboards/zhaqian/djinn/rev1/rev1.c
new file mode 100644
index 000000000000..c5ec8bd48676
--- /dev/null
+++ b/keyboards/zhaqian/djinn/rev1/rev1.c
@@ -0,0 +1,102 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include "rev1.h"
+
+#ifdef USE_PLUG_DETECT_PIN
+bool is_keyboard_master(void) {
+ static bool determined = false;
+ static bool is_master;
+ if (!determined) {
+ determined = true;
+ setPinInputLow(SPLIT_PLUG_DETECT_PIN);
+ wait_ms(50);
+ is_master = readPin(SPLIT_PLUG_DETECT_PIN) ? true : false;
+ if (!is_master) {
+ usbStop(&USBD1);
+ }
+ }
+
+ return is_master;
+}
+#endif // USE_PLUG_DETECT_PIN
+
+#ifdef RGB_MATRIX_ENABLE
+// clang-format off
+#define RLO 42
+#define LLI(x) (x)
+#define LLP(x,y) {(x),(y)}
+#define RLI(x) (RLO+(x))
+#define RLP(x,y) {(224-(x)),((y))}
+led_config_t g_led_config = {
+ {
+ // Key Matrix to LED Index
+ { LLI(35), LLI(36), LLI(37), LLI(38), LLI(39), LLI(40), LLI(41) },
+ { LLI(34), LLI(33), LLI(32), LLI(31), LLI(30), LLI(29), LLI(28) },
+ { LLI(21), LLI(22), LLI(23), LLI(24), LLI(25), LLI(26), LLI(27) },
+ { LLI(20), LLI(19), LLI(18), LLI(17), LLI(16), LLI(15), LLI(14) },
+ { NO_LED, NO_LED, NO_LED, LLI(10), LLI(11), LLI(12), LLI(13) },
+ { NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, },
+ { RLI(35), RLI(36), RLI(37), RLI(38), RLI(39), RLI(40), RLI(41) },
+ { RLI(34), RLI(33), RLI(32), RLI(31), RLI(30), RLI(29), RLI(28) },
+ { RLI(21), RLI(22), RLI(23), RLI(24), RLI(25), RLI(26), RLI(27) },
+ { RLI(20), RLI(19), RLI(18), RLI(17), RLI(16), RLI(15), RLI(14) },
+ { NO_LED, NO_LED, NO_LED, RLI(10), RLI(11), RLI(12), RLI(13) },
+ { NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, },
+ },
+ {
+ // LED Index to Physical Position
+ // Underglow left
+ LLP(110, 30), LLP(110, 80), LLP(110, 130), LLP(95, 180), LLP(75, 195), LLP(60, 210), LLP(45, 190), LLP(35, 175), LLP(20, 160), LLP(5, 160),
+ // Matrix left
+ LLP( 78, 150), LLP(104, 150), LLP(130, 150), LLP(156, 150),
+ LLP(156, 120), LLP(130, 120), LLP(104, 120), LLP( 78, 120), LLP( 52, 120), LLP( 26, 120), LLP( 0, 120),
+ LLP( 0, 90), LLP( 26, 90), LLP( 52, 90), LLP( 78, 90), LLP(104, 90), LLP(130, 90), LLP(156, 90),
+ LLP(156, 60), LLP(130, 60), LLP(104, 60), LLP( 78, 60), LLP( 52, 60), LLP( 26, 60), LLP( 0, 60),
+ LLP( 0, 30), LLP( 26, 30), LLP( 52, 30), LLP( 78, 30), LLP(104, 30), LLP(130, 30), LLP(156, 30),
+ // Underglow right
+ RLP(110, 30), RLP(110, 80), RLP(110, 130), RLP(95, 180), RLP(75, 195), RLP(60, 210), RLP(45, 190), RLP(35, 175), RLP(20, 160), RLP(5, 160),
+ // Matrix right
+ RLP( 78, 150), RLP(104, 150), RLP(130, 150), RLP(156, 150),
+ RLP(156, 120), RLP(130, 120), RLP(104, 120), RLP( 78, 120), RLP( 52, 120), RLP( 26, 120), RLP( 0, 120),
+ RLP( 0, 90), RLP( 26, 90), RLP( 52, 90), RLP( 78, 90), RLP(104, 90), RLP(130, 90), RLP(156, 90),
+ RLP(156, 60), RLP(130, 60), RLP(104, 60), RLP( 78, 60), RLP( 52, 60), RLP( 26, 60), RLP( 0, 60),
+ RLP( 0, 30), RLP( 26, 30), RLP( 52, 30), RLP( 78, 30), RLP(104, 30), RLP(130, 30), RLP(156, 30),
+ },
+ {
+ // LED Index to Flag
+ // Underglow left
+ LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW,
+ // Matrix left
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ // Underglow right
+ LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW,
+ // Matrix right
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ }
+};
+// clang-format on
+#endif // RGB_MATRIX_ENABLE
diff --git a/keyboards/zhaqian/djinn/rev1/rev1.h b/keyboards/zhaqian/djinn/rev1/rev1.h
new file mode 100644
index 000000000000..f4fa5ed40158
--- /dev/null
+++ b/keyboards/zhaqian/djinn/rev1/rev1.h
@@ -0,0 +1,17 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
diff --git a/keyboards/zhaqian/djinn/rev1/rules.mk b/keyboards/zhaqian/djinn/rev1/rules.mk
new file mode 100644
index 000000000000..c6e298832137
--- /dev/null
+++ b/keyboards/zhaqian/djinn/rev1/rules.mk
@@ -0,0 +1 @@
+SERIAL_DRIVER = usart
diff --git a/keyboards/zhaqian/djinn/rev2/config.h b/keyboards/zhaqian/djinn/rev2/config.h
new file mode 100644
index 000000000000..cd24d9bf54d3
--- /dev/null
+++ b/keyboards/zhaqian/djinn/rev2/config.h
@@ -0,0 +1,60 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+// Split configuration
+#define SPLIT_HAND_PIN B9
+
+#if defined(SERIAL_DRIVER_USART)
+# define SERIAL_USART_DRIVER SD3
+# define SERIAL_USART_PIN_SWAP
+# define SERIAL_USART_TX_PIN B10
+# define SERIAL_USART_TX_PAL_MODE 7
+# define SERIAL_USART_RX_PIN B11
+# define SERIAL_USART_RX_PAL_MODE 7
+# ifndef SERIAL_USART_SPEED
+# define SERIAL_USART_SPEED 1200000
+# endif // SERIAL_USART_SPEED
+# define SERIAL_USART_FULL_DUPLEX
+#endif // defined(SERIAL_DRIVER_USART)
+
+// RGB configuration
+#define RGB_POWER_ENABLE_PIN B0
+#define RGB_CURR_1500mA_OK_PIN C5
+#define RGB_CURR_3000mA_OK_PIN C4
+#define RGBLED_NUM 86
+#define RGBLED_SPLIT \
+ { 43, 43 }
+
+// EEPROM configuration
+#define EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN B5
+#define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR 8 // (160MHz/8) => 20MHz
+#define EXTERNAL_EEPROM_BYTE_COUNT 8192
+#define EXTERNAL_EEPROM_PAGE_SIZE 64 // it's FRAM, so it doesn't actually matter, this just sets the RAM buffer
+
+// External flash config
+#define EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN A8
+#define EXTERNAL_FLASH_SPI_CLOCK_DIVISOR 8 // (160MHz/8) => 20MHz
+#define EXTERNAL_FLASH_BYTE_COUNT (4 * 1024 * 1024) // 32Mb/4MB capacity
+#define EXTERNAL_FLASH_PAGE_SIZE (4 * 1024) // 4kB pages
+
+// Fault indicators
+#define BOARD_POWER_FAULT_PIN C9
+#define RGB_POWER_FAULT_PIN C4
+
+// Limit the backlight brightness
+#define BACKLIGHT_LIMIT_VAL 144
\ No newline at end of file
diff --git a/keyboards/zhaqian/djinn/rev2/rev2.c b/keyboards/zhaqian/djinn/rev2/rev2.c
new file mode 100644
index 000000000000..dc95255ab643
--- /dev/null
+++ b/keyboards/zhaqian/djinn/rev2/rev2.c
@@ -0,0 +1,105 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include "rev2.h"
+
+// Delays can be shorter than 30us.
+void matrix_io_delay(void) {
+ for (int i = 0; i < 10; ++i) __asm__ volatile("nop\nnop\nnop\n");
+}
+
+bool is_keyboard_master(void) {
+ static bool determined = false;
+ static bool is_master;
+ if (!determined) {
+ determined = true;
+ setPinInput(SPLIT_PLUG_DETECT_PIN);
+ wait_ms(50);
+ is_master = readPin(SPLIT_PLUG_DETECT_PIN) ? true : false;
+ if (!is_master) {
+ usbStop(&USBD1);
+ }
+ }
+
+ return is_master;
+}
+
+#ifdef RGB_MATRIX_ENABLE
+// clang-format off
+#define RLO 43
+#define LLI(x) (x)
+#define LLP(x,y) {(x),(y)}
+#define RLI(x) (RLO+(x))
+#define RLP(x,y) {(224-(x)),((y))}
+led_config_t g_led_config = {
+ {
+ // Key Matrix to LED Index
+ { LLI(36), LLI(37), LLI(38), LLI(39), LLI(40), LLI(41), LLI(42) },
+ { LLI(35), LLI(34), LLI(33), LLI(32), LLI(31), LLI(30), LLI(29) },
+ { LLI(22), LLI(23), LLI(24), LLI(25), LLI(26), LLI(27), LLI(28) },
+ { LLI(21), LLI(20), LLI(19), LLI(18), LLI(17), LLI(16), LLI(15) },
+ { NO_LED, NO_LED, NO_LED, LLI(11), LLI(12), LLI(13), LLI(14) },
+ { NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, },
+ { RLI(36), RLI(37), RLI(38), RLI(39), RLI(40), RLI(41), RLI(42) },
+ { RLI(35), RLI(34), RLI(33), RLI(32), RLI(31), RLI(30), RLI(29) },
+ { RLI(22), RLI(23), RLI(24), RLI(25), RLI(26), RLI(27), RLI(28) },
+ { RLI(21), RLI(20), RLI(19), RLI(18), RLI(17), RLI(16), RLI(15) },
+ { NO_LED, NO_LED, NO_LED, RLI(11), RLI(12), RLI(13), RLI(14) },
+ { NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, },
+ },
+ {
+ // LED Index to Physical Position
+ // Underglow left
+ LLP(110, 30), LLP(110, 80), LLP(110, 130), LLP(95, 180), LLP(75, 195), LLP(60, 210), LLP(45, 190), LLP(35, 175), LLP(20, 160), LLP(5, 160), LLP(5, 160),
+ // Matrix left
+ LLP( 78, 150), LLP(104, 150), LLP(130, 150), LLP(156, 150),
+ LLP(156, 120), LLP(130, 120), LLP(104, 120), LLP( 78, 120), LLP( 52, 120), LLP( 26, 120), LLP( 0, 120),
+ LLP( 0, 90), LLP( 26, 90), LLP( 52, 90), LLP( 78, 90), LLP(104, 90), LLP(130, 90), LLP(156, 90),
+ LLP(156, 60), LLP(130, 60), LLP(104, 60), LLP( 78, 60), LLP( 52, 60), LLP( 26, 60), LLP( 0, 60),
+ LLP( 0, 30), LLP( 26, 30), LLP( 52, 30), LLP( 78, 30), LLP(104, 30), LLP(130, 30), LLP(156, 30),
+ // Underglow right
+ RLP(110, 30), RLP(110, 80), RLP(110, 130), RLP(95, 180), RLP(75, 195), RLP(60, 210), RLP(45, 190), RLP(35, 175), RLP(20, 160), RLP(5, 160), RLP(5, 160),
+ // Matrix right
+ RLP( 78, 150), RLP(104, 150), RLP(130, 150), RLP(156, 150),
+ RLP(156, 120), RLP(130, 120), RLP(104, 120), RLP( 78, 120), RLP( 52, 120), RLP( 26, 120), RLP( 0, 120),
+ RLP( 0, 90), RLP( 26, 90), RLP( 52, 90), RLP( 78, 90), RLP(104, 90), RLP(130, 90), RLP(156, 90),
+ RLP(156, 60), RLP(130, 60), RLP(104, 60), RLP( 78, 60), RLP( 52, 60), RLP( 26, 60), RLP( 0, 60),
+ RLP( 0, 30), RLP( 26, 30), RLP( 52, 30), RLP( 78, 30), RLP(104, 30), RLP(130, 30), RLP(156, 30),
+ },
+ {
+ // LED Index to Flag
+ // Underglow left
+ LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW,
+ // Matrix left
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ // Underglow right
+ LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW,
+ // Matrix right
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ }
+};
+// clang-format on
+#endif // RGB_MATRIX_ENABLE
diff --git a/keyboards/zhaqian/djinn/rev2/rev2.h b/keyboards/zhaqian/djinn/rev2/rev2.h
new file mode 100644
index 000000000000..f4fa5ed40158
--- /dev/null
+++ b/keyboards/zhaqian/djinn/rev2/rev2.h
@@ -0,0 +1,17 @@
+/* Copyright 2021 Nick Brassel (@tzarc)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
diff --git a/keyboards/zhaqian/djinn/rev2/rules.mk b/keyboards/zhaqian/djinn/rev2/rules.mk
new file mode 100644
index 000000000000..c6e298832137
--- /dev/null
+++ b/keyboards/zhaqian/djinn/rev2/rules.mk
@@ -0,0 +1 @@
+SERIAL_DRIVER = usart
diff --git a/keyboards/zhaqian/djinn/rules.mk b/keyboards/zhaqian/djinn/rules.mk
new file mode 100644
index 000000000000..781167367969
--- /dev/null
+++ b/keyboards/zhaqian/djinn/rules.mk
@@ -0,0 +1,45 @@
+MCU = STM32G474
+
+BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration
+MOUSEKEY_ENABLE = no # Mouse keys
+EXTRAKEY_ENABLE = yes # Audio control and System control
+CONSOLE_ENABLE = no # Console for debug
+COMMAND_ENABLE = no # Commands for debug and configuration
+SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
+NKRO_ENABLE = no # USB Nkey Rollover
+UNICODE_ENABLE = no # Unicode
+WPM_ENABLE = yes
+
+SPLIT_KEYBOARD = yes
+
+ENCODER_ENABLE = yes
+
+USBPD_ENABLE = yes
+
+BACKLIGHT_ENABLE = yes
+BACKLIGHT_DRIVER = pwm
+
+WS2812_DRIVER = pwm
+CIE1931_CURVE = yes
+
+RGBLIGHT_ENABLE = no
+RGBLIGHT_DRIVER = WS2812
+
+RGB_MATRIX_ENABLE = yes
+RGB_MATRIX_DRIVER = WS2812
+
+EEPROM_DRIVER = spi
+
+AUDIO_ENABLE = yes
+AUDIO_DRIVER = pwm_software
+AUDIO_PIN = A5
+AUDIO_PIN_ALT = A4
+
+QUANTUM_PAINTER_ENABLE = yes
+QUANTUM_PAINTER_DRIVERS = ili9341_spi
+
+USE_FPU = yes
+LTO_ENABLE = yes
+OPT = 2
+
+DEFAULT_FOLDER = tzarc/djinn/rev2
\ No newline at end of file
diff --git a/keyboards/zhaqian/gmmkjellyred/config.h b/keyboards/zhaqian/gmmkjellyred/config.h
new file mode 100644
index 000000000000..a76ad2c3be31
--- /dev/null
+++ b/keyboards/zhaqian/gmmkjellyred/config.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include "config_common.h"
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID 0xFEED
+#define PRODUCT_ID 0x4C88
+#define DEVICE_VER 0x0001
+#define MANUFACTURER Glorious
+#define PRODUCT GmmkPro_Jelly
+
+/* key matrix size */
+#define MATRIX_ROWS 6
+#define MATRIX_COLS 15
+
+/* key matrix pins */
+#define MATRIX_ROW_PINS { F7, F6, F5, F4, F1, F0 }
+#define MATRIX_COL_PINS { B4, B5, B6, C6, C7, E6, B0, B1, D0, D1, D2, D3, D5, D4, D6 }
+#define UNUSED_PINS
+
+/* COL2ROW or ROW2COL */
+#define DIODE_DIRECTION COL2ROW
+#define DEBOUNCE 5
+
+/* number of backlight levels */
+#define LED_CAPS_LOCK_PIN B7
+#define LED_PIN_ON_STATE 0
+
+/* prevent stuck modifiers */
+#define PREVENT_STUCK_MODIFIERS
+
+#define RGB_DI_PIN D7
+#define RGBLIGHT_ANIMATIONS
+#define RGBLED_NUM 16
+#define RGBLIGHT_LED_MAP { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }
+
+#ifdef RGB_MATRIX_ENABLE
+#define RGB_DI_PIN D7
+#define RGBLED_NUM 16
+#define DRIVER_LED_TOTAL RGBLED_NUM
+#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200
+#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_MATRIX_ANIMATION
+#endif
+
+/* Capslock
+const rgblight_segment_t PROGMEM my_capslock_layer[] = RGBLIGHT_LAYER_SEGMENTS(
+ {1, 1, HSV_RED}
+);
+*/
+
+/* 编码器 */
+#define ENCODERS_PAD_A { B2 }
+#define ENCODERS_PAD_B { B3 }
+#define ENCODER_RESOLUTION 2
+#define TAP_CODE_DELAY 10
diff --git a/keyboards/zhaqian/gmmkjellyred/gmmkjellyred.c b/keyboards/zhaqian/gmmkjellyred/gmmkjellyred.c
new file mode 100644
index 000000000000..facc3a47e470
--- /dev/null
+++ b/keyboards/zhaqian/gmmkjellyred/gmmkjellyred.c
@@ -0,0 +1,32 @@
+#include "gmmkjellyred.h"
+
+#ifdef RGB_MATRIX_ENABLE
+led_config_t g_led_config = {
+ {
+ {NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED },
+ {NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED },
+ {NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED },
+ {NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED },
+ {NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED },
+ {NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED }
+ }, {
+ {112, 63}, {112, 54}, {112, 45}, {112, 36}, {112, 27}, {112, 18}, {112, 9}, {112, 0},
+ {112, 0}, {112, 9}, {112, 18}, {112, 27}, {112, 36}, {112, 45}, {112, 54}, {112, 63}
+ }, {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
+ }
+};
+
+#endif
+
+#ifdef RGB_DISABLE_WHEN_USB_SUSPENDED
+void suspend_power_down_kb(void) {
+ rgb_matrix_set_suspend_state(true);
+ suspend_power_down_user();
+}
+
+void suspend_wakeup_init_kb(void) {
+ rgb_matrix_set_suspend_state(false);
+ suspend_wakeup_init_user();
+}
+#endif
diff --git a/keyboards/zhaqian/gmmkjellyred/gmmkjellyred.h b/keyboards/zhaqian/gmmkjellyred/gmmkjellyred.h
new file mode 100644
index 000000000000..c4cf8adb230f
--- /dev/null
+++ b/keyboards/zhaqian/gmmkjellyred/gmmkjellyred.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#define XXX KC_NO
+
+#include "quantum.h"
+
+#define LAYOUT_all( \
+ K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, K0E, \
+ K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, K1E, \
+ K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, K2E, \
+ K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3E, \
+ K40, K41, K42, K43, K44, K45, K46, K47, K48, K49, K4A, K4B, K4D, K4E, \
+ K50, K51, K52, K55, K59, K5A, K5B, K5C, K5D, K5E \
+){ \
+ {K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, K0E }, \
+ {K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, K1E }, \
+ {K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, K2E }, \
+ {K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, XXX, K3E }, \
+ {K40, K41, K42, K43, K44, K45, K46, K47, K48, K49, K4A, K4B, XXX, K4D, K4E }, \
+ {K50, K51, K52, XXX, XXX, K55, XXX, XXX, XXX, K59, K5A, K5B, K5C, K5D, K5E } \
+}
+
+/* K000, K001, K002, K003, K004, K005, K006, K007, K008, K009, K010, K011, K012, K013, K014, \
+ K100, K101, K102, K103, K104, K105, K106, K107, K108, K109, K110, K111, K112, K113, K114, \
+ K200, K201, K202, K203, K204, K205, K206, K207, K208, K209, K210, K211, K212, K213, K214, \
+ K300, K301, K302, K303, K304, K305, K306, K307, K308, K309, K310, K311, K312, K314, \
+ K400, K401, K402, K403, K404, K405, K406, K407, K408, K409, K410, K411, K413, K414, \
+ K500, K501, K502, K505, K509, K510, K511, K512, K513, K514 \
+) { \
+ { K000, K001, K002, K003, K004, K005, K006, K007, K008, K009, K010, K011, K012, K013, K014 }, \
+ { K100, K101, K102, K103, K104, K105, K106, K107, K108, K109, K110, K111, K112, K113, K114 }, \
+ { K200, K201, K202, K203, K204, K205, K206, K207, K208, K209, K210, K211, K212, K213, K214 }, \
+ { K300, K301, K302, K303, K304, K305, K306, K307, K308, K309, K310, K311, K312, KC_NO, K314 }, \
+ { K400, K401, K402, K403, K404, K405, K406, K407, K408, K409, K410, K411, KC_NO, K413, K414 }, \
+ { K500, K501, K502, KC_NO, KC_NO, K505, KC_NO, KC_NO, KC_NO, K509, K510, K511, K512, K513, K514 } \
+}
+*/
diff --git a/keyboards/zhaqian/gmmkjellyred/keymaps/default/keymap.c b/keyboards/zhaqian/gmmkjellyred/keymaps/default/keymap.c
new file mode 100644
index 000000000000..6054d9f3ea32
--- /dev/null
+++ b/keyboards/zhaqian/gmmkjellyred/keymaps/default/keymap.c
@@ -0,0 +1,39 @@
+#include QMK_KEYBOARD_H
+
+enum layer_names {
+ _BASE,
+ _FN
+};
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+ [_BASE] = LAYOUT_all(
+ KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_MUTE,
+ KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_HOME,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_END,
+ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGUP,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN,
+ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
+ ),
+[_FN] = LAYOUT_all(
+ RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, RGB_TOG, RGB_VAD, RGB_VAI, RGB_HUD, RGB_HUI, RGB_SAD, RGB_SAI, RGB_RMOD, RGB_MOD, RGB_SPD, RGB_SPI, RGB_M_P, _______, _______,
+ _______, BL_TOGG, BL_STEP, BL_DEC, BL_INC, BL_BRTG, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, MO(_FN), _______, _______, _______, _______
+ )
+};
+
+
+/* #ifdef ENCODER_ENABLE */
+bool encoder_update_user(uint8_t index, bool clockwise) {
+ if (index == 0) {
+ if (clockwise) {
+ tap_code(KC_VOLU);
+ } else {
+ tap_code(KC_VOLD);
+ }
+ }
+ return true;
+}
diff --git a/keyboards/zhaqian/gmmkjellyred/rules.mk b/keyboards/zhaqian/gmmkjellyred/rules.mk
new file mode 100644
index 000000000000..44985bc8b82e
--- /dev/null
+++ b/keyboards/zhaqian/gmmkjellyred/rules.mk
@@ -0,0 +1,22 @@
+# MCU name
+MCU = atmega32u4
+
+# Bootloader selection
+BOOTLOADER = atmel-dfu
+
+# Build Options
+# comment out to disable the options.
+#
+BOOTMAGIC_ENABLE = yes
+MOUSEKEY_ENABLE = yes
+EXTRAKEY_ENABLE = yes
+CONSOLE_ENABLE = no
+COMMAND_ENABLE = no
+SLEEP_LED_ENABLE = no
+NKRO_ENABLE = yes
+BACKLIGHT_ENABLE = no
+RGBLIGHT_ENABLE = no
+RGB_MATRIX_ENABLE = yes
+RGB_MATRIX_DRIVER = WS2812
+ENCODER_ENABLE = yes
+VIA_ENABLE = yes
diff --git a/keyboards/zhaqian/tester/l433/halconf.h b/keyboards/zhaqian/tester/l433/halconf.h
new file mode 100644
index 000000000000..aeba543aafe5
--- /dev/null
+++ b/keyboards/zhaqian/tester/l433/halconf.h
@@ -0,0 +1,21 @@
+/* Copyright 2020 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+// #define HAL_USE_PWM TRUE
+
+#include_next
diff --git a/keyboards/zhaqian/tester/l433/mcuconf.h b/keyboards/zhaqian/tester/l433/mcuconf.h
new file mode 100644
index 000000000000..25ef9ac1a419
--- /dev/null
+++ b/keyboards/zhaqian/tester/l433/mcuconf.h
@@ -0,0 +1,25 @@
+/* Copyright 2020 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include_next
+
+// #undef STM32_PWM_USE_TIM2
+// #define STM32_PWM_USE_TIM2 TRUE
+
+// #undef STM32_ST_USE_TIMER
+// #define STM32_ST_USE_TIMER 3
diff --git a/keyboards/zhaqian/tester/tester.json b/keyboards/zhaqian/tester/tester.json
new file mode 100644
index 000000000000..4c5c51152c4b
--- /dev/null
+++ b/keyboards/zhaqian/tester/tester.json
@@ -0,0 +1,75 @@
+{
+ "name": "tester",
+ "vendorProductId": 11184646,
+ "macros": ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""],
+ "layers": [
+ [
+ "KC_A",
+ "KC_A",
+ "MT(MOD_LSFT | MOD_LGUI | MOD_RSFT | MOD_RGUI,KC_MAIL)",
+ "MT(MOD_LSFT | MOD_LGUI | MOD_RSFT | MOD_RGUI,KC_CALC)",
+ "KC_SPC",
+ "KC_SPC",
+ "KC_SPC",
+ "KC_SPC",
+ "KC_SPC",
+ "RGB_VAI",
+ "KC_SPC",
+ "KC_SPC",
+ "KC_SPC",
+ "KC_SPC",
+ "RGB_VAD"
+ ],
+ [
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS"
+ ],
+ [
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS"
+ ],
+ [
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS",
+ "KC_TRNS"
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/keyboards/zhaqian/zq68/config.h b/keyboards/zhaqian/zq68/config.h
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/keymaps/default/keymap.c b/keyboards/zhaqian/zq68/keymaps/default/keymap.c
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/keymaps/default/rgb_matrix_kb.inc b/keyboards/zhaqian/zq68/keymaps/default/rgb_matrix_kb.inc
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/keymaps/default/rules.mk b/keyboards/zhaqian/zq68/keymaps/default/rules.mk
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/keymaps/via/keymap.c b/keyboards/zhaqian/zq68/keymaps/via/keymap.c
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/keymaps/via/rules.mk b/keyboards/zhaqian/zq68/keymaps/via/rules.mk
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/readme.md b/keyboards/zhaqian/zq68/readme.md
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/rules.mk b/keyboards/zhaqian/zq68/rules.mk
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/zq68.c b/keyboards/zhaqian/zq68/zq68.c
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/zq68.h b/keyboards/zhaqian/zq68/zq68.h
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zq68/zq68_via.json b/keyboards/zhaqian/zq68/zq68_via.json
old mode 100644
new mode 100755
diff --git a/keyboards/zhaqian/zqlib/radial_controller/radial_controller_encoder.c b/keyboards/zhaqian/zqlib/radial_controller/radial_controller_encoder.c
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/keyboards/zhaqian/zqlib/radial_controller/radial_controller_encoder.h b/keyboards/zhaqian/zqlib/radial_controller/radial_controller_encoder.h
new file mode 100644
index 000000000000..3686ae81b27b
--- /dev/null
+++ b/keyboards/zhaqian/zqlib/radial_controller/radial_controller_encoder.h
@@ -0,0 +1,35 @@
+/* Copyright 2022 zhaqian
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include "quantum.h"
+
+typedef union {
+ uint16_t raw;
+ struct __attribute__ ((packed)) {
+ uint16_t button : 1;
+ int16_t dial : 15;
+ };
+} report_radial_controller_t;
+
+void radial_controller_task(void);
+void host_radial_controller_send(uint16_t report);
+void radial_controller_event_finished(void);
+void radial_controller_button_update(bool pressed);
+void radial_controller_dial_update(bool clockwise, bool continued);
+void radial_controller_dial_finished(void);
+bool process_radial_controller(const uint16_t keycode, const keyrecord_t *record);
diff --git a/keyboards/zhaqian/zqlib/radial_controller/radial_controller_switch.c b/keyboards/zhaqian/zqlib/radial_controller/radial_controller_switch.c
new file mode 100644
index 000000000000..7eb1ca4c8f79
--- /dev/null
+++ b/keyboards/zhaqian/zqlib/radial_controller/radial_controller_switch.c
@@ -0,0 +1,146 @@
+/* Copyright 2022 zhaqian
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "radial_controller_switch.h"
+#include "report.h"
+#include "host.h"
+
+// support encoder and switches
+#ifndef RADIAL_CONTROLLER_RESOLUTION
+#define RADIAL_CONTROLLER_RESOLUTION 100
+#endif
+
+#ifndef RADIAL_CONTROLLER_ROTATION_STEP
+#define RADIAL_CONTROLLER_ROTATION_STEP 10
+#endif
+
+#ifndef RADIAL_CONTROLLER_TIMER_DELAY
+#define RADIAL_CONTROLLER_TIMER_DELAY 15
+#endif
+
+#ifndef RADIAL_CONTROLLER_ROTATION_CONTINUE_STEP
+#define RADIAL_CONTROLLER_ROTATION_CONTINUE_STEP RADIAL_CONTROLLER_RESOLUTION
+#endif
+
+report_radial_controller_t radial_controller_report;
+
+static int16_t radial_controller_rotation = 0;
+static bool is_radial_controller_rotate_finished = true;
+static bool is_clockwise = true;
+static uint16_t radial_controller_timer = 0;
+
+void radial_controller_task(void) {
+ if (!is_radial_controller_rotate_finished) {
+ if (timer_elapsed(radial_controller_timer) > RADIAL_CONTROLLER_TIMER_DELAY) {
+ if (is_clockwise) {
+ radial_controller_rotation = radial_controller_rotation > (3600 - RADIAL_CONTROLLER_ROTATION_STEP) ? \
+ 3600 : radial_controller_rotation + RADIAL_CONTROLLER_ROTATION_STEP;
+ } else {
+ radial_controller_rotation = radial_controller_rotation < (-(3600 - RADIAL_CONTROLLER_ROTATION_STEP)) ? \
+ -3600 : radial_controller_rotation - RADIAL_CONTROLLER_ROTATION_STEP;
+ }
+ radial_controller_timer = timer_read();
+#ifdef RADIAL_CONTROLLER_ROTATION_CONTINUE_BUTTON_ENABLE
+ if (radial_controller_rotation >= RADIAL_CONTROLLER_ROTATION_CONTINUE_STEP \
+ || radial_controller_rotation <= -RADIAL_CONTROLLER_ROTATION_CONTINUE_STEP) {
+ radial_controller_dial_finished();
+ is_radial_controller_rotate_finished = false;
+ }
+#endif
+ }
+ }
+}
+
+void host_radial_controller_send(uint16_t report) {
+ if (!host_get_driver()) return;
+ (host_get_driver()->send_radial)(report);
+}
+
+void radial_controller_event_finished(void) {
+ radial_controller_report.raw = 0;
+ host_radial_controller_send(radial_controller_report.raw);
+}
+
+void radial_controller_button_update(bool pressed) {
+ if (pressed) {
+ radial_controller_report.button = 1;
+ } else {
+ radial_controller_report.raw = 0;
+ }
+ host_radial_controller_send(radial_controller_report.raw);
+}
+
+void radial_controller_dial_update(bool clockwise, bool continued) {
+ if (!continued) {
+ if (clockwise) {
+ radial_controller_report.dial = RADIAL_CONTROLLER_RESOLUTION;
+ } else {
+ radial_controller_report.dial = -RADIAL_CONTROLLER_RESOLUTION;
+ }
+ host_radial_controller_send(radial_controller_report.raw);
+ radial_controller_report.dial = 0;
+ } else {
+ is_clockwise = clockwise;
+ is_radial_controller_rotate_finished = false;
+ radial_controller_timer = timer_read();
+ }
+}
+
+void radial_controller_dial_finished(void) {
+ is_radial_controller_rotate_finished = true;
+ radial_controller_report.dial = radial_controller_rotation;
+ host_radial_controller_send(radial_controller_report.raw);
+ radial_controller_report.dial = 0;
+ radial_controller_rotation = 0;
+ radial_controller_timer = 0;
+}
+
+bool process_radial_controller(const uint16_t keycode, const keyrecord_t *record) {
+ switch (keycode) {
+ case DIAL_BUT:
+ if (record->event.pressed) {
+ radial_controller_button_update(true);
+ } else {
+ radial_controller_button_update(false);
+ }
+ return false;
+ case DIAL_L:
+ if (record->event.pressed) {
+ radial_controller_dial_update(false, false);
+ }
+ return false;
+ case DIAL_R:
+ if (record->event.pressed) {
+ radial_controller_dial_update(true, false);
+ }
+ return false;
+ case DIAL_LC:
+ if (record->event.pressed) {
+ radial_controller_dial_update(false, true);
+ } else {
+ radial_controller_dial_finished();
+ }
+ return false;
+ case DIAL_RC:
+ if (record->event.pressed) {
+ radial_controller_dial_update(true, true);
+ } else {
+ radial_controller_dial_finished();
+ }
+ return false;
+ }
+ return true;
+}
diff --git a/keyboards/zhaqian/zqlib/radial_controller/radial_controller_switch.h b/keyboards/zhaqian/zqlib/radial_controller/radial_controller_switch.h
new file mode 100644
index 000000000000..3686ae81b27b
--- /dev/null
+++ b/keyboards/zhaqian/zqlib/radial_controller/radial_controller_switch.h
@@ -0,0 +1,35 @@
+/* Copyright 2022 zhaqian
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include "quantum.h"
+
+typedef union {
+ uint16_t raw;
+ struct __attribute__ ((packed)) {
+ uint16_t button : 1;
+ int16_t dial : 15;
+ };
+} report_radial_controller_t;
+
+void radial_controller_task(void);
+void host_radial_controller_send(uint16_t report);
+void radial_controller_event_finished(void);
+void radial_controller_button_update(bool pressed);
+void radial_controller_dial_update(bool clockwise, bool continued);
+void radial_controller_dial_finished(void);
+bool process_radial_controller(const uint16_t keycode, const keyrecord_t *record);
diff --git a/keyboards/zhaqian/zqlib/st7789/st7789.c b/keyboards/zhaqian/zqlib/st7789/st7789.c
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/keyboards/zhaqian/zqlib/st7789/st7789.h b/keyboards/zhaqian/zqlib/st7789/st7789.h
new file mode 100644
index 000000000000..96e41e9713e2
--- /dev/null
+++ b/keyboards/zhaqian/zqlib/st7789/st7789.h
@@ -0,0 +1,121 @@
+/* Copyright 2022 zhaqian
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+
+#include "spi_master.h"
+
+#ifndef ST7789_SCL_PIN
+# define ST7789_SCL_PIN B13
+#endif
+
+#ifndef ST7789_SDA_PIN
+# define ST7789_SDA_PIN B15
+#endif
+
+#ifndef ST7789_RES_PIN
+# define ST7789_RES_PIN B0
+#endif
+
+#ifndef ST7789_DC_PIN
+# define ST7789_DC_PIN B1
+#endif
+
+#ifndef ST7789_CS_PIN
+# define ST7789_CS_PIN B12
+#endif
+
+#ifndef ST7789_BLK_PIN
+# define ST7789_BLK_PIN B4
+#endif
+
+#define SPI_SCK_PIN ST7789_SCL_PIN
+
+#define SPI_MOSI_PIN ST7789_SDA_PIN
+
+#ifndef ST7789_DISPLAY_WIDTH
+# define ST7789_DISPLAY_WIDTH 240
+#endif
+
+#ifndef ST7789_DISPLAY_HEIGHT
+# define ST7789_DISPLAY_HEIGHT 135
+#endif
+
+#ifndef ST7789_MATRIX_SIZE
+# define ST7789_MATRIX_SIZE (ST7789_DISPLAY_HEIGHT / 15 * ST7789_DISPLAY_WIDTH) // 9 * 240
+#endif
+
+#ifndef ST7789_BLOCK_TYPE
+# define ST7789_BLOCK_TYPE uint16_t
+#endif
+
+#ifndef ST7789_BLOCK_COUNT
+# define ST7789_BLOCK_COUNT (sizeof(ST7565_BLOCK_TYPE) * 8) // 32 (compile time mathed)
+#endif
+
+#ifndef ST7789_BLOCK_SIZE
+# define ST7789_BLOCK_SIZE (ST7565_MATRIX_SIZE / ST7565_BLOCK_COUNT) // 32 (compile time mathed)
+#endif
+
+// the column address corresponding to the first column in the display hardware
+#if !defined(ST7565_COLUMN_OFFSET)
+# define ST7565_COLUMN_OFFSET 0
+#endif
+
+// spi clock divisor
+#if !defined(ST7565_SPI_CLK_DIVISOR)
+# define ST7565_SPI_CLK_DIVISOR 4
+#endif
+
+// Custom font file to use
+#if !defined(ST7565_FONT_H)
+# define ST7565_FONT_H "glcdfont.c"
+#endif
+// unsigned char value of the first character in the font file
+#if !defined(ST7565_FONT_START)
+# define ST7565_FONT_START 0
+#endif
+// unsigned char value of the last character in the font file
+#if !defined(ST7565_FONT_END)
+# define ST7565_FONT_END 223
+#endif
+// Font render width
+#if !defined(ST7565_FONT_WIDTH)
+# define ST7565_FONT_WIDTH 6
+#endif
+// Font render height
+#if !defined(ST7565_FONT_HEIGHT)
+# define ST7565_FONT_HEIGHT 8
+#endif
+// Default contrast level
+#if !defined(ST7565_CONTRAST)
+# define ST7565_CONTRAST 32
+#endif
+
+#if !defined(ST7565_TIMEOUT)
+# if defined(ST7565_DISABLE_TIMEOUT)
+# define ST7565_TIMEOUT 0
+# else
+# define ST7565_TIMEOUT 60000
+# endif
+#endif
+
+#if !defined(ST7565_UPDATE_INTERVAL) && defined(SPLIT_KEYBOARD)
+# define ST7565_UPDATE_INTERVAL 50
+#endif
diff --git a/lib/RTT/SEGGER_RTT.c b/lib/RTT/SEGGER_RTT.c
new file mode 100644
index 000000000000..d76c7eb5bf2a
--- /dev/null
+++ b/lib/RTT/SEGGER_RTT.c
@@ -0,0 +1,1704 @@
+/*********************************************************************
+* SEGGER Microcontroller GmbH *
+* The Embedded Experts *
+**********************************************************************
+* *
+* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
+* *
+* www.segger.com Support: support@segger.com *
+* *
+**********************************************************************
+* *
+* SEGGER RTT * Real Time Transfer for embedded targets *
+* *
+**********************************************************************
+* *
+* All rights reserved. *
+* *
+* SEGGER strongly recommends to not make any changes *
+* to or modify the source code of this software in order to stay *
+* compatible with the RTT protocol and J-Link. *
+* *
+* Redistribution and use in source and binary forms, with or *
+* without modification, are permitted provided that the following *
+* conditions are met: *
+* *
+* o Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* *
+* o Redistributions in binary form must reproduce the above *
+* copyright notice, this list of conditions and the following *
+* disclaimer in the documentation and/or other materials provided *
+* with the distribution. *
+* *
+* o Neither the name of SEGGER Microcontroller GmbH *
+* nor the names of its contributors may be used to endorse or *
+* promote products derived from this software without specific *
+* prior written permission. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
+* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
+* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
+* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
+* DAMAGE. *
+* *
+**********************************************************************
+* *
+* RTT version: 6.46c *
+* *
+**********************************************************************
+---------------------------END-OF-HEADER------------------------------
+File : SEGGER_RTT.c
+Purpose : Implementation of SEGGER real-time transfer (RTT) which
+ allows real-time communication on targets which support
+ debugger memory accesses while the CPU is running.
+Revision: $Rev: 14765 $
+
+Additional information:
+ Type "int" is assumed to be 32-bits in size
+ H->T Host to target communication
+ T->H Target to host communication
+
+ RTT channel 0 is always present and reserved for Terminal usage.
+ Name is fixed to "Terminal"
+
+ Effective buffer size: SizeOfBuffer - 1
+
+ WrOff == RdOff: Buffer is empty
+ WrOff == (RdOff - 1): Buffer is full
+ WrOff > RdOff: Free space includes wrap-around
+ WrOff < RdOff: Used space includes wrap-around
+ (WrOff == (SizeOfBuffer - 1)) && (RdOff == 0):
+ Buffer full and wrap-around after next byte
+
+
+----------------------------------------------------------------------
+*/
+
+#include "SEGGER_RTT.h"
+
+#include // for memcpy
+
+/*********************************************************************
+*
+* Configuration, default values
+*
+**********************************************************************
+*/
+
+#ifndef BUFFER_SIZE_UP
+ #define BUFFER_SIZE_UP 1024 // Size of the buffer for terminal output of target, up to host
+#endif
+
+#ifndef BUFFER_SIZE_DOWN
+ #define BUFFER_SIZE_DOWN 16 // Size of the buffer for terminal input to target from host (Usually keyboard input)
+#endif
+
+#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS
+ #define SEGGER_RTT_MAX_NUM_UP_BUFFERS 2 // Number of up-buffers (T->H) available on this target
+#endif
+
+#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS
+ #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS 2 // Number of down-buffers (H->T) available on this target
+#endif
+
+#ifndef SEGGER_RTT_BUFFER_SECTION
+ #if defined(SEGGER_RTT_SECTION)
+ #define SEGGER_RTT_BUFFER_SECTION SEGGER_RTT_SECTION
+ #endif
+#endif
+
+#ifndef SEGGER_RTT_ALIGNMENT
+ #define SEGGER_RTT_ALIGNMENT 0
+#endif
+
+#ifndef SEGGER_RTT_BUFFER_ALIGNMENT
+ #define SEGGER_RTT_BUFFER_ALIGNMENT 0
+#endif
+
+#ifndef SEGGER_RTT_MODE_DEFAULT
+ #define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP
+#endif
+
+#ifndef SEGGER_RTT_LOCK
+ #define SEGGER_RTT_LOCK()
+#endif
+
+#ifndef SEGGER_RTT_UNLOCK
+ #define SEGGER_RTT_UNLOCK()
+#endif
+
+#ifndef STRLEN
+ #define STRLEN(a) strlen((a))
+#endif
+
+#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ #define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0
+#endif
+
+#ifndef SEGGER_RTT_MEMCPY
+ #ifdef MEMCPY
+ #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) MEMCPY((pDest), (pSrc), (NumBytes))
+ #else
+ #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) memcpy((pDest), (pSrc), (NumBytes))
+ #endif
+#endif
+
+#ifndef MIN
+ #define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+ #define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+//
+// For some environments, NULL may not be defined until certain headers are included
+//
+#ifndef NULL
+ #define NULL 0
+#endif
+
+/*********************************************************************
+*
+* Defines, fixed
+*
+**********************************************************************
+*/
+#if (defined __ICCARM__) || (defined __ICCRX__)
+ #define RTT_PRAGMA(P) _Pragma(#P)
+#endif
+
+#if SEGGER_RTT_ALIGNMENT || SEGGER_RTT_BUFFER_ALIGNMENT
+ #if (defined __GNUC__)
+ #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__ ((aligned (Alignment)))
+ #elif (defined __ICCARM__) || (defined __ICCRX__)
+ #define PRAGMA(A) _Pragma(#A)
+#define SEGGER_RTT_ALIGN(Var, Alignment) RTT_PRAGMA(data_alignment=Alignment) \
+ Var
+ #elif (defined __CC_ARM)
+ #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__ ((aligned (Alignment)))
+ #else
+ #error "Alignment not supported for this compiler."
+ #endif
+#else
+ #define SEGGER_RTT_ALIGN(Var, Alignment) Var
+#endif
+
+#if defined(SEGGER_RTT_SECTION) || defined (SEGGER_RTT_BUFFER_SECTION)
+ #if (defined __GNUC__)
+ #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__ ((section (Section))) Var
+ #elif (defined __ICCARM__) || (defined __ICCRX__)
+#define SEGGER_RTT_PUT_SECTION(Var, Section) RTT_PRAGMA(location=Section) \
+ Var
+ #elif (defined __CC_ARM)
+ #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__ ((section (Section), zero_init)) Var
+ #else
+ #error "Section placement not supported for this compiler."
+ #endif
+#else
+ #define SEGGER_RTT_PUT_SECTION(Var, Section) Var
+#endif
+
+
+#if SEGGER_RTT_ALIGNMENT
+ #define SEGGER_RTT_CB_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_ALIGNMENT)
+#else
+ #define SEGGER_RTT_CB_ALIGN(Var) Var
+#endif
+
+#if SEGGER_RTT_BUFFER_ALIGNMENT
+ #define SEGGER_RTT_BUFFER_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_BUFFER_ALIGNMENT)
+#else
+ #define SEGGER_RTT_BUFFER_ALIGN(Var) Var
+#endif
+
+
+#if defined(SEGGER_RTT_SECTION)
+ #define SEGGER_RTT_PUT_CB_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_SECTION)
+#else
+ #define SEGGER_RTT_PUT_CB_SECTION(Var) Var
+#endif
+
+#if defined(SEGGER_RTT_BUFFER_SECTION)
+ #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_BUFFER_SECTION)
+#else
+ #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) Var
+#endif
+
+/*********************************************************************
+*
+* Static const data
+*
+**********************************************************************
+*/
+
+static unsigned char _aTerminalId[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+/*********************************************************************
+*
+* Static data
+*
+**********************************************************************
+*/
+//
+// RTT Control Block and allocate buffers for channel 0
+//
+SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT));
+
+SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBuffer [BUFFER_SIZE_UP]));
+SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[BUFFER_SIZE_DOWN]));
+
+static unsigned char _ActiveTerminal;
+
+/*********************************************************************
+*
+* Static functions
+*
+**********************************************************************
+*/
+
+/*********************************************************************
+*
+* _DoInit()
+*
+* Function description
+* Initializes the control block an buffers.
+* May only be called via INIT() to avoid overriding settings.
+*
+*/
+#define INIT() do { \
+ if (_SEGGER_RTT.acID[0] == '\0') { _DoInit(); } \
+ } while (0)
+static void _DoInit(void) {
+ SEGGER_RTT_CB* p;
+ //
+ // Initialize control block
+ //
+ p = &_SEGGER_RTT;
+ p->MaxNumUpBuffers = SEGGER_RTT_MAX_NUM_UP_BUFFERS;
+ p->MaxNumDownBuffers = SEGGER_RTT_MAX_NUM_DOWN_BUFFERS;
+ //
+ // Initialize up buffer 0
+ //
+ p->aUp[0].sName = "Terminal";
+ p->aUp[0].pBuffer = _acUpBuffer;
+ p->aUp[0].SizeOfBuffer = sizeof(_acUpBuffer);
+ p->aUp[0].RdOff = 0u;
+ p->aUp[0].WrOff = 0u;
+ p->aUp[0].Flags = SEGGER_RTT_MODE_DEFAULT;
+ //
+ // Initialize down buffer 0
+ //
+ p->aDown[0].sName = "Terminal";
+ p->aDown[0].pBuffer = _acDownBuffer;
+ p->aDown[0].SizeOfBuffer = sizeof(_acDownBuffer);
+ p->aDown[0].RdOff = 0u;
+ p->aDown[0].WrOff = 0u;
+ p->aDown[0].Flags = SEGGER_RTT_MODE_DEFAULT;
+ //
+ // Finish initialization of the control block.
+ // Copy Id string in three steps to make sure "SEGGER RTT" is not found
+ // in initializer memory (usually flash) by J-Link
+ //
+ strcpy(&p->acID[7], "RTT");
+ strcpy(&p->acID[0], "SEGGER");
+ p->acID[6] = ' ';
+}
+
+/*********************************************************************
+*
+* _WriteBlocking()
+*
+* Function description
+* Stores a specified number of characters in SEGGER RTT ring buffer
+* and updates the associated write pointer which is periodically
+* read by the host.
+* The caller is responsible for managing the write chunk sizes as
+* _WriteBlocking() will block until all data has been posted successfully.
+*
+* Parameters
+* pRing Ring buffer to post to.
+* pBuffer Pointer to character array. Does not need to point to a \0 terminated string.
+* NumBytes Number of bytes to be stored in the SEGGER RTT control block.
+*
+* Return value
+* >= 0 - Number of bytes written into buffer.
+*/
+static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, unsigned NumBytes) {
+ unsigned NumBytesToWrite;
+ unsigned NumBytesWritten;
+ unsigned RdOff;
+ unsigned WrOff;
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ char* pDst;
+#endif
+ //
+ // Write data to buffer and handle wrap-around if necessary
+ //
+ NumBytesWritten = 0u;
+ WrOff = pRing->WrOff;
+ do {
+ RdOff = pRing->RdOff; // May be changed by host (debug probe) in the meantime
+ if (RdOff > WrOff) {
+ NumBytesToWrite = RdOff - WrOff - 1u;
+ } else {
+ NumBytesToWrite = pRing->SizeOfBuffer - (WrOff - RdOff + 1u);
+ }
+ NumBytesToWrite = MIN(NumBytesToWrite, (pRing->SizeOfBuffer - WrOff)); // Number of bytes that can be written until buffer wrap-around
+ NumBytesToWrite = MIN(NumBytesToWrite, NumBytes);
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ pDst = pRing->pBuffer + WrOff;
+ NumBytesWritten += NumBytesToWrite;
+ NumBytes -= NumBytesToWrite;
+ WrOff += NumBytesToWrite;
+ while (NumBytesToWrite--) {
+ *pDst++ = *pBuffer++;
+ };
+#else
+ SEGGER_RTT_MEMCPY(pRing->pBuffer + WrOff, pBuffer, NumBytesToWrite);
+ NumBytesWritten += NumBytesToWrite;
+ pBuffer += NumBytesToWrite;
+ NumBytes -= NumBytesToWrite;
+ WrOff += NumBytesToWrite;
+#endif
+ if (WrOff == pRing->SizeOfBuffer) {
+ WrOff = 0u;
+ }
+ pRing->WrOff = WrOff;
+ } while (NumBytes);
+ //
+ return NumBytesWritten;
+}
+
+/*********************************************************************
+*
+* _WriteNoCheck()
+*
+* Function description
+* Stores a specified number of characters in SEGGER RTT ring buffer
+* and updates the associated write pointer which is periodically
+* read by the host.
+* It is callers responsibility to make sure data actually fits in buffer.
+*
+* Parameters
+* pRing Ring buffer to post to.
+* pBuffer Pointer to character array. Does not need to point to a \0 terminated string.
+* NumBytes Number of bytes to be stored in the SEGGER RTT control block.
+*
+* Notes
+* (1) If there might not be enough space in the "Up"-buffer, call _WriteBlocking
+*/
+static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP* pRing, const char* pData, unsigned NumBytes) {
+ unsigned NumBytesAtOnce;
+ unsigned WrOff;
+ unsigned Rem;
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ char* pDst;
+#endif
+
+ WrOff = pRing->WrOff;
+ Rem = pRing->SizeOfBuffer - WrOff;
+ if (Rem > NumBytes) {
+ //
+ // All data fits before wrap around
+ //
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ pDst = pRing->pBuffer + WrOff;
+ WrOff += NumBytes;
+ while (NumBytes--) {
+ *pDst++ = *pData++;
+ };
+ pRing->WrOff = WrOff;
+#else
+ SEGGER_RTT_MEMCPY(pRing->pBuffer + WrOff, pData, NumBytes);
+ pRing->WrOff = WrOff + NumBytes;
+#endif
+ } else {
+ //
+ // We reach the end of the buffer, so need to wrap around
+ //
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ pDst = pRing->pBuffer + WrOff;
+ NumBytesAtOnce = Rem;
+ while (NumBytesAtOnce--) {
+ *pDst++ = *pData++;
+ };
+ pDst = pRing->pBuffer;
+ NumBytesAtOnce = NumBytes - Rem;
+ while (NumBytesAtOnce--) {
+ *pDst++ = *pData++;
+ };
+ pRing->WrOff = NumBytes - Rem;
+#else
+ NumBytesAtOnce = Rem;
+ SEGGER_RTT_MEMCPY(pRing->pBuffer + WrOff, pData, NumBytesAtOnce);
+ NumBytesAtOnce = NumBytes - Rem;
+ SEGGER_RTT_MEMCPY(pRing->pBuffer, pData + Rem, NumBytesAtOnce);
+ pRing->WrOff = NumBytesAtOnce;
+#endif
+ }
+}
+
+/*********************************************************************
+*
+* _PostTerminalSwitch()
+*
+* Function description
+* Switch terminal to the given terminal ID. It is the caller's
+* responsibility to ensure the terminal ID is correct and there is
+* enough space in the buffer for this to complete successfully.
+*
+* Parameters
+* pRing Ring buffer to post to.
+* TerminalId Terminal ID to switch to.
+*/
+static void _PostTerminalSwitch(SEGGER_RTT_BUFFER_UP* pRing, unsigned char TerminalId) {
+ unsigned char ac[2];
+
+ ac[0] = 0xFFu;
+ ac[1] = _aTerminalId[TerminalId]; // Caller made already sure that TerminalId does not exceed our terminal limit
+ _WriteBlocking(pRing, (const char*)ac, 2u);
+}
+
+/*********************************************************************
+*
+* _GetAvailWriteSpace()
+*
+* Function description
+* Returns the number of bytes that can be written to the ring
+* buffer without blocking.
+*
+* Parameters
+* pRing Ring buffer to check.
+*
+* Return value
+* Number of bytes that are free in the buffer.
+*/
+static unsigned _GetAvailWriteSpace(SEGGER_RTT_BUFFER_UP* pRing) {
+ unsigned RdOff;
+ unsigned WrOff;
+ unsigned r;
+ //
+ // Avoid warnings regarding volatile access order. It's not a problem
+ // in this case, but dampen compiler enthusiasm.
+ //
+ RdOff = pRing->RdOff;
+ WrOff = pRing->WrOff;
+ if (RdOff <= WrOff) {
+ r = pRing->SizeOfBuffer - 1u - WrOff + RdOff;
+ } else {
+ r = RdOff - WrOff - 1u;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* Public code
+*
+**********************************************************************
+*/
+/*********************************************************************
+*
+* SEGGER_RTT_ReadNoLock()
+*
+* Function description
+* Reads characters from SEGGER real-time-terminal control block
+* which have been previously stored by the host.
+* Do not lock against interrupts and multiple access.
+*
+* Parameters
+* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal").
+* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to.
+* BufferSize Size of the target application buffer.
+*
+* Return value
+* Number of bytes that have been read.
+*/
+unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) {
+ unsigned NumBytesRem;
+ unsigned NumBytesRead;
+ unsigned RdOff;
+ unsigned WrOff;
+ unsigned char* pBuffer;
+ SEGGER_RTT_BUFFER_DOWN* pRing;
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ const char* pSrc;
+#endif
+ //
+ INIT();
+ pRing = &_SEGGER_RTT.aDown[BufferIndex];
+ pBuffer = (unsigned char*)pData;
+ RdOff = pRing->RdOff;
+ WrOff = pRing->WrOff;
+ NumBytesRead = 0u;
+ //
+ // Read from current read position to wrap-around of buffer, first
+ //
+ if (RdOff > WrOff) {
+ NumBytesRem = pRing->SizeOfBuffer - RdOff;
+ NumBytesRem = MIN(NumBytesRem, BufferSize);
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ pSrc = pRing->pBuffer + RdOff;
+ NumBytesRead += NumBytesRem;
+ BufferSize -= NumBytesRem;
+ RdOff += NumBytesRem;
+ while (NumBytesRem--) {
+ *pBuffer++ = *pSrc++;
+ };
+#else
+ SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem);
+ NumBytesRead += NumBytesRem;
+ pBuffer += NumBytesRem;
+ BufferSize -= NumBytesRem;
+ RdOff += NumBytesRem;
+#endif
+ //
+ // Handle wrap-around of buffer
+ //
+ if (RdOff == pRing->SizeOfBuffer) {
+ RdOff = 0u;
+ }
+ }
+ //
+ // Read remaining items of buffer
+ //
+ NumBytesRem = WrOff - RdOff;
+ NumBytesRem = MIN(NumBytesRem, BufferSize);
+ if (NumBytesRem > 0u) {
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ pSrc = pRing->pBuffer + RdOff;
+ NumBytesRead += NumBytesRem;
+ BufferSize -= NumBytesRem;
+ RdOff += NumBytesRem;
+ while (NumBytesRem--) {
+ *pBuffer++ = *pSrc++;
+ };
+#else
+ SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem);
+ NumBytesRead += NumBytesRem;
+ pBuffer += NumBytesRem;
+ BufferSize -= NumBytesRem;
+ RdOff += NumBytesRem;
+#endif
+ }
+ if (NumBytesRead) {
+ pRing->RdOff = RdOff;
+ }
+ //
+ return NumBytesRead;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_Read
+*
+* Function description
+* Reads characters from SEGGER real-time-terminal control block
+* which have been previously stored by the host.
+*
+* Parameters
+* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal").
+* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to.
+* BufferSize Size of the target application buffer.
+*
+* Return value
+* Number of bytes that have been read.
+*/
+unsigned SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) {
+ unsigned NumBytesRead;
+ //
+ SEGGER_RTT_LOCK();
+ //
+ // Call the non-locking read function
+ //
+ NumBytesRead = SEGGER_RTT_ReadNoLock(BufferIndex, pBuffer, BufferSize);
+ //
+ // Finish up.
+ //
+ SEGGER_RTT_UNLOCK();
+ //
+ return NumBytesRead;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_WriteWithOverwriteNoLock
+*
+* Function description
+* Stores a specified number of characters in SEGGER RTT
+* control block.
+* SEGGER_RTT_WriteWithOverwriteNoLock does not lock the application
+* and overwrites data if the data does not fit into the buffer.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
+* pBuffer Pointer to character array. Does not need to point to a \0 terminated string.
+* NumBytes Number of bytes to be stored in the SEGGER RTT control block.
+*
+* Notes
+* (1) If there is not enough space in the "Up"-buffer, data is overwritten.
+* (2) For performance reasons this function does not call Init()
+* and may only be called after RTT has been initialized.
+* Either by calling SEGGER_RTT_Init() or calling another RTT API function first.
+* (3) Do not use SEGGER_RTT_WriteWithOverwriteNoLock if a J-Link
+* connection reads RTT data.
+*/
+void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) {
+ const char* pData;
+ SEGGER_RTT_BUFFER_UP* pRing;
+ unsigned Avail;
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ char* pDst;
+#endif
+
+ pData = (const char *)pBuffer;
+ //
+ // Get "to-host" ring buffer and copy some elements into local variables.
+ //
+ pRing = &_SEGGER_RTT.aUp[BufferIndex];
+ //
+ // Check if we will overwrite data and need to adjust the RdOff.
+ //
+ if (pRing->WrOff == pRing->RdOff) {
+ Avail = pRing->SizeOfBuffer - 1u;
+ } else if ( pRing->WrOff < pRing->RdOff) {
+ Avail = pRing->RdOff - pRing->WrOff - 1u;
+ } else {
+ Avail = pRing->RdOff - pRing->WrOff - 1u + pRing->SizeOfBuffer;
+ }
+ if (NumBytes > Avail) {
+ pRing->RdOff += (NumBytes - Avail);
+ while (pRing->RdOff >= pRing->SizeOfBuffer) {
+ pRing->RdOff -= pRing->SizeOfBuffer;
+ }
+ }
+ //
+ // Write all data, no need to check the RdOff, but possibly handle multiple wrap-arounds
+ //
+ Avail = pRing->SizeOfBuffer - pRing->WrOff;
+ do {
+ if (Avail > NumBytes) {
+ //
+ // Last round
+ //
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ pDst = pRing->pBuffer + pRing->WrOff;
+ Avail = NumBytes;
+ while (NumBytes--) {
+ *pDst++ = *pData++;
+ };
+ pRing->WrOff += Avail;
+#else
+ SEGGER_RTT_MEMCPY(pRing->pBuffer + pRing->WrOff, pData, NumBytes);
+ pRing->WrOff += NumBytes;
+#endif
+ break;
+ } else {
+ //
+ // Wrap-around necessary, write until wrap-around and reset WrOff
+ //
+#if SEGGER_RTT_MEMCPY_USE_BYTELOOP
+ pDst = pRing->pBuffer + pRing->WrOff;
+ NumBytes -= Avail;
+ while (Avail--) {
+ *pDst++ = *pData++;
+ };
+ pRing->WrOff = 0;
+#else
+ SEGGER_RTT_MEMCPY(pRing->pBuffer + pRing->WrOff, pData, Avail);
+ pData += Avail;
+ pRing->WrOff = 0;
+ NumBytes -= Avail;
+#endif
+ Avail = (pRing->SizeOfBuffer - 1);
+ }
+ } while (NumBytes);
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_WriteSkipNoLock
+*
+* Function description
+* Stores a specified number of characters in SEGGER RTT
+* control block which is then read by the host.
+* SEGGER_RTT_WriteSkipNoLock does not lock the application and
+* skips all data, if the data does not fit into the buffer.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
+* pBuffer Pointer to character array. Does not need to point to a \0 terminated string.
+* NumBytes Number of bytes to be stored in the SEGGER RTT control block.
+* MUST be > 0!!!
+* This is done for performance reasons, so no initial check has do be done.
+*
+* Return value
+* 1: Data has been copied
+* 0: No space, data has not been copied
+*
+* Notes
+* (1) If there is not enough space in the "Up"-buffer, all data is dropped.
+* (2) For performance reasons this function does not call Init()
+* and may only be called after RTT has been initialized.
+* Either by calling SEGGER_RTT_Init() or calling another RTT API function first.
+*/
+#if (RTT_USE_ASM == 0)
+unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) {
+ const char* pData;
+ SEGGER_RTT_BUFFER_UP* pRing;
+ unsigned Avail;
+ unsigned RdOff;
+ unsigned WrOff;
+ unsigned Rem;
+ //
+ // Cases:
+ // 1) RdOff <= WrOff => Space until wrap-around is sufficient
+ // 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks)
+ // 3) RdOff < WrOff => No space in buf
+ // 4) RdOff > WrOff => Space is sufficient
+ // 5) RdOff > WrOff => No space in buf
+ //
+ // 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough
+ //
+ pData = (const char *)pBuffer;
+ pRing = &_SEGGER_RTT.aUp[BufferIndex];
+ RdOff = pRing->RdOff;
+ WrOff = pRing->WrOff;
+ if (RdOff <= WrOff) { // Case 1), 2) or 3)
+ Avail = pRing->SizeOfBuffer - WrOff - 1u; // Space until wrap-around (assume 1 byte not usable for case that RdOff == 0)
+ if (Avail >= NumBytes) { // Case 1)?
+CopyStraight:
+ memcpy(pRing->pBuffer + WrOff, pData, NumBytes);
+ pRing->WrOff = WrOff + NumBytes;
+ return 1;
+ }
+ Avail += RdOff; // Space incl. wrap-around
+ if (Avail >= NumBytes) { // Case 2? => If not, we have case 3) (does not fit)
+ Rem = pRing->SizeOfBuffer - WrOff; // Space until end of buffer
+ memcpy(pRing->pBuffer + WrOff, pData, Rem); // Copy 1st chunk
+ NumBytes -= Rem;
+ //
+ // Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used
+ // But 2nd check (considering space until wrap-around and until RdOff) revealed that RdOff is not 0, so we can use the last element
+ // In this case, we may use a copy straight until buffer end anyway without needing to copy 2 chunks
+ // Therefore, check if 2nd memcpy is necessary at all
+ //
+ if (NumBytes) {
+ memcpy(pRing->pBuffer, pData + Rem, NumBytes);
+ }
+ pRing->WrOff = NumBytes;
+ return 1;
+ }
+ } else { // Potential case 4)
+ Avail = RdOff - WrOff - 1u;
+ if (Avail >= NumBytes) { // Case 4)? => If not, we have case 5) (does not fit)
+ goto CopyStraight;
+ }
+ }
+ return 0; // No space in buffer
+}
+#endif
+
+/*********************************************************************
+*
+* SEGGER_RTT_WriteNoLock
+*
+* Function description
+* Stores a specified number of characters in SEGGER RTT
+* control block which is then read by the host.
+* SEGGER_RTT_WriteNoLock does not lock the application.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
+* pBuffer Pointer to character array. Does not need to point to a \0 terminated string.
+* NumBytes Number of bytes to be stored in the SEGGER RTT control block.
+*
+* Return value
+* Number of bytes which have been stored in the "Up"-buffer.
+*
+* Notes
+* (1) Data is stored according to buffer flags.
+* (2) For performance reasons this function does not call Init()
+* and may only be called after RTT has been initialized.
+* Either by calling SEGGER_RTT_Init() or calling another RTT API function first.
+*/
+unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) {
+ unsigned Status;
+ unsigned Avail;
+ const char* pData;
+ SEGGER_RTT_BUFFER_UP* pRing;
+
+ pData = (const char *)pBuffer;
+ //
+ // Get "to-host" ring buffer.
+ //
+ pRing = &_SEGGER_RTT.aUp[BufferIndex];
+ //
+ // How we output depends upon the mode...
+ //
+ switch (pRing->Flags) {
+ case SEGGER_RTT_MODE_NO_BLOCK_SKIP:
+ //
+ // If we are in skip mode and there is no space for the whole
+ // of this output, don't bother.
+ //
+ Avail = _GetAvailWriteSpace(pRing);
+ if (Avail < NumBytes) {
+ Status = 0u;
+ } else {
+ Status = NumBytes;
+ _WriteNoCheck(pRing, pData, NumBytes);
+ }
+ break;
+ case SEGGER_RTT_MODE_NO_BLOCK_TRIM:
+ //
+ // If we are in trim mode, trim to what we can output without blocking.
+ //
+ Avail = _GetAvailWriteSpace(pRing);
+ Status = Avail < NumBytes ? Avail : NumBytes;
+ _WriteNoCheck(pRing, pData, Status);
+ break;
+ case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL:
+ //
+ // If we are in blocking mode, output everything.
+ //
+ Status = _WriteBlocking(pRing, pData, NumBytes);
+ break;
+ default:
+ Status = 0u;
+ break;
+ }
+ //
+ // Finish up.
+ //
+ return Status;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_Write
+*
+* Function description
+* Stores a specified number of characters in SEGGER RTT
+* control block which is then read by the host.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
+* pBuffer Pointer to character array. Does not need to point to a \0 terminated string.
+* NumBytes Number of bytes to be stored in the SEGGER RTT control block.
+*
+* Return value
+* Number of bytes which have been stored in the "Up"-buffer.
+*
+* Notes
+* (1) Data is stored according to buffer flags.
+*/
+unsigned SEGGER_RTT_Write(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) {
+ unsigned Status;
+ //
+ INIT();
+ SEGGER_RTT_LOCK();
+ //
+ // Call the non-locking write function
+ //
+ Status = SEGGER_RTT_WriteNoLock(BufferIndex, pBuffer, NumBytes);
+ //
+ // Finish up.
+ //
+ SEGGER_RTT_UNLOCK();
+ //
+ return Status;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_WriteString
+*
+* Function description
+* Stores string in SEGGER RTT control block.
+* This data is read by the host.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
+* s Pointer to string.
+*
+* Return value
+* Number of bytes which have been stored in the "Up"-buffer.
+*
+* Notes
+* (1) Data is stored according to buffer flags.
+* (2) String passed to this function has to be \0 terminated
+* (3) \0 termination character is *not* stored in RTT buffer
+*/
+unsigned SEGGER_RTT_WriteString(unsigned BufferIndex, const char* s) {
+ unsigned Len;
+
+ Len = STRLEN(s);
+ return SEGGER_RTT_Write(BufferIndex, s, Len);
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_PutCharSkipNoLock
+*
+* Function description
+* Stores a single character/byte in SEGGER RTT buffer.
+* SEGGER_RTT_PutCharSkipNoLock does not lock the application and
+* skips the byte, if it does not fit into the buffer.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
+* c Byte to be stored.
+*
+* Return value
+* Number of bytes which have been stored in the "Up"-buffer.
+*
+* Notes
+* (1) If there is not enough space in the "Up"-buffer, the character is dropped.
+* (2) For performance reasons this function does not call Init()
+* and may only be called after RTT has been initialized.
+* Either by calling SEGGER_RTT_Init() or calling another RTT API function first.
+*/
+
+unsigned SEGGER_RTT_PutCharSkipNoLock(unsigned BufferIndex, char c) {
+ SEGGER_RTT_BUFFER_UP* pRing;
+ unsigned WrOff;
+ unsigned Status;
+ //
+ // Get "to-host" ring buffer.
+ //
+ pRing = &_SEGGER_RTT.aUp[BufferIndex];
+ //
+ // Get write position and handle wrap-around if necessary
+ //
+ WrOff = pRing->WrOff + 1;
+ if (WrOff == pRing->SizeOfBuffer) {
+ WrOff = 0;
+ }
+ //
+ // Output byte if free space is available
+ //
+ if (WrOff != pRing->RdOff) {
+ pRing->pBuffer[pRing->WrOff] = c;
+ pRing->WrOff = WrOff;
+ Status = 1;
+ } else {
+ Status = 0;
+ }
+ //
+ return Status;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_PutCharSkip
+*
+* Function description
+* Stores a single character/byte in SEGGER RTT buffer.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
+* c Byte to be stored.
+*
+* Return value
+* Number of bytes which have been stored in the "Up"-buffer.
+*
+* Notes
+* (1) If there is not enough space in the "Up"-buffer, the character is dropped.
+*/
+
+unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c) {
+ SEGGER_RTT_BUFFER_UP* pRing;
+ unsigned WrOff;
+ unsigned Status;
+ //
+ // Prepare
+ //
+ INIT();
+ SEGGER_RTT_LOCK();
+ //
+ // Get "to-host" ring buffer.
+ //
+ pRing = &_SEGGER_RTT.aUp[BufferIndex];
+ //
+ // Get write position and handle wrap-around if necessary
+ //
+ WrOff = pRing->WrOff + 1;
+ if (WrOff == pRing->SizeOfBuffer) {
+ WrOff = 0;
+ }
+ //
+ // Output byte if free space is available
+ //
+ if (WrOff != pRing->RdOff) {
+ pRing->pBuffer[pRing->WrOff] = c;
+ pRing->WrOff = WrOff;
+ Status = 1;
+ } else {
+ Status = 0;
+ }
+ //
+ // Finish up.
+ //
+ SEGGER_RTT_UNLOCK();
+ //
+ return Status;
+}
+
+ /*********************************************************************
+*
+* SEGGER_RTT_PutChar
+*
+* Function description
+* Stores a single character/byte in SEGGER RTT buffer.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
+* c Byte to be stored.
+*
+* Return value
+* Number of bytes which have been stored in the "Up"-buffer.
+*
+* Notes
+* (1) Data is stored according to buffer flags.
+*/
+
+unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) {
+ SEGGER_RTT_BUFFER_UP* pRing;
+ unsigned WrOff;
+ unsigned Status;
+ //
+ // Prepare
+ //
+ INIT();
+ SEGGER_RTT_LOCK();
+ //
+ // Get "to-host" ring buffer.
+ //
+ pRing = &_SEGGER_RTT.aUp[BufferIndex];
+ //
+ // Get write position and handle wrap-around if necessary
+ //
+ WrOff = pRing->WrOff + 1;
+ if (WrOff == pRing->SizeOfBuffer) {
+ WrOff = 0;
+ }
+ //
+ // Wait for free space if mode is set to blocking
+ //
+ if (pRing->Flags == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) {
+ while (WrOff == pRing->RdOff) {
+ ;
+ }
+ }
+ //
+ // Output byte if free space is available
+ //
+ if (WrOff != pRing->RdOff) {
+ pRing->pBuffer[pRing->WrOff] = c;
+ pRing->WrOff = WrOff;
+ Status = 1;
+ } else {
+ Status = 0;
+ }
+ //
+ // Finish up.
+ //
+ SEGGER_RTT_UNLOCK();
+ //
+ return Status;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_GetKey
+*
+* Function description
+* Reads one character from the SEGGER RTT buffer.
+* Host has previously stored data there.
+*
+* Return value
+* < 0 - No character available (buffer empty).
+* >= 0 - Character which has been read. (Possible values: 0 - 255)
+*
+* Notes
+* (1) This function is only specified for accesses to RTT buffer 0.
+*/
+int SEGGER_RTT_GetKey(void) {
+ char c;
+ int r;
+
+ r = (int)SEGGER_RTT_Read(0u, &c, 1u);
+ if (r == 1) {
+ r = (int)(unsigned char)c;
+ } else {
+ r = -1;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_WaitKey
+*
+* Function description
+* Waits until at least one character is avaible in the SEGGER RTT buffer.
+* Once a character is available, it is read and this function returns.
+*
+* Return value
+* >=0 - Character which has been read.
+*
+* Notes
+* (1) This function is only specified for accesses to RTT buffer 0
+* (2) This function is blocking if no character is present in RTT buffer
+*/
+int SEGGER_RTT_WaitKey(void) {
+ int r;
+
+ do {
+ r = SEGGER_RTT_GetKey();
+ } while (r < 0);
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_HasKey
+*
+* Function description
+* Checks if at least one character for reading is available in the SEGGER RTT buffer.
+*
+* Return value
+* == 0 - No characters are available to read.
+* == 1 - At least one character is available.
+*
+* Notes
+* (1) This function is only specified for accesses to RTT buffer 0
+*/
+int SEGGER_RTT_HasKey(void) {
+ unsigned RdOff;
+ int r;
+
+ INIT();
+ RdOff = _SEGGER_RTT.aDown[0].RdOff;
+ if (RdOff != _SEGGER_RTT.aDown[0].WrOff) {
+ r = 1;
+ } else {
+ r = 0;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_HasData
+*
+* Function description
+* Check if there is data from the host in the given buffer.
+*
+* Return value:
+* ==0: No data
+* !=0: Data in buffer
+*
+*/
+unsigned SEGGER_RTT_HasData(unsigned BufferIndex) {
+ SEGGER_RTT_BUFFER_DOWN* pRing;
+ unsigned v;
+
+ pRing = &_SEGGER_RTT.aDown[BufferIndex];
+ v = pRing->WrOff;
+ return v - pRing->RdOff;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_HasDataUp
+*
+* Function description
+* Check if there is data remaining to be sent in the given buffer.
+*
+* Return value:
+* ==0: No data
+* !=0: Data in buffer
+*
+*/
+unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex) {
+ SEGGER_RTT_BUFFER_UP* pRing;
+ unsigned v;
+
+ pRing = &_SEGGER_RTT.aUp[BufferIndex];
+ v = pRing->RdOff;
+ return pRing->WrOff - v;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_AllocDownBuffer
+*
+* Function description
+* Run-time configuration of the next down-buffer (H->T).
+* The next buffer, which is not used yet is configured.
+* This includes: Buffer address, size, name, flags, ...
+*
+* Parameters
+* sName Pointer to a constant name string.
+* pBuffer Pointer to a buffer to be used.
+* BufferSize Size of the buffer.
+* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message).
+*
+* Return value
+* >= 0 - O.K. Buffer Index
+* < 0 - Error
+*/
+int SEGGER_RTT_AllocDownBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) {
+ int BufferIndex;
+
+ INIT();
+ SEGGER_RTT_LOCK();
+ BufferIndex = 0;
+ do {
+ if (_SEGGER_RTT.aDown[BufferIndex].pBuffer == NULL) {
+ break;
+ }
+ BufferIndex++;
+ } while (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers);
+ if (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers) {
+ _SEGGER_RTT.aDown[BufferIndex].sName = sName;
+ _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char*)pBuffer;
+ _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize;
+ _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u;
+ _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u;
+ _SEGGER_RTT.aDown[BufferIndex].Flags = Flags;
+ } else {
+ BufferIndex = -1;
+ }
+ SEGGER_RTT_UNLOCK();
+ return BufferIndex;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_AllocUpBuffer
+*
+* Function description
+* Run-time configuration of the next up-buffer (T->H).
+* The next buffer, which is not used yet is configured.
+* This includes: Buffer address, size, name, flags, ...
+*
+* Parameters
+* sName Pointer to a constant name string.
+* pBuffer Pointer to a buffer to be used.
+* BufferSize Size of the buffer.
+* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message).
+*
+* Return value
+* >= 0 - O.K. Buffer Index
+* < 0 - Error
+*/
+int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) {
+ int BufferIndex;
+
+ INIT();
+ SEGGER_RTT_LOCK();
+ BufferIndex = 0;
+ do {
+ if (_SEGGER_RTT.aUp[BufferIndex].pBuffer == NULL) {
+ break;
+ }
+ BufferIndex++;
+ } while (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers);
+ if (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers) {
+ _SEGGER_RTT.aUp[BufferIndex].sName = sName;
+ _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char*)pBuffer;
+ _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize;
+ _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u;
+ _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u;
+ _SEGGER_RTT.aUp[BufferIndex].Flags = Flags;
+ } else {
+ BufferIndex = -1;
+ }
+ SEGGER_RTT_UNLOCK();
+ return BufferIndex;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_ConfigUpBuffer
+*
+* Function description
+* Run-time configuration of a specific up-buffer (T->H).
+* Buffer to be configured is specified by index.
+* This includes: Buffer address, size, name, flags, ...
+*
+* Parameters
+* BufferIndex Index of the buffer to configure.
+* sName Pointer to a constant name string.
+* pBuffer Pointer to a buffer to be used.
+* BufferSize Size of the buffer.
+* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message).
+*
+* Return value
+* >= 0 - O.K.
+* < 0 - Error
+*
+* Additional information
+* Buffer 0 is configured on compile-time.
+* May only be called once per buffer.
+* Buffer name and flags can be reconfigured using the appropriate functions.
+*/
+int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) {
+ int r;
+
+ INIT();
+ if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) {
+ SEGGER_RTT_LOCK();
+ if (BufferIndex > 0u) {
+ _SEGGER_RTT.aUp[BufferIndex].sName = sName;
+ _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char*)pBuffer;
+ _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize;
+ _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u;
+ _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u;
+ }
+ _SEGGER_RTT.aUp[BufferIndex].Flags = Flags;
+ SEGGER_RTT_UNLOCK();
+ r = 0;
+ } else {
+ r = -1;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_ConfigDownBuffer
+*
+* Function description
+* Run-time configuration of a specific down-buffer (H->T).
+* Buffer to be configured is specified by index.
+* This includes: Buffer address, size, name, flags, ...
+*
+* Parameters
+* BufferIndex Index of the buffer to configure.
+* sName Pointer to a constant name string.
+* pBuffer Pointer to a buffer to be used.
+* BufferSize Size of the buffer.
+* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message).
+*
+* Return value
+* >= 0 O.K.
+* < 0 Error
+*
+* Additional information
+* Buffer 0 is configured on compile-time.
+* May only be called once per buffer.
+* Buffer name and flags can be reconfigured using the appropriate functions.
+*/
+int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) {
+ int r;
+
+ INIT();
+ if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) {
+ SEGGER_RTT_LOCK();
+ if (BufferIndex > 0u) {
+ _SEGGER_RTT.aDown[BufferIndex].sName = sName;
+ _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char*)pBuffer;
+ _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize;
+ _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u;
+ _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u;
+ }
+ _SEGGER_RTT.aDown[BufferIndex].Flags = Flags;
+ SEGGER_RTT_UNLOCK();
+ r = 0;
+ } else {
+ r = -1;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_SetNameUpBuffer
+*
+* Function description
+* Run-time configuration of a specific up-buffer name (T->H).
+* Buffer to be configured is specified by index.
+*
+* Parameters
+* BufferIndex Index of the buffer to renamed.
+* sName Pointer to a constant name string.
+*
+* Return value
+* >= 0 O.K.
+* < 0 Error
+*/
+int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName) {
+ int r;
+
+ INIT();
+ if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) {
+ SEGGER_RTT_LOCK();
+ _SEGGER_RTT.aUp[BufferIndex].sName = sName;
+ SEGGER_RTT_UNLOCK();
+ r = 0;
+ } else {
+ r = -1;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_SetNameDownBuffer
+*
+* Function description
+* Run-time configuration of a specific Down-buffer name (T->H).
+* Buffer to be configured is specified by index.
+*
+* Parameters
+* BufferIndex Index of the buffer to renamed.
+* sName Pointer to a constant name string.
+*
+* Return value
+* >= 0 O.K.
+* < 0 Error
+*/
+int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) {
+ int r;
+
+ INIT();
+ if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) {
+ SEGGER_RTT_LOCK();
+ _SEGGER_RTT.aDown[BufferIndex].sName = sName;
+ SEGGER_RTT_UNLOCK();
+ r = 0;
+ } else {
+ r = -1;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_SetFlagsUpBuffer
+*
+* Function description
+* Run-time configuration of specific up-buffer flags (T->H).
+* Buffer to be configured is specified by index.
+*
+* Parameters
+* BufferIndex Index of the buffer.
+* Flags Flags to set for the buffer.
+*
+* Return value
+* >= 0 O.K.
+* < 0 Error
+*/
+int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) {
+ int r;
+
+ INIT();
+ if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) {
+ SEGGER_RTT_LOCK();
+ _SEGGER_RTT.aUp[BufferIndex].Flags = Flags;
+ SEGGER_RTT_UNLOCK();
+ r = 0;
+ } else {
+ r = -1;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_SetFlagsDownBuffer
+*
+* Function description
+* Run-time configuration of specific Down-buffer flags (T->H).
+* Buffer to be configured is specified by index.
+*
+* Parameters
+* BufferIndex Index of the buffer to renamed.
+* Flags Flags to set for the buffer.
+*
+* Return value
+* >= 0 O.K.
+* < 0 Error
+*/
+int SEGGER_RTT_SetFlagsDownBuffer(unsigned BufferIndex, unsigned Flags) {
+ int r;
+
+ INIT();
+ if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) {
+ SEGGER_RTT_LOCK();
+ _SEGGER_RTT.aDown[BufferIndex].Flags = Flags;
+ SEGGER_RTT_UNLOCK();
+ r = 0;
+ } else {
+ r = -1;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_Init
+*
+* Function description
+* Initializes the RTT Control Block.
+* Should be used in RAM targets, at start of the application.
+*
+*/
+void SEGGER_RTT_Init (void) {
+ _DoInit();
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_SetTerminal
+*
+* Function description
+* Sets the terminal to be used for output on channel 0.
+*
+* Parameters
+* TerminalId Index of the terminal.
+*
+* Return value
+* >= 0 O.K.
+* < 0 Error (e.g. if RTT is configured for non-blocking mode and there was no space in the buffer to set the new terminal Id)
+*/
+int SEGGER_RTT_SetTerminal (unsigned char TerminalId) {
+ unsigned char ac[2];
+ SEGGER_RTT_BUFFER_UP* pRing;
+ unsigned Avail;
+ int r;
+ //
+ INIT();
+ //
+ r = 0;
+ ac[0] = 0xFFu;
+ if (TerminalId < sizeof(_aTerminalId)) { // We only support a certain number of channels
+ ac[1] = _aTerminalId[TerminalId];
+ pRing = &_SEGGER_RTT.aUp[0]; // Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed
+ SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we are and number of free bytes in buffer does not change downwards after checking and before writing
+ if ((pRing->Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) {
+ _ActiveTerminal = TerminalId;
+ _WriteBlocking(pRing, (const char*)ac, 2u);
+ } else { // Skipping mode or trim mode? => We cannot trim this command so handling is the same for both modes
+ Avail = _GetAvailWriteSpace(pRing);
+ if (Avail >= 2) {
+ _ActiveTerminal = TerminalId; // Only change active terminal in case of success
+ _WriteNoCheck(pRing, (const char*)ac, 2u);
+ } else {
+ r = -1;
+ }
+ }
+ SEGGER_RTT_UNLOCK();
+ } else {
+ r = -1;
+ }
+ return r;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_TerminalOut
+*
+* Function description
+* Writes a string to the given terminal
+* without changing the terminal for channel 0.
+*
+* Parameters
+* TerminalId Index of the terminal.
+* s String to be printed on the terminal.
+*
+* Return value
+* >= 0 - Number of bytes written.
+* < 0 - Error.
+*
+*/
+int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s) {
+ int Status;
+ unsigned FragLen;
+ unsigned Avail;
+ SEGGER_RTT_BUFFER_UP* pRing;
+ //
+ INIT();
+ //
+ // Validate terminal ID.
+ //
+ if (TerminalId < (char)sizeof(_aTerminalId)) { // We only support a certain number of channels
+ //
+ // Get "to-host" ring buffer.
+ //
+ pRing = &_SEGGER_RTT.aUp[0];
+ //
+ // Need to be able to change terminal, write data, change back.
+ // Compute the fixed and variable sizes.
+ //
+ FragLen = STRLEN(s);
+ //
+ // How we output depends upon the mode...
+ //
+ SEGGER_RTT_LOCK();
+ Avail = _GetAvailWriteSpace(pRing);
+ switch (pRing->Flags & SEGGER_RTT_MODE_MASK) {
+ case SEGGER_RTT_MODE_NO_BLOCK_SKIP:
+ //
+ // If we are in skip mode and there is no space for the whole
+ // of this output, don't bother switching terminals at all.
+ //
+ if (Avail < (FragLen + 4u)) {
+ Status = 0;
+ } else {
+ _PostTerminalSwitch(pRing, TerminalId);
+ Status = (int)_WriteBlocking(pRing, s, FragLen);
+ _PostTerminalSwitch(pRing, _ActiveTerminal);
+ }
+ break;
+ case SEGGER_RTT_MODE_NO_BLOCK_TRIM:
+ //
+ // If we are in trim mode and there is not enough space for everything,
+ // trim the output but always include the terminal switch. If no room
+ // for terminal switch, skip that totally.
+ //
+ if (Avail < 4u) {
+ Status = -1;
+ } else {
+ _PostTerminalSwitch(pRing, TerminalId);
+ Status = (int)_WriteBlocking(pRing, s, (FragLen < (Avail - 4u)) ? FragLen : (Avail - 4u));
+ _PostTerminalSwitch(pRing, _ActiveTerminal);
+ }
+ break;
+ case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL:
+ //
+ // If we are in blocking mode, output everything.
+ //
+ _PostTerminalSwitch(pRing, TerminalId);
+ Status = (int)_WriteBlocking(pRing, s, FragLen);
+ _PostTerminalSwitch(pRing, _ActiveTerminal);
+ break;
+ default:
+ Status = -1;
+ break;
+ }
+ //
+ // Finish up.
+ //
+ SEGGER_RTT_UNLOCK();
+ } else {
+ Status = -1;
+ }
+ return Status;
+}
+
+
+/*************************** End of file ****************************/
diff --git a/lib/RTT/SEGGER_RTT.h b/lib/RTT/SEGGER_RTT.h
new file mode 100644
index 000000000000..d999dd1e7fd7
--- /dev/null
+++ b/lib/RTT/SEGGER_RTT.h
@@ -0,0 +1,281 @@
+/*********************************************************************
+* SEGGER Microcontroller GmbH *
+* The Embedded Experts *
+**********************************************************************
+* *
+* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
+* *
+* www.segger.com Support: support@segger.com *
+* *
+**********************************************************************
+* *
+* SEGGER RTT * Real Time Transfer for embedded targets *
+* *
+**********************************************************************
+* *
+* All rights reserved. *
+* *
+* SEGGER strongly recommends to not make any changes *
+* to or modify the source code of this software in order to stay *
+* compatible with the RTT protocol and J-Link. *
+* *
+* Redistribution and use in source and binary forms, with or *
+* without modification, are permitted provided that the following *
+* conditions are met: *
+* *
+* o Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* *
+* o Redistributions in binary form must reproduce the above *
+* copyright notice, this list of conditions and the following *
+* disclaimer in the documentation and/or other materials provided *
+* with the distribution. *
+* *
+* o Neither the name of SEGGER Microcontroller GmbH *
+* nor the names of its contributors may be used to endorse or *
+* promote products derived from this software without specific *
+* prior written permission. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
+* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
+* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
+* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
+* DAMAGE. *
+* *
+**********************************************************************
+* *
+* RTT version: 6.46c *
+* *
+**********************************************************************
+---------------------------END-OF-HEADER------------------------------
+File : SEGGER_RTT.h
+Purpose : Implementation of SEGGER real-time transfer which allows
+ real-time communication on targets which support debugger
+ memory accesses while the CPU is running.
+Revision: $Rev: 14765 $
+----------------------------------------------------------------------
+*/
+
+#ifndef SEGGER_RTT_H
+#define SEGGER_RTT_H
+
+#include "SEGGER_RTT_Conf.h"
+
+
+
+/*********************************************************************
+*
+* Defines, defaults
+*
+**********************************************************************
+*/
+#ifndef RTT_USE_ASM
+ #if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__) || (defined __clang__)) && (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__))
+ #define RTT_USE_ASM (1)
+ #else
+ #define RTT_USE_ASM (0)
+ #endif
+#endif
+
+#ifndef SEGGER_RTT_ASM // defined when SEGGER_RTT.h is included from assembly file
+#include
+#include
+
+/*********************************************************************
+*
+* Defines, fixed
+*
+**********************************************************************
+*/
+
+/*********************************************************************
+*
+* Types
+*
+**********************************************************************
+*/
+
+//
+// Description for a circular buffer (also called "ring buffer")
+// which is used as up-buffer (T->H)
+//
+typedef struct {
+ const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
+ char* pBuffer; // Pointer to start of buffer
+ unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
+ unsigned WrOff; // Position of next item to be written by either target.
+ volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host.
+ unsigned Flags; // Contains configuration flags
+} SEGGER_RTT_BUFFER_UP;
+
+//
+// Description for a circular buffer (also called "ring buffer")
+// which is used as down-buffer (H->T)
+//
+typedef struct {
+ const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
+ char* pBuffer; // Pointer to start of buffer
+ unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
+ volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host.
+ unsigned RdOff; // Position of next item to be read by target (down-buffer).
+ unsigned Flags; // Contains configuration flags
+} SEGGER_RTT_BUFFER_DOWN;
+
+//
+// RTT control block which describes the number of buffers available
+// as well as the configuration for each buffer
+//
+//
+typedef struct {
+ char acID[16]; // Initialized to "SEGGER RTT"
+ int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2)
+ int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2)
+ SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host
+ SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target
+} SEGGER_RTT_CB;
+
+/*********************************************************************
+*
+* Global data
+*
+**********************************************************************
+*/
+extern SEGGER_RTT_CB _SEGGER_RTT;
+
+/*********************************************************************
+*
+* RTT API functions
+*
+**********************************************************************
+*/
+#ifdef __cplusplus
+ extern "C" {
+#endif
+int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
+int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
+int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
+int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
+int SEGGER_RTT_GetKey (void);
+unsigned SEGGER_RTT_HasData (unsigned BufferIndex);
+int SEGGER_RTT_HasKey (void);
+unsigned SEGGER_RTT_HasDataUp (unsigned BufferIndex);
+void SEGGER_RTT_Init (void);
+unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
+unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
+int SEGGER_RTT_SetNameDownBuffer (unsigned BufferIndex, const char* sName);
+int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName);
+int SEGGER_RTT_SetFlagsDownBuffer (unsigned BufferIndex, unsigned Flags);
+int SEGGER_RTT_SetFlagsUpBuffer (unsigned BufferIndex, unsigned Flags);
+int SEGGER_RTT_WaitKey (void);
+unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
+unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
+unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
+unsigned SEGGER_RTT_ASM_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
+unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s);
+void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
+unsigned SEGGER_RTT_PutChar (unsigned BufferIndex, char c);
+unsigned SEGGER_RTT_PutCharSkip (unsigned BufferIndex, char c);
+unsigned SEGGER_RTT_PutCharSkipNoLock (unsigned BufferIndex, char c);
+//
+// Function macro for performance optimization
+//
+#define SEGGER_RTT_HASDATA(n) (_SEGGER_RTT.aDown[n].WrOff - _SEGGER_RTT.aDown[n].RdOff)
+
+#if RTT_USE_ASM
+ #define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock
+#endif
+
+/*********************************************************************
+*
+* RTT "Terminal" API functions
+*
+**********************************************************************
+*/
+int SEGGER_RTT_SetTerminal (unsigned char TerminalId);
+int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s);
+
+/*********************************************************************
+*
+* RTT printf functions (require SEGGER_RTT_printf.c)
+*
+**********************************************************************
+*/
+int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...);
+int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif // ifndef(SEGGER_RTT_ASM)
+
+/*********************************************************************
+*
+* Defines
+*
+**********************************************************************
+*/
+
+//
+// Operating modes. Define behavior if buffer is full (not enough space for entire message)
+//
+#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0) // Skip. Do not block, output nothing. (Default)
+#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1) // Trim: Do not block, output as much as fits.
+#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2) // Block: Wait until there is space in the buffer.
+#define SEGGER_RTT_MODE_MASK (3)
+
+//
+// Control sequences, based on ANSI.
+// Can be used to control color, and clear the screen
+//
+#define RTT_CTRL_RESET "\x1B[0m" // Reset to default colors
+#define RTT_CTRL_CLEAR "\x1B[2J" // Clear screen, reposition cursor to top left
+
+#define RTT_CTRL_TEXT_BLACK "\x1B[2;30m"
+#define RTT_CTRL_TEXT_RED "\x1B[2;31m"
+#define RTT_CTRL_TEXT_GREEN "\x1B[2;32m"
+#define RTT_CTRL_TEXT_YELLOW "\x1B[2;33m"
+#define RTT_CTRL_TEXT_BLUE "\x1B[2;34m"
+#define RTT_CTRL_TEXT_MAGENTA "\x1B[2;35m"
+#define RTT_CTRL_TEXT_CYAN "\x1B[2;36m"
+#define RTT_CTRL_TEXT_WHITE "\x1B[2;37m"
+
+#define RTT_CTRL_TEXT_BRIGHT_BLACK "\x1B[1;30m"
+#define RTT_CTRL_TEXT_BRIGHT_RED "\x1B[1;31m"
+#define RTT_CTRL_TEXT_BRIGHT_GREEN "\x1B[1;32m"
+#define RTT_CTRL_TEXT_BRIGHT_YELLOW "\x1B[1;33m"
+#define RTT_CTRL_TEXT_BRIGHT_BLUE "\x1B[1;34m"
+#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "\x1B[1;35m"
+#define RTT_CTRL_TEXT_BRIGHT_CYAN "\x1B[1;36m"
+#define RTT_CTRL_TEXT_BRIGHT_WHITE "\x1B[1;37m"
+
+#define RTT_CTRL_BG_BLACK "\x1B[24;40m"
+#define RTT_CTRL_BG_RED "\x1B[24;41m"
+#define RTT_CTRL_BG_GREEN "\x1B[24;42m"
+#define RTT_CTRL_BG_YELLOW "\x1B[24;43m"
+#define RTT_CTRL_BG_BLUE "\x1B[24;44m"
+#define RTT_CTRL_BG_MAGENTA "\x1B[24;45m"
+#define RTT_CTRL_BG_CYAN "\x1B[24;46m"
+#define RTT_CTRL_BG_WHITE "\x1B[24;47m"
+
+#define RTT_CTRL_BG_BRIGHT_BLACK "\x1B[4;40m"
+#define RTT_CTRL_BG_BRIGHT_RED "\x1B[4;41m"
+#define RTT_CTRL_BG_BRIGHT_GREEN "\x1B[4;42m"
+#define RTT_CTRL_BG_BRIGHT_YELLOW "\x1B[4;43m"
+#define RTT_CTRL_BG_BRIGHT_BLUE "\x1B[4;44m"
+#define RTT_CTRL_BG_BRIGHT_MAGENTA "\x1B[4;45m"
+#define RTT_CTRL_BG_BRIGHT_CYAN "\x1B[4;46m"
+#define RTT_CTRL_BG_BRIGHT_WHITE "\x1B[4;47m"
+
+
+#endif
+
+/*************************** End of file ****************************/
diff --git a/lib/RTT/SEGGER_RTT_Conf.h b/lib/RTT/SEGGER_RTT_Conf.h
new file mode 100644
index 000000000000..60813f394fa2
--- /dev/null
+++ b/lib/RTT/SEGGER_RTT_Conf.h
@@ -0,0 +1,342 @@
+/*********************************************************************
+* SEGGER Microcontroller GmbH *
+* The Embedded Experts *
+**********************************************************************
+* *
+* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
+* *
+* www.segger.com Support: support@segger.com *
+* *
+**********************************************************************
+* *
+* SEGGER RTT * Real Time Transfer for embedded targets *
+* *
+**********************************************************************
+* *
+* All rights reserved. *
+* *
+* SEGGER strongly recommends to not make any changes *
+* to or modify the source code of this software in order to stay *
+* compatible with the RTT protocol and J-Link. *
+* *
+* Redistribution and use in source and binary forms, with or *
+* without modification, are permitted provided that the following *
+* conditions are met: *
+* *
+* o Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* *
+* o Redistributions in binary form must reproduce the above *
+* copyright notice, this list of conditions and the following *
+* disclaimer in the documentation and/or other materials provided *
+* with the distribution. *
+* *
+* o Neither the name of SEGGER Microcontroller GmbH *
+* nor the names of its contributors may be used to endorse or *
+* promote products derived from this software without specific *
+* prior written permission. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
+* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
+* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
+* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
+* DAMAGE. *
+* *
+**********************************************************************
+* *
+* RTT version: 6.46c *
+* *
+**********************************************************************
+---------------------------END-OF-HEADER------------------------------
+File : SEGGER_RTT_Conf.h
+Purpose : Implementation of SEGGER real-time transfer (RTT) which
+ allows real-time communication on targets which support
+ debugger memory accesses while the CPU is running.
+Revision: $Rev: 13430 $
+
+*/
+
+#ifndef SEGGER_RTT_CONF_H
+#define SEGGER_RTT_CONF_H
+
+#ifdef __IAR_SYSTEMS_ICC__
+ #include
+#endif
+
+/*********************************************************************
+*
+* Defines, configurable
+*
+**********************************************************************
+*/
+
+#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (3) // Max. number of up-buffers (T->H) available on this target (Default: 3)
+#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (3) // Max. number of down-buffers (H->T) available on this target (Default: 3)
+
+#define BUFFER_SIZE_UP (1024) // Size of the buffer for terminal output of target, up to host (Default: 1k)
+#define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16)
+
+#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64)
+
+#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0)
+
+/*********************************************************************
+*
+* RTT memcpy configuration
+*
+* memcpy() is good for large amounts of data,
+* but the overhead is big for small amounts, which are usually stored via RTT.
+* With SEGGER_RTT_MEMCPY_USE_BYTELOOP a simple byte loop can be used instead.
+*
+* SEGGER_RTT_MEMCPY() can be used to replace standard memcpy() in RTT functions.
+* This is may be required with memory access restrictions,
+* such as on Cortex-A devices with MMU.
+*/
+#define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop
+//
+// Example definition of SEGGER_RTT_MEMCPY to external memcpy with GCC toolchains and Cortex-A targets
+//
+//#if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)) && (defined (__ARM_ARCH_7A__))
+// #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) SEGGER_memcpy((pDest), (pSrc), (NumBytes))
+//#endif
+
+//
+// Target is not allowed to perform other RTT operations while string still has not been stored completely.
+// Otherwise we would probably end up with a mixed string in the buffer.
+// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here.
+//
+// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4.
+// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches.
+// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly.
+// (Higher priority = lower priority number)
+// Default value for embOS: 128u
+// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC
+// or define SEGGER_RTT_LOCK() to completely disable interrupts.
+//
+
+#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20)
+
+/*********************************************************************
+*
+* RTT lock configuration for SEGGER Embedded Studio,
+* Rowley CrossStudio and GCC
+*/
+#if (defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__) || (defined __clang__)
+ #if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__))
+ #define SEGGER_RTT_LOCK() { \
+ unsigned int LockState; \
+ __asm volatile ("mrs %0, primask \n\t" \
+ "movs r1, $1 \n\t" \
+ "msr primask, r1 \n\t" \
+ : "=r" (LockState) \
+ : \
+ : "r1" \
+ );
+
+ #define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \
+ : \
+ : "r" (LockState) \
+ : \
+ ); \
+ }
+ #elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__))
+ #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
+ #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
+ #endif
+ #define SEGGER_RTT_LOCK() { \
+ unsigned int LockState; \
+ __asm volatile ("mrs %0, basepri \n\t" \
+ "mov r1, %1 \n\t" \
+ "msr basepri, r1 \n\t" \
+ : "=r" (LockState) \
+ : "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \
+ : "r1" \
+ );
+
+ #define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \
+ : \
+ : "r" (LockState) \
+ : \
+ ); \
+ }
+
+ #elif defined(__ARM_ARCH_7A__)
+ #define SEGGER_RTT_LOCK() { \
+ unsigned int LockState; \
+ __asm volatile ("mrs r1, CPSR \n\t" \
+ "mov %0, r1 \n\t" \
+ "orr r1, r1, #0xC0 \n\t" \
+ "msr CPSR_c, r1 \n\t" \
+ : "=r" (LockState) \
+ : \
+ : "r1" \
+ );
+
+ #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \
+ "mrs r1, CPSR \n\t" \
+ "bic r1, r1, #0xC0 \n\t" \
+ "and r0, r0, #0xC0 \n\t" \
+ "orr r1, r1, r0 \n\t" \
+ "msr CPSR_c, r1 \n\t" \
+ : \
+ : "r" (LockState) \
+ : "r0", "r1" \
+ ); \
+ }
+#else
+ #define SEGGER_RTT_LOCK()
+ #define SEGGER_RTT_UNLOCK()
+ #endif
+#endif
+
+/*********************************************************************
+*
+* RTT lock configuration for IAR EWARM
+*/
+#ifdef __ICCARM__
+ #if (defined (__ARM6M__) && (__CORE__ == __ARM6M__))
+ #define SEGGER_RTT_LOCK() { \
+ unsigned int LockState; \
+ LockState = __get_PRIMASK(); \
+ __set_PRIMASK(1);
+
+ #define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \
+ }
+ #elif ((defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || (defined (__ARM7M__) && (__CORE__ == __ARM7M__)))
+ #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
+ #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
+ #endif
+ #define SEGGER_RTT_LOCK() { \
+ unsigned int LockState; \
+ LockState = __get_BASEPRI(); \
+ __set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
+
+ #define SEGGER_RTT_UNLOCK() __set_BASEPRI(LockState); \
+ }
+ #endif
+#endif
+
+/*********************************************************************
+*
+* RTT lock configuration for IAR RX
+*/
+#ifdef __ICCRX__
+ #define SEGGER_RTT_LOCK() { \
+ unsigned long LockState; \
+ LockState = __get_interrupt_state(); \
+ __disable_interrupt();
+
+ #define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \
+ }
+#endif
+
+/*********************************************************************
+*
+* RTT lock configuration for IAR RL78
+*/
+#ifdef __ICCRL78__
+ #define SEGGER_RTT_LOCK() { \
+ __istate_t LockState; \
+ LockState = __get_interrupt_state(); \
+ __disable_interrupt();
+
+ #define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \
+ }
+#endif
+
+/*********************************************************************
+*
+* RTT lock configuration for KEIL ARM
+*/
+#ifdef __CC_ARM
+ #if (defined __TARGET_ARCH_6S_M)
+ #define SEGGER_RTT_LOCK() { \
+ unsigned int LockState; \
+ register unsigned char PRIMASK __asm( "primask"); \
+ LockState = PRIMASK; \
+ PRIMASK = 1u; \
+ __schedule_barrier();
+
+ #define SEGGER_RTT_UNLOCK() PRIMASK = LockState; \
+ __schedule_barrier(); \
+ }
+ #elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))
+ #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
+ #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
+ #endif
+ #define SEGGER_RTT_LOCK() { \
+ unsigned int LockState; \
+ register unsigned char BASEPRI __asm( "basepri"); \
+ LockState = BASEPRI; \
+ BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \
+ __schedule_barrier();
+
+ #define SEGGER_RTT_UNLOCK() BASEPRI = LockState; \
+ __schedule_barrier(); \
+ }
+ #endif
+#endif
+
+/*********************************************************************
+*
+* RTT lock configuration for TI ARM
+*/
+#ifdef __TI_ARM__
+ #if defined (__TI_ARM_V6M0__)
+ #define SEGGER_RTT_LOCK() { \
+ unsigned int LockState; \
+ LockState = __get_PRIMASK(); \
+ __set_PRIMASK(1);
+
+ #define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \
+ }
+ #elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__))
+ #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
+ #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
+ #endif
+ #define SEGGER_RTT_LOCK() { \
+ unsigned int LockState; \
+ LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
+
+ #define SEGGER_RTT_UNLOCK() _set_interrupt_priority(LockState); \
+ }
+ #endif
+#endif
+
+/*********************************************************************
+*
+* RTT lock configuration for CCRX
+*/
+#ifdef __RX
+ #define SEGGER_RTT_LOCK() { \
+ unsigned long LockState; \
+ LockState = get_psw() & 0x010000; \
+ clrpsw_i();
+
+ #define SEGGER_RTT_UNLOCK() set_psw(get_psw() | LockState); \
+ }
+#endif
+
+/*********************************************************************
+*
+* RTT lock configuration fallback
+*/
+#ifndef SEGGER_RTT_LOCK
+ #define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts)
+#endif
+
+#ifndef SEGGER_RTT_UNLOCK
+ #define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state)
+#endif
+
+#endif
+/*************************** End of file ****************************/
diff --git a/lib/RTT/SEGGER_RTT_printf.c b/lib/RTT/SEGGER_RTT_printf.c
new file mode 100644
index 000000000000..2627e47edd95
--- /dev/null
+++ b/lib/RTT/SEGGER_RTT_printf.c
@@ -0,0 +1,514 @@
+/*********************************************************************
+* SEGGER Microcontroller GmbH *
+* The Embedded Experts *
+**********************************************************************
+* *
+* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
+* *
+* www.segger.com Support: support@segger.com *
+* *
+**********************************************************************
+* *
+* SEGGER RTT * Real Time Transfer for embedded targets *
+* *
+**********************************************************************
+* *
+* All rights reserved. *
+* *
+* SEGGER strongly recommends to not make any changes *
+* to or modify the source code of this software in order to stay *
+* compatible with the RTT protocol and J-Link. *
+* *
+* Redistribution and use in source and binary forms, with or *
+* without modification, are permitted provided that the following *
+* conditions are met: *
+* *
+* o Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* *
+* o Redistributions in binary form must reproduce the above *
+* copyright notice, this list of conditions and the following *
+* disclaimer in the documentation and/or other materials provided *
+* with the distribution. *
+* *
+* o Neither the name of SEGGER Microcontroller GmbH *
+* nor the names of its contributors may be used to endorse or *
+* promote products derived from this software without specific *
+* prior written permission. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
+* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
+* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
+* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
+* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
+* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
+* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
+* DAMAGE. *
+* *
+**********************************************************************
+* *
+* RTT version: 6.46c *
+* *
+**********************************************************************
+---------------------------END-OF-HEADER------------------------------
+File : SEGGER_RTT_printf.c
+Purpose : Replacement for printf to write formatted data via RTT
+Revision: $Rev: 12360 $
+----------------------------------------------------------------------
+*/
+#include "SEGGER_RTT.h"
+#include "SEGGER_RTT_Conf.h"
+
+/*********************************************************************
+*
+* Defines, configurable
+*
+**********************************************************************
+*/
+
+#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
+ #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
+#endif
+
+#include
+#include
+
+
+#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
+#define FORMAT_FLAG_PAD_ZERO (1u << 1)
+#define FORMAT_FLAG_PRINT_SIGN (1u << 2)
+#define FORMAT_FLAG_ALTERNATE (1u << 3)
+
+/*********************************************************************
+*
+* Types
+*
+**********************************************************************
+*/
+
+typedef struct {
+ char* pBuffer;
+ unsigned BufferSize;
+ unsigned Cnt;
+
+ int ReturnValue;
+
+ unsigned RTTBufferIndex;
+} SEGGER_RTT_PRINTF_DESC;
+
+/*********************************************************************
+*
+* Function prototypes
+*
+**********************************************************************
+*/
+
+/*********************************************************************
+*
+* Static code
+*
+**********************************************************************
+*/
+/*********************************************************************
+*
+* _StoreChar
+*/
+static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
+ unsigned Cnt;
+
+ Cnt = p->Cnt;
+ if ((Cnt + 1u) <= p->BufferSize) {
+ *(p->pBuffer + Cnt) = c;
+ p->Cnt = Cnt + 1u;
+ p->ReturnValue++;
+ }
+ //
+ // Write part of string, when the buffer is full
+ //
+ if (p->Cnt == p->BufferSize) {
+ if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
+ p->ReturnValue = -1;
+ } else {
+ p->Cnt = 0u;
+ }
+ }
+}
+
+/*********************************************************************
+*
+* _PrintUnsigned
+*/
+static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
+ static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ unsigned Div;
+ unsigned Digit;
+ unsigned Number;
+ unsigned Width;
+ char c;
+
+ Number = v;
+ Digit = 1u;
+ //
+ // Get actual field width
+ //
+ Width = 1u;
+ while (Number >= Base) {
+ Number = (Number / Base);
+ Width++;
+ }
+ if (NumDigits > Width) {
+ Width = NumDigits;
+ }
+ //
+ // Print leading chars if necessary
+ //
+ if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {
+ if (FieldWidth != 0u) {
+ if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {
+ c = '0';
+ } else {
+ c = ' ';
+ }
+ while ((FieldWidth != 0u) && (Width < FieldWidth)) {
+ FieldWidth--;
+ _StoreChar(pBufferDesc, c);
+ if (pBufferDesc->ReturnValue < 0) {
+ break;
+ }
+ }
+ }
+ }
+ if (pBufferDesc->ReturnValue >= 0) {
+ //
+ // Compute Digit.
+ // Loop until Digit has the value of the highest digit required.
+ // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100.
+ //
+ while (1) {
+ if (NumDigits > 1u) { // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned)
+ NumDigits--;
+ } else {
+ Div = v / Digit;
+ if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done
+ break;
+ }
+ }
+ Digit *= Base;
+ }
+ //
+ // Output digits
+ //
+ do {
+ Div = v / Digit;
+ v -= Div * Digit;
+ _StoreChar(pBufferDesc, _aV2C[Div]);
+ if (pBufferDesc->ReturnValue < 0) {
+ break;
+ }
+ Digit /= Base;
+ } while (Digit);
+ //
+ // Print trailing spaces if necessary
+ //
+ if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
+ if (FieldWidth != 0u) {
+ while ((FieldWidth != 0u) && (Width < FieldWidth)) {
+ FieldWidth--;
+ _StoreChar(pBufferDesc, ' ');
+ if (pBufferDesc->ReturnValue < 0) {
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*********************************************************************
+*
+* _PrintInt
+*/
+static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
+ unsigned Width;
+ int Number;
+
+ Number = (v < 0) ? -v : v;
+
+ //
+ // Get actual field width
+ //
+ Width = 1u;
+ while (Number >= (int)Base) {
+ Number = (Number / (int)Base);
+ Width++;
+ }
+ if (NumDigits > Width) {
+ Width = NumDigits;
+ }
+ if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
+ FieldWidth--;
+ }
+
+ //
+ // Print leading spaces if necessary
+ //
+ if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {
+ if (FieldWidth != 0u) {
+ while ((FieldWidth != 0u) && (Width < FieldWidth)) {
+ FieldWidth--;
+ _StoreChar(pBufferDesc, ' ');
+ if (pBufferDesc->ReturnValue < 0) {
+ break;
+ }
+ }
+ }
+ }
+ //
+ // Print sign if necessary
+ //
+ if (pBufferDesc->ReturnValue >= 0) {
+ if (v < 0) {
+ v = -v;
+ _StoreChar(pBufferDesc, '-');
+ } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
+ _StoreChar(pBufferDesc, '+');
+ } else {
+
+ }
+ if (pBufferDesc->ReturnValue >= 0) {
+ //
+ // Print leading zeros if necessary
+ //
+ if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {
+ if (FieldWidth != 0u) {
+ while ((FieldWidth != 0u) && (Width < FieldWidth)) {
+ FieldWidth--;
+ _StoreChar(pBufferDesc, '0');
+ if (pBufferDesc->ReturnValue < 0) {
+ break;
+ }
+ }
+ }
+ }
+ if (pBufferDesc->ReturnValue >= 0) {
+ //
+ // Print number without sign
+ //
+ _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
+ }
+ }
+ }
+}
+
+/*********************************************************************
+*
+* Public code
+*
+**********************************************************************
+*/
+/*********************************************************************
+*
+* SEGGER_RTT_vprintf
+*
+* Function description
+* Stores a formatted string in SEGGER RTT control block.
+* This data is read by the host.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
+* sFormat Pointer to format string
+* pParamList Pointer to the list of arguments for the format string
+*
+* Return values
+* >= 0: Number of bytes which have been stored in the "Up"-buffer.
+* < 0: Error
+*/
+int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
+ char c;
+ SEGGER_RTT_PRINTF_DESC BufferDesc;
+ int v;
+ unsigned NumDigits;
+ unsigned FormatFlags;
+ unsigned FieldWidth;
+ char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
+
+ BufferDesc.pBuffer = acBuffer;
+ BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE;
+ BufferDesc.Cnt = 0u;
+ BufferDesc.RTTBufferIndex = BufferIndex;
+ BufferDesc.ReturnValue = 0;
+
+ do {
+ c = *sFormat;
+ sFormat++;
+ if (c == 0u) {
+ break;
+ }
+ if (c == '%') {
+ //
+ // Filter out flags
+ //
+ FormatFlags = 0u;
+ v = 1;
+ do {
+ c = *sFormat;
+ switch (c) {
+ case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
+ case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break;
+ case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break;
+ case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break;
+ default: v = 0; break;
+ }
+ } while (v);
+ //
+ // filter out field with
+ //
+ FieldWidth = 0u;
+ do {
+ c = *sFormat;
+ if ((c < '0') || (c > '9')) {
+ break;
+ }
+ sFormat++;
+ FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
+ } while (1);
+
+ //
+ // Filter out precision (number of digits to display)
+ //
+ NumDigits = 0u;
+ c = *sFormat;
+ if (c == '.') {
+ sFormat++;
+ do {
+ c = *sFormat;
+ if ((c < '0') || (c > '9')) {
+ break;
+ }
+ sFormat++;
+ NumDigits = NumDigits * 10u + ((unsigned)c - '0');
+ } while (1);
+ }
+ //
+ // Filter out length modifier
+ //
+ c = *sFormat;
+ do {
+ if ((c == 'l') || (c == 'h')) {
+ sFormat++;
+ c = *sFormat;
+ } else {
+ break;
+ }
+ } while (1);
+ //
+ // Handle specifiers
+ //
+ switch (c) {
+ case 'c': {
+ char c0;
+ v = va_arg(*pParamList, int);
+ c0 = (char)v;
+ _StoreChar(&BufferDesc, c0);
+ break;
+ }
+ case 'd':
+ v = va_arg(*pParamList, int);
+ _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
+ break;
+ case 'u':
+ v = va_arg(*pParamList, int);
+ _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
+ break;
+ case 'x':
+ case 'X':
+ v = va_arg(*pParamList, int);
+ _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
+ break;
+ case 's':
+ {
+ const char * s = va_arg(*pParamList, const char *);
+ do {
+ c = *s;
+ s++;
+ if (c == '\0') {
+ break;
+ }
+ _StoreChar(&BufferDesc, c);
+ } while (BufferDesc.ReturnValue >= 0);
+ }
+ break;
+ case 'p':
+ v = va_arg(*pParamList, int);
+ _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
+ break;
+ case '%':
+ _StoreChar(&BufferDesc, '%');
+ break;
+ default:
+ break;
+ }
+ sFormat++;
+ } else {
+ _StoreChar(&BufferDesc, c);
+ }
+ } while (BufferDesc.ReturnValue >= 0);
+
+ if (BufferDesc.ReturnValue > 0) {
+ //
+ // Write remaining data, if any
+ //
+ if (BufferDesc.Cnt != 0u) {
+ SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
+ }
+ BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
+ }
+ return BufferDesc.ReturnValue;
+}
+
+/*********************************************************************
+*
+* SEGGER_RTT_printf
+*
+* Function description
+* Stores a formatted string in SEGGER RTT control block.
+* This data is read by the host.
+*
+* Parameters
+* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
+* sFormat Pointer to format string, followed by the arguments for conversion
+*
+* Return values
+* >= 0: Number of bytes which have been stored in the "Up"-buffer.
+* < 0: Error
+*
+* Notes
+* (1) Conversion specifications have following syntax:
+* %[flags][FieldWidth][.Precision]ConversionSpecifier
+* (2) Supported flags:
+* -: Left justify within the field width
+* +: Always print sign extension for signed conversions
+* 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
+* Supported conversion specifiers:
+* c: Print the argument as one char
+* d: Print the argument as a signed integer
+* u: Print the argument as an unsigned integer
+* x: Print the argument as an hexadecimal integer
+* s: Print the string pointed to by the argument
+* p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
+*/
+int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
+ int r;
+ va_list ParamList;
+
+ va_start(ParamList, sFormat);
+ r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
+ va_end(ParamList);
+ return r;
+}
+/*************************** End of file ****************************/
diff --git a/platforms/chibios/cm32_compatibility.h b/platforms/chibios/cm32_compatibility.h
index d5176e445859..c9fdb51ad7a4 100644
--- a/platforms/chibios/cm32_compatibility.h
+++ b/platforms/chibios/cm32_compatibility.h
@@ -33,8 +33,8 @@
# define FLASH_CR_STRT FLASH_CTRL_START
# define FLASH_CR_LOCK FLASH_CTRL_LOCK
# define FLASH_CR_PG FLASH_CTRL_PG
-# define FLASH_KEY1 0x45670123U
-# define FLASH_KEY2 0xCDEF89ABU
+// # define FLASH_KEY1 0x45670123U
+// # define FLASH_KEY2 0xCDEF89ABU
#endif
diff --git a/quantum/keyboard.c b/quantum/keyboard.c
index 40af016c4be8..94b16b6cad08 100644
--- a/quantum/keyboard.c
+++ b/quantum/keyboard.c
@@ -33,6 +33,7 @@ along with this program. If not, see .
#include "sendchar.h"
#include "eeconfig.h"
#include "action_layer.h"
+// #include "../lib/RTT/SEGGER_RTT.h"
#ifdef BACKLIGHT_ENABLE
# include "backlight.h"
#endif
diff --git a/tmk_core/protocol/chibios/chibios.c b/tmk_core/protocol/chibios/chibios.c
index c9a480c32555..dd0a29c212b2 100644
--- a/tmk_core/protocol/chibios/chibios.c
+++ b/tmk_core/protocol/chibios/chibios.c
@@ -59,12 +59,20 @@ uint8_t keyboard_leds(void);
void send_keyboard(report_keyboard_t *report);
void send_mouse(report_mouse_t *report);
void send_system(uint16_t data);
+#ifdef RADIAL_CONTROLLER_ENABLE
+void send_radial(uint16_t data);
+#endif
void send_consumer(uint16_t data);
void send_programmable_button(uint32_t data);
void send_digitizer(report_digitizer_t *report);
/* host struct */
-host_driver_t chibios_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button};
+host_driver_t chibios_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, \
+
+#ifdef RADIAL_CONTROLLER_ENABLE
+ send_radial,
+#endif
+ send_consumer, send_programmable_button};
#ifdef VIRTSER_ENABLE
void virtser_task(void);
@@ -74,6 +82,10 @@ void virtser_task(void);
void raw_hid_task(void);
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+void openrgb_hid_task(void);
+#endif
+
#ifdef CONSOLE_ENABLE
void console_task(void);
#endif
@@ -218,4 +230,7 @@ void protocol_post_task(void) {
#ifdef RAW_ENABLE
raw_hid_task();
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ openrgb_hid_task();
+#endif
}
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
index 19e2e858fc9b..29b9d0916f1b 100644
--- a/tmk_core/protocol/chibios/usb_main.c
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -313,6 +313,9 @@ typedef struct {
#ifdef RAW_ENABLE
usb_driver_config_t raw_driver;
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ usb_driver_config_t openrgb_driver;
+#endif
#ifdef MIDI_ENABLE
usb_driver_config_t midi_driver;
#endif
@@ -349,7 +352,13 @@ static usb_driver_configs_t drivers = {
# define RAW_OUT_MODE USB_EP_MODE_TYPE_INTR
.raw_driver = QMK_USB_DRIVER_CONFIG(RAW, 0, false),
#endif
-
+#ifdef OPENRGB_PROTOCOL_ENABLE
+# define OPENRGB_IN_CAPACITY 4
+# define OPENRGB_OUT_CAPACITY 4
+# define OPENRGB_IN_MODE USB_EP_MODE_TYPE_INTR
+# define OPENRGB_OUT_MODE USB_EP_MODE_TYPE_INTR
+ .openrgb_driver = QMK_USB_DRIVER_CONFIG(OPENRGB, 0, false),
+#endif
#ifdef MIDI_ENABLE
# define MIDI_STREAM_IN_CAPACITY 4
# define MIDI_STREAM_OUT_CAPACITY 4
@@ -510,6 +519,10 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
case USB_EVENT_UNCONFIGURED:
/* Falls into.*/
case USB_EVENT_RESET:
+ keyboard_protocol = 1;
+#ifdef NKRO_ENABLE
+ keymap_config.nkro = !!keyboard_protocol;
+#endif
usb_event_queue_enqueue(event);
for (int i = 0; i < NUM_USB_DRIVERS; i++) {
chSysLockFromISR();
@@ -979,6 +992,14 @@ void send_system(uint16_t data) {
#endif
}
+#ifdef RADIAL_CONTROLLER_ENABLE
+void send_radial(uint16_t data) {
+#ifdef EXTRAKEY_ENABLE
+ send_extra(REPORT_ID_RADIAL, data);
+#endif
+}
+#endif
+
void send_consumer(uint16_t data) {
#ifdef EXTRAKEY_ENABLE
send_extra(REPORT_ID_CONSUMER, data);
@@ -1115,6 +1136,34 @@ void raw_hid_task(void) {
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+void openrgb_hid_send(uint8_t *data, uint8_t length) {
+ // TODO: implement variable size packet
+ if (length != OPENRGB_EPSIZE) {
+ return;
+ }
+ chnWrite(&drivers.openrgb_driver.driver, data, length);
+}
+
+__attribute__((weak)) void openrgb_hid_receive(uint8_t *data, uint8_t length) {
+ // Users should #include "raw_hid.h" in their own code
+ // and implement this function there. Leave this as weak linkage
+ // so users can opt to not handle data coming in.
+}
+
+void openrgb_hid_task(void) {
+ uint8_t buffer[OPENRGB_EPSIZE];
+ size_t size = 0;
+ do {
+ size_t size = chnReadTimeout(&drivers.openrgb_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
+ if (size > 0) {
+ openrgb_hid_receive(buffer, size);
+ }
+ } while (size > 0);
+}
+
+#endif
+
#ifdef MIDI_ENABLE
void send_midi_packet(MIDI_EventPacket_t *event) {
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index b4b03357a36b..d9983368710d 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -102,9 +102,17 @@ static uint8_t keyboard_leds(void);
static void send_keyboard(report_keyboard_t *report);
static void send_mouse(report_mouse_t *report);
static void send_system(uint16_t data);
+#ifdef RADIAL_CONTROLLER_ENABLE
+static void send_radial(uint16_t data);
+#endif
static void send_consumer(uint16_t data);
static void send_programmable_button(uint32_t data);
-host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button};
+host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, \
+
+#ifdef RADIAL_CONTROLLER_ENABLE
+ send_radial,
+#endif
+ send_consumer, send_programmable_button};
#ifdef VIRTSER_ENABLE
// clang-format off
@@ -209,6 +217,78 @@ static void raw_hid_task(void) {
}
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+
+void openrgb_hid_send(uint8_t *data, uint8_t length) {
+ // TODO: implement variable size packet
+ if (length != OPENRGB_EPSIZE) {
+ return;
+ }
+
+ if (USB_DeviceState != DEVICE_STATE_Configured) {
+ return;
+ }
+
+ // TODO: decide if we allow calls to raw_hid_send() in the middle
+ // of other endpoint usage.
+ uint8_t ep = Endpoint_GetCurrentEndpoint();
+
+ Endpoint_SelectEndpoint(OPENRGB_IN_EPNUM);
+
+ // Check to see if the host is ready to accept another packet
+ if (Endpoint_IsINReady()) {
+ // Write data
+ Endpoint_Write_Stream_LE(data, OPENRGB_EPSIZE, NULL);
+ // Finalize the stream transfer to send the last packet
+ Endpoint_ClearIN();
+ }
+
+ Endpoint_SelectEndpoint(ep);
+}
+
+/** \brief Raw HID Receive
+ *
+ * FIXME: Needs doc
+ */
+__attribute__((weak)) void openrgb_hid_receive(uint8_t *data, uint8_t length) {
+ // Users should #include "raw_hid.h" in their own code
+ // and implement this function there. Leave this as weak linkage
+ // so users can opt to not handle data coming in.
+}
+
+/** \brief Raw HID Task
+ *
+ * FIXME: Needs doc
+ */
+static void openrgb_hid_task(void) {
+ // Create a temporary buffer to hold the read in data from the host
+ uint8_t data[OPENRGB_EPSIZE];
+ bool data_read = false;
+
+ // Device must be connected and configured for the task to run
+ if (USB_DeviceState != DEVICE_STATE_Configured) return;
+
+ Endpoint_SelectEndpoint(OPENRGB_OUT_EPNUM);
+
+ // Check to see if a packet has been sent from the host
+ if (Endpoint_IsOUTReceived()) {
+ // Check to see if the packet contains data
+ if (Endpoint_IsReadWriteAllowed()) {
+ /* Read data */
+ Endpoint_Read_Stream_LE(data, sizeof(data), NULL);
+ data_read = true;
+ }
+
+ // Finalize the stream transfer to receive the last packet
+ Endpoint_ClearOUT();
+
+ if (data_read) {
+ openrgb_hid_receive(data, sizeof(data));
+ }
+ }
+}
+#endif
+
/*******************************************************************************
* Console
******************************************************************************/
@@ -471,6 +551,11 @@ void EVENT_USB_Device_ConfigurationChanged(void) {
ConfigSuccess &= Endpoint_ConfigureEndpoint((RAW_OUT_EPNUM | ENDPOINT_DIR_OUT), EP_TYPE_INTERRUPT, RAW_EPSIZE, 1);
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ ConfigSuccess &= Endpoint_ConfigureEndpoint((OPENRGB_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, OPENRGB_EPSIZE, 1);
+ ConfigSuccess &= Endpoint_ConfigureEndpoint((OPENRGB_OUT_EPNUM | ENDPOINT_DIR_OUT), EP_TYPE_INTERRUPT, OPENRGB_EPSIZE, 1);
+#endif
+
#ifdef CONSOLE_ENABLE
/* Setup console endpoint */
ConfigSuccess &= Endpoint_ConfigureEndpoint((CONSOLE_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, CONSOLE_EPSIZE, 1);
@@ -764,6 +849,13 @@ static void send_system(uint16_t data) {
#endif
}
+#ifdef RADIAL_CONTROLLER_ENABLE
+static void send_radial(uint16_t data) {
+#ifdef EXTRAKEY_ENABLE
+ send_extra(REPORT_ID_RADIAL, data);
+#endif
+}
+#endif
/** \brief Send Consumer
*
* FIXME: Needs doc
@@ -1096,6 +1188,10 @@ void protocol_post_task(void) {
raw_hid_task();
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ openrgb_hid_task();
+#endif
+
#if !defined(INTERRUPT_CONTROL_ENDPOINT)
USB_USBTask();
#endif
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index 063bd2c3f177..113af5fd2057 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -223,6 +223,36 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
+#ifdef RADIAL_CONTROLLER_ENABLE
+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+ 0x09, 0x0e, // USAGE (System Multi-Axis Controller)
+ 0xa1, 0x01, // COLLECTION (Application)
+ 0x85, REPORT_ID_RADIAL, // REPORT_ID (Radial Controller)
+ 0x05, 0x0d, // USAGE_PAGE (Digitizers)
+ 0x09, 0x21, // USAGE (Puck)
+ 0xa1, 0x00, // COLLECTION (Physical)
+ 0x05, 0x09, // USAGE_PAGE (Buttons)
+ 0x09, 0x01, // USAGE (Button 1)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x75, 0x01, // REPORT_SIZE (1)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x25, 0x01, // LOGICAL_MAXIMUM (1)
+ 0x81, 0x02, // INPUT (Data,Var,Abs)
+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+ 0x09, 0x37, // USAGE (Dial)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x75, 0x0f, // REPORT_SIZE (15)
+ 0x55, 0x0f, // UNIT_EXPONENT (-1)
+ 0x65, 0x14, // UNIT (Degrees, English Rotation)
+ 0x36, 0xf0, 0xf1, // PHYSICAL_MINIMUM (-3600)
+ 0x46, 0x10, 0x0e, // PHYSICAL_MAXIMUM (3600)
+ 0x16, 0xf0, 0xf1, // LOGICAL_MINIMUM (-3600)
+ 0x26, 0x10, 0x0e, // LOGICAL_MAXIMUM (3600)
+ 0x81, 0x06, // INPUT (Data,Var,Rel)
+ 0xc0, // END_COLLECTION
+ 0xc0, // END_COLLECTION
+#endif
+
HID_RI_USAGE_PAGE(8, 0x0C), // Consumer
HID_RI_USAGE(8, 0x01), // Consumer Control
HID_RI_COLLECTION(8, 0x01), // Application
@@ -322,6 +352,30 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM RawReport[] = {
};
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+const USB_Descriptor_HIDReport_Datatype_t PROGMEM OPENRGBReport[] = {
+ HID_RI_USAGE_PAGE(16, OPENRGB_USAGE_PAGE), // Vendor Defined
+ HID_RI_USAGE(8, OPENRGB_USAGE_ID), // Vendor Defined
+ HID_RI_COLLECTION(8, 0x01), // Application
+ // Data to host
+ HID_RI_USAGE(8, 0x62), // Vendor Defined
+ HID_RI_LOGICAL_MINIMUM(8, 0x00),
+ HID_RI_LOGICAL_MAXIMUM(16, 0x00FF),
+ HID_RI_REPORT_COUNT(8, OPENRGB_EPSIZE),
+ HID_RI_REPORT_SIZE(8, 0x08),
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
+
+ // Data from host
+ HID_RI_USAGE(8, 0x63), // Vendor Defined
+ HID_RI_LOGICAL_MINIMUM(8, 0x00),
+ HID_RI_LOGICAL_MAXIMUM(16, 0x00FF),
+ HID_RI_REPORT_COUNT(8, OPENRGB_EPSIZE),
+ HID_RI_REPORT_SIZE(8, 0x08),
+ HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
+ HID_RI_END_COLLECTION(0),
+};
+#endif
+
#ifdef CONSOLE_ENABLE
const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] = {
HID_RI_USAGE_PAGE(16, 0xFF31), // Vendor Defined (PJRC Teensy compatible)
@@ -554,6 +608,53 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = {
},
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ .OPENRGB_Interface = {
+ .Header = {
+ .Size = sizeof(USB_Descriptor_Interface_t),
+ .Type = DTYPE_Interface
+ },
+ .InterfaceNumber = OPENRGB_INTERFACE,
+ .AlternateSetting = 0x00,
+ .TotalEndpoints = 2,
+ .Class = HID_CSCP_HIDClass,
+ .SubClass = HID_CSCP_NonBootSubclass,
+ .Protocol = HID_CSCP_NonBootProtocol,
+ .InterfaceStrIndex = NO_DESCRIPTOR
+ },
+ .OPENRGB_HID = {
+ .Header = {
+ .Size = sizeof(USB_HID_Descriptor_HID_t),
+ .Type = HID_DTYPE_HID
+ },
+ .HIDSpec = VERSION_BCD(1, 1, 1),
+ .CountryCode = 0x00,
+ .TotalReportDescriptors = 1,
+ .HIDReportType = HID_DTYPE_Report,
+ .HIDReportLength = sizeof(OPENRGBReport)
+ },
+ .OPENRGB_INEndpoint = {
+ .Header = {
+ .Size = sizeof(USB_Descriptor_Endpoint_t),
+ .Type = DTYPE_Endpoint
+ },
+ .EndpointAddress = (ENDPOINT_DIR_IN | OPENRGB_IN_EPNUM),
+ .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+ .EndpointSize = OPENRGB_EPSIZE,
+ .PollingIntervalMS = 0x01
+ },
+ .OPENRGB_OUTEndpoint = {
+ .Header = {
+ .Size = sizeof(USB_Descriptor_Endpoint_t),
+ .Type = DTYPE_Endpoint
+ },
+ .EndpointAddress = (ENDPOINT_DIR_OUT | OPENRGB_OUT_EPNUM),
+ .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+ .EndpointSize = OPENRGB_EPSIZE,
+ .PollingIntervalMS = 0x01
+ },
+#endif
+
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
/*
* Mouse
@@ -1148,6 +1249,14 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
break;
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ case OPENRGB_INTERFACE:
+ Address = &ConfigurationDescriptor.OPENRGB_HID;
+ Size = sizeof(USB_HID_Descriptor_HID_t);
+
+ break;
+#endif
+
#ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE:
Address = &ConfigurationDescriptor.Console_HID;
@@ -1205,6 +1314,14 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
break;
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ case OPENRGB_INTERFACE:
+ Address = &OPENRGBReport;
+ Size = sizeof(OPENRGBReport);
+
+ break;
+#endif
+
#ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE:
Address = &ConsoleReport;
@@ -1212,12 +1329,14 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
break;
#endif
+
#ifdef JOYSTICK_ENABLE
case JOYSTICK_INTERFACE:
Address = &JoystickReport;
Size = sizeof(JoystickReport);
break;
#endif
+
#if defined(DIGITIZER_ENABLE) && !defined(DIGITIZER_SHARED_EP)
case DIGITIZER_INTERFACE:
Address = &DigitizerReport;
diff --git a/tmk_core/protocol/usb_descriptor.h b/tmk_core/protocol/usb_descriptor.h
index 6c3424145ce5..300a8549eb6e 100644
--- a/tmk_core/protocol/usb_descriptor.h
+++ b/tmk_core/protocol/usb_descriptor.h
@@ -75,6 +75,13 @@ typedef struct {
USB_Descriptor_Endpoint_t Raw_OUTEndpoint;
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ USB_Descriptor_Interface_t OPENRGB_Interface;
+ USB_HID_Descriptor_HID_t OPENRGB_HID;
+ USB_Descriptor_Endpoint_t OPENRGB_INEndpoint;
+ USB_Descriptor_Endpoint_t OPENRGB_OUTEndpoint;
+#endif
+
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
// Mouse HID Interface
USB_Descriptor_Interface_t Mouse_Interface;
@@ -162,6 +169,10 @@ enum usb_interfaces {
RAW_INTERFACE,
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ OPENRGB_INTERFACE,
+#endif
+
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
MOUSE_INTERFACE,
#endif
@@ -223,6 +234,15 @@ enum usb_endpoints {
# endif
#endif
+#ifdef OPENRGB_PROTOCOL_ENABLE
+ OPENRGB_IN_EPNUM = NEXT_EPNUM,
+# if STM32_USB_USE_OTG1
+# define OPENRGB_OUT_EPNUM OPENRGB_IN_EPNUM
+# else
+ OPENRGB_OUT_EPNUM = NEXT_EPNUM,
+# endif
+#endif
+
#ifdef SHARED_EP_ENABLE
SHARED_IN_EPNUM = NEXT_EPNUM,
#endif
@@ -303,6 +323,7 @@ enum usb_endpoints {
#define SHARED_EPSIZE 32
#define MOUSE_EPSIZE 8
#define RAW_EPSIZE 32
+#define OPENRGB_EPSIZE 64
#define CONSOLE_EPSIZE 32
#define MIDI_STREAM_EPSIZE 64
#define CDC_NOTIFICATION_EPSIZE 8
diff --git a/tmk_core/protocol/usb_descriptor_common.h b/tmk_core/protocol/usb_descriptor_common.h
index ce0cf09763bc..9224a51fd2a8 100644
--- a/tmk_core/protocol/usb_descriptor_common.h
+++ b/tmk_core/protocol/usb_descriptor_common.h
@@ -31,5 +31,16 @@
# define RAW_USAGE_ID 0x61
#endif
+#ifndef OPENRGB_USAGE_PAGE
+# define OPENRGB_USAGE_PAGE 0xFF59
+#endif
+
+#ifndef OPENRGB_USAGE_ID
+# define OPENRGB_USAGE_ID 0x60
+#endif
+
#define RAW_USAGE_PAGE_HI ((uint8_t)(RAW_USAGE_PAGE >> 8))
#define RAW_USAGE_PAGE_LO ((uint8_t)(RAW_USAGE_PAGE & 0xFF))
+
+#define OPENRGB_USAGE_PAGE_HI ((uint8_t)(OPENRGB_USAGE_PAGE >> 8))
+#define OPENRGB_USAGE_PAGE_LO ((uint8_t)(OPENRGB_USAGE_PAGE & 0xFF))