diff --git a/Makefile b/Makefile index 60bf62e..4f58a92 100644 --- a/Makefile +++ b/Makefile @@ -6,11 +6,12 @@ BASE_NAME := T-962-controller SRC_DIR := ./src/ +CLI_DIR := ./src/SimpleCLI/src/ BUILD_DIR := ./build/ TARGET := $(BUILD_DIR)$(BASE_NAME).axf -vpath %.c $(SRC_DIR) +vpath %.c $(SRC_DIR):$(CLI_DIR) vpath %.o $(BUILD_DIR) vpath %.d $(BUILD_DIR) @@ -29,16 +30,22 @@ COLOR_END = $(shell echo "\033[0m") # Source files C_SRCS += $(wildcard $(SRC_DIR)*.c) $(BUILD_DIR)version.c +CLI_SRCS := $(wildcard $(CLI_DIR)*.c) S_SRCS += $(wildcard $(SRC_DIR)*.s) -OBJS := $(patsubst $(SRC_DIR)%.c,$(BUILD_DIR)%.o,$(C_SRCS)) $(patsubst $(SRC_DIR)%.s,$(BUILD_DIR)%.o,$(S_SRCS)) +OBJS := $(patsubst $(SRC_DIR)%.c,$(BUILD_DIR)%.o,$(C_SRCS)) \ + $(patsubst $(CLI_DIR)%.c,$(BUILD_DIR)%.o,$(CLI_SRCS)) \ + $(patsubst $(SRC_DIR)%.s,$(BUILD_DIR)%.o,$(S_SRCS)) C_DEPS := $(wildcard *.d) +C_FLAGS := -DNDEBUG -D__NEWLIB__ -Os -g -Wall -Wextra -std=gnu99 -Isrc -fmessage-length=0 -fno-builtin \ + -ffunction-sections -fdata-sections -flto -ffat-lto-objects -mcpu=arm7tdmi all: axf $(BUILD_DIR)version.c: $(BUILD_DIR)tag + @echo $(OBJS) git describe --tag --always --dirty | \ sed 's/.*/const char* Version_GetGitVersion(void) { return "&"; }/' > $@ @@ -51,21 +58,26 @@ $(BUILD_DIR)tag: $(BUILD_DIR)%.o: $(SRC_DIR)%.c $(BUILD_DIR)tag @echo 'Building file: $<' - $(CC) -std=gnu99 -DNDEBUG -D__NEWLIB__ -Os -g -Wall -Wunused -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -flto -ffat-lto-objects -mcpu=arm7tdmi -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -MT"$(@:%.o=%.d)" -o "$@" "$<" + $(CC) $(C_FLAGS) -c -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -MT"$(@:%.o=%.d)" -o "$@" "$<" @echo 'Finished building: $(COLOR_GREEN)$<$(COLOR_END)' @echo ' ' -$(BUILD_DIR)%.o: $(SRC_DIR)%.s $(BUILD_DIR)tag +$(BUILD_DIR)%.o: $(CLI_DIR)%.c $(BUILD_DIR)tag @echo 'Building file: $<' - $(CC) -c -x assembler-with-cpp -I $(BUILD_DIR) -DNDEBUG -D__NEWLIB__ -mcpu=arm7tdmi -o "$@" "$<" + $(CC) $(C_FLAGS) -c -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -MT"$(@:%.o=%.d)" -o "$@" "$<" @echo 'Finished building: $(COLOR_GREEN)$<$(COLOR_END)' @echo ' ' +$(BUILD_DIR)%.o: $(SRC_DIR)%.s $(BUILD_DIR)tag + @echo 'Building file: $<' + $(CC) $(C_FLAGS) -c -x assembler-with-cpp -I $(BUILD_DIR) -o "$@" "$<" + @echo 'Finished building: $(COLOR_GREEN)$<$(COLOR_END)' + @echo ' ' axf: $(OBJS) $(USER_OBJS) @echo 'Building target: $@' @echo 'Invoking: MCU Linker' - $(CC) -nostdlib -Xlinker -Map="$(BUILD_DIR)$(BASE_NAME).map" -Xlinker --gc-sections -flto -Os -mcpu=arm7tdmi --specs=nano.specs -u _printf_float -u _scanf_float -T "$(BASE_NAME).ld" -o "$(TARGET)" $(OBJS) $(USER_OBJS) $(LIBS) + $(CC) $(C_FLAGS) -nostdlib -Xlinker -Map="$(BUILD_DIR)$(BASE_NAME).map" -Xlinker --gc-sections --specs=nano.specs -u _printf_float -u _scanf_float -T "$(BASE_NAME).ld" -o "$(TARGET)" $(OBJS) $(USER_OBJS) $(LIBS) @echo 'Finished building target: $(COLOR_GREEN)$@$(COLOR_END)' @echo ' ' $(MAKE) --no-print-directory post-build diff --git a/src/SimpleCLI/LICENSE b/src/SimpleCLI/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/src/SimpleCLI/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. + + {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 . + +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: + + {project} Copyright (C) {year} {fullname} + 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/src/SimpleCLI/README.md b/src/SimpleCLI/README.md new file mode 100644 index 0000000..3cf226b --- /dev/null +++ b/src/SimpleCLI/README.md @@ -0,0 +1,2 @@ +# SimpleCLI +A simple command line interpreter for small embedded systems diff --git a/src/SimpleCLI/cfg/scliConfig.h b/src/SimpleCLI/cfg/scliConfig.h new file mode 100644 index 0000000..815d4ec --- /dev/null +++ b/src/SimpleCLI/cfg/scliConfig.h @@ -0,0 +1,47 @@ +/* + * scliConfig.h + * + * Created on: 27.01.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +#ifndef SCLI_CFG_H_ +#define SCLI_CFG_H_ + +/* + * Usage flags + */ +#define SCLI_USE_OWN_PRINTF 0 +#define SCLI_USE_OWN_STDC_FUNC 0 +#define SCLI_USE_CFG_SYSTEM 0 + +/* + * Size configuration + */ +#define SCLI_CMD_HIST 10 +#define SCLI_CMD_MAX_LEN 180 +#define SCLI_CMD_MAX_ARGS 10 +#define SCLI_GETCH_BUF_SIZE 20 +#define SCLI_CMD_NAME_MAX_LEN 10 +#define SCLI_CONF_MAX_HANDLE 10 + +#if SCLI_USE_OWN_PRINTF > 0 +#error "Remove this line and add own printf header" +//#include "printf.h" +#endif + +#endif /* SCLI_CFG_H_ */ diff --git a/src/SimpleCLI/inc/scliConf.h b/src/SimpleCLI/inc/scliConf.h new file mode 100644 index 0000000..eb82071 --- /dev/null +++ b/src/SimpleCLI/inc/scliConf.h @@ -0,0 +1,35 @@ +/* + * scliConf.h + * + * Created on: 12.02.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +#ifndef SCLICONF_H_ +#define SCLICONF_H_ + +#include "SimpleCLI/inc/scliTypes.h" + +#if SCLI_USE_CFG_SYSTEM > 0 + +extern SCLI_CMD_RET scliConf_SetCmd(uint8_t argc, char **argv); +extern SCLI_CMD_RET scliConf_GetCmd(uint8_t argc, char **argv); +extern SCLI_CMD_RET scliConf_ConfCmd(uint8_t argc, char **argv); +extern SCLI_CFG_HANDLE_T * scliConf_RegisterConfig(const char *const Name, const char *const Desc, SCLI_CFG_ENTRY_T *Table); +#endif + +#endif /* SCLICONF_H_ */ diff --git a/src/SimpleCLI/inc/scliCore.h b/src/SimpleCLI/inc/scliCore.h new file mode 100644 index 0000000..1215cba --- /dev/null +++ b/src/SimpleCLI/inc/scliCore.h @@ -0,0 +1,45 @@ +/* + * scliCore.h + * + * Created on: 27.01.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +#ifndef SCLI_CORE_H_ +#define SCLI_CORE_H_ + +#include "SimpleCLI/cfg/scliConfig.h" +#include "SimpleCLI/inc/scliTypes.h" +#include "SimpleCLI/inc/scliText.h" +#include "SimpleCLI/inc/scliConf.h" + +#if SCLI_USE_OWN_PRINTF > 0 +#include +#else +#include +#endif + +extern uint8_t scliCore_Init(SCLI_INTERFACE_T* Interface); +extern void scliCore_ExecuteCommand(SCLI_CMD_INPUT_T *InputBuffer); +extern void scliCore_ReleaseBuffer(SCLI_CMD_INPUT_T *InputBuffer); +extern int scliCore_getchar(void); +extern SCLI_CMD_T * scliCore_GetCommandInTable(char * Cmd, SCLI_CMD_T * Table, SCLI_LINE_IDX CmdLen); +extern void scliCore_PrintHelp(SCLI_CMD_T * Table, uint8_t SingleEntry); + + + +#endif /* SCLI_CORE_H_ */ diff --git a/src/SimpleCLI/inc/scliStdC.h b/src/SimpleCLI/inc/scliStdC.h new file mode 100644 index 0000000..bfdd3b1 --- /dev/null +++ b/src/SimpleCLI/inc/scliStdC.h @@ -0,0 +1,48 @@ +/* + * scliStdC.h + * + * Created on: 31.01.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +#ifndef SCLISTDC_H_ +#define SCLISTDC_H_ + +#include "SimpleCLI/cfg/scliConfig.h" +#include "SimpleCLI/inc/scliTypes.h" + +#if SCLI_USE_OWN_STDC_FUNC > 0 +extern uint32_t scliStdC_strlen(char *); +extern int scliStdC_strncmp(char *, char *, size_t); +extern void scliStdC_memset(void*, int8_t, size_t); +extern char * scliStdC_strncpy(char *, const char *, size_t ); +extern uint32_t scliStdC_strtoul(char *, char **, int ); +extern int32_t scliStdC_strtol(char *, char **, int ); + +#define strlen scliStdC_strlen +#define strncmp scliStdC_strncmp +#define memset scliStdC_memset +#define strncpy scliStdC_strncpy +#define strtoul scliStdC_strtoul +#define strtol scliStdC_strtol + +#else +#include +#include +#endif + +#endif /* SCLISTDC_H_ */ diff --git a/src/SimpleCLI/inc/scliText.h b/src/SimpleCLI/inc/scliText.h new file mode 100644 index 0000000..9170058 --- /dev/null +++ b/src/SimpleCLI/inc/scliText.h @@ -0,0 +1,44 @@ +/* + * scliText.h + * + * Created on: 31.01.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +#ifndef SCLITEXT_H_ +#define SCLITEXT_H_ + +extern const char scliText_ColRedBold[]; +extern const char scliText_ColGreBold[]; +extern const char scliText_ColYelBold[]; +extern const char scliText_ColBluBold[]; +extern const char scliText_ColMagBold[]; +extern const char scliText_ColCyaBold[]; +extern const char scliText_ColDef[]; +extern const char scliText_ColDefBold[]; +extern const char scliText_DeleteRight[]; + +extern const char scliText_WelcomeMsg[]; +extern const char scliText_Prompt[]; +extern const char scliText_Help[]; +extern const char scliText_Version[]; +extern const char scliText_Set[]; +extern const char scliText_Get[]; +extern const char scliText_ConfNoTable[]; +extern const char scliText_Conf[]; + +#endif /* SCLITEXT_H_ */ diff --git a/src/SimpleCLI/inc/scliTypes.h b/src/SimpleCLI/inc/scliTypes.h new file mode 100644 index 0000000..623ac1f --- /dev/null +++ b/src/SimpleCLI/inc/scliTypes.h @@ -0,0 +1,182 @@ +/* + * scliTypes.h + * + * Created on: 27.01.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +#ifndef SCLI_TYPES_H_ +#define SCLI_TYPES_H_ + +#include "SimpleCLI/cfg/scliConfig.h" +#include +#include + +#define SCLI_CMD_LIST_END {0,0,0,0} +#define SCLI_FIFO_EMPTY (-1) + +#if SCLI_CMD_HIST < 256 +typedef uint8_t SCLI_BUF_IDX; +#else +typedef uint16_t SCLI_BUF_IDX; +#endif + +#if SCLI_CMD_MAX_LEN < 256 +typedef uint8_t SCLI_LINE_IDX; +#else +typedef uint16_t SCLI_LINE_IDX; +#endif + +#if SCLI_GETCH_BUF_SIZE < 256 +typedef uint8_t SCLI_FIFO_IDX; +#else +typedef uint16_t SCLI_FIFO_IDX; +#endif + +typedef int32_t SCLI_CMD_RET; +typedef SCLI_CMD_RET (*SCLI_CMD_CB)(uint8_t argc, char **argv); + +typedef enum +{ + SCLI_BUF_INIT = 0, + SCLI_BUF_READY, + SCLI_BUF_ESC_CLI, + SCLI_BUF_ESC_CMD, + SCLI_BUF_PARSING, + SCLI_BUF_EXEC +}SCLI_BUF_STATE; + +typedef struct +{ + SCLI_CMD_CB CmdCallback; + const char *const CmdName; + const char *const HelpShort; + const char *HelpLong; +}SCLI_CMD_T; + +typedef struct +{ + SCLI_BUF_STATE State; + char Line[SCLI_CMD_MAX_LEN]; + SCLI_BUF_IDX HistRefs; + SCLI_LINE_IDX LineIdx; +}SCLI_CMD_INPUT_T; + +typedef struct +{ + void (*SubsystemInit)(void (*)(uint8_t )); + void (*PutCh)(char ch); + void (*UserLevelHandOver)(SCLI_CMD_INPUT_T *Input); + uint32_t (*CriticalEnter)(void); + void (*CriticalExit)(uint32_t reg); + SCLI_CMD_T *UserLevelCommands; + +}SCLI_INTERFACE_T; + +typedef struct +{ + char Buffer[SCLI_GETCH_BUF_SIZE]; + SCLI_FIFO_IDX Write; + SCLI_FIFO_IDX Read; + SCLI_FIFO_IDX Size; +}SCLI_FIFO_T; + +#if SCLI_USE_CFG_SYSTEM > 0 + +#define SCLI_CFG_VAR_SIZE_MASK 0x0F +#define SCLI_CFG_CMP_LIST_END {.Str = 0, .Value.Unsigned = 0} +#define SCLI_CFG_ENTRY_LIST_END {0, SCLI_CFG_VAR_NONE, SCLI_CFG_PARSE_INT, 0, 0, 0, 0} + +typedef enum +{ + SCLI_CFG_VAR_NONE = 0x00, + SCLI_CFG_VAR_INT8S = 0x11, + SCLI_CFG_VAR_INT8U = 0x21, + SCLI_CFG_VAR_INT16S = 0x32, + SCLI_CFG_VAR_INT16U = 0x42, + SCLI_CFG_VAR_INT32S = 0x54, + SCLI_CFG_VAR_INT32U = 0x64, + SCLI_CFG_VAR_STRING = 0xFF, +}SCLI_CFG_VAR_TYPE; + +typedef enum +{ + SCLI_CFG_PARSE_INT = 0, + SCLI_CFG_PARSE_STR_CMP, + SCLI_CFG_PARSE_STR_PLAIN, +}SCLI_CFG_P_METHOD; + +typedef struct +{ + const char *const Str; + union + { + int32_t Signed; + uint32_t Unsigned; + }Value; +}SCLI_CFG_CMP_T; + +typedef struct +{ + const char *const Name; + SCLI_CFG_VAR_TYPE Type; + SCLI_CFG_P_METHOD ParseMethod; + SCLI_CFG_CMP_T *StrCmpTable; + const char *const Desc; + size_t Size; + void *Target; +}SCLI_CFG_ENTRY_T; + +typedef struct _SCLI_CFG_HANDLE +{ + char * Name; + char * Desc; + SCLI_CFG_ENTRY_T *Table; + struct _SCLI_CFG_HANDLE *Prev; + struct _SCLI_CFG_HANDLE *Next; +}SCLI_CFG_HANDLE_T; + +typedef struct _SCLI_CFG_FS_ENTRY +{ + SCLI_CFG_VAR_TYPE Type; + struct _SCLI_CFG_FS_ENTRY *Next; + union + { + struct + { + uint32_t Value; + char Name; + }UnsignedNum; + struct + { + int32_t Value; + char Name; + }SignedNum; + char String; + }Payload; +}SCLI_CFG_FS_ENTRY_T; + +typedef struct _SCLI_CFG_RAW_FS +{ + uint32_t Hash; + SCLI_CFG_FS_ENTRY_T *Start; + struct _SCLI_CFG_RAW_FS *Prev; + struct _SCLI_CFG_RAW_FS *Next; +}SCLI_CFG_RAW_FS_T; +#endif + +#endif /* SCLI_TYPES_H_ */ diff --git a/src/SimpleCLI/src/scliConf.c b/src/SimpleCLI/src/scliConf.c new file mode 100644 index 0000000..fa0cfee --- /dev/null +++ b/src/SimpleCLI/src/scliConf.c @@ -0,0 +1,514 @@ +/* + * scliConf.c + * + * Created on: 12.02.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +#include "SimpleCLI/inc/scliCore.h" +#include "SimpleCLI/inc/scliStdC.h" + +#if SCLI_USE_CFG_SYSTEM > 0 + +static SCLI_CFG_HANDLE_T _scliConf_HandleTable[SCLI_CONF_MAX_HANDLE]; +static SCLI_CFG_HANDLE_T * _scliConf_HandleHead = (SCLI_CFG_HANDLE_T *)0; + +/* + * Forward declaration for internal commands + */ +static SCLI_CMD_RET _scliConf_ConfStore(uint8_t argc, char **argv); +static SCLI_CMD_RET _scliCore_ConfLoad(uint8_t argc, char **argv); +static SCLI_CMD_RET _scliConf_ConfShow(uint8_t argc, char **argv); + +/* + * Internal subcommand table + */ +static SCLI_CMD_T _scliConf_ConfSubcommands[] = +{ + {_scliConf_ConfStore, "store", "Save configuration", 0}, + {_scliCore_ConfLoad, "load", "Load configuration", 0}, + {_scliConf_ConfShow, "show", "Display system variables", 0}, + SCLI_CMD_LIST_END +}; + +static SCLI_CFG_HANDLE_T * _scliConf_GetFreeConfigSlot(void) +{ + unsigned int i = 0; + for (i = 0; i < SCLI_CONF_MAX_HANDLE; i++) + { + if( _scliConf_HandleTable[i].Next == (SCLI_CFG_HANDLE_T *)0 + && _scliConf_HandleTable[i].Prev == (SCLI_CFG_HANDLE_T *)0 + && _scliConf_HandleTable[i].Table == (SCLI_CFG_ENTRY_T *)0) + { + return &_scliConf_HandleTable[i]; + } + } + return (SCLI_CFG_HANDLE_T *)0; +} + +static SCLI_CFG_ENTRY_T * _scliConf_LookupEntry(char *VarName) +{ + SCLI_CFG_HANDLE_T *CurrentHandle = _scliConf_HandleHead; + SCLI_CFG_ENTRY_T *Entry = (SCLI_CFG_ENTRY_T *)0; + while(CurrentHandle) + { + Entry = CurrentHandle->Table; + + while(Entry->Type != SCLI_CFG_VAR_NONE) + { + size_t EntryNameLen = strlen((char *)Entry->Name); + size_t VarNameLen = strlen(VarName); + + if(EntryNameLen == VarNameLen && strncmp(VarName,(char *)Entry->Name,EntryNameLen) == 0) + return Entry; + + Entry++; + } + + CurrentHandle = CurrentHandle->Next; + } + + return (SCLI_CFG_ENTRY_T *)0; +} + +static SCLI_CFG_HANDLE_T * _scliConf_LookupHandle(char *ConfName) +{ + SCLI_CFG_HANDLE_T *CurrentHandle = _scliConf_HandleHead; + while(CurrentHandle) + { + size_t HandleNameLen = strlen((char *)CurrentHandle->Name); + size_t ConfNameLen = strlen(ConfName); + + if(HandleNameLen == ConfNameLen && strncmp(ConfName,(char *)CurrentHandle->Name,HandleNameLen) == 0) + return CurrentHandle; + + CurrentHandle = CurrentHandle->Next; + } + + return (SCLI_CFG_HANDLE_T *)0; +} + +static SCLI_CMD_RET _scliConf_ParseInt(SCLI_CFG_ENTRY_T * Entry , char * String) +{ + + char *CheckPointer; + uint32_t Unsigned = 0; + int32_t Signed = 0; + + switch(Entry->Type) + { + case SCLI_CFG_VAR_INT8S: + case SCLI_CFG_VAR_INT16S: + case SCLI_CFG_VAR_INT32S: + Signed = strtol(String, &CheckPointer, 10); + break; + case SCLI_CFG_VAR_INT8U: + case SCLI_CFG_VAR_INT16U: + case SCLI_CFG_VAR_INT32U: + Unsigned = strtoul(String, &CheckPointer, 10); + break; + default: + return -1; + } + + if(String == CheckPointer) + { + printf(" Invalid value\r\n"); + return -1; + } + + switch(Entry->Type) + { + case SCLI_CFG_VAR_INT8S: *((int8_t *)Entry->Target) = (int8_t)(Signed & 0x00FF); break; + case SCLI_CFG_VAR_INT16S: *((int16_t *)Entry->Target) = (int16_t)(Signed & 0xFFFF); break; + case SCLI_CFG_VAR_INT32S: *((int32_t *)Entry->Target) = Signed; break; + + case SCLI_CFG_VAR_INT8U: *((uint8_t *)Entry->Target) = (uint8_t)(Unsigned & 0x00FF); break; + case SCLI_CFG_VAR_INT16U: *((uint16_t *)Entry->Target) = (uint16_t)(Unsigned & 0xFFFF); break; + case SCLI_CFG_VAR_INT32U: *((uint32_t *)Entry->Target) = Unsigned; break; + + default: + return -1; + } + return 0; +} + +static SCLI_CMD_RET _scliConf_ParseStrTbl(SCLI_CFG_ENTRY_T * Entry, char * String) +{ + SCLI_CFG_CMP_T *StrCmpTable = Entry->StrCmpTable; + + if(StrCmpTable == (SCLI_CFG_CMP_T *)0) + { + printf(" Missing string table!\r\n"); + return -1; + } + + while(StrCmpTable->Str != 0) + { + size_t StrValueLen = strlen((char *)StrCmpTable->Str); + size_t VarValueLen = strlen(String); + + if(StrValueLen == VarValueLen && strncmp(String,(char *)StrCmpTable->Str,StrValueLen) == 0) + { + switch(Entry->Type) + { + case SCLI_CFG_VAR_INT8S: *((int8_t *)Entry->Target) = (int8_t)(StrCmpTable->Value.Signed & 0x00FF); break; + case SCLI_CFG_VAR_INT16S: *((int16_t *)Entry->Target) = (int16_t)(StrCmpTable->Value.Signed & 0xFFFF); break; + case SCLI_CFG_VAR_INT32S: *((int32_t *)Entry->Target) = StrCmpTable->Value.Signed; break; + + case SCLI_CFG_VAR_INT8U: *((uint8_t *)Entry->Target) = (uint8_t)(StrCmpTable->Value.Unsigned & 0x00FF); break; + case SCLI_CFG_VAR_INT16U: *((uint16_t *)Entry->Target) = (uint16_t)(StrCmpTable->Value.Unsigned & 0xFFFF); break; + case SCLI_CFG_VAR_INT32U: *((uint32_t *)Entry->Target) = StrCmpTable->Value.Unsigned; break; + + default: + return -1; + } + return 0; + } + StrCmpTable++; + } + + printf("\r\n Value %s for variable %s not found!\r\n" + " Possible values are [", String, Entry->Name); + + StrCmpTable = Entry->StrCmpTable; + while(StrCmpTable->Str != 0) + { + printf(" %s", StrCmpTable->Str); + StrCmpTable++; + } + printf(" ]\r\n"); + + return -1; +} + +static SCLI_CMD_RET _scliConf_ParseStr(SCLI_CFG_ENTRY_T * Entry, char * String) +{ + strncpy((char *)Entry->Target, (const char *)String,Entry->Size - 1); + ((char *)Entry->Target)[Entry->Size - 1] = '\0'; + return 0; +} + +static SCLI_CMD_RET _scliConf_DisplayInt(SCLI_CFG_ENTRY_T * Entry, unsigned int Verbose) +{ + char Buffer[11]; + + switch(Entry->Type) + { + case SCLI_CFG_VAR_INT8S: sprintf(Buffer, "%d",(int32_t)*((int8_t *)(Entry->Target))); break; + case SCLI_CFG_VAR_INT16S: sprintf(Buffer, "%d",(int32_t)*((int16_t *)(Entry->Target))); break; + case SCLI_CFG_VAR_INT32S: sprintf(Buffer, "%d",(int32_t)*((int32_t *)(Entry->Target))); break; + + case SCLI_CFG_VAR_INT8U: sprintf(Buffer, "%u",(uint32_t)*((uint8_t *)(Entry->Target))); break; + case SCLI_CFG_VAR_INT16U: sprintf(Buffer, "%u",(uint32_t)*((uint16_t *)(Entry->Target))); break; + case SCLI_CFG_VAR_INT32U: sprintf(Buffer, "%u",(uint32_t)*((uint32_t *)(Entry->Target))); break; + + default: + return -1; + } + if(Verbose) + { + printf(" %s %s %s \r\n", (char *)Entry->Name, Buffer, (char *)Entry->Desc); + } + else + { + printf("\r\n get %s -> %s\r\n",(char *)Entry->Name, Buffer); + } + return 0; +} + +static SCLI_CMD_RET _scliConf_DisplayStrTbl(SCLI_CFG_ENTRY_T * Entry, unsigned int Verbose) +{ + SCLI_CFG_CMP_T *StrCmpTable = Entry->StrCmpTable; + SCLI_CFG_CMP_T CmpHelper; + while(StrCmpTable->Str != 0) + { + switch(Entry->Type) + { + case SCLI_CFG_VAR_INT8S: CmpHelper.Value.Signed = (int32_t) *((int8_t *)Entry->Target); break; + case SCLI_CFG_VAR_INT16S: CmpHelper.Value.Signed = (int32_t) *((int16_t *)Entry->Target); break; + case SCLI_CFG_VAR_INT32S: CmpHelper.Value.Signed = (int32_t) *((int32_t *)Entry->Target); break; + + case SCLI_CFG_VAR_INT8U: CmpHelper.Value.Unsigned = (uint32_t) *((uint8_t *)Entry->Target); break; + case SCLI_CFG_VAR_INT16U: CmpHelper.Value.Unsigned = (uint32_t) *((uint16_t *)Entry->Target); break; + case SCLI_CFG_VAR_INT32U: CmpHelper.Value.Unsigned = (uint32_t) *((uint32_t *)Entry->Target); break; + + default: + return -1; + } + if(CmpHelper.Value.Signed == StrCmpTable->Value.Signed + || CmpHelper.Value.Unsigned == StrCmpTable->Value.Unsigned) + break; + StrCmpTable++; + } + if(StrCmpTable->Str == 0) + { + return -1; + } + if(Verbose) + { + printf(" %s %s %s \r\n", (char *)Entry->Name, (char *)StrCmpTable->Str, (char *)Entry->Desc); + } + else + { + printf("\r\n get %s -> %s\r\n",(char *)Entry->Name, (char *)StrCmpTable->Str); + } + return 0; +} + +static SCLI_CMD_RET _scliConf_DisplayStr(SCLI_CFG_ENTRY_T * Entry, unsigned int Verbose) +{ + if(Verbose) + { + printf(" %s %s %s \r\n", (char *)Entry->Name, (char *)Entry->Target, (char *)Entry->Desc); + } + else + { + printf("\r\n get %s -> %s\r\n",(char *)Entry->Name, (char *)Entry->Target); + } + return 0; +} + +static void _scliConf_PrintConfig(SCLI_CFG_HANDLE_T *Handle) +{ + printf("\r\n Configuration Entry %s: %s\r\n", Handle->Name, Handle->Desc); + SCLI_CFG_ENTRY_T *Entry = Handle->Table; + while(Entry->Type != SCLI_CFG_VAR_NONE) + { + switch(Entry->ParseMethod) + { + case SCLI_CFG_PARSE_INT: + _scliConf_DisplayInt(Entry, 1); + break; + case SCLI_CFG_PARSE_STR_CMP: + _scliConf_DisplayStrTbl(Entry, 1); + break; + case SCLI_CFG_PARSE_STR_PLAIN: + _scliConf_DisplayStr(Entry, 1); + break; + default: + printf("\r\n Unknown parsing method in config table\r\n"); + break;; + } + Entry++; + } +} + +static SCLI_CMD_RET _scliConf_ConfStore(uint8_t argc, char **argv) +{ + return 0; +} + +static SCLI_CMD_RET _scliCore_ConfLoad(uint8_t argc, char **argv) +{ + return 0; +} + +static SCLI_CMD_RET _scliConf_ConfShow(uint8_t argc, char **argv) +{ + SCLI_CFG_HANDLE_T * CurrentHandle = _scliConf_HandleHead; + uint32_t i = 0; + + if(argc == 1) + { + while(CurrentHandle) + { + _scliConf_PrintConfig(CurrentHandle); + + CurrentHandle = CurrentHandle->Next; + } + } + else + { + for(i=1; i < argc; i++) + { + CurrentHandle = _scliConf_LookupHandle(argv[i]); + if(CurrentHandle) + { + _scliConf_PrintConfig(CurrentHandle); + } + else + { + printf("\r\n No entry for %s\r\n",argv[i]); + } + } + } + return 0; +} + +SCLI_CFG_HANDLE_T * scliConf_RegisterConfig(const char *const Name, const char *const Desc, SCLI_CFG_ENTRY_T *Table) +{ + SCLI_CFG_HANDLE_T *NewHandle = _scliConf_GetFreeConfigSlot(); + + if(NewHandle == (SCLI_CFG_HANDLE_T *)0) + return NewHandle; + + NewHandle->Name = (char *)Name; + NewHandle->Desc = (char *)Desc; + NewHandle->Table = Table; + NewHandle->Next = ((SCLI_CFG_HANDLE_T *)0); + + if(_scliConf_HandleHead == (SCLI_CFG_HANDLE_T *)0) + { + _scliConf_HandleHead = NewHandle; + NewHandle->Prev = ((SCLI_CFG_HANDLE_T *)0); + } + else + { + SCLI_CFG_HANDLE_T *CurrentHandle = _scliConf_HandleHead; + + while(CurrentHandle->Next != (SCLI_CFG_HANDLE_T *)0) + CurrentHandle = CurrentHandle->Next; + + CurrentHandle->Next = NewHandle; + NewHandle->Prev = CurrentHandle; + + } + return NewHandle; +} + +SCLI_CMD_RET scliConf_SetCmd(uint8_t argc, char **argv) +{ + SCLI_CMD_RET Ret = 0; + + if(_scliConf_HandleHead == (SCLI_CFG_HANDLE_T *)0) + { + printf("%s",scliText_ConfNoTable); + return -1; + } + + if(argc != 3) + { + printf("\r\n Usage: set \r\n"); + return -1; + } + + SCLI_CFG_ENTRY_T *Entry = _scliConf_LookupEntry(argv[1]); + + if(Entry == (SCLI_CFG_ENTRY_T *)0) + { + printf("\r\n No match found for %s\r\n",argv[1]); + return -1; + } + + switch(Entry->ParseMethod) + { + case SCLI_CFG_PARSE_INT: + Ret = _scliConf_ParseInt(Entry ,argv[2]); + break; + case SCLI_CFG_PARSE_STR_CMP: + Ret = _scliConf_ParseStrTbl(Entry ,argv[2]); + break; + case SCLI_CFG_PARSE_STR_PLAIN: + Ret = _scliConf_ParseStr(Entry ,argv[2]); + break; + default: + printf(" Unknown parsing method in config table\r\n"); + return -1; + } + + if(Ret < 0) + { + printf(" Failed to set %s %s\r\n",(char *)Entry->Name, argv[2]); + } + else + { + printf("\r\n Done!\r\n"); + } + return Ret; + +} + +SCLI_CMD_RET scliConf_GetCmd(uint8_t argc, char **argv) +{ + if(_scliConf_HandleHead == (SCLI_CFG_HANDLE_T *)0) + { + printf("%s",scliText_ConfNoTable); + return -1; + } + + if(argc != 2) + { + printf("\r\n Usage: get \r\n"); + return -1; + } + + SCLI_CFG_ENTRY_T *Entry = _scliConf_LookupEntry(argv[1]); + + if(Entry == (SCLI_CFG_ENTRY_T *)0) + { + printf("\r\n No match found for %s\r\n",argv[1]); + return -1; + } + + switch(Entry->ParseMethod) + { + case SCLI_CFG_PARSE_INT: + return _scliConf_DisplayInt(Entry,0); + case SCLI_CFG_PARSE_STR_CMP: + return _scliConf_DisplayStrTbl(Entry,0); + case SCLI_CFG_PARSE_STR_PLAIN: + return _scliConf_DisplayStr(Entry,0); + default: + printf("\r\n Unknown parsing method in config table\r\n"); + return -1; + } + + return 0; + +} + +SCLI_CMD_RET scliConf_ConfCmd(uint8_t argc, char **argv) +{ + uint8_t PrintSubcommands = 0; + SCLI_CMD_RET Ret = 0; + + if(_scliConf_HandleHead == (SCLI_CFG_HANDLE_T *)0) + { + printf("%s",scliText_ConfNoTable); + return -1; + } + + if(argc == 1) + { + PrintSubcommands = 1; + } + else + { + SCLI_CMD_T * Cmd = scliCore_GetCommandInTable(argv[1], _scliConf_ConfSubcommands,strlen(argv[1])); + if(Cmd) + { + Ret = Cmd->CmdCallback(argc - 1, &argv[1] ); + } + else + { + printf("\r\n Unknown subcommand!"); + PrintSubcommands = 1; + Ret = -1; + } + } + + if(PrintSubcommands) + { + printf("\r\n Available subcommands:\r\n"); + scliCore_PrintHelp(_scliConf_ConfSubcommands, 0); + } + + return Ret; +} + +#endif diff --git a/src/SimpleCLI/src/scliCore.c b/src/SimpleCLI/src/scliCore.c new file mode 100644 index 0000000..6c85081 --- /dev/null +++ b/src/SimpleCLI/src/scliCore.c @@ -0,0 +1,762 @@ +/* + * scliCore.c + * + * Created on: 27.01.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +#include "SimpleCLI/inc/scliCore.h" +#include "SimpleCLI/inc/scliStdC.h" +#include "SimpleCLI/inc/scliConf.h" + +/* + * Static variables + */ +static SCLI_CMD_INPUT_T _scliCore_InputBuffer[SCLI_CMD_HIST]; +static SCLI_BUF_IDX _scliCore_CurBufferIdx = 0; +static SCLI_BUF_IDX _scliCore_CmdHist[SCLI_CMD_HIST]; +static SCLI_BUF_IDX _scliCore_CmdHistHead = 0; +static SCLI_BUF_IDX _scliCore_CmdHistCurIdx = 0; +static SCLI_INTERFACE_T* _scliCore_Interface = 0; +static SCLI_FIFO_T _scliCore_GetCharBuffer; +static SCLI_BUF_IDX _scliCore_CmdHistWrapArround = 0; + +/* + * Forward declaration for internal commands + */ +static SCLI_CMD_RET _scliCore_HelpCmd(uint8_t argc, char **argv); +static SCLI_CMD_RET _scliCore_VersionCmd(uint8_t argc, char **argv); +static SCLI_CMD_RET _scliCore_HistoryCmd(uint8_t argc, char **argv); + +/* + * Internal command table + */ +static SCLI_CMD_T _scliCore_BasicCommands[] = +{ + {_scliCore_HelpCmd, "help", "Displays help text", scliText_Help}, + {_scliCore_VersionCmd, "version", "Displays version text", scliText_Version}, + {_scliCore_HistoryCmd, "history", "Displays history", scliText_Version}, +#if SCLI_USE_CFG_SYSTEM > 0 + {scliConf_SetCmd, "set", "Set system variable", scliText_Set}, + {scliConf_GetCmd, "get", "Get system variable", scliText_Get}, + {scliConf_ConfCmd, "conf", "Configuration overview", scliText_Conf}, +#endif + SCLI_CMD_LIST_END +}; + +/* + * Print prompt + */ +static inline void _scliCore_PrintPrompt(void) +{ + printf("\r\n%s%s%s",scliText_ColDefBold, scliText_Prompt, scliText_ColDef); +} + +/* + * Print welcome message + */ +static inline void _scliCore_PrintWelcome(void) +{ + printf("\r\n%s",scliText_WelcomeMsg); +} + +/* + * Return next free input buffer + */ +static SCLI_BUF_IDX _scliCore_GetNextCmdBuffer(SCLI_BUF_IDX CurIdx) +{ + SCLI_BUF_IDX i = 0; + SCLI_BUF_IDX LookupIdx = 0; + for(i = 1; i < (SCLI_CMD_HIST - 1); i++) + { + LookupIdx = (i + CurIdx) % (SCLI_CMD_HIST - 1); + if(_scliCore_InputBuffer[LookupIdx].HistRefs == 0) + return LookupIdx; + } + return LookupIdx; +} + +/* + * help command + * print helptext of a command + */ +static SCLI_CMD_RET _scliCore_HelpCmd(uint8_t argc, char **argv) +{ + SCLI_CMD_T * Cmd; + /* + * No additional parameter + * -> print short help text for all + * available commands + */ + if(argc == 1) + { + SCLI_CMD_T * Table = _scliCore_Interface->UserLevelCommands; + + if(Table != _scliCore_BasicCommands) + { + printf("\r\n User defined commands:\r\n"); + scliCore_PrintHelp(Table,0); + } + Table = _scliCore_BasicCommands; + printf("\r\n Internal commands:\r\n"); + + scliCore_PrintHelp(Table,0); + + return 0; + } + /* + * print command usage, if more than + * one parameter was passed + */ + else if(argc != 2) + { + printf("\r\n%s",scliText_Help); + return -1; + } + /* + * Get length of passed parameter + */ + uint32_t Length = strlen(argv[1]); + + /* + * Perform lookup in user level command table + * -> print long help text + */ + if((Cmd = scliCore_GetCommandInTable(argv[1], _scliCore_Interface->UserLevelCommands,Length))) + { + scliCore_PrintHelp(Cmd,1); + + return 0; + } + + /* + * Nothing found, perform + * lookup with internal command table + * -> print long help text + */ + if((Cmd = scliCore_GetCommandInTable(argv[1], _scliCore_BasicCommands,Length))) + { + printf("\r\n%s\r\n",Cmd->HelpLong); + return 0; + } + + /* + * No command found + */ + printf("\r\n Can't find cmd \"%s\" in command list\r\n", argv[1]); + + return -1; +} + +/* + * version command + * print current version + */ +static SCLI_CMD_RET _scliCore_VersionCmd(uint8_t argc __attribute__((unused)), char **argv __attribute__((unused))) +{ + printf("\r\n%s\r\n",scliText_Version); + return 0; +} + +/* + * history command + * print command history + */ +static SCLI_CMD_RET _scliCore_HistoryCmd(uint8_t argc __attribute__((unused)), char **argv __attribute__((unused))) +{ + SCLI_BUF_IDX i = 0; + SCLI_BUF_IDX LookupIdx = 0; + + printf("\r\n Command history" + "\r\n Current commands in history: %4d" + "\r\n Maximum history buffer: %4d" + "\r\n" + "\r\n Id Buffer Command\r\n", _scliCore_CmdHistWrapArround, SCLI_CMD_HIST); + + for(i = 1; i < _scliCore_CmdHistWrapArround; i++) + { + LookupIdx = (_scliCore_CmdHistHead > i) ? _scliCore_CmdHistHead - i : + SCLI_CMD_HIST + _scliCore_CmdHistHead - i; + + printf(" %4d %4d %s\r\n",i ,_scliCore_CmdHist[LookupIdx], _scliCore_InputBuffer[_scliCore_CmdHist[LookupIdx]].Line); + } + + printf("\r\n"); + return 0; +} + +/* + * Tabcompletion + */ +static void _scliCore_TabCompletion(SCLI_CMD_INPUT_T *InputBuffer) +{ + SCLI_CMD_T * Table = _scliCore_Interface->UserLevelCommands; + SCLI_CMD_T * LastCmd; + uint32_t CommandsFound = 0; + /* + * Search inside the user defined command table + */ + while(Table->CmdCallback != (SCLI_CMD_CB)0) + { + if(strncmp(InputBuffer->Line,(char *)Table->CmdName,InputBuffer->LineIdx) == 0) + { + /* + * Match found, print newline (for the first command) + * print possible command + */ + if(!CommandsFound) + printf("\r\n"); + + printf("%s ",Table->CmdName); + LastCmd = Table; + CommandsFound++; + } + Table++; + } + /* + * Do the same for the internal command table + */ + if(Table != _scliCore_BasicCommands) + { + Table = _scliCore_BasicCommands; + while(Table->CmdCallback != (SCLI_CMD_CB)0) + { + if(strncmp(InputBuffer->Line,(char *)Table->CmdName,InputBuffer->LineIdx) == 0) + { + /* + * Match found, print newline (for the first command) + * print possible command + */ + if(!CommandsFound) + printf("\r\n"); + + printf("%s ",Table->CmdName); + LastCmd = Table; + CommandsFound++; + } + Table++; + } + } + /* + * Print current prompt in a new line + */ + if(CommandsFound) + { + if(CommandsFound == 1) + { + /* + * Complete command automatically + * if only one command was found + */ + InputBuffer->LineIdx = sprintf(InputBuffer->Line,"%s",LastCmd->CmdName); + } + _scliCore_PrintPrompt(); + printf("%s",InputBuffer->Line); + } +} + +static SCLI_CMD_T * _scliCore_CommandLookup(SCLI_CMD_INPUT_T *InputBuffer) +{ + SCLI_LINE_IDX i = 0; + SCLI_CMD_T * Cmd; + /* + * Get name of cmd + */ + for(i = 0; i < InputBuffer->LineIdx; i++) + { + if(InputBuffer->Line[i] == ' ') + break; + } + + /* + * Lookup in user defined commands + */ + if((Cmd = scliCore_GetCommandInTable(InputBuffer->Line, _scliCore_Interface->UserLevelCommands,i))) + return Cmd; + + /* + * Lookup in user defined commands + */ + if((Cmd = scliCore_GetCommandInTable(InputBuffer->Line, _scliCore_BasicCommands,i))) + return Cmd; + + return (SCLI_CMD_T *)0; +} + +/* + * Add a char to the getch buffer, + * overwrite oldest entry if the buffer is full + */ +static void _scliCore_PushGetCh(char ch) +{ + uint32_t psr = _scliCore_Interface->CriticalEnter(); + + if(_scliCore_GetCharBuffer.Size < SCLI_GETCH_BUF_SIZE) + { + _scliCore_GetCharBuffer.Size++; + } + else + { + _scliCore_GetCharBuffer.Read = (_scliCore_GetCharBuffer.Read + 1) % SCLI_GETCH_BUF_SIZE; + } + _scliCore_GetCharBuffer.Buffer[_scliCore_GetCharBuffer.Write] = ch; + _scliCore_GetCharBuffer.Write = (_scliCore_GetCharBuffer.Write + 1) % SCLI_GETCH_BUF_SIZE; + + _scliCore_Interface->CriticalExit(psr); +} + +/* + * Pop char from getch buffer, + * return SCLI_FIFO_EMPTY (EOF) if the FIFO is empty + */ +static int _scliCore_PopGetCh(void) +{ + char ch = 0; + + if(_scliCore_GetCharBuffer.Size == 0) + return SCLI_FIFO_EMPTY; + + uint32_t psr = _scliCore_Interface->CriticalEnter(); + ch = _scliCore_GetCharBuffer.Buffer[_scliCore_GetCharBuffer.Read]; + _scliCore_GetCharBuffer.Read = (_scliCore_GetCharBuffer.Read + 1) % SCLI_GETCH_BUF_SIZE; + _scliCore_GetCharBuffer.Size--; + _scliCore_Interface->CriticalExit(psr); + + return (int)ch; +} + +/* + * Flush getch buffer + */ +static void _scliCore_FlushGetCh(void) +{ + _scliCore_GetCharBuffer.Size = 0; + _scliCore_GetCharBuffer.Read = _scliCore_GetCharBuffer.Write; +} + +/* + * Input FSM for character parsing + */ +static void _scliCore_Input(uint8_t ch) +{ + /* + * Do character check inside a critical + * region, with deactivated IRQs + */ + uint32_t psr = _scliCore_Interface->CriticalEnter(); + SCLI_CMD_INPUT_T *CurInputBuffer = &_scliCore_InputBuffer[_scliCore_CurBufferIdx]; + switch(CurInputBuffer->State) + { + /* + * Default character parsing + */ + case SCLI_BUF_READY: + switch(ch) + { + case 0x03: + /* + * STRG-C + */ + scliCore_ReleaseBuffer(CurInputBuffer); + _scliCore_PrintPrompt(); + break; + case '\e': + /* + * ESC -> start esc seq. parsing for the next ch + */ + CurInputBuffer->State = SCLI_BUF_ESC_CLI; + break; + case '\n': + /* + * Skip + */ + break; + case '\t': + /* + * Call tabcompletion + */ + _scliCore_TabCompletion(CurInputBuffer); + break; + case '\b': + /* + * Backspace + */ + if(CurInputBuffer->LineIdx) + { + CurInputBuffer->LineIdx--; + CurInputBuffer->Line[CurInputBuffer->LineIdx] = '\0'; + printf("\r%s%s%s%s \b",scliText_ColDefBold, scliText_Prompt, scliText_ColDef, CurInputBuffer->Line); + } + break; + case '\r': + /* + * Received ENTER, + * -> call user level + * -> set buffer state to SCLI_BUF_PARSING + */ + CurInputBuffer->State = SCLI_BUF_PARSING; + _scliCore_Interface->UserLevelHandOver(CurInputBuffer); + _scliCore_CmdHistWrapArround = (_scliCore_CmdHistWrapArround < SCLI_CMD_HIST) ? + _scliCore_CmdHistWrapArround + 1 : SCLI_CMD_HIST; + break; + default: + /* + * Add any other ch to the input buffer + */ + CurInputBuffer->Line[CurInputBuffer->LineIdx] = ch; + CurInputBuffer->LineIdx++; + _scliCore_Interface->PutCh(ch); + break; + } + break; + /* + * Wait for '[' + */ + case SCLI_BUF_ESC_CLI: + if(ch != '[') + { + CurInputBuffer->State = SCLI_BUF_READY; + } + else + { + CurInputBuffer->State = SCLI_BUF_ESC_CMD; + } + break; + /* + * Parse ESC sequence character + */ + case SCLI_BUF_ESC_CMD: + { + switch(ch) + { + /* + * Arrow up + */ + case 'A': + _scliCore_CmdHistCurIdx = (_scliCore_CmdHistCurIdx > 0) ? + _scliCore_CmdHistCurIdx - 1 : _scliCore_CmdHistWrapArround - 1; + break; + /* + * Arrow down + */ + case 'B': + _scliCore_CmdHistCurIdx = (_scliCore_CmdHistCurIdx < (_scliCore_CmdHistWrapArround - 1)) ? + _scliCore_CmdHistCurIdx + 1 : 0; + break; + default: + return; + } + /* + * Use buffer from history as new input buffer + */ + _scliCore_CurBufferIdx = _scliCore_CmdHist[_scliCore_CmdHistCurIdx]; + _scliCore_CmdHist[_scliCore_CmdHistHead] = _scliCore_CurBufferIdx; + CurInputBuffer->State = SCLI_BUF_READY; + CurInputBuffer = &_scliCore_InputBuffer[_scliCore_CurBufferIdx]; + CurInputBuffer->State = SCLI_BUF_READY; + CurInputBuffer->Line[CurInputBuffer->LineIdx] = '\0'; + printf("\r%s%s%s%s%s",scliText_ColDefBold, scliText_Prompt, scliText_ColDef, CurInputBuffer->Line,scliText_DeleteRight); + break; + } + case SCLI_BUF_EXEC: + /* + * During command execution, + * pass ch to getch buffer + */ + _scliCore_PushGetCh(ch); + break; + case SCLI_BUF_PARSING: + /* + * Skip ch during command parsing + */ + default: + break; + } + _scliCore_Interface->CriticalExit(psr); +} + +void scliCore_ReleaseBuffer(SCLI_CMD_INPUT_T *InputBuffer) +{ + /* + * Add last buffer to command history, + * increment history reference counter + * and history head/idx + */ + _scliCore_CmdHist[_scliCore_CmdHistHead] = _scliCore_CurBufferIdx; + InputBuffer->HistRefs++; + _scliCore_CmdHistHead = (_scliCore_CmdHistHead + 1) % SCLI_CMD_HIST; + _scliCore_CmdHistCurIdx = _scliCore_CmdHistHead; + + /* + * Set current buffer to the next input buffer + * inside our history + */ + _scliCore_CurBufferIdx = _scliCore_CmdHist[_scliCore_CmdHistHead]; + InputBuffer = &_scliCore_InputBuffer[_scliCore_CurBufferIdx]; + + /* + * Decrement history reference counter and check if zero + * if HistRefs != 0 we can't use this buffer, as another + * reference to this buffer exists inside our history + * ->call _scliCore_GetNextCmdBuffer + */ + InputBuffer->HistRefs = (InputBuffer->HistRefs) ? InputBuffer->HistRefs - 1 : 0; + if(InputBuffer->HistRefs) + { + _scliCore_CurBufferIdx = _scliCore_GetNextCmdBuffer(_scliCore_CurBufferIdx); + InputBuffer = &_scliCore_InputBuffer[_scliCore_CurBufferIdx]; + } + + /* + * Reset our new buffer to the default state + */ + InputBuffer->State = SCLI_BUF_READY; + InputBuffer->LineIdx = 0; +} + +/* + * Parse input buffer and execute command + */ +void scliCore_ExecuteCommand(SCLI_CMD_INPUT_T *InputBuffer) +{ + SCLI_LINE_IDX i = 0; + SCLI_CMD_RET ret = 0; + uint8_t argc = 0; + char *argv[SCLI_CMD_MAX_ARGS]; + /* + * Init argc & argv with + * command entry + */ + argv[0] = &(InputBuffer->Line[0]); + argc = 1; + + /* + * Empty command, return new prompt + */ + if(InputBuffer->LineIdx == 0) + { + _scliCore_PrintWelcome(); + _scliCore_PrintPrompt(); + InputBuffer->State = SCLI_BUF_READY; + return; + } + + /* + * Command lookup inside all command + * tables + */ + SCLI_CMD_T* Cmd = _scliCore_CommandLookup(InputBuffer); + + /* + * Command not found + */ + if(Cmd == (SCLI_CMD_T*)0) + { + printf("\r\n %sCommand not found%s\r\n",scliText_ColRedBold,scliText_ColDef); + _scliCore_PrintPrompt(); + scliCore_ReleaseBuffer(InputBuffer); + return; + } + + + /* + * Insert \0 for each ' ' + * for str zero termination in argv + */ + for(i=0; i < InputBuffer->LineIdx; i++) + { + if(InputBuffer->Line[i] == ' ') + { + InputBuffer->Line[i] = '\0'; + if((i+1) < InputBuffer->LineIdx && + InputBuffer->Line[i+1] >= 33 && + InputBuffer->Line[i+1] <= 126) + { + argv[argc] = &(InputBuffer->Line[i+1]); + argc++; + } + } + } + InputBuffer->Line[i] = '\0'; + + /* + * Call function + */ + InputBuffer->State = SCLI_BUF_EXEC; + ret=Cmd->CmdCallback(argc,argv); + + /* + * Revert buffer for + * call history + */ + for(i=0; i < InputBuffer->LineIdx; i++) + { + if(InputBuffer->Line[i] == '\0') + { + InputBuffer->Line[i] = ' '; + } + } + + /* + * Flush get char buffer + */ + _scliCore_FlushGetCh(); + + /* + * Report error + */ + if(ret < 0) + { + printf("\r\n %s%s returned %d%s\r\n",scliText_ColRedBold, Cmd->CmdName, (int) ret, scliText_ColDef); + } + + /* + * Release input buffer + */ + scliCore_ReleaseBuffer(InputBuffer); + + /* + * Print new prompt + */ + _scliCore_PrintPrompt(); + + return; +} + +/* + * Print help message + * either the long version of a single + * or the short version of multiple entries + */ +void scliCore_PrintHelp(SCLI_CMD_T * Table, uint8_t SingleEntry) +{ + if(SingleEntry) + { + if(Table->HelpLong) + printf("\r\n%s\r\n",Table->HelpLong); + + return; + } + else + { + while(Table->CmdCallback != (SCLI_CMD_CB)0) + { + size_t StrLen = strlen((char *)Table->CmdName); + size_t i = 0; + + for(i = StrLen; i < SCLI_CMD_NAME_MAX_LEN; i++) + _scliCore_Interface->PutCh(' '); + + printf(" %s:", Table->CmdName); + + + printf(" %s\r\n", Table->HelpShort); + Table++; + } + } +} + +/* + * Perform command lookup, + * return pointer to command if successful + */ +SCLI_CMD_T * scliCore_GetCommandInTable(char * Cmd, SCLI_CMD_T * Table, SCLI_LINE_IDX CmdLen) +{ + size_t CmdNameLen = 0; + while(Table->CmdCallback != (SCLI_CMD_CB)0) + { + CmdNameLen = strlen((char *)Table->CmdName); + if(CmdNameLen == CmdLen && strncmp(Cmd,(char *)Table->CmdName,CmdNameLen) == 0) + return Table; + Table++; + } + + return (SCLI_CMD_T *)0; +} + +/* + * Return a char from the input buffer + * during command execution + */ +int scliCore_getchar(void) +{ + return _scliCore_PopGetCh(); +} + +/* + * Init command line subsystem + */ +uint8_t scliCore_Init( SCLI_INTERFACE_T* Interface) +{ + + if( Interface->CriticalEnter == 0 || Interface->CriticalExit == 0 || + Interface->PutCh == 0 || Interface->SubsystemInit == 0 || + Interface->UserLevelHandOver == 0) + return 0; + + /* + * Set internal interface + * pointer + */ + _scliCore_Interface = Interface; + + /* + * Check for external + * cmd table + */ + if(_scliCore_Interface->UserLevelCommands == 0) + _scliCore_Interface->UserLevelCommands = _scliCore_BasicCommands; + + /* + * Call init function for + * hardware and printf init + */ + _scliCore_Interface->SubsystemInit(_scliCore_Input); + + /* + * Init internal input & get char buffer + */ + memset(_scliCore_InputBuffer,0,sizeof(_scliCore_InputBuffer)); + memset(&_scliCore_GetCharBuffer,0,sizeof(_scliCore_GetCharBuffer)); + _scliCore_FlushGetCh(); + + /* + * Print welcome message & prompt + */ + _scliCore_PrintWelcome(); + _scliCore_PrintPrompt(); + + /* + * Release buffers + */ + SCLI_BUF_IDX i = 0; + uint32_t psr = _scliCore_Interface->CriticalEnter(); + + for(i = 0; i < SCLI_CMD_HIST; i++) + { + _scliCore_InputBuffer[i].State = SCLI_BUF_READY; + _scliCore_InputBuffer[i].LineIdx = 0; + _scliCore_InputBuffer[i].HistRefs = 0; + _scliCore_CmdHist[i] = i; + } + _scliCore_CmdHistHead = 0; + _scliCore_CmdHistCurIdx = _scliCore_CmdHistHead; + + _scliCore_Interface->CriticalExit(psr); + + return 1; +} diff --git a/src/SimpleCLI/src/scliStdC.c b/src/SimpleCLI/src/scliStdC.c new file mode 100644 index 0000000..b7822ff --- /dev/null +++ b/src/SimpleCLI/src/scliStdC.c @@ -0,0 +1,181 @@ +/* + * scliStdC.c + * + * Created on: 31.01.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +#include "SimpleCLI/inc/scliStdC.h" + +#if SCLI_USE_OWN_STDC_FUNC > 0 + +uint32_t scliStdC_strlen(char *str) +{ + uint32_t i = 0; + + while(str[i]) + i++; + + return i; +} + +int scliStdC_strncmp(char * str1,char *str2,size_t Len) +{ + size_t i = 0; + + for(i=0; i < Len; i++) + { + if(str1[i] != str2[i]) + return -1; + } + + return 0; +} +void scliStdC_memset(void* buf, int8_t Val,size_t Len) +{ + int8_t *target = (int8_t *)buf; + size_t i = 0; + + for(i=0; i < Len; i++) + target[i] = Val; + +} + +char *scliStdC_strncpy(char * dst, const char * src, size_t n) +{ + size_t i = 0; + for(i = 0; i < n; i++) + { + dst[i] = src[i]; + if(dst[i] == '\0') + break; + } + return(dst); +} + +uint32_t scliStdC_strtoul(char *str, char **endPtr, int base) +{ + uint32_t res = 0; + + if( base != 2 && + base != 8 && + base != 10 && + base != 16) + return 0; + + /* + * Skip any leading blanks. + */ + while(*str == ' ') + str++; + + /* + * Skip + + */ + if(*str == '+') + str++; + + while(*str) + { + uint32_t value = 0; + switch(*str) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + value = *str - '0'; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + value = *str - 'A' + 10; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + value = *str - 'a' + 10; + break; + default: + value = 255; + break; + } + + if(value > (base-1)) + break; + + res = value + res*base; + str++; + } + + if(endPtr) + *endPtr = str; + + return res; + +} + +int32_t scliStdC_strtol(char *str, char **endPtr, int base) +{ + int32_t sign = 1; + int32_t result = 0; + char * start = str; + + /* + * Skip any leading blanks. + */ + while(*str == ' ') + str++; + + /* + * Check for a sign. + */ + switch(*str) + { + case '-': + sign = -1; + str++; + break; + case '+': + sign = 1; + str++; + break; + default: + break; + } + + result = sign*scliStdC_strtoul(str, endPtr, base); + + if ((result == 0) && (endPtr != 0) && (*endPtr == str)) { + *endPtr = start; + } + return result; +} + +#endif diff --git a/src/SimpleCLI/src/scliText.c b/src/SimpleCLI/src/scliText.c new file mode 100644 index 0000000..c605270 --- /dev/null +++ b/src/SimpleCLI/src/scliText.c @@ -0,0 +1,62 @@ +/* + * scliText.c + * + * Created on: 31.01.2016 + * Author: Matthias Beckert + * + * 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 . + * + */ + +const char scliText_ColRedBold[] = "\x1b[01;31m"; +const char scliText_ColGreBold[] = "\x1b[01;32m"; +const char scliText_ColYelBold[] = "\x1b[01;33m"; +const char scliText_ColBluBold[] = "\x1b[01;34m"; +const char scliText_ColMagBold[] = "\x1b[01;35m"; +const char scliText_ColCyaBold[] = "\x1b[01;36m"; +const char scliText_ColDef[] = "\x1b[0m"; +const char scliText_ColDefBold[] = "\x1b[01;30m"; +const char scliText_DeleteRight[]= "\x1b[K"; + +const char scliText_Error[] = + ""; + +const char scliText_WelcomeMsg[] = + " T-962 Reflow Oven"; + +const char scliText_Prompt[] = + "t-962> "; + +const char scliText_Help[] = + " This is the help function\r\n help "; + +const char scliText_Version[] = + " T-962-controller\r\n" + " https://github.com/UnifiedEngineering/T-962-improvement\r\n" + " including SimpleCLI V0.1\r\n" + " Author Mattias Beckert\r\n" + " "; + +const char scliText_Set[] = + " Set a system variable to a given value\r\n set "; + +const char scliText_Get[] = + " Get value of a system variable\r\n get "; + +const char scliText_Conf[] = + " Manage configuration subsystem\r\n"; + +const char scliText_ConfNoTable[] = + " No config table found, system might be uninitialized\r\n" + " scliConf_RegisterConfig(...) must be called before at least once!\r\n"; diff --git a/src/adc.c b/src/adc.c index 02f710a..5eb342f 100644 --- a/src/adc.c +++ b/src/adc.c @@ -19,45 +19,59 @@ #include "LPC214x.h" #include -#include +#include "log.h" #include "adc.h" #include "t962.h" #include "sched.h" +#include "config.h" -#define NUM_ADCH (2) -#define OVERSAMPLING_BITS (4) // This is n (how many additional bits to supply) -#define NUM_ACCUM (256) // This needs to be 4 ^ n -#define ACCUM_MASK (NUM_ACCUM-1) +// indices for channel 1 and 2 respectively +static uint8_t i=0; +static uint8_t j=0; +// hold intermediate sums of 16 ADC samples (with 10 bits -> 14bits needed) +static uint16_t sum1 = 0; +static uint16_t sum2 = 0; +// average values +static uint32_t avg1 = 0; +static uint32_t avg2 = 0; -static uint32_t ADres[NUM_ADCH]; -static uint16_t ADidx[NUM_ADCH]; -static uint16_t ADaccum[NUM_ADCH][NUM_ACCUM]; +// running average over 16 values (each a sum of 16 ADC samples) +#define N 16 -static void ADC_Accum(uint32_t chnum, uint32_t value) { - uint16_t temp; - chnum--; - uint8_t idx = ADidx[chnum]; - - // Done - if (value & (1 << 31)) { - temp = (value >> 6) & 0x3ff; - ADres[chnum] -= ADaccum[chnum][idx]; - ADaccum[chnum][idx] = temp; - ADres[chnum] += temp; - idx++; - idx &= ACCUM_MASK; - ADidx[chnum] = idx; +// create a running average over 16 values of sums of 16 samples +// duplicate code, it's not worth the effort of indirection +static void average(uint32_t adc1, uint32_t adc2) +{ + // for ADC1 + if (adc1 & (1 << 31)) { + adc1 = (adc1 >> 6) & 0x3ff; + sum1 += adc1; + if (i == 15) { + avg1 = ((N - 1) * avg1 + sum1) / N; + i = sum1 = 0; + } else + i++; + } + // for ADC2 + if (adc2 & (1 << 31)) { + adc2 = (adc2 >> 6) & 0x3ff; + sum2 += adc2; + if (j == 15) { + avg2 = ((N - 1) * avg2 + sum2) / N; + j = sum2 = 0; + } else + j++; } } static int32_t ADC_Work(void) { - ADC_Accum( 1, AD0DR1); - ADC_Accum( 2, AD0DR2); - return TICKS_US( 100 ); // Run 10000 times per second + average(AD0DR1, AD0DR2); + // Run once per ms, at 256 fold oversampling leads to 1 value every 0.256s + return TICKS_US(1000); } void ADC_Init( void ) { - printf("\n%s called", __FUNCTION__); + log(LOG_DEBUG, "%s called", __FUNCTION__); Sched_SetWorkfunc(ADC_WORK, ADC_Work); // 1MHz adc clock, enabling ch1 and 2 @@ -65,19 +79,37 @@ void ADC_Init( void ) { AD0CR |= (1 << 16); // Burst AD0DR1; AD0DR2; - for (int i = 0; i < NUM_ADCH; i++) { - ADres[i] = ADidx[i] = 0; - for (int j = 0; j < NUM_ACCUM; j++) { - ADaccum[i][j] = 0; - } - } Sched_SetState( ADC_WORK, 2, 0); // Start right away } + + +/* + * This is supposed to deliver values in 1/16 degree Celsius, + * which is about 1 LSB for a pre-amplifier gain of about 80. + * 80 x 41.276uV/K = 3.3021mV/K --> 0.9772 LSB/K (for Vref=3.3V) + * The board has a 3.3V, 1% regulator, so nothing better than 3 degC is + * to be hoped for! Returning a resolution of 1/16 deg C is pretty + * useless. + * Using a precision OPamp is strongly recommended (using a gain + * of 222.2 --> 9.172mV/K -> 2.7141 LSB/K (for Vref=3.3V). + */ int32_t ADC_Read(uint32_t chnum) { - int32_t result=-1; - if (chnum >= 1 && chnum <= 2) { - result = ADres[chnum - 1] >> OVERSAMPLING_BITS; - } - return result; +#ifndef USE_PRECISION_OPAMP + if (chnum == 1) + return avg1; + if (chnum == 2) + return avg2; +#else + // take care not to overflow an unsigned 32 bit value! + // input is in 1/16th LSBs (up to 16*1024-1, or 14 bit) + // factor is 0.36845 = 7369/20000 +#define TC_ADJUST(x) ((int32_t) ((x * 7369) / 20000)) + + if (chnum == 1) + return TC_ADJUST(avg1); + if (chnum == 2) + return TC_ADJUST(avg2); +#endif + return -1; } diff --git a/src/buzzer.c b/src/buzzer.c index 1f81e43..9218c31 100644 --- a/src/buzzer.c +++ b/src/buzzer.c @@ -19,7 +19,7 @@ #include "LPC214x.h" #include "buzzer.h" -#include +#include "log.h" #include "sched.h" static BuzzFreq_t requested_buzz_freq; @@ -44,7 +44,7 @@ static int32_t Buzzer_Work(void) { } void Buzzer_Init(void) { - printf("\n%s ", __FUNCTION__); + log(LOG_DEBUG, "%s called", __FUNCTION__); Sched_SetWorkfunc(BUZZER_WORK, Buzzer_Work); } diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..52187a3 --- /dev/null +++ b/src/config.h @@ -0,0 +1,104 @@ +/* + * config.h - configuration for several builds of the T-962 reflow controller + * + * Copyright (C) 2017 Helmut Raiger helmut.raiger@gmx.net + * + * 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 . + */ + +/* + * this is a patch that drives a mica heating element placed + * underneath the PCB to be soldered. To use it an additional + * PWM channel is required, currently the only one left is used + * by the cold junction compensation patch, but this can be + * moved to P0.5 (pin 29), which is moved by this define! + */ +#define USE_SECONDARY_HEATER + +/* + * if the 74hc04 is replaced by 2 FETs to make sure the Opto-TRIAC + * receives the correct amount of drive current, the drive logic is + * inverted, i.e. high means TRIAC on. This changes the logic in io.c + */ +#define USE_FET_DRIVER + +/* + * use this to adjust gain and omit offset compensation settings + * in sensor.c and setup.c + * This needs a precision operational amplifier (like an OPA2333) + * at a rather precise gain of 222.2 on the TC input! + * The feedback resistors are 220k + 1.2k and 1.0k with 0.1% tolerance + */ +#define USE_PRECISION_OPAMP + +/* + * The software deals with up-to 4 temperatures, configure their + * association with the names 'left', 'right', 'extra1' and 'extra2'. + * They need to be one of TC_ONE_WIRE, TC_SPI_BRIDGE, TC_INTERNAL or TC_NONE + * and a channel after the comma (may be left away, defaults to 0) + * + * Note: the original software falls back to internal when no other + * interface works, this mechanism is gone now. The configuration MUST + * work. On the other hand if the internal TC were not connected, this + * led to an error even in the original version. + */ +#define TC_LEFT_IF TC_INTERNAL, 0 +#define TC_RIGHT_IF TC_INTERNAL, 1 +#define TC_EXTRA1_IF TC_NONE +#define TC_EXTRA2_IF TC_NONE +// the CJ compensation sensor, internal means the DS18B20 (or alike), no channel! +#define COLD_JUNCTION_IF TC_INTERNAL + +/* + * Define the control strategy: + * LR_AVERAGE ... left and right TC average is used (even if undefined) + * + * MAX_TEMP_OVERRIDE: + * By defining this any TC that has a readout 5C (or more) higher + * than the TC0 and TC1 average will be used as control input instead. + * Use if you have very sensitive components. Note that this will also + * kick in if the two sides of the oven has different readouts, as the + * code treats all four TCs the same way. + * + * LR_WEIGHTED_AVERAGE: + * This includes code to allow the user to specify a measure for the + * thermal capacity of the PCB to be soldered. This weight is + * used to create a weighted average of the left and right thermocouple. + * This is ONLY useful if the TCs are patched to carry such loads, i.e. + * a 5c Euro coin on the right thermo-couple and 0.2mm copper foil on the left. + */ +#define CONTROL_TEMPERATURE LR_WEIGHTED_AVERAGE + +/* + * Fully dump the content of the eeprom at startup, mainly for debugging + */ +// define DUMP_EEPROM + +/* + * include a ramp test profile into the standard profiles (see reflow_profiles.c) + */ +#define RAMPTEST_PROFILE + +/* + * don't use the font width information in bit 7 of the font, simply always use + * a width of 6 pixels (see lcd.c) + */ +// #define MINIMALISTIC + + +/* + * serial baudrate: + * allowed values 2000842 (special), 115200, 57600, 38400, 19200, 9600, 4800 + */ +#define UART0_BAUDRATE 115200 diff --git a/src/cr_startup_lpc21.s b/src/cr_startup_lpc21.s index ec3ad73..66a435b 100644 --- a/src/cr_startup_lpc21.s +++ b/src/cr_startup_lpc21.s @@ -55,28 +55,28 @@ #ifndef USE_OLD_STYLE_DATA_BSS_INIT /***************************************************************************** -/ The following symbols are constructs generated by the linker, indicating -/ the location of various points in the "Global Section Table". This table is -/ created by the linker via the Code Red managed linker script mechanism. It -/ contains the load address, execution address and length of each RW data -/ section and the execution and length of each BSS (zero initialized) section. -/*****************************************************************************/ + The following symbols are constructs generated by the linker, indicating + the location of various points in the "Global Section Table". This table is + created by the linker via the Code Red managed linker script mechanism. It + contains the load address, execution address and length of each RW data + section and the execution and length of each BSS (zero initialized) section. + *****************************************************************************/ .global __data_section_table .global __data_section_table_end .global __bss_section_table .global __bss_section_table_end #else /***************************************************************************** -/ The following symbols are constructs generated by the linker, indicating -/ the load address, execution address and length of the RW data section and -/ the execution and length of the BSS (zero initialized) section. -/ Note that these symbols are not normally used by the managed linker script -/ mechanism in Red Suite/LPCXpresso 3.6 (Windows) and LPCXpresso 3.8 (Linux). -/ They are provide here simply so this startup code can be used with earlier -/ versions of Red Suite which do not support the more advanced managed linker -/ script mechanism introduced in the above version. To enable their use, -/ define "USE_OLD_STYLE_DATA_BSS_INIT". -/*****************************************************************************/ + The following symbols are constructs generated by the linker, indicating + the load address, execution address and length of the RW data section and + the execution and length of the BSS (zero initialized) section. + Note that these symbols are not normally used by the managed linker script + mechanism in Red Suite/LPCXpresso 3.6 (Windows) and LPCXpresso 3.8 (Linux). + They are provide here simply so this startup code can be used with earlier + versions of Red Suite which do not support the more advanced managed linker + script mechanism introduced in the above version. To enable their use, + define "USE_OLD_STYLE_DATA_BSS_INIT". + *****************************************************************************/ .global _etext .global _data .global _edata diff --git a/src/eeprom.c b/src/eeprom.c index 29f0a0d..6bc55c6 100644 --- a/src/eeprom.c +++ b/src/eeprom.c @@ -24,9 +24,10 @@ #include "t962.h" #include "eeprom.h" #include "i2c.h" +#include "log.h" +#include "config.h" #define EEADDR (0x50<<1) -//#define DUMP_EEPROM void EEPROM_Init(void) { #ifdef DUMP_EEPROM @@ -39,7 +40,7 @@ void EEPROM_Dump(void) { uint8_t dumpbuf[256]; EEPROM_Read(dumpbuf, 0, sizeof(dumpbuf)); printf("\nEEPROM contents:"); - for (int i = 0; i < sizeof(dumpbuf); i++) { + for (unsigned i = 0; i < sizeof(dumpbuf); i++) { if ((i & 0x0f) == 0){ printf("\n0x%04x:", i); } @@ -61,6 +62,8 @@ int32_t EEPROM_Read(uint8_t* dest, uint32_t startpos, uint32_t len) { int32_t EEPROM_Write(uint32_t startdestpos, uint8_t* src, uint32_t len) { int32_t retval = 0; + + log(LOG_DEBUG, "EEPROM_Write %lu bytes to %lu", len, startdestpos); if (startdestpos < 256 && len && len <= 256) { uint8_t tmpbuf[9]; uint8_t i = startdestpos; diff --git a/src/images/cool-89x64.bmp b/src/images/cool-89x64.bmp new file mode 100644 index 0000000..4a71d0a Binary files /dev/null and b/src/images/cool-89x64.bmp differ diff --git a/src/import.s b/src/import.s index e10b683..13dba35 100644 --- a/src/import.s +++ b/src/import.s @@ -20,6 +20,13 @@ stopbmp: stopbmpsize: .word .-stopbmp + .global coolbmp + .global coolbmpsize +coolbmp: + .incbin "../src/images/cool-89x64.bmp" +coolbmpsize: + .word .-coolbmp + .global selectbmp .global selectbmpsize selectbmp: diff --git a/src/io.c b/src/io.c index 9724b04..6fb4e8a 100644 --- a/src/io.c +++ b/src/io.c @@ -24,26 +24,34 @@ #include "io.h" #include "sched.h" #include "vic.h" +#include "config.h" void Set_Heater(uint8_t enable) { - if (enable < 0xff) { - PINSEL0 |= (2<<18); // Make sure PWM6 function is enabled - } else { // Fully on is dealt with separately to avoid output glitch - PINSEL0 &= ~(2<<18); // Disable PWM6 function on pin - enable = 0xfe; // Not fully on according to PWM hardware but we force GPIO low anyway - } +#ifdef USE_FET_DRIVER + PWMMR6 = enable; +#else PWMMR6 = 0xff - enable; +#endif PWMLER |= (1<<6); } +#ifdef USE_SECONDARY_HEATER +// This is always ON with a high level, i.e. uses a kind of FET driver +void Set_Secondary_Heater(uint8_t enable) { + PWMMR2 = enable; + PWMLER |= (1<<2); +} +#else +// do nothing if not supported by the hardware +void Set_Secondary_Heater(uint8_t enable) {} +#endif + void Set_Fan(uint8_t enable) { - if (enable < 0xff) { - PINSEL0 |= (2<<16); // Make sure PWM4 function is enabled - } else { // Fully on is dealt with separately to avoid output glitch - PINSEL0 &= ~(2<<16); // Disable PWM4 function on pin - enable = 0xfe; // Not fully on according to PWM hardware but we force GPIO low anyway - } +#ifdef USE_FET_DRIVER + PWMMR4 = enable; +#else PWMMR4 = 0xff - enable; +#endif PWMLER |= (1<<4); } @@ -75,6 +83,7 @@ void IO_InitWatchdog(void) { WDFEED = 0x55; } +// this should be a shell command not logging! void IO_PrintResetReason(void) { uint8_t resetreason = RSIR; RSIR = 0x0f; // Clear it out @@ -116,7 +125,7 @@ int IO_Partinfo(char* buf, int n, char* format) { command[0] = IAP_READ_PART; iap_entry((void *)command, (void *)result); const char* partstrptr = NULL; - for (int i = 0; i < NUM_PARTS; i++) { + for (unsigned i = 0; i < NUM_PARTS; i++) { if (result[1] == partmap[i].id) { partstrptr = partmap[i].name; break; @@ -144,12 +153,25 @@ void IO_JumpBootloader(void) { // Bootloader must use legacy mode IO if you call this later too, so do: // SCS = 0; - // Turn off FAN & Heater using legacy registers so they stay off during bootloader - // Fan = PIN0.8 - // Heater = PIN0.9 - IODIR0 = (1 << 8) | (1 << 9); + // Turn off FAN & Heater(s) using legacy registers so they stay off during bootloader + // Fan = P0.8, Heater = P0.9, secondary heater = P0.7 (if enabled) + // and P0.14 (ISP) as suggested in AN10356 +#ifdef USE_SECONDARY_HEATER + IODIR0 = (1 << 7) | (1 << 8) | (1 << 9) | (1 << 14); +#ifdef USE_FET_DRIVER + IOCLR0 = (1 << 7) | (1 << 8) | (1 << 9) | (1 << 14); +#else IOSET0 = (1 << 8) | (1 << 9); - + IOCLR0 = (1 << 7) | (1 << 14); +#endif +#else // no secondary heater +#ifdef USE_FET_DRIVER + IOCLR0 = (1 << 8) | (1 << 9) | (1 << 14); +#else + IOSET0 = (1 << 8) | (1 << 9); + IOCLR0 = (1 << 14); +#endif +#endif //Re-enter ISP Mode, this function will never return command[0] = IAP_REINVOKE_ISP; iap_entry((void *)command, (void *)result); @@ -159,22 +181,56 @@ void IO_JumpBootloader(void) { void IO_Init(void) { SCS = 0b11; // Enable fast GPIO on both port 0 and 1 - PINSEL0 = 0b10100000000001010101; // PWM6 + PWM4 + I2C0 + UART0 + // don't care to select PMW pins here, they are enabled on the fly in Set_Heater() etc. + // the default GPIO is selected here! + + // 10987654321098765432109876543210 + PINSEL0 = 0b00000000000000000000000001010101; // I2C0 + UART0 PINSEL1 = 0b00000101000000000000000000000000; // ADC0 1+2 +#ifdef USE_SECONDARY_HEATER + // 10987654321098765432109876543210 + FIO0MASK = 0b01001101000000100000010001000000; // Mask out all unknown/unused pins + FIO0DIR = 0b10000010011011000011101110000001; // Default output pins (add P0.7) +#else + // 10987654321098765432109876543210 FIO0MASK = 0b01001101000000100000010001100000; // Mask out all unknown/unused pins - FIO1MASK = 0b11111111000000001111111111111111; // Only LCD D0-D7 + FIO0DIR = 0b10000010011011000011101100000001; // Default output pins +#endif - FIO0DIR = 0b10000010011011000011101100000001; // Default output pins - FIO1DIR = 0b00000000000000000000000000000000; - - FIO0PIN = 0x00; // Turn LED on and make PWM outputs active when in GPIO mode (to help 100% duty cycle issue) + FIO1MASK = 0b11111111000000001111111111111111; // Only LCD D0-D7 + FIO1DIR = 0b00000000000000000000000000000000; + + // PMW 6 is P0.9, PWM 4 is P0.8, PWM 2 is P0.7 set them active if GPIO selected to force 100% on +#ifdef USE_SECONDARY_HEATER +#ifdef USE_FET_DRIVER + FIO0PIN = (1 << 7) | (1 << 8) | (1 << 9); +#else + FIO0PIN = (1 << 7); +#endif +#else // no secondary heater +#ifdef USE_FET_DRIVER + FIO0PIN = (1 << 8) | (1 << 9); +#else + FIO0PIN = 0; +#endif +#endif PWMPR = PCLKFREQ / (256 * 5); // Let's have the PWM perform 5 cycles per second with 8 bits of precision (way overkill) PWMMCR = (1<<1); // Reset TC on mr0 overflow (period time) - PWMMR0 = 0xff; // Period time + PWMMR0 = 0xfe; // Period time to 254, so 255 will never be reached, i.e. pin is fully turned on PWMLER = (1<<0); // Enable latch on mr0 (Do I really need to do this?) - PWMPCR = (1<<12) | (1<<14); // Enable PWM4 and 6 + // Enable PWM4 and 6 and possibly PWM2 + PWMPCR = (1<<12) | (1<<14) +#ifdef USE_SECONDARY_HEATER + | (1 << 10) +#endif + ; + PINSEL0 |= (2<<18) | (2<<16) +#ifdef USE_SECONDARY_HEATER + | (1 << 14) +#endif + ; PWMTCR = (1<<3) | (1<<0); // Enable timer in PWM mode Sched_SetWorkfunc(SLEEP_WORK, Sleep_Work); diff --git a/src/io.h b/src/io.h index aa234b7..9923292 100644 --- a/src/io.h +++ b/src/io.h @@ -11,6 +11,7 @@ typedef struct { } partmapStruct; void Set_Heater(uint8_t enable); +void Set_Secondary_Heater(uint8_t enable); void Set_Fan(uint8_t enable); void IO_InitWatchdog(void); void IO_PrintResetReason(void); diff --git a/src/keypad.c b/src/keypad.c index 31d53cc..8d7742f 100644 --- a/src/keypad.c +++ b/src/keypad.c @@ -19,8 +19,8 @@ #include "LPC214x.h" #include -#include #include "t962.h" +#include "log.h" #include "keypad.h" #include "io.h" #include "sched.h" @@ -80,18 +80,43 @@ static int32_t Keypad_Work(void) { return TICKS_MS(100); } -uint32_t Keypad_Get(void) { - uint32_t retval = latchedkeypadstate; +/* + * get pressed key info: mask, acceleration and priorized key + */ +fkey_t Keypad_Get(uint16_t lowlimit, uint16_t highlimit) { + fkey_t retval; + + retval.acceleration = latchedkeypadstate >> 16; + if (retval.acceleration > highlimit) + retval.acceleration = highlimit; + if (retval.acceleration < lowlimit) + retval.acceleration = lowlimit; + + retval.keymask = latchedkeypadstate & 0xffff; + + // ternery ?: has pretty unpredictable precedence, so be more eplicit + retval.priorized_key = 0; + if (retval.keymask & KEY_S) + retval.priorized_key = KEY_S; + else if (retval.keymask & KEY_F1) + retval.priorized_key = KEY_F1; + else if (retval.keymask & KEY_F2) + retval.priorized_key = KEY_F2; + else if (retval.keymask & KEY_F3) + retval.priorized_key = KEY_F3; + else if (retval.keymask & KEY_F4) + retval.priorized_key = KEY_F4; + latchedkeypadstate = 0; return retval; } void Keypad_Init(void) { Sched_SetWorkfunc(KEYPAD_WORK, Keypad_Work); - printf("\nWaiting for keys to be released... "); + log(LOG_DEBUG, "Waiting for keys to be released ..."); // Note that if this takes longer than ~1 second the watchdog will bite - while (Keypad_GetRaw()); - printf("Done!"); + while (Keypad_GetRaw()) ; + log(LOG_DEBUG, "Done waiting for keys"); // Potential noise gets suppressed as well Sched_SetState(KEYPAD_WORK, 1, TICKS_MS(250)); // Wait 250ms before starting to scan the keypad diff --git a/src/keypad.h b/src/keypad.h index 30b1d04..fe94338 100644 --- a/src/keypad.h +++ b/src/keypad.h @@ -1,14 +1,22 @@ #ifndef KEYPAD_H_ #define KEYPAD_H_ -#define KEY_F1 (1<<0) -#define KEY_F2 (1<<1) -#define KEY_F3 (1<<2) -#define KEY_F4 (1<<3) -#define KEY_S (1<<4) -#define KEY_ANY (KEY_F1 | KEY_F2 | KEY_F3 | KEY_F4 | KEY_S) - -uint32_t Keypad_Get(void); +/* bit masks */ +typedef enum { + KEY_F1 = 1, + KEY_F2 = 2, + KEY_F3 = 4, + KEY_F4 = 8, + KEY_S = 16 +} key_mask_t; + +typedef struct { + key_mask_t priorized_key; + uint8_t keymask; + uint16_t acceleration; +} fkey_t; + +fkey_t Keypad_Get(uint16_t, uint16_t); void Keypad_Init(void); #endif /* KEYPAD_H_ */ diff --git a/src/lcd.c b/src/lcd.c index f828797..81e9cf1 100644 --- a/src/lcd.c +++ b/src/lcd.c @@ -20,10 +20,13 @@ #include "LPC214x.h" #include +#include #include #include +#include "log.h" #include "lcd.h" #include "smallfont.h" +#include "config.h" // Frame buffer storage (each "page" is 8 pixels high) static uint8_t FB[FB_HEIGHT / 8][FB_WIDTH]; @@ -47,7 +50,11 @@ typedef struct __attribute__ ((packed)) { uint32_t aColors[2]; // Palette data, first color is used if pixel bit is 0, second if pixel bit is 1 } BMhdr_t; -void charoutsmall(uint8_t theChar, uint8_t X, uint8_t Y) { +// font is 6 pixels, this results in 128 / 6 = 21 characters and 2 pixels unused +#define LCD_ALIGN_RIGHT(x) (FB_WIDTH - 2 - (x) * 6) // leave the 2 pixels unused +#define LCD_ALIGN_CENTER(x) (LCD_ALIGN_RIGHT(x) / 2) + +static void charoutsmall(uint8_t theChar, uint8_t X, uint8_t Y) { // First of all, make lowercase into uppercase // (as there are no lowercase letters in the font) if ((theChar & 0x7f) >= 0x61 && (theChar & 0x7f) <= 0x7a) { @@ -84,7 +91,7 @@ void charoutsmall(uint8_t theChar, uint8_t X, uint8_t Y) { } } -void LCD_disp_str(uint8_t* theStr, uint8_t theLen, uint8_t startx, uint8_t y, uint8_t theFormat) { +static void disp_str(uint8_t* theStr, uint8_t theLen, uint8_t startx, uint8_t y, uint8_t theFormat) { #ifdef MINIMALISTIC for (uint8_t q = 0; q < theLen; q++) { charoutsmall(theStr[q], startx, y); @@ -99,24 +106,30 @@ void LCD_disp_str(uint8_t* theStr, uint8_t theLen, uint8_t startx, uint8_t y, ui #endif } -void LCD_MultiLineH(uint8_t startx, uint8_t endx, uint64_t ymask) { - for (uint8_t x = startx; x <= endx; x++) { - FB[0][x] |= ymask & 0xff; - FB[1][x] |= ymask >> 8; - FB[2][x] |= ymask >> 16; - FB[3][x] |= ymask >> 24; -#if FB_HEIGHT == 64 - FB[4][x] |= ymask >> 32; - FB[5][x] |= ymask >> 40; - FB[6][x] |= ymask >> 48; - FB[7][x] |= ymask >> 56; -#endif + +void LCD_printf(uint8_t x, uint8_t y, uint8_t flags, const char *format, ...) { + char buf[22]; + uint8_t len; + va_list arg; + + va_start(arg, format); + len = vsnprintf(buf, sizeof(buf), format, arg); + + if (flags & CENTERED) { + x = LCD_ALIGN_CENTER(len); + } else if (flags & RIGHT_ALIGNED) { + x = LCD_ALIGN_RIGHT(len); } + // filter flags again + flags &= ~(CENTERED | RIGHT_ALIGNED); + disp_str((uint8_t *) buf, len, x, y, flags); + va_end(arg); } /* * At the moment this is a very basic BMP file reader with the following limitations: * The bitmap must be 1-bit, uncompressed with a BITMAPINFOHEADER. + * NOTE: this will OR-in the bitmap content, i.e. only 1s survive! */ uint8_t LCD_BMPDisplay(uint8_t* thebmp, uint8_t xoffset, uint8_t yoffset) { BMhdr_t* bmhdr; @@ -133,10 +146,10 @@ uint8_t LCD_BMPDisplay(uint8_t* thebmp, uint8_t xoffset, uint8_t yoffset) { } bmhdr = &temp; -// printf("\n%s: bfSize=%x biSize=%x", __FUNCTION__, (uint16_t)bmhdr->bfSize, (uint16_t)bmhdr->biSize); -// printf("\n%s: Image size is %d x %d", __FUNCTION__, (int16_t)bmhdr->biWidth, (int16_t)bmhdr->biHeight); + log(LOG_DEBUG, "%s: bfSize=%x biSize=%x", __FUNCTION__, (uint16_t)bmhdr->bfSize, (uint16_t)bmhdr->biSize); + log(LOG_DEBUG, "%s: Image size is %d x %d", __FUNCTION__, (int16_t)bmhdr->biWidth, (int16_t)bmhdr->biHeight); if (bmhdr->biPlanes != 1 || bmhdr->biBitCount != 1 || bmhdr->biCompression != 0) { - printf("\n%s: Incompatible bitmap format!", __FUNCTION__); + log(LOG_WARN, "%s: Incompatible bitmap format!", __FUNCTION__); return 1; } pixeloffset = bmhdr->bfOffBits; @@ -148,7 +161,7 @@ uint8_t LCD_BMPDisplay(uint8_t* thebmp, uint8_t xoffset, uint8_t yoffset) { upsidedown = 0; } if ((bmhdr->biWidth+xoffset > FB_WIDTH) || (bmhdr->biHeight+yoffset > FB_HEIGHT)) { - printf("\n%s: Image won't fit on display!", __FUNCTION__); + log(LOG_WARN, "%s: Image won't fit on display!", __FUNCTION__); return 1; } @@ -156,7 +169,7 @@ uint8_t LCD_BMPDisplay(uint8_t* thebmp, uint8_t xoffset, uint8_t yoffset) { // If the image is 132 pixels wide then the pixel lines will be 20 bytes (160 pixels) // 132&31 is 4 which means that there are 3 bytes of padding numpadbytes = (4 - ((((bmhdr->biWidth) & 0x1f) + 7) >> 3)) & 0x03; -// printf("\n%s: Skipping %d padding bytes after each line", __FUNCTION__, numpadbytes); + log(LOG_DEBUG, "%s: Skipping %d padding bytes after each line", __FUNCTION__, numpadbytes); for (int8_t y = bmhdr->biHeight - 1; y >= 0; y--) { uint8_t realY = upsidedown ? (uint8_t)y : (uint8_t)(bmhdr->biHeight) - y; diff --git a/src/lcd.h b/src/lcd.h index b34bfb2..ba17e92 100644 --- a/src/lcd.h +++ b/src/lcd.h @@ -8,18 +8,17 @@ #ifndef LCD_H_ #define LCD_H_ -#define FB_HEIGHT (64) -#define FB_WIDTH (128) +#define FB_HEIGHT 64 +#define FB_WIDTH 128 +#define LCD_CENTER 64 -#define FONT6X6 (0) -#define INVERT (0x80) +#define INVERT 0x80 // used internally (within a 7bit value) +#define CENTERED 1 +#define RIGHT_ALIGNED 2 -#define LCD_CENTER (64) -#define LCD_ALIGN_CENTER(x) (LCD_CENTER - (x * 3)) -#define LCD_ALIGN_RIGHT(x) (127 - (x * 6)) +void LCD_printf(uint8_t x, uint8_t y, uint8_t flags, const char *format, ...) + __attribute__((format (printf, 4, 5))); -void charoutsmall(uint8_t theChar, uint8_t X, uint8_t Y); -void LCD_disp_str(uint8_t* theStr, uint8_t theLen, uint8_t startx, uint8_t y, uint8_t theFormat); void LCD_MultiLineH(uint8_t startx, uint8_t endx, uint64_t ymask); uint8_t LCD_BMPDisplay(uint8_t* thebmp, uint8_t xoffset, uint8_t yoffset); void LCD_SetPixel(uint8_t x, uint8_t y); diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..f1f214b --- /dev/null +++ b/src/log.c @@ -0,0 +1,39 @@ +#include +#include + +#include "log.h" + +// for now log everything at startup (this needs a NV setup) +static int log_level = LOG_VERBOSE; + +void set_log_level(int loglvl) +{ + log_level = loglvl; +} + +const char *log_level_name(int loglvl) +{ + switch(loglvl) { + case LOG_FATAL: return "FATAL"; + case LOG_ERROR: return "ERROR"; + case LOG_WARN: return "WARN"; + case LOG_INFO: return "INFO"; + case LOG_DEBUG: return "DEBUG"; + case LOG_VERBOSE: return "VERBOSE"; + default: return "STRANGE"; + } +} + +/* simply use printf for now */ +void log(int loglvl, const char* str, ...) +{ + va_list arg; + + if (loglvl <= log_level) { + va_start(arg, str); + printf("%s: ", log_level_name(loglvl)); + vprintf(str, arg); + printf("\n"); + va_end(arg); + } +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..4dc8e5c --- /dev/null +++ b/src/log.h @@ -0,0 +1,16 @@ +#ifndef _LOG_H +#define _LOG_H + +// Define logging levels +#define LOG_NONE -9 // only for set_level to completely turn off logging +#define LOG_FATAL -2 // A fatal error has occurred: program will block +#define LOG_ERROR -1 // An error has occurred: program may not exit +#define LOG_WARN 0 // Any circumstance that may not affect normal operation +#define LOG_INFO 1 // Necessary information regarding program operation +#define LOG_DEBUG 2 // Standard debug messages +#define LOG_VERBOSE 3 // All debug messages + +void log(int loglvl, const char* str, ...) __attribute__((format (printf, 2, 3))); +void set_log_level(int loglvl); + +#endif diff --git a/src/main.c b/src/main.c index ed0376a..8fb4638 100644 --- a/src/main.c +++ b/src/main.c @@ -21,7 +21,10 @@ #include #include #include +#include + #include "serial.h" +#include "log.h" #include "lcd.h" #include "io.h" #include "sched.h" @@ -44,6 +47,7 @@ extern uint8_t logobmp[]; extern uint8_t stopbmp[]; +extern uint8_t coolbmp[]; extern uint8_t selectbmp[]; extern uint8_t editbmp[]; extern uint8_t f3editbmp[]; @@ -53,34 +57,59 @@ __attribute__((weak)) const char* Version_GetGitVersion(void) { return "no version info"; } -static char* format_about = \ -"\nT-962-controller open source firmware (%s)" \ -"\n" \ -"\nSee https://github.com/UnifiedEngineering/T-962-improvement for more details." \ -"\n" \ -"\nInitializing improved reflow oven..."; - -static char* help_text = \ -"\nT-962-controller serial interface.\n\n" \ -" about Show about + debug information\n" \ -" bake Enter Bake mode with setpoint\n" \ -" bake