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