diff options
author | Thomas Albers Raviola <thomas@thomaslabs.org> | 2024-11-21 15:55:03 +0100 |
---|---|---|
committer | Thomas Albers Raviola <thomas@thomaslabs.org> | 2024-11-21 15:55:03 +0100 |
commit | 6d4ad089c5b758ad8af4f68bf385a26ec4e9653a (patch) | |
tree | 2fd65006b57d646b53e121aef42bba5ee5852840 |
Initial commit
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | COPYING | 674 | ||||
-rw-r--r-- | Makefile | 65 | ||||
-rw-r--r-- | README.md | 37 | ||||
-rw-r--r-- | asm/crt0.asm | 64 | ||||
-rw-r--r-- | asm/delay.asm | 13 | ||||
-rw-r--r-- | asm/isr.asm | 17 | ||||
-rw-r--r-- | include/fifo.h | 45 | ||||
-rw-r--r-- | include/hardware.h | 80 | ||||
-rw-r--r-- | include/i2c.h | 24 | ||||
-rw-r--r-- | include/input.h | 22 | ||||
-rw-r--r-- | include/tft.h | 132 | ||||
-rw-r--r-- | include/tty.h | 34 | ||||
-rw-r--r-- | include/zeta.h | 67 | ||||
-rw-r--r-- | manifest.scm | 6 | ||||
-rw-r--r-- | src/bootloader.c | 310 | ||||
-rw-r--r-- | src/crc16.c | 48 | ||||
-rw-r--r-- | src/fifo.c | 0 | ||||
-rw-r--r-- | src/font.c | 101 | ||||
-rw-r--r-- | src/i2c.c | 103 | ||||
-rw-r--r-- | src/input.c | 59 | ||||
-rw-r--r-- | src/main.c | 185 | ||||
-rw-r--r-- | src/menu.c | 269 | ||||
-rw-r--r-- | src/tft.c | 138 | ||||
-rw-r--r-- | src/tty.c | 164 |
25 files changed, 2658 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a007fea --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/* @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU 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 <https://www.gnu.org/licenses/>. + +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: + + <program> Copyright (C) <year> <name of author> + 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 +<https://www.gnu.org/licenses/>. + + 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 +<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9311c3e --- /dev/null +++ b/Makefile @@ -0,0 +1,65 @@ +PROJECT=firmware + +AS=sdasz80 +CC=sdcc +CPP=sdcpp + +ASM=crt0.asm\ + isr.asm\ + delay.asm +SRC=crc16.c\ + bootloader.c\ + font.c\ + i2c.c\ + input.c\ + main.c\ + tft.c\ + tty.c\ + menu.c + +OBJ=$(ASM:%.asm=build/%.rel)\ + $(SRC:%.c=build/%.rel) + +IHX=build/$(PROJECT).ihx +TARGET=build/$(PROJECT).hex + +INCLUDE=include +CFLAGS=-mz80 -I$(INCLUDE) --Werror +LDFLAGS=-mz80 --no-std-crt0\ + --code-loc 0x0100\ + --data-loc 0x8010\ + -Wl-b_ISR_TABLE=0x0070\ + -Wl-b_GSINIT=0x0080 + +ROM_CHIP=AT28C256 + +all : $(TARGET) + +$(OBJ): | build + +build: + @mkdir -p build + +build/%.rel : asm/%.asm + @echo ' (AS)' $< + @$(CPP) -P -I$(INCLUDE) -DASSEMBLY $< > build/$(notdir $<) + @$(AS) -g -o $@ build/$(notdir $<) + +build/%.rel : src/%.c + @echo ' (CC)' $< + @$(CC) $(CFLAGS) -c -o $@ $< + +$(IHX) : $(OBJ) + @echo ' (LD)' $(OBJ) + @$(CC) $(LDFLAGS) -o $@ $(OBJ) + +$(TARGET) : $(IHX) + @hex2bin.py $< $@ + +.PHONE : flash +flash : + @minipro -y -sp $(ROM_CHIP) -w $(TARGET) + +.PHONY : clean +clean : + @find build -type f -delete diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ef7710 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# Firmware for the Southern Star Mk II + +This repository contains the firmware for the Southern Star Mk II. A wearable +computer built using a Z80 microprocessor. + +The code here is *really* early in development. It consists mostly code of code +fragments from other prototypes held together by duct tape. Almost nothing of +the architecture and capabilities of the operating system has been decided. + +The firmware includes a modified version of the +[zbootloader](https://git.thomaslabs.org/zbootloader/) for uploading programs +over the serial port. (see [zup](https://git.thomaslabs.org/zup/), the upload +utility) + +## What is missing? + +The question should be, what is not missing? Nonetheless: +- Documentation on the hardware and software architecture +- Tests for the bootloader +- Update ROM contents over USB +- scheme interpreter and compiler +- multitasking (if doable in such a restricted environment) +- Filesystem support + +## File structure +- asm: Assembly code +- doc: Documentation (not ready yet) +- include: header files for both C and Assembly +- src: C source code +- manifest.scm: Guix packages for compiling the firmware image + +## Related repositories +[Computer schematics](https://git.thomaslabs.org/southern-star-mk2/hardware/) +[3D Model of the enclosure](https://git.thomaslabs.org/southern-star-mk2/3d/) + +## Acknowledgements +- SDCC developers; Big part of asm/crt0.asm is taken from the defualt crt0 file diff --git a/asm/crt0.asm b/asm/crt0.asm new file mode 100644 index 0000000..6f92149 --- /dev/null +++ b/asm/crt0.asm @@ -0,0 +1,64 @@ +#include <hardware.h> + + .module crt0 + .globl _main + + .area _HEADER (ABS) + .org 0x0000 +start: + xor a + ld i, a + ld sp, #0x0000 + di + + call gsinit + call _main +1$: + halt + jr 1$ + + ;; Ordering of segments for the linker. + .area _HOME + .area _CODE + .area _INITIALIZER + .area _GSINIT + .area _GSFINAL + + .area _DATA + .area _INITIALIZED + .area _BSEG + .area _BSS + .area _HEAP + + .area _CODE + + .area _GSINIT +gsinit: + ;; Default-initialized global variables. + ld bc, #l__DATA + ld a, b + or a, c + jr Z, zeroed_data + ld hl, #s__DATA + ld (hl), #0x00 + dec bc + ld a, b + or a, c + jr Z, zeroed_data + ld e, l + ld d, h + inc de + ldir +zeroed_data: + ;; Explicitly initialized global variables. + ld bc, #l__INITIALIZER + ld a, b + or a, c + jr Z, gsinit_next + ld de, #s__INITIALIZED + ld hl, #s__INITIALIZER + ldir + +gsinit_next: + .area _GSFINAL + ret diff --git a/asm/delay.asm b/asm/delay.asm new file mode 100644 index 0000000..f04f046 --- /dev/null +++ b/asm/delay.asm @@ -0,0 +1,13 @@ + .module delay + +__delay_ms:: + ld b, a +1$: + ld hl, #400 +2$: + dec hl + ld a, h + or l + jr nz, 2$ + djnz 1$ + ret diff --git a/asm/isr.asm b/asm/isr.asm new file mode 100644 index 0000000..ad810e5 --- /dev/null +++ b/asm/isr.asm @@ -0,0 +1,17 @@ + .module isr + + .area _ISR_TABLE (REL) +_ctc0_isr_ptr:: + .dw #0 +_ctc1_isr_ptr:: + .dw #_ctc1_isr +_ctc2_isr_ptr:: + .dw #_timer +_ctc3_isr_ptr:: + .dw #_blink_cursor +_port_a_isr_ptr:: + .dw #0 +_port_b_isr_ptr:: + .dw #_input_event +_rx_isr_ptr:: + .dw #_rx_isr diff --git a/include/fifo.h b/include/fifo.h new file mode 100644 index 0000000..c6eee2d --- /dev/null +++ b/include/fifo.h @@ -0,0 +1,45 @@ +#ifndef FIFO_H +#define FIFO_H + +#include <zeta.h> + +#define FIFO_LEN 32 + +struct fifo { + uint8_t head; + uint8_t tail; + uint8_t data[FIFO_LEN]; +}; + +static inline uint8_t +fifo_pop(struct fifo *fifo) +{ + uint8_t ret = fifo->data[fifo->head]; + if (++fifo->head >= LENGTH(fifo->data)) + fifo->head = 0; + return ret; +} + +static inline void +fifo_push(struct fifo *fifo, uint8_t v) +{ + fifo->data[fifo->tail] = v; + + if (++fifo->tail >= LENGTH(fifo->data)) + fifo->tail = 0; +} + +static inline bool +fifo_empty(const struct fifo *fifo) +{ + return (fifo->head == fifo->tail); +} + +static inline void +fifo_clear(struct fifo *fifo) +{ + fifo->head = 0; + fifo->tail = 0; +} + +#endif // FIFO_H diff --git a/include/hardware.h b/include/hardware.h new file mode 100644 index 0000000..2e6c9da --- /dev/null +++ b/include/hardware.h @@ -0,0 +1,80 @@ +#ifndef HARDWARE_H +#define HARDWARE_H + +// ******************************************************** +#define CTC_CHANNEL_0 0x00 +#define CTC_CHANNEL_1 0x01 +#define CTC_CHANNEL_2 0x02 +#define CTC_CHANNEL_3 0x03 + +#define CTC_CTRL_OR_VECTOR_BIT 0x01 +#define CTC_RST_BIT 0x02 +#define CTC_TIME_CONST_BIT 0x04 +#define CTC_TIME_TRG_BIT 0x08 +#define CTC_CLK_TRG_BIT 0x10 +#define CTC_PRESCALER_BIT 0x20 +#define CTC_MODE_BIT 0x40 +#define CTC_INT_BIT 0x80 + +#define CTC_CTRL(x) ((x) | CTC_CTRL_OR_VECTOR_BIT) + +// ******************************************************** +#define PORT_A_CTRL 0x42 +#define PORT_A_DATA 0x40 +#define PORT_B_CTRL 0x43 +#define PORT_B_DATA 0x41 + +#define PIO_MODE_3 0xCF + +#define PIO_INT_CTRL(x) ((x) | 0x07) +#define PIO_OR 0x00 +#define PIO_AND 0x40 +#define PIO_LOW 0x00 +#define PIO_HIGH 0x20 +#define PIO_MASK 0x10 +#define PIO_INT_EN 0x80 + +// ******************************************************** +#define SIO_A_CTRL 0x22 +#define SIO_A_DATA 0x20 +#define SIO_B_CTRL 0x23 +#define SIO_B_DATA 0x21 + +#define SIO_EX_INT_EN 0x01 +#define SIO_TX_INT_EN 0x02 +#define SIO_STATUS_AFFECTS_VECTOR 0x04 +#define SIO_RX_INT_MD0 0x08 +#define SIO_RX_INT_MD1 0x10 +#define SIO_WAIT_RDY_ON_RX_TX 0x20 +#define SIO_WAIT_RDY_FTN 0x40 +#define SIO_WAIT_RDY_EN 0x80 + +// ******************************************************** +#define TFT_CTRL 0x60 +#define TFT_DATA 0x61 + +#ifndef ASSEMBLY +__sfr __at(CTC_CHANNEL_0) ctc_channel_0; +__sfr __at(CTC_CHANNEL_1) ctc_channel_1; +__sfr __at(CTC_CHANNEL_2) ctc_channel_2; +__sfr __at(CTC_CHANNEL_3) ctc_channel_3; + +__sfr __at(SIO_A_DATA) sio_a_data; +__sfr __at(SIO_B_DATA) sio_b_data; +__sfr __at(SIO_A_CTRL) sio_a_ctrl; +__sfr __at(SIO_B_CTRL) sio_b_ctrl; + +__sfr __at(PORT_A_DATA) port_a_data; +__sfr __at(PORT_B_DATA) port_b_data; +__sfr __at(PORT_A_CTRL) port_a_ctrl; +__sfr __at(PORT_B_CTRL) port_b_ctrl; + +__sfr __at(TFT_CTRL) tft_ctrl; +__sfr __at(TFT_DATA) tft_data; + +#define IM(__mode) __asm__("im " #__mode) +#define EI __asm__("ei") +#define DI __asm__("di") +#endif // ASSEMBLY + +#endif // HARDWARE_H diff --git a/include/i2c.h b/include/i2c.h new file mode 100644 index 0000000..18fa5e9 --- /dev/null +++ b/include/i2c.h @@ -0,0 +1,24 @@ +#ifndef I2C_H +#define I2C_H + +#include <stdint.h> + +#define NACK 0 +#define ACK 1 + +void +i2c_start_condition(void); + +void +i2c_restart_condition(void); + +void +i2c_stop_condition(void); + +void +i2c_send(uint8_t b); + +uint8_t +i2c_recv(uint8_t ack); + +#endif // I2C_H diff --git a/include/input.h b/include/input.h new file mode 100644 index 0000000..a2f03e2 --- /dev/null +++ b/include/input.h @@ -0,0 +1,22 @@ +#ifndef INPUT_H +#define INPUT_H + +#include <fifo.h> + +static inline uint8_t +poll_keys(void) +{ + return (port_b_data & 0x7C) >> 2; +} + +enum keys { + KEY1 = 0x01, + KEY2 = 0x02, + KEY3 = 0x04, + KEY4 = 0x08, + KEY5 = 0x10 +}; + +extern struct fifo input_fifo; + +#endif // INPUT_H diff --git a/include/tft.h b/include/tft.h new file mode 100644 index 0000000..22303a1 --- /dev/null +++ b/include/tft.h @@ -0,0 +1,132 @@ +#ifndef TFT_H +#define TFT_H + +#include <hardware.h> +#include <stdint.h> + +#define TFT_WIDTH 480 +#define TFT_HEIGHT 320 + +enum tft_command { + NOP = 0x00, + SWRESET = 0x01, + RDDID = 0x04, + RDNUMPE = 0x05, + RDRED = 0x06, + RDGREEN = 0x07, + RDBLUE = 0x08, + RDDPM = 0x0A, + RDDMADCTL = 0x0B, + RDDCOLMOD = 0x0C, + RDDIM = 0x0D, + RDDSM = 0x0E, + RDDSDR = 0x0F, + SPLIN = 0x10, + SLPOUT = 0x11, + PTLON = 0x12, + NORON = 0x13, + INVOFF = 0x20, + INVON = 0x21, + ALLPOFF = 0x22, + ALLPON = 0x23, + GAMSET = 0x26, + DISPOFF = 0x28, + DISPON = 0x29, + CASET = 0x2A, + PASET = 0x2B, + RAMWR = 0x2C, + RAMRD = 0x2E, + PLTAR = 0x30, + VSCRDEF = 0x33, + TEOFF = 0x34, + TEON = 0x35, + MADCTL = 0x36, + VSCRSADD = 0x37, + IDMOFF = 0x38, + IDMON = 0x39, + COLMOD = 0x3A, + CONRAMWR = 0x3C, + CONRAMRD = 0x3E, + TESL = 0x44, + GETSL = 0x45, + WRDISBV = 0x51, + RDDISBV = 0x52, + WRCTRLD = 0x53, + RDCTRLD = 0x54, + WRCABC = 0x55, + RDCABC = 0x56, + WRCABCMB = 0x5E, + RDCABCMB = 0x5F, + RDABVCSDR = 0x68, + RDBWLK = 0x70, + RDBKX = 0x71, + RDBKY = 0x72, + RDWX = 0x73, + RDWY = 0x74, + RDRGLB = 0x75, + RDRX = 0x76, + RDRY = 0x77, + RDGX = 0x78, + RDGY = 0x79, + RDBALB = 0x7A, + RDBX = 0x7B, + RDBY = 0x7C, + RDAX = 0x7D, + RDAY = 0x7E, + + RDID1 = 0xDA, + RDID2 = 0xDB, + RDID3 = 0xDC, + SETOSC = 0xB0, + SETPOWER = 0xB1, + SETDISCTRL = 0xB2, + SETRGB = 0xB3, + SETCYC = 0xB4, + SETBGP = 0xB5, + SETCOM = 0xB6, + SETOTP = 0xB7, + SETEXTC = 0xB9, + SETSTBA = 0xC0, + SETDGC = 0xC1, + SETID = 0xC3, + SETDDB = 0xC4, + SETCABC = 0xC9, + SETPANEL = 0xCC, + SETGAMMA = 0xE0, + SETIMAGE = 0xE9, + SETMESSI = 0xEA, + SETCOLOR = 0xEB +}; + +enum pixel_format { + BIT12 = 0x03, + BIT16 = 0x05, + BIT18 = 0x06, + BIT24 = 0x07 +}; + +static inline void +tft_ram_wr(void) +{ + tft_ctrl = RAMWR; +} + +static inline void +tft_pixel(uint8_t r, uint8_t g, uint8_t b) +{ + tft_data = r; + tft_data = g; + tft_data = b; +} + +void +tft_set_area(unsigned int x, unsigned int y, unsigned int w, unsigned int h); + +void +tft_init(void); + +void +clear_screen(void); + + +#endif // TFT_H diff --git a/include/tty.h b/include/tty.h new file mode 100644 index 0000000..ea73e5f --- /dev/null +++ b/include/tty.h @@ -0,0 +1,34 @@ +#ifndef TTY_H +#define TTY_H + +#include <tft.h> +#define TTY_WIDTH (TFT_WIDTH / 8) +#define TTY_HEIGHT (TFT_HEIGHT / 8) + +void +addch(char c); + +void +addstr(const char *str); + +void +setcur(unsigned int ncol, unsigned int nrow); + +void +swap_colors(void); + +static inline void +mvaddch(int y, int x, char c) +{ + setcur(x, y); + addch(c); +} + +static inline void +mvaddstr(int y, int x, const char *str) +{ + setcur(x, y); + addstr(str); +} + +#endif // TTY_H diff --git a/include/zeta.h b/include/zeta.h new file mode 100644 index 0000000..291a2ff --- /dev/null +++ b/include/zeta.h @@ -0,0 +1,67 @@ +#ifndef ZETA_H +#define ZETA_H + +#include <stdint.h> +#include <stdbool.h> + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +#define LENGTH(x) (sizeof(x) / sizeof(x[0])) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +// Corrent version, but the compiler does not recognize this as a constant +// expression +// #define ISR_ADDRESS(x) (((u16)&x) & 0xFF) +#define ISR_ADDRESS(x) ((u16)&x) + +extern void *rx_isr_ptr; +extern void *ctc0_isr_ptr; +extern void *ctc1_isr_ptr; +extern void *ctc2_isr_ptr; +extern void *ctc3_isr_ptr; +extern void *port_a_isr_ptr; +extern void *port_b_isr_ptr; + +void +bootloader(void); + +uint16_t +crc16(const void *buf, size_t len); + +void +_menu(void); + +static inline int +max(int a, int b) +{ + return a > b ? a : b; +} + +static inline int +min(int a, int b) +{ + return a < b ? a : b; +} + +static inline int +clamp(int v, int low, int high) +{ + return min(max(v, low), high); +} + +static inline uint8_t +bcd(uint8_t x) +{ + return ((x / 10) << 4) | (x % 10); +} + +#endif // ZETA_H diff --git a/manifest.scm b/manifest.scm new file mode 100644 index 0000000..a956edd --- /dev/null +++ b/manifest.scm @@ -0,0 +1,6 @@ +(specifications->manifest + '("zup" ; Upload firmware over usb + "sdcc" ; Assembler and C compiler for the Z80 (and different other 8-bit CPUs) + "minipro" ; Write firmware directly to ROM + "python-intelhex" ; Convert output of compiler into raw binary data + )) diff --git a/src/bootloader.c b/src/bootloader.c new file mode 100644 index 0000000..0f67269 --- /dev/null +++ b/src/bootloader.c @@ -0,0 +1,310 @@ +#include <zeta.h> +#include <tty.h> +#include <hardware.h> +#include <fifo.h> + +#include <assert.h> +#include <stddef.h> +#include <string.h> + +#ifdef __GNUC__ +#define PACKED __attribute__((packed)) +#else +#define PACKED +#endif + +enum header_type { + CMD_PING, + CMD_INFO, + CMD_BOOT, + CMD_READ, + CMD_WRITE, + CMD_IO_READ, + CMD_IO_WRITE, + CMD_ECHO +}; + +struct header { + uint8_t type; + uint8_t bank; + uint16_t address; + uint16_t length; + uint16_t checksum; +} PACKED; + +// static_assert(sizeof(struct header) == 8, "struct header is not PACKED"); + +enum error { + ERR_TIMEOUT = -1 +}; + +#define MAX_PACKET_SIZE 256 +#define TIMEOUT_MS 500 +#define MAX_ATTEMPTS 3 +#define MAX_TRANS_ATTEMPTS 5 + +uint16_t +crc16(const void *buf, size_t len); + +volatile struct fifo rx_fifo = {0, 0, {0}}; + +enum ack { + ACK = 0x00, + NACK = 0xFF +}; + +void +rx_isr(void) __critical __interrupt(0) +{ + fifo_push(&rx_fifo, sio_a_data); +} + +static volatile uint32_t millis = 0; + +void +ctc1_isr(void) __critical __interrupt(1) +{ + millis += 5; +} + +uint32_t +clock(void) +{ + volatile uint32_t ret; + DI; + ret = millis; + EI; + return ret; +} + +void +putbyte(unsigned char b) +{ + unsigned char ctrl = 0; + + sio_a_data = b; + + while (!(ctrl & 0x04)) { + sio_a_ctrl = 0; + ctrl = sio_a_ctrl; + } +} + +static volatile int32_t errno = 0; + +uint8_t +getbyte(void) +{ + uint8_t b; + uint32_t ms = clock(); + errno = 0; + while (fifo_empty(&rx_fifo)) { + if (clock() - ms > TIMEOUT_MS) { + errno = ERR_TIMEOUT; + return 0; + } + } + DI; + b = fifo_pop(&rx_fifo); + EI; + return b; +} + +void +flush(void) +{ + DI; + fifo_clear(&rx_fifo); + EI; +} + + +// Hamming(7,4) encoding +uint8_t +encode(uint8_t x) +{ + uint8_t y = 0; + const uint8_t c[4] = {0x61, 0x52, 0x34, 0x78}; + + for (uint8_t i = 0; i < 4; ++i) + y ^= ((x >> i) & 1) ? c[i] : 0; + + return y; +} + +// Hamming(7,4) decoding +uint8_t +decode(uint8_t x) +{ + uint8_t p = 0; + const uint8_t r[7] = {6, 5, 3, 7, 1, 2, 4}; + + for (int i = 0; i < 7; ++i) + p ^= ((x >> i) & 1) ? r[i] : 0; + + // Assume simple error, attempt correction + if (p) { + size_t i = 0; + + for (i = 0; i < LENGTH(r); ++i) { + if (r[i] == x) + break; + } + + x ^= (1 << i); + } + + return x & 0x0F; +} + + +int +read(void *buf, size_t count) +{ + uint8_t b; + uint8_t *p = buf; + + for (int n = 0; n < count; ++n) { + b = decode(getbyte()); + if (errno) + return errno; + + b |= (decode(getbyte()) << 4); + if (errno) + return errno; + + p[n] = b; + } + + return 0; +} + +int +write(const void *buf, size_t count) +{ + const uint8_t *p = buf; + + for (size_t i = 0; i < count; ++i) { + putbyte(encode(p[i] & 0x0F)); + putbyte(encode((p[i] >> 4) & 0x0F)); + } + + return 0; +} + +int +read_header(struct header *header) +{ + int err; + uint8_t ack; + uint16_t checksum; + + while (1) { + if ((err = read(header, sizeof(*header)))) + return err; + + checksum = header->checksum; + header->checksum = 0; + + if (checksum == crc16(header, sizeof(*header))) { + header->checksum = checksum; + ack = ACK; + write(&ack, sizeof(ack)); + return 0; + } else { + ack = NACK; + write(&ack, sizeof(ack)); + } + } +} + +int +read_buf(size_t len, void *buf) +{ + int err; + uint8_t ack; + uint16_t checksum; + + for (int i = 0; i < MAX_TRANS_ATTEMPTS; ++i) { + // TODO: reduce code? + if ((err = read(&checksum, sizeof(checksum))) + || (err = read(buf, len))) + break; + + if (checksum == crc16(buf, len)) { + ack = ACK; + write(&ack, sizeof(ack)); + return 0; + } else { + ack = NACK; + write(&ack, sizeof(ack)); + } + } + + return -1; +} + +int +write_buf(size_t len, const void *buf) +{ + int err; + uint8_t ack = NACK; + uint16_t checksum = crc16(buf, len); + + for (int i = 0; i < MAX_TRANS_ATTEMPTS; ++i){ + write(&checksum, sizeof(checksum)); + write(buf, len); + + // If TIMEOUT sending just give up + if ((err = read(&ack, sizeof(ack)))) + return err; + + if (ack == ACK) + return 0; + } + + return -1; +} + +// TODO: Restart after timeouts +void +bootloader(void) +{ + struct header header; + uint8_t buf[MAX_PACKET_SIZE]; + + const char *msg = "Bootloader ...\r\n"; + addstr(msg); + + while (1) { + if (read_header(&header)) { + flush(); + continue; + } + + switch (header.type) { + case CMD_BOOT: + ((void (*)(void))header.address)(); + break; + + case CMD_READ: + write_buf(header.length, (const void *)header.address); + break; + + case CMD_WRITE: + if (!read_buf(header.length, buf)) + memcpy((void *)header.address, buf, header.length); + break; + + case CMD_ECHO: + if (!read_buf(header.length, buf)) + write_buf(header.length, buf); + break; + + default: + break; + } + + flush(); + } +} diff --git a/src/crc16.c b/src/crc16.c new file mode 100644 index 0000000..6c80738 --- /dev/null +++ b/src/crc16.c @@ -0,0 +1,48 @@ +#include <zeta.h> + +static const u16 crc_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; + +u16 +crc16(const void *buf, size_t len) +{ + const u8 *p = buf; + + u16 crc = 0; + while (len--) + crc = crc_table[(crc >> 8) ^ (*p++)] ^ (crc << 8); + + return crc; +} diff --git a/src/fifo.c b/src/fifo.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/fifo.c diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..c6eb038 --- /dev/null +++ b/src/font.c @@ -0,0 +1,101 @@ +#include <stdint.h> + +const uint8_t font[97][8] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* SPACE */ + {0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, /* ! */ + {0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00}, /* " */ + {0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, 0x00}, /* # */ + {0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, 0x00}, /* $ */ + {0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x00}, /* % */ + {0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, 0x00}, /* & */ + {0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ' */ + {0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00}, /* ( */ + {0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00}, /* ) */ + {0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, /* * */ + {0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00}, /* + */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C}, /* , */ + {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, /* - */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}, /* . */ + {0x00, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00}, /* / */ + {0x3C, 0x66, 0x76, 0x6E, 0x66, 0x66, 0x3C, 0x00}, /* 0 */ + {0x18, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00}, /* 1 */ + {0x3C, 0x66, 0x60, 0x30, 0x0C, 0x06, 0x7E, 0x00}, /* 2 */ + {0x3C, 0x66, 0x60, 0x38, 0x60, 0x66, 0x3C, 0x00}, /* 3 */ + {0x60, 0x70, 0x78, 0x66, 0xFE, 0x60, 0x60, 0x00}, /* 4 */ + {0x7E, 0x06, 0x3E, 0x60, 0x60, 0x66, 0x3C, 0x00}, /* 5 */ + {0x3C, 0x66, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00}, /* 6 */ + {0x7E, 0x66, 0x30, 0x18, 0x18, 0x18, 0x18, 0x00}, /* 7 */ + {0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00}, /* 8 */ + {0x3C, 0x66, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00}, /* 9 */ + {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00}, /* : */ + {0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0C}, /* / */ + {0x70, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x70, 0x00}, /* < */ + {0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00}, /* = */ + {0x0E, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0E, 0x00}, /* > */ + {0x3C, 0x66, 0x60, 0x30, 0x18, 0x00, 0x18, 0x00}, /* ? */ + {0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, 0x00}, /* @ */ + {0x18, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00}, /* A */ + {0x3E, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00}, /* B */ + {0x3C, 0x66, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00}, /* C */ + {0x1E, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1E, 0x00}, /* D */ + {0x7E, 0x06, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00}, /* E */ + {0x7E, 0x06, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00}, /* F */ + {0x3C, 0x66, 0x06, 0x76, 0x66, 0x66, 0x3C, 0x00}, /* G */ + {0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00}, /* H */ + {0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, /* I */ + {0x78, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00}, /* J */ + {0x66, 0x36, 0x1E, 0x0E, 0x1E, 0x36, 0x66, 0x00}, /* K */ + {0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00}, /* L */ + {0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0x00}, /* M */ + {0x66, 0x6E, 0x7E, 0x7E, 0x76, 0x66, 0x66, 0x00}, /* N */ + {0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, /* O */ + {0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00}, /* P */ + {0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00}, /* Q */ + {0x3E, 0x66, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00}, /* R */ + {0x3C, 0x66, 0x06, 0x3C, 0x60, 0x66, 0x3C, 0x00}, /* S */ + {0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, /* T */ + {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, /* U */ + {0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00}, /* V */ + {0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00}, /* W */ + {0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00}, /* X */ + {0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00}, /* Y */ + {0x7E, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00}, /* Z */ + {0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00}, /* [ */ + {0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00}, /* \ */ + {0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00}, /* ] */ + {0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00}, /* ^ */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, /* _ */ + {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ` */ + {0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00}, /* a */ + {0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00}, /* b */ + {0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00}, /* c */ + {0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00}, /* d */ + {0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00}, /* e */ + {0x00, 0x70, 0x18, 0x7C, 0x18, 0x18, 0x18, 0x00}, /* f */ + {0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x3E}, /* g */ + {0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00}, /* h */ + {0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00}, /* i */ + {0x00, 0x60, 0x00, 0x60, 0x60, 0x60, 0x60, 0x3C}, /* j */ + {0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00}, /* k */ + {0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, /* l */ + {0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00}, /* m */ + {0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00}, /* n */ + {0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00}, /* o */ + {0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06}, /* p */ + {0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60}, /* q */ + {0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00}, /* r */ + {0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00}, /* s */ + {0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00}, /* t */ + {0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00}, /* u */ + {0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00}, /* v */ + {0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00}, /* w */ + {0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00}, /* x */ + {0x00, 0x00, 0x66, 0x66, 0x66, 0x7C, 0x30, 0x1E}, /* y */ + {0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00}, /* z */ + {0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00}, /* { */ + {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, /* | */ + {0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00}, /* } */ + {0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ~ */ + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* DEL */ + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} /* CURSOR */ +}; diff --git a/src/i2c.c b/src/i2c.c new file mode 100644 index 0000000..cca68c6 --- /dev/null +++ b/src/i2c.c @@ -0,0 +1,103 @@ +#include <i2c.h> +#include <hardware.h> + +#define SDA (1 << 0) +#define SCL (1 << 1) + +void +_delay_ms(uint8_t ms); + +void +i2c_start_condition(void) +{ + port_a_data &= ~SDA; + _delay_ms(1); + port_a_data &= ~SCL; + _delay_ms(1); +} + +void +i2c_restart_condition(void) +{ + port_a_data |= SDA; + _delay_ms(1); + port_a_data |= SCL; + _delay_ms(1); + i2c_start_condition(); +} + +void +i2c_stop_condition(void) +{ + port_a_data |= SCL; + _delay_ms(1); + port_a_data |= SDA; + _delay_ms(1); +} + +void +i2c_send(uint8_t b) +{ + uint8_t i; + + for (i = 0; i < 8; ++i) { + if (b & 1) + port_a_data |= SDA; + else + port_a_data &= ~SDA; + + port_a_data |= SCL; + _delay_ms(1); + port_a_data &= ~SCL; + _delay_ms(1); + + b >>= 1; + } + + port_a_ctrl = PIO_MODE_3; + port_a_ctrl = 0x7D; + + // Read ack + port_a_data |= SCL; + _delay_ms(1); + port_a_data &= ~SCL; + _delay_ms(1); + + port_a_ctrl = PIO_MODE_3; + port_a_ctrl = 0x7C; +} + +uint8_t +i2c_recv(uint8_t ack) +{ + uint8_t i; + uint8_t b = 0; + + port_a_ctrl = PIO_MODE_3; + port_a_ctrl = 0x7D; + + for (i = 0; i < 8; ++i) { + port_a_data |= SCL; + _delay_ms(1); + if (port_a_data & 1) + b |= 1; + + port_a_data &= ~SCL; + _delay_ms(1); + b <<= 1; + } + + port_a_ctrl = PIO_MODE_3; + port_a_ctrl = 0x7C; + + if (ack) + port_a_data |= SDA; + else + port_a_data &= ~SDA; + + port_a_data |= SCL; + _delay_ms(1); + port_a_data &= ~SCL; + _delay_ms(1); + return b; +} diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..db306ea --- /dev/null +++ b/src/input.c @@ -0,0 +1,59 @@ +#include <hardware.h> +#include <tty.h> +#include <stdint.h> +#include <input.h> + +enum encoder_state { + START, + CW_START, + CW_NEXT, + CW_FINAL, + CCW_START, + CCW_NEXT, + CCW_FINAL, + CW = 0x10, + CCW = 0x20 +}; + +/* State machine to keep track of encoder */ +static const uint8_t encoder_table[7][4] = { + /* 00 01 10 11*/ + [START] = { START, CCW_START, CW_START, START }, + [CCW_START] = { CCW_NEXT, CCW_START, START, START }, + [CCW_NEXT] = { CCW_NEXT, CCW_START, CCW_FINAL, START }, + [CCW_FINAL] = { CCW_NEXT, START, CCW_FINAL, START | CCW }, + [CW_START] = { CW_NEXT, START, CW_START, START }, + [CW_NEXT] = { CW_NEXT, CW_FINAL, CW_START, START }, + [CW_FINAL] = { CW_NEXT, CW_FINAL, START, START | CW } +}; + +struct fifo input_fifo = {0, 0, {0}}; + +void +input_event(void) __critical __interrupt(4) +{ + if ((port_b_data & 0x03) != 0x03) { + // Encoder + uint8_t state = START; + uint8_t encoder; + uint8_t next_state; + + do { + encoder = port_b_data & 0x03; + next_state = encoder_table[state][encoder]; + state = next_state & 0x0F; + } while (state != START); + + if (next_state == CW || next_state == CCW) + fifo_push(&input_fifo, next_state); + } else if (port_b_data & 0x7C) { + // Key pressed + for (int i = 0; i < 5; i++) { + uint8_t bit = 1 << (i + 2); + uint8_t state = !(port_b_data & bit); + + if (state) + fifo_push(&input_fifo, i); + } + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..fe3da0e --- /dev/null +++ b/src/main.c @@ -0,0 +1,185 @@ +#include <tft.h> +#include <tty.h> +#include <i2c.h> +#include <zeta.h> +#include <input.h> + +void +uart_putchar(char c); + +static inline void +enable_input_fifo(void) +{ +} + +static inline void +disable_input_fifo(void) +{ +} + +static inline void +init_pio(void) +{ + // Control mode - i.e. no parallel port communication + port_b_ctrl = PIO_MODE_3; + // A, B and five keys as inputs + port_b_ctrl = 0x7F; + // Load interrupt vector + // port_b_ctrl = ISR_ADDRESS(port_b_isr_ptr); + // Interrupt word - interrupt if any pin goes low, mask follows + // port_b_ctrl = PIO_INT_CTRL(PIO_INT_EN | PIO_OR | PIO_LOW | PIO_MASK); + // Mask - 0 means to check line + // port_b_ctrl = 0x80; + + /* port_a_ctrl = PIO_MODE_3; */ + + /* port_a_ctrl = 0x7C; */ + + /* // Load interrupt vector */ + /* port_a_ctrl = ISR_ADDRESS(port_a_isr_ptr); */ + + /* port_a_ctrl = PIO_INT_CTRL(PIO_INT_EN | PIO_OR | PIO_HIGH | PIO_MASK); */ + /* port_a_ctrl = 0x83; */ + + /* // SDA and SCL high */ + /* port_a_data = 0x03; */ +} + +static inline void +init_ctc(void) +{ + /* 200Hz clock */ + ctc_channel_1 = CTC_CTRL(CTC_INT_BIT | CTC_PRESCALER_BIT + | CTC_TIME_CONST_BIT | CTC_RST_BIT); + ctc_channel_1 = 0; + + /* 200Hz clock */ + ctc_channel_2 = CTC_CTRL(CTC_INT_BIT | CTC_PRESCALER_BIT + | CTC_TIME_CONST_BIT | CTC_RST_BIT); + ctc_channel_2 = 0; + + /* ctc_channel_3 = (CPU_FREQ / 256 / 144); */ + + ctc_channel_3 = CTC_CTRL(CTC_INT_BIT | CTC_PRESCALER_BIT + | CTC_TIME_CONST_BIT | CTC_RST_BIT); + ctc_channel_3 = 0; // 256 + + // Interrupt table for CTC + // Final address is (Ireg << 8) | ctc_isr_ptr | {00/01/10/11} | 0 + ctc_channel_0 = ISR_ADDRESS(ctc0_isr_ptr); +} + +static inline void +init_sio(void) +{ + static const u8 sio_a_cfg[] = { + 0b00011000, // Reset channel + 4 , // wr4 + 0b01000100, // X16 clock (115200), one stop bit, no parity + 1 , // wr1 + SIO_RX_INT_MD0 | SIO_RX_INT_MD1, // interrupt on every Rx, no wait function + 3 , // wr3 + 0b11000001, // enable Rx - 8 bit char + 5 , // wr5 + 0b01101000 // enable Tx - 8 bit char + }; + + static const u8 sio_b_cfg[] = { + 0b00011000, // Reset channel + 2 , // load interrupt vector + ISR_ADDRESS(rx_isr_ptr) // int_table_rx + }; + + for (u8 i = 0; i < LENGTH(sio_a_cfg); ++i) + sio_a_ctrl = sio_a_cfg[i]; + + for (u8 i = 0; i < LENGTH(sio_b_cfg); ++i) + sio_b_ctrl = sio_b_cfg[i]; +} + +// copy code to ram, so function pointer is modifyable + +static uint8_t tick = 0; + +void +timer(void) __critical __interrupt(5) +{ + static int prescale = 0; + + if (++prescale == 150) { + prescale = 0; + tick = 1; + } +} + +/* i2c_start_condition(); */ +/* i2c_send(0xA0); */ +/* i2c_send(0x00); */ +/* i2c_send(0x00); */ +/* i2c_restart_condition(); */ +/* i2c_send(0xA1); */ +/* b = i2c_recv(NACK); */ +/* i2c_stop_condition(); */ + +void +main(void) +{ + tft_init(); + + init_ctc(); + init_pio(); + init_sio(); + + // Interrupt mode 2 + IM(2); + // Enable interrupts + EI; + + // Boot menu + addstr("1) Programming mode\r\n"); + addstr("2) Normal boot (default)\r\n"); + addstr("3) Boot address 0xC000\r\n"); + + for (int i = 5; i > 0; --i) { + addch('\r'); + addch(i + '0'); + + while (!tick) { + u8 keys = poll_keys(); + + if (!(keys & KEY2)) { + addch('\r'); + bootloader(); + } + + if (!(keys & KEY3)) { + goto boot; + } + + if (!(keys & KEY4)) { + // Definitely safe looking C code ... + void (*ptr)(void) = (void (*)(void))0xC000; + ptr(); + } + } + + DI; + tick = 0; + EI; + } + + addch('\r'); + +boot: + addstr("Starting system ...\r\n"); + // Load interrupt vector + port_b_ctrl = ISR_ADDRESS(port_b_isr_ptr); + // Interrupt word - interrupt if any pin goes low, mask follows + port_b_ctrl = PIO_INT_CTRL(PIO_INT_EN | PIO_OR | PIO_LOW | PIO_MASK); + // Mask - 0 means to check line + port_b_ctrl = 0x80; + _menu(); + + while (1) + ; +} diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..51f7c31 --- /dev/null +++ b/src/menu.c @@ -0,0 +1,269 @@ +#include <zeta.h> +#include <hardware.h> +#include <tty.h> +#include <input.h> +#include <stdio.h> +#include <string.h> + +struct time { + uint8_t second; + uint8_t minute; + uint8_t hour; + uint8_t wkday; + uint8_t date; + uint8_t month; + uint8_t year; +}; + +struct value { + uint8_t roll; + int val; + int min, max; +}; + +void +value_inc(struct value *v, int d) +{ + v->val += d; + + if (v->roll) { + if (v->val > v->max) + v->val = v->min; + else if(v->val < v->min) + v->val = v->max - 1; + } else { + v->val = clamp(v->val, v->min, v->max); + } +} + +enum item_type { + VOID, + BUTTON, + VALUE, + LABEL +}; + +void +draw_time(void) +{ + char buf[32]; + struct time time; + memset(&time, 0, sizeof(time)); + // rtc_get_bcd_time(&time); + sprintf(buf, "20%hhd%hhd-%hhd%hhd-%hhd%hhd %hhd%hhd:%hhd%hhd:%hhd%hhd", + time.year >> 4, time.year & 0xF, + time.month >> 4, time.month & 0xF, + time.date >> 4, time.date & 0xF, + time.hour >> 4, time.hour & 0xF, + time.minute >> 4, time.minute & 0xF, + time.second >> 4, time.second & 0xF); + mvaddstr(5, 1, buf); +} + +void +draw_battery(void) +{ + uint16_t soc = 100; // bat_state_of_charge(); + char buf[16]; + sprintf(buf, "%u%%", soc); + mvaddstr(7, 1, buf); +} + +void +set_time(void); + +struct item { + uint8_t type; + const char *text; + union { + void (*action)(void); + struct value value; + } v; +}; + +struct menu_entry { + const char *text; + struct item items[8]; +}; + +struct menu_entry menu[] = { + { + .text = "TIME ", + .items = { + {.type = LABEL, .v = {.action = draw_time}}, + {.type = LABEL, .v = {.action = draw_battery}}, + {.type = VOID}, + {.type = VOID}, + {.type = VOID}, + {.type = VOID}, + {.type = VOID}, + {.type = VOID} + } + }, + { + .text = "CONF ", + .items = { + {.type = VALUE, .text = "SEC", .v = {.value = {1, 0, 0, 59}}}, + {.type = VALUE, .text = "MIN", .v = {.value = {1, 0, 0, 59}}}, + {.type = VALUE, .text = "HOUR", .v = {.value = {1, 0, 0, 23}}}, + {.type = VALUE, .text = "WKDAY", .v = {.value = {1, 0, 1, 7}}}, + {.type = VALUE, .text = "DATE", .v = {.value = {1, 1, 1, 31}}}, + {.type = VALUE, .text = "MONTH", .v = {.value = {1, 1, 1, 12}}}, + {.type = VALUE, .text = "YEAR", .v = {.value = {1, 0, 0, 3000}}}, + {.type = BUTTON, .text = "LOAD", .v = {.action = set_time}} + } + } +}; + +void +set_time(void) +{ + struct time time; + struct item *items = menu[1].items; + + time.second = items[0].v.value.val; + time.minute = items[1].v.value.val; + time.hour = items[2].v.value.val; + time.wkday = items[3].v.value.val; + time.date = items[4].v.value.val; + time.month = items[5].v.value.val; + time.year = items[6].v.value.val; + + // rtc_set_time(&time); +} + +enum direction { + VERTICAL, + HORIZONTAL +}; + +static uint8_t dir = HORIZONTAL; +static int menu_index = 0; +static int sub_menu_index = -1; +static int edit = 0; + +#define BUILD_VERSION "20241117" + +void +draw_menu(void) +{ + const char *build_version = BUILD_VERSION; + const int padding = (TTY_WIDTH - 8 * LENGTH(menu)) / 2; + + mvaddstr(1, 0, " ************* THE SOUTHERN STAR MK II ************* "); + mvaddch(3, 1, dir == HORIZONTAL ? '>' : '^'); + + for (int i = 0; i < LENGTH(menu); ++i) { + if (i == menu_index) { + swap_colors(); + mvaddstr(3, padding + i * 8, menu[i].text); + swap_colors(); + } else { + mvaddstr(3, padding + i * 8, menu[i].text); + } + } + + const struct menu_entry *entry = &menu[menu_index]; + + for (int i = 0; i < LENGTH(entry->items); ++i) { + mvaddstr(5 + 2 * i, 1, " "); + + if (entry->items[i].type == VOID) + continue; + + if (i == sub_menu_index && menu_index != 0) { + swap_colors(); + mvaddstr(5 + 2 * i, 1, entry->items[i].text); + swap_colors(); + } else { + mvaddstr(5 + 2 * i, 1, entry->items[i].text); + } + + if (entry->items[i].type == VALUE) { + char buf[16]; + sprintf(buf, "%8d", entry->items[i].v.value.val); + mvaddstr(5 + 2 * i, 6, buf); + } + + if (entry->items[i].type == LABEL) { + entry->items[i].v.action(); + } + } + + mvaddstr(TTY_HEIGHT - 2, TTY_WIDTH - strlen(build_version) - 1, build_version); +} + +void +dir_callback(void) +{ + if (sub_menu_index >= 0) { + struct item *item = &menu[menu_index].items[sub_menu_index]; + + switch (item->type) { + case VALUE: + edit = !edit; + break; + + case BUTTON: + if (item->v.action) + item->v.action(); + break; + } + } else { + dir = (dir + 1) & 1; + draw_menu(); + } +} + +#define CW 0x10 +#define CCW 0x20 + +typedef void (*callback)(void); +volatile callback callbacks[5] = {NULL, NULL, NULL, NULL, NULL}; + +void +_menu(void) +{ + callbacks[0] = dir_callback; + clear_screen(); + setcur(0, 0); + draw_menu(); + + while (1) { + DI; + while (!fifo_empty(&input_fifo)) { + u8 event = fifo_pop(&input_fifo); + if (event == CW) { + if (dir == HORIZONTAL) { + if (++menu_index >= LENGTH(menu)) + menu_index = 0; + } else { + if (edit) { + value_inc(&menu[menu_index].items[sub_menu_index].v.value, 1); + } else { + if (++sub_menu_index >= LENGTH(menu[0].items)) + sub_menu_index = 0; + } + } + draw_menu(); + } else if (event == CCW) { + if (dir == HORIZONTAL) { + if (--menu_index < 0) + menu_index = LENGTH(menu) - 1; + } else { + if (edit) { + value_inc(&menu[menu_index].items[sub_menu_index].v.value, -1); + } else { + if (--sub_menu_index < -1) + sub_menu_index = LENGTH(menu[0].items) - 1; + } + } + draw_menu(); + } else { + if (callbacks[event]) + callbacks[event](); + } + } + EI; + } +} diff --git a/src/tft.c b/src/tft.c new file mode 100644 index 0000000..d0c7d8f --- /dev/null +++ b/src/tft.c @@ -0,0 +1,138 @@ +#include <tft.h> +#include <hardware.h> +#include <zeta.h> + +void +_delay_ms(uint8_t ms); + +/* + * Driver for the ILI9341 TFT Chip + */ + +static inline void +tft_soft_reset(void) +{ + tft_ctrl = SWRESET; +} + +static inline void +tft_enable_ext_cmd(void) +{ + tft_ctrl = SETEXTC; + tft_data = 0xFF; + tft_data = 0x83; + tft_data = 0x57; +} + +static inline void +tft_memory_access_ctrl(uint8_t bits) +{ + tft_ctrl = MADCTL; + tft_data = bits; +} + +static inline void +tft_sleep_out(void) { + tft_ctrl = SLPOUT; +} + +static inline void +tft_display_on(void) +{ + tft_ctrl = DISPON; +} + +static inline void +tft_pixel_format(uint8_t dbi, uint8_t dpi) +{ + tft_ctrl = COLMOD; + tft_data = (dpi << 4) | dbi; +} + +static inline void +tft_set_rgb_interface(void) +{ + tft_ctrl = SETRGB; + tft_data = 0x00; + tft_data = 0x00; + tft_data = 0x06; + tft_data = 0x06; +} + +static inline void +tft_set_col_addr(uint16_t start, uint16_t end) +{ + tft_ctrl = CASET; + tft_data = start >> 8; + tft_data = start & 0xFF; + tft_data = end >> 8; + tft_data = end & 0xFF; +} + +static inline void +tft_set_page_addr(uint16_t start, uint16_t end) +{ + tft_ctrl = PASET; + tft_data = start >> 8; + tft_data = start & 0xFF; + tft_data = end >> 8; + tft_data = end & 0xFF; +} + +void +tft_set_area(unsigned int x, unsigned int y, unsigned int w, unsigned int h) +{ + tft_set_col_addr(x, x + w - 1); + tft_set_page_addr(y, y + h - 1); +} + +enum memory_access { + // MY MX MV ML | BGR SS X X + MV = 0x20, // 1: landscape 0 <= x < 480; 0 <= y < 320 + MX = 0x40, // MV = 0: Invert X; MV = 1: Invert Y + MY = 0x80, // MV = 0: Invert Y; MV = 1: Invert X + ML = 0x10 +}; + +void +clear_screen(void) +{ + DI; + tft_set_col_addr(0, TFT_WIDTH - 1); + tft_set_page_addr(0, TFT_HEIGHT - 1); + + tft_ctrl = RAMWR; + for (u16 i = 0; i < TFT_HEIGHT; ++i) { + for (u16 j = 0; j < TFT_WIDTH; ++j) { + tft_data = 0x00; + tft_data = 0x00; + tft_data = 0x00; + } + } + EI; +} + +void +tft_init(void) +{ + _delay_ms(200); + + tft_soft_reset(); + tft_enable_ext_cmd(); + + _delay_ms(250); + + tft_set_rgb_interface(); + + tft_pixel_format(BIT18, BIT18); + + tft_memory_access_ctrl(MV | 0x0C); + tft_sleep_out(); + + _delay_ms(150); + + tft_display_on(); + + _delay_ms(50); + clear_screen(); +} diff --git a/src/tty.c b/src/tty.c new file mode 100644 index 0000000..f9413b4 --- /dev/null +++ b/src/tty.c @@ -0,0 +1,164 @@ +#include <tft.h> +#include <zeta.h> +#include <tty.h> + +struct color { + uint8_t r, g, b; +}; + +static unsigned int row = 0; +static unsigned int col = 0; + +// Index of first row inside buf +static volatile uint8_t head = 0; + +// TTY's current contents +static volatile uint8_t buf[TTY_HEIGHT][TTY_WIDTH]; + +static volatile struct color bg_color = {0x00, 0x00, 0x00}; +static volatile struct color fg_color = {0xFF, 0xFB, 0x00}; + +extern const uint8_t font[97][8]; + + +static uint8_t cursor = 0; +static uint8_t timer = 0; + +void +blink_cursor(void) __critical __interrupt(3) +{ + if (++timer >= 75) { + uint8_t i; + + tft_set_area(8 * col, 8 * row, 8, 8); + tft_ram_wr(); + + if ((cursor ^= 1)) { + for (i = 0; i < 64; ++i) + tft_pixel(fg_color.r, fg_color.g, fg_color.b); + } else { + for (i = 0; i < 64; ++i) + tft_pixel(bg_color.r, bg_color.g, bg_color.b); + } + timer = 0; + } +} + +static void +draw(u8 c) +{ + u8 i, j; + const u8 *chr; + + if (c < ' ') + return; + + chr = font[c - ' ']; + + tft_ram_wr(); + + for (i = 0; i < 8; ++i) { + u8 row = chr[i]; + for (j = 0; j < 8; ++j) { + if (row & 1) + tft_pixel(fg_color.r, fg_color.g, fg_color.b); + else + tft_pixel(bg_color.r, bg_color.g, bg_color.b); + row >>= 1; + } + } +} + +static void +scroll(void) +{ + uint16_t i, j; + head = (head + 1) % TTY_HEIGHT; + + for (i = head; i < TTY_HEIGHT; ++i) { + for (j = 0; j < TTY_WIDTH; ++j) { + tft_set_area(8 * j, 8 * (i - head), 8, 8); + draw(buf[i][j]); + } + } + + for (i = 0; i < head - 1; ++i) { + for (j = 0; j < TTY_WIDTH; ++j) { + tft_set_area(8 * j, 8 * (TTY_HEIGHT - head + i), 8, 8); + draw(buf[i][j]); + } + } + + for (j = 0; j < TTY_WIDTH; ++j) { + tft_set_area(8 * j, 8 * (TTY_HEIGHT - 1), 8, 8); + draw(' '); + } +} + +static void +newline(void) +{ + if (++row >= TTY_HEIGHT) { + row = TTY_HEIGHT - 1; + scroll(); + } +} + +static void +advance(void) +{ + if (++col >= TTY_WIDTH) { + newline(); + col = 0; + } +} + +void +addch(char c) +{ + switch (c) { + case '\b': + if (col != 0) + --col; + return; + + case '\r': + col = 0; + return; + + case '\n': + newline(); + return; + } + + tft_set_area(8 * col, 8 * row, 8, 8); + + draw(c); + + buf[(head + row) % TTY_HEIGHT][col] = c; + advance(); +} + +void +setcur(unsigned int ncol, unsigned int nrow) +{ + col = ncol; + row = nrow; +} + +void +swap_colors(void) +{ + struct color tmp = {fg_color.r, fg_color.g, fg_color.b}; + fg_color = bg_color; + bg_color = tmp; +} + +void +addstr(const char *str) +{ + while (*str) { + addch(*str); + ++str; + } +} |