Initial commit Most of the code received basic testing. Most of the code comes from...
authorNathael Pajani <nathael.pajani@ed3l.fr>
Wed, 15 Jun 2016 16:41:56 +0000 (18:41 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Fri, 10 Feb 2023 18:02:59 +0000 (19:02 +0100)
50 files changed:
.gitignore [new file with mode: 0644]
LICENCE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
core/bootstrap.c [new file with mode: 0644]
core/fault_handlers.c [new file with mode: 0644]
core/pio.c [new file with mode: 0644]
core/rom_helpers.c [new file with mode: 0644]
core/system.c [new file with mode: 0644]
core/systick.c [new file with mode: 0644]
core/watchdog.c [new file with mode: 0644]
drivers/adc.c [new file with mode: 0644]
drivers/gpio.c [new file with mode: 0644]
drivers/i2c.c [new file with mode: 0644]
drivers/serial.c [new file with mode: 0644]
extdrv/tmp101_temp_sensor.c [new file with mode: 0644]
extdrv/ws2812.c [new file with mode: 0644]
include/core/iap.h [new file with mode: 0644]
include/core/lpc_core.h [new file with mode: 0644]
include/core/lpc_regs.h [new file with mode: 0644]
include/core/pio.h [new file with mode: 0644]
include/core/system.h [new file with mode: 0644]
include/core/systick.h [new file with mode: 0644]
include/core/watchdog.h [new file with mode: 0644]
include/drivers/adc.h [new file with mode: 0644]
include/drivers/gpio.h [new file with mode: 0644]
include/drivers/i2c.h [new file with mode: 0644]
include/drivers/serial.h [new file with mode: 0644]
include/extdrv/tmp101_temp_sensor.h [new file with mode: 0644]
include/extdrv/ws2812.h [new file with mode: 0644]
include/lib/errno.h [new file with mode: 0644]
include/lib/font.h [new file with mode: 0644]
include/lib/list.h [new file with mode: 0644]
include/lib/protocols/dtplug/defs.h [new file with mode: 0644]
include/lib/protocols/dtplug/slave.h [new file with mode: 0644]
include/lib/stddef.h [new file with mode: 0644]
include/lib/stdint.h [new file with mode: 0644]
include/lib/stdio.h [new file with mode: 0644]
include/lib/stdlib.h [new file with mode: 0644]
include/lib/string.h [new file with mode: 0644]
include/lib/time.h [new file with mode: 0644]
include/lib/utils.h [new file with mode: 0644]
lib/font.c [new file with mode: 0644]
lib/protocols/dtplug/slave.c [new file with mode: 0644]
lib/stdlib.c [new file with mode: 0644]
lib/string.c [new file with mode: 0644]
lib/time.c [new file with mode: 0644]
lib/uprintf.c [new file with mode: 0644]
lib/utils.c [new file with mode: 0644]
lib/vsprintf.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..92034fa
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# Normal rules
+#
+*.o
+*.d
+*.bin
+*.elf
+*.map
+*/objs/*
+*.zip
+*.svg
+*.dump
+*.img
+*.bak
+tags
diff --git a/LICENCE b/LICENCE
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..e7a33ed
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,81 @@
+# Makefile for LPC82x 
+
+TARGET_DIR = apps/$(MODULE)/$(NAME)
+
+LPC = lpc82x
+CPU = cortex-m0
+ARCH = armv6-m
+
+CROSS_COMPILE ?= arm-none-eabi-
+CC = $(CROSS_COMPILE)gcc
+FOPTS = -fno-builtin -ffunction-sections -fdata-sections -ffreestanding
+CFLAGS = -Wall -g -O2 -mthumb -mcpu=$(CPU) $(FOPTS)
+LINKOPTS = -static -g -nostartfiles -nostdlib \
+                  -Wl,--gc-sections -Wl,--build-id=none \
+                  -Wl,-Map=$(TARGET_DIR)/lpc_map_$(LPC).map -Tlpc_link_$(LPC).ld
+
+
+APPS = $(subst apps/,,$(wildcard apps/*/*))
+
+.PHONY: all $(APPS)
+all: $(APPS)
+
+INCLUDES = include/
+TARGET_INCLUDES = $(TARGET_DIR)/
+OBJDIR = objs
+
+SRC = $(wildcard */*.c)
+SRC += $(wildcard lib/*/*.c)
+SRC += $(wildcard lib/protocols/*/*.c)
+OBJS = ${SRC:%.c=${OBJDIR}/%.o}
+DEPS = ${OBJS:%.o=$(OBJDIR)/%.d}
+
+NAME_SRC = $(wildcard $(TARGET_DIR)/*.c)
+NAME_OBJS = ${NAME_SRC:%.c=${OBJDIR}/%.o}
+NAME_DEPS = ${NAME_OBJS:%.o=$(OBJDIR)/%.d}
+
+-include $(DEPS) $(NAME_DEPS)
+
+.SECONDARY: $(OBJS) $(NAME_OBJS)
+.PRECIOUS: %.elf
+%.elf: $(OBJS) $(NAME_OBJS)
+       @echo "Linking $(MODULE)/$(NAME) ..."
+       @$(CC) $(LINKOPTS) $(OBJS) $(NAME_OBJS) -o $@
+
+%.bin: %.elf
+       @echo "Creating image : \e[32m$@\e[39m"
+       @$(CROSS_COMPILE)objcopy -R .stack -R .bss -O binary $^ $@
+       @ls -l $@
+       @$(CROSS_COMPILE)size $^
+       @echo Done.
+
+${OBJDIR}/%.o: %.c
+       @mkdir -p $(dir $@)
+       @echo "-- compiling" $<
+       @$(CC) -MMD -MP -MF ${OBJDIR}/$*.d $(CFLAGS) $< -c -o $@ -I$(INCLUDES) -I$(TARGET_INCLUDES)
+
+
+$(APPS):
+       @make --no-print-directory MODULE=$(shell dirname $@) NAME=$(shell basename $@) apps/$(shell dirname $@)/$(shell basename $@)/$(shell basename $@).bin
+
+all_apps: $(APPS)
+
+clean:
+       rm -rf $(OBJDIR)
+
+mrproper: clean
+       rm -f apps/*/*/*.bin apps/*/*/*.elf apps/*/*/*.map
+
+
+# Some notes :
+# The command "make -f /path/to/here/Makefile module/app_name" does not work, as well
+# as the command "make -f /path/to/here/apps/module/app_name/Makefile".
+# This could be solved in the app Makefiles by replacing
+#   "NAME = $(shell basename $(CURDIR))"
+# with
+#   "NAME = $(shell basename $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))"
+# and possibly some similar trick for the base Makefile but this is just
+# unreadable and moslty unusefull, so it won't be supported.
+# Use "make -C /path/to/here/ module/app_name" or "make -C /path/to/here/apps/module/app_name"
+# instead.
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..3d1b7d7
--- /dev/null
+++ b/README
@@ -0,0 +1,102 @@
+This repository provides support and example code for LPC82x based boards.
+
+It has support for the LPC82x micro-controller and the peripherals used on
+the boards we made.
+Support for various other cool stuff is added when we play with it.
+
+Example applications are created in the apps/[module name] directories for
+each module, with one sub-directory for each application. These are (and must
+stay) independent.
+Each module has it's own directory under apps/.
+
+More usefull stuff is up to you. Creating an app is *very* simple. Copy
+an example from apps/[module name]/ to the name you want and start coding.
+** Please, no spaces (or special characters) in the directory names ! **
+
+
+********************
+BUID and FLASH
+
+Build has been tested using gcc, and only gcc, in the version provided by
+Debian GNU/Linux distribution, and a few other binary versions available for
+download on the Internet, but any ARM gcc toolchain should do.
+
+In order to get the debian ARM gcc cross-toolchain you should install the
+following packaages : gcc-arm-none-eabi, binutils-arm-none-eabi
+
+There's no need for the related libc package here, the libc does not fit
+in our micro-controller memory. Instead have a look at the content of the
+lib/ directory, and add stuff there.
+
+Once done you should build using the provided makefile by running the
+simple "make" command in the base directory, which will build all apps, or
+run "make <module_name>/<app_name>" to build a specific application. You can
+also run the simple "make" command in the specific app subdirectory to compile
+this application alone.
+
+To flash the binary (the one with .bin) to the LPC Flash you will need the
+lpctool package, now packaged for Debian, starting with Jessie, or available
+in our git repository : http://git.techno-innov.fr/lpctools (Clone using :
+git clone http://gitclone.techno-innov.fr/lpctools and then build (make) and
+use :)
+Usual command lines :
+   lpcprog -d /dev/ttyUSB0 -c id
+   lpcprog -d /dev/ttyUSB0 -c flash app_name.bin
+See lpctools readme and lpcprog or isp help (-h) or manpages for more
+information.
+
+
+********************
+SUPPORTED FEATURES and INTERFACES
+
+- LPC82x micro-controller definitions
+   - Cortex-M0 specific definitions
+   - Cortex-M0 and LPC82x Registers
+   - Interrupts
+   - ROM based division routines
+   - Utility functions to replace ctz and clz instructions (not present in Cortex M0)
+   - IAP ROM based functions (Not tested on LPC82x)
+
+- Bootstrap
+   - vector table
+   - reset handler
+
+- System
+   - watchdog (Not tested yet)
+   - clock / PLL config (Tested using internal RC only)
+   - systick
+   - precise msleep and usleep functions (using systick)
+   - pio configuration
+
+- Simple C Library
+   - memcpy and memset
+   - strcpy, strncpy, strcmp, strncmp, strchr, strrchr, strlen, strnlen
+   - snprintf, vsnprintf
+   - uprintf for easy debug over UART
+
+- Integrated Interface drivers
+   - UART (as UART or RS485)
+   - I²C
+   - ADC
+   - GPIO
+   - GPIO interrupts
+
+- External Device drivers
+   - TMP101 I²C temperature sensor
+   - WS2812 chainable leds
+
+- Other
+
+
+********************
+TODO :
+
+- Sleep mode support
+- Test all the GPIO in different modes
+- Add SPI Support
+- Comparator support
+- Test Watchdog support
+- CRC engine support
+- DMA support
+- More external drivers !
+
diff --git a/core/bootstrap.c b/core/bootstrap.c
new file mode 100644 (file)
index 0000000..1ed9e8f
--- /dev/null
@@ -0,0 +1,173 @@
+/****************************************************************************
+ *   core/bootstrap.c
+ *
+ * This file holds the bootstrap code, the vector table, and nothing more.
+ * The bootstrap code is the code of the reset handler, which is called by
+ *   the bootloader (executed from internal ROM after power on or reset).
+ * The reset handler code perform copy of data section, clears bss, and
+ *   calls the main function.
+ *
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * Example code from frozeneskimo.com :
+ *   http://dev.frozeneskimo.com/notes/getting_started_with_cortex_m3_cmsis_and_gnu_tools
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *****************************************************************************/
+
+
+extern unsigned int _end_stack;
+extern unsigned int _end_text;
+extern unsigned int _start_data;
+extern unsigned int _end_data;
+extern unsigned int _start_bss;
+extern unsigned int _end_bss;
+
+extern int main(void);
+
+/* Cortex M0 core interrupt handlers */
+void Reset_Handler(void);
+void NMI_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void HardFault_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SVC_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PendSV_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SysTick_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+/* LPC82x specific interrupt handlers */
+void WAKEUP_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void I2C_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void I2C_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void I2C_2_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void I2C_3_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SSP_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SSP_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void UART_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void UART_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void UART_2_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Comparator_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void ADC_SEQA_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void ADC_SEQB_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void ADC_THCMP_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void ADC_OVR_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void WDT_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void BOD_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void FLASH_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PININT_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PININT_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PININT_2_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PININT_3_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PININT_4_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PININT_5_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PININT_6_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PININT_7_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void DMA_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void RTC_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SCT_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void MRT_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void WKT_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+
+
+void Dummy_Handler(void);
+
+
+/***************************************************************************** */
+/*                      Vector table                                           */
+/***************************************************************************** */
+void *vector_table[] __attribute__ ((section(".vectors"))) = {
+       &_end_stack, /* Initial SP value */ /* 0 */
+       Reset_Handler,
+       NMI_Handler,
+       HardFault_Handler,
+       0,
+       0, /* 5 */
+       0,
+       /* Entry 7 (8th entry) must contain the 2’s complement of the check-sum
+          of table entries 0 through 6. This causes the checksum of the first 8
+          table entries to be 0 */
+       (void *)0xDEADBEEF, /* Actually, this is done using an external tool. */
+       0,
+       0,
+       0, /* 10 */
+       SVC_Handler,
+       0,
+       0,
+       PendSV_Handler,
+       SysTick_Handler, /* 15 */
+       /* LPC82x specific interrupt vectors, see chapter 4 of LPC82x User manual (UM10800) */
+       SSP_0_Handler, /* 16 */ /* IRQ0 */
+       SSP_1_Handler,
+       0,
+       UART_0_Handler,
+       UART_1_Handler, /* 20 */
+       UART_2_Handler, /* 21 */ /* IRQ5 */
+       0,
+       I2C_1_Handler,
+       I2C_0_Handler,
+       SCT_Handler, /* 25 */
+       MRT_Handler, /* 26 */ /* IRQ10 */
+       Comparator_Handler,
+       WDT_Handler,
+       BOD_Handler,
+       FLASH_Handler, /* 30 */ 
+       WKT_Handler, /* IRQ15 */
+       ADC_SEQA_Handler,
+       ADC_SEQB_Handler,
+       ADC_THCMP_Handler,
+       ADC_OVR_Handler, /* 35 */
+       DMA_Handler, /* IRQ20 */
+       I2C_2_Handler,
+       I2C_3_Handler,
+       0,
+       PININT_0_Handler,  /* 40 */
+       PININT_1_Handler,  /* IRQ25 */
+       PININT_2_Handler,
+       PININT_3_Handler,
+       PININT_4_Handler,
+       PININT_5_Handler,  /* 45 */
+       PININT_6_Handler,  /* IRQ30 */
+       PININT_7_Handler,
+};
+
+
+extern void rom_helpers_init(void);
+/*
+ * This is the entry point of the programm
+ * It does the set up of the memory and then starts the main.
+ */
+void Reset_Handler(void)
+{
+       unsigned int *src, *dst;
+
+       /* Copy data section from flash to RAM */
+       src = &_end_text;
+       dst = &_start_data;
+       while (dst < &_end_data)
+               *dst++ = *src++;
+
+       /* Clear the bss section */
+       dst = &_start_bss;
+       while (dst < &_end_bss)
+               *dst++ = 0;
+
+       /* Initialize rom based division helpers */
+       rom_helpers_init();
+       /* Start main programm */
+       main();
+}
+
+void Dummy_Handler(void) {
+       while (1);
+}
+
diff --git a/core/fault_handlers.c b/core/fault_handlers.c
new file mode 100644 (file)
index 0000000..f49e63e
--- /dev/null
@@ -0,0 +1,57 @@
+/****************************************************************************
+ *   core/fault_handlers.c
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * Example code from frozeneskimo.com :
+ *   http://dev.frozeneskimo.com/notes/getting_started_with_cortex_m3_cmsis_and_gnu_tools
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ *****************************************************************************/
+
+/* Default "fault" handlers, which catch the fault exceptions.
+ * These are defined as weak aliases of a dummy fault handler which enters an empty infinite
+ *   loop and chould be overidden by user defined handlers.
+ */
+
+#include "lib/stdint.h"
+
+void fault_info(const char* name, uint32_t len) __attribute__ ((weak, alias ("Dummy_Fault_Handler")));
+
+void Dummy_Fault_Handler(const char* name, uint32_t len) {
+       while (1);
+}
+
+/* Cortex M0 core interrupt handlers */
+void NMI_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void HardFault_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void SVC_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void PendSV_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+
+
+
diff --git a/core/pio.c b/core/pio.c
new file mode 100644 (file)
index 0000000..a1ffd11
--- /dev/null
@@ -0,0 +1,158 @@
+/****************************************************************************
+ *  core/pio.c
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/***************************************************************************** */
+/*                GPIOs                                                        */
+/***************************************************************************** */
+
+/*   Public access to Pins setup
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+
+
+#include "lib/stdint.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "lib/string.h"
+
+
+
+/***************************************************************************** */
+static volatile uint32_t* pio_regs_handles_port0[PORT0_NB_PINS] = {
+       &(LPC_IO_CONTROL->pio0_0),
+       &(LPC_IO_CONTROL->pio0_1),
+       &(LPC_IO_CONTROL->pio0_2),
+       &(LPC_IO_CONTROL->pio0_3),
+       &(LPC_IO_CONTROL->pio0_4),
+       &(LPC_IO_CONTROL->pio0_5),
+       &(LPC_IO_CONTROL->pio0_6),
+       &(LPC_IO_CONTROL->pio0_7),
+       &(LPC_IO_CONTROL->pio0_8),
+       &(LPC_IO_CONTROL->pio0_9),
+       &(LPC_IO_CONTROL->pio0_10),
+       &(LPC_IO_CONTROL->pio0_11),
+       &(LPC_IO_CONTROL->pio0_12),
+       &(LPC_IO_CONTROL->pio0_13),
+       &(LPC_IO_CONTROL->pio0_14),
+       &(LPC_IO_CONTROL->pio0_15),
+       &(LPC_IO_CONTROL->pio0_16),
+       &(LPC_IO_CONTROL->pio0_17),
+       &(LPC_IO_CONTROL->pio0_18),
+       &(LPC_IO_CONTROL->pio0_19),
+       &(LPC_IO_CONTROL->pio0_20),
+       &(LPC_IO_CONTROL->pio0_21),
+       &(LPC_IO_CONTROL->pio0_22),
+       &(LPC_IO_CONTROL->pio0_23),
+       &(LPC_IO_CONTROL->pio0_24),
+       &(LPC_IO_CONTROL->pio0_25),
+       &(LPC_IO_CONTROL->pio0_26),
+       &(LPC_IO_CONTROL->pio0_27),
+       &(LPC_IO_CONTROL->pio0_28),
+};
+
+/* IO config clock */
+/* To change GPIO config the io config block must be powered on */
+static void io_config_clk_on(void)
+{
+    subsystem_power(LPC_SYS_ABH_CLK_CTRL_IO_CONFIG, 1);
+    subsystem_power(LPC_SYS_ABH_CLK_CTRL_SWM, 1);
+}
+static void io_config_clk_off(void)
+{
+    subsystem_power(LPC_SYS_ABH_CLK_CTRL_IO_CONFIG, 0);
+    subsystem_power(LPC_SYS_ABH_CLK_CTRL_SWM, 0);
+}
+
+
+/* Simple copy function. */
+void pio_copy(struct pio* dst, const struct pio* src)
+{
+       if ((dst == NULL) || (src == NULL)) {
+               return;
+       }
+       memcpy(dst, src, sizeof(struct pio));
+}
+
+/* Configure the pin in the requested function and mode. */
+static void config_pio_safe(const struct pio* pp, const struct pin_matrix_entry* me, uint16_t mode)
+{
+       struct lpc_switch_matrix* matrix = LPC_SWITCH_MATRIX;
+       volatile uint32_t* handle = NULL;
+
+       if (pp->pin >= PORT0_NB_PINS) {
+               return;
+       }
+       /* Movable (offset0 & 0x80) or Fixed pin function */
+       if (pp->offset0 & 0x80) {
+               /* Disable fixed pin functions for this pin */
+               if ((pp->offset0 & 0x7F) <= 31) {
+                       matrix->pin_enable[0] |= (1 << (pp->offset0 & 0x7F));
+               }
+               if (pp->offset1 <= 31) {
+                       matrix->pin_enable[0] |= (1 << pp->offset1);
+               }
+               /* Assign the function to the pin if not a GPIO or fixed pin function */
+               if ((me != NULL) && (me->reg_offset < LPC_MATRIX_NB_PIN_ASSIGN)) {
+                       matrix->pin_assign[me->reg_offset] &= ~(0xFF << me->bit_shift);
+                       matrix->pin_assign[me->reg_offset] |= (pp->pin << me->bit_shift);
+               }
+               /* Configure the GPIO mode */
+               handle = pio_regs_handles_port0[pp->pin];
+               *handle = mode;
+       } else {
+               /* Maybe disable the other fixed pin entry ? */
+               if (pp->offset1 <= 31) {
+                       matrix->pin_enable[0] |= (1 << pp->offset1);
+               }
+               /* Enable our own fixed pin entry */
+               if (pp->offset0 <= 31) {
+                       matrix->pin_enable[0] &= ~(1 << pp->offset0);
+               }
+       }
+
+}
+void config_pio(const struct pio* pp, const struct pin_matrix_entry* matrix, uint16_t mode)
+{
+       if (pp == NULL) {
+               return;
+       }
+
+       /* Make sure IO_Config is clocked */
+       io_config_clk_on();
+
+       config_pio_safe(pp, matrix, mode);
+
+       /* Config done, power off IO_CONFIG block */
+       io_config_clk_off();
+}
+
+
+void set_pins(const struct pio_config* pins)
+{
+       int i = 0;
+       /* Make sure IO_Config is clocked */
+       io_config_clk_on();
+       for (i = 0; pins[i].pio.pin != 0xFF; i++) {
+               config_pio_safe(&(pins[i].pio), &(pins[i].matrix), pins[i].mode);
+       }
+       /* Config done, power off IO_CONFIG block */
+       io_config_clk_off();
+}
+
diff --git a/core/rom_helpers.c b/core/rom_helpers.c
new file mode 100644 (file)
index 0000000..dd55c39
--- /dev/null
@@ -0,0 +1,203 @@
+/****************************************************************************
+ *   core/rom_helpers.c
+ *
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/* ROM helpers are functions avalable for the user which do not use space in the
+ *  internal reprogrammable flash.
+ * They are stored in the internal ROM memory and may be called using specific
+ *  calls with defined parameters depending on the ROM call used.
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+
+#include "lib/stdint.h"
+#include "core/system.h"
+#include "core/lpc_core.h"
+
+/*******************************************************************************/
+/*            Integer division using ROM based division routines               */
+/*******************************************************************************/
+
+struct idiv_return {
+       int quotient;
+       int remainder;
+};
+struct uidiv_return {
+       unsigned quotient;
+       unsigned remainder;
+};
+
+struct lpc_rom_div_helpers {
+       /* Signed integer division */
+       int (*rom_sidiv)(int numerator, int denominator);
+       /* Unsigned integer division */
+       unsigned (*rom_uidiv)(unsigned numerator, unsigned denominator);
+       /* Signed integer division with remainder */
+       struct idiv_return (*rom_sidivmod)(int numerator, int denominator);
+       /* Unsigned integer division with remainder */
+       struct uidiv_return (*rom_uidivmod)(unsigned numerator, unsigned denominator);
+};
+
+static struct lpc_rom_div_helpers* rom_div_helpers;
+
+/* Division (/) */
+int __aeabi_idiv(int numerator, int denominator)
+{
+       return rom_div_helpers->rom_sidiv(numerator, denominator);
+}
+unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator)
+{
+       return rom_div_helpers->rom_uidiv(numerator, denominator);
+}
+
+/* Modulo (%) */
+void __aeabi_idivmod(int numerator, int denominator)
+{
+       struct idiv_return result = rom_div_helpers->rom_sidivmod(numerator, denominator);
+       register uint32_t r0 asm("r0") = result.quotient;
+       register uint32_t r1 asm("r1") = result.remainder;
+       asm volatile("" : "+r"(r0), "+r"(r1) : "r"(r0), "r"(r1));
+}
+void __aeabi_uidivmod(unsigned numerator, unsigned denominator)
+{
+       struct uidiv_return result = rom_div_helpers->rom_uidivmod(numerator, denominator);
+       register uint32_t r0 asm("r0") = result.quotient;
+       register uint32_t r1 asm("r1") = result.remainder;
+       asm volatile("" : "+r"(r0), "+r"(r1) : "r"(r0), "r"(r1));
+}
+
+
+/*******************************************************************************/
+/*            In Application Programming ROM based routines                    */
+/*******************************************************************************/
+
+enum iap_status {
+       IAP_STATUS_CMD_SUCCESS = 0,
+       IAP_STATUS_INVALID_COMMAND,
+       IAP_STATUS_SRC_ADDR_ERROR,
+       IAP_STATUS_DST_ADDR_ERROR,
+       IAP_STATUS_SRC_ADDR_NOT_MAPPED,
+       IAP_STATUS_DST_ADDR_NOT_MAPPED,
+       IAP_STATUS_COUNT_ERROR,
+       IAP_STATUS_INVALID_SECTOR,
+       IAP_STATUS_SECTOR_NOT_BLANK,
+       IAP_STATUS_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION,
+       IAP_STATUS_COMPARE_ERROR,
+       IAP_STATUS_BUSY,
+};
+
+enum iap_commands {
+       IAP_CMD_PREPARE_SECTORS_FOR_WRITE = 50,
+       IAP_CMD_COPY_RAM_TO_FLASH = 51,
+       IAP_CMD_ERASE_SECTORS = 52,
+       IAP_CMD_BLANK_CHECK_SECTORS = 53,
+       IAP_CMD_READ_PART_ID = 54,
+       IAP_CMD_READ_BOOT_CODE_VERSION = 55,
+       IAP_CMD_COMPARE = 56,
+       IAP_CMD_REINVOQUE_ISP = 57,
+       IAP_CMD_READ_UID = 58,
+       IAP_CMD_ERASE_PAGE = 59,
+};
+
+typedef void (*iap_entry_func)(uint32_t*, uint32_t*);
+iap_entry_func iap_entry;
+
+static uint32_t params[5];
+static uint32_t results[4];
+
+
+int iap_prepare_flash(uint32_t start_sector, uint32_t end_sector)
+{
+       params[0] = IAP_CMD_PREPARE_SECTORS_FOR_WRITE;
+       params[1] = start_sector;
+       params[2] = end_sector;
+       iap_entry(params, results);
+       return results[0];
+}
+
+int iap_erase_flash_sectors(uint32_t start_sector, uint32_t end_sector)
+{
+       params[0] = IAP_CMD_ERASE_SECTORS;
+       params[1] = start_sector;
+       params[2] = end_sector;
+       params[3] = (get_main_clock() / 1000);
+       lpc_disable_irq();
+       iap_entry(params, results);
+       lpc_enable_irq();
+       return results[0];
+}
+
+int iap_erase_flash_pages(uint32_t start_page, uint32_t end_page)
+{
+       params[0] = IAP_CMD_ERASE_PAGE;
+       params[1] = start_page;
+       params[2] = end_page;
+       params[3] = (get_main_clock() / 1000);
+       lpc_disable_irq();
+       iap_entry(params, results);
+       lpc_enable_irq();
+       return results[0];
+}
+int iap_copy_ram_to_flash(uint32_t dest, uint32_t src, uint32_t size)
+{
+       params[0] = IAP_CMD_COPY_RAM_TO_FLASH;
+       params[1] = dest & ~(0x03);
+       params[2] = src & ~(0x03);
+       params[3] = size & ~(0x03);
+       params[4] = (get_main_clock() / 1000);
+       lpc_disable_irq();
+       iap_entry(params, results);
+       lpc_enable_irq();
+       return results[0];
+}
+
+uint32_t iap_read_part_id(void)
+{
+       params[0] = IAP_CMD_READ_PART_ID;
+       iap_entry(params, results);
+       return results[1];
+}
+
+
+/*******************************************************************************/
+/*            Rom based routines initialisation                                */
+/*******************************************************************************/
+#define LPC_82x_ROM_HELPERS (0x1FFF1FF8)
+#define LPC_82x_IAP_ROM_LOC (0x1FFF1FF1)
+
+struct rom_helpers {
+    const unsigned p_dev0;
+    const unsigned p_dev1;
+    const unsigned p_dev2;
+    const unsigned rom_power_profiles;
+    const unsigned rom_div;
+    const unsigned rom_i2c_driver;
+    const unsigned p_dev6;
+    const unsigned rom_spi_driver;
+    const unsigned rom_adc_driver;
+    const unsigned rom_usart_driver;
+    const unsigned p_dev10;
+};
+#define ROM_DRIVERS ((struct rom_helpers *)(*((uint32_t *)LPC_82x_ROM_HELPERS)))
+
+void rom_helpers_init(void)
+{
+       rom_div_helpers = (struct lpc_rom_div_helpers*)(ROM_DRIVERS->rom_div);
+       iap_entry = (iap_entry_func)LPC_82x_IAP_ROM_LOC;
+}
+
diff --git a/core/system.c b/core/system.c
new file mode 100644 (file)
index 0000000..c52e09e
--- /dev/null
@@ -0,0 +1,311 @@
+/****************************************************************************
+ *   core/system.c
+ *
+ * All low-level functions for clocks configuration and switch, system
+ *  power-up, reset, and power-down.
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/*
+ * This file holds some system wide initialisation functions and clock or sleep
+ *   related functions.
+ */
+
+#include "lib/stdint.h"
+
+#include "core/lpc_regs.h"
+#include "core/lpc_core.h"
+#include "core/system.h"
+
+
+/* Private defines */
+#define LPC_IRC_OSC_CLK  (12000000UL)  /* Internal RC oscillator frequency : 12MHz */
+
+/***************************************************************************** */
+/*                     Global data                                             */
+/***************************************************************************** */
+struct lpc_desc_private {
+       uint32_t main_clock;
+       uint8_t brown_out_detection_enabled;
+       uint8_t need_IRC;
+};
+static struct lpc_desc_private lpc_private = {
+       .main_clock = LPC_IRC_OSC_CLK,
+       .brown_out_detection_enabled = 0,
+       .need_IRC = 1,
+};
+
+/***************************************************************************** */
+/*                     Required system inits                                  */
+/***************************************************************************** */
+
+/* Configure the brown-out detection */
+void system_brown_out_detection_config(uint32_t level)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+
+       if (level == 0) {
+               /* Disable Brown-Out Detection, power it down */
+               sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_BOD;
+               lpc_private.brown_out_detection_enabled = 0;
+       } else {
+               /* Power on Brown-Out Detection. */
+               sys_config->powerdown_run_cfg &= ~(LPC_POWER_DOWN_BOD);
+               lpc_private.brown_out_detection_enabled = 1;
+               /* Configure Brown-Out Detection */
+               /* FIXME */
+       }
+}
+
+/***************************************************************************** */
+/*                       Power                                                 */
+/***************************************************************************** */
+/* Set up power-down control
+ * Change reset power state to our default, removing power from unused interfaces
+ */
+void system_set_default_power_state(void)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       /* Start with all memory powered on and nothing else */
+       sys_config->sys_AHB_clk_ctrl = LPC_SYS_ABH_CLK_CTRL_MEM_ALL;
+}
+
+/* Enter deep sleep.
+ * NOTE : entering deep sleep implies a lot of side effects. I'll try to list them all here
+ *        so this can be done right.
+ *
+ * Note : see remark about RTC and deep sleep in section 5.3.3 of UM10441
+ */
+void enter_deep_sleep(void)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+
+       /* Ask for the same clock status when waking up */
+       sys_config->powerdown_wake_cfg = sys_config->powerdown_run_cfg;
+       /* Set deep_sleep config */
+       if (lpc_private.brown_out_detection_enabled) {
+               sys_config->powerdown_sleep_cfg = LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_ON;
+       } else {
+               sys_config->powerdown_sleep_cfg = LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_OFF;
+       }
+       /* Enter deep sleep */
+       /* FIXME */
+}
+
+/* Power on or off a subsystem */
+void subsystem_power(uint32_t power_bit, uint32_t on_off)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       if (on_off == 1) {
+               sys_config->sys_AHB_clk_ctrl |= power_bit;
+       } else {
+               sys_config->sys_AHB_clk_ctrl &= ~(power_bit);
+       }
+}
+/* Check whether a subsystem is powered or not */
+uint8_t subsystem_powered(uint32_t power_bit)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       return (sys_config->sys_AHB_clk_ctrl & power_bit);
+}
+
+/* Reset a subsystem */
+void subsystem_reset_hold(uint32_t reset_bit)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       sys_config->peripheral_reset_ctrl &= ~(reset_bit);
+}
+void subsystem_reset_release(uint32_t reset_bit)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       sys_config->peripheral_reset_ctrl |= reset_bit;
+}
+void subsystem_reset(uint32_t reset_bit)
+{
+       subsystem_reset_hold(reset_bit);
+       /* Arbitrary and short delay */
+       nop();
+       nop();
+       subsystem_reset_release(reset_bit);
+}
+
+/***************************************************************************** */
+/*                      System Clock                                           */
+/***************************************************************************** */
+static void propagate_main_clock(void);
+
+/* Main clock config : set up the system clock
+ * We use internal RC oscilator as sys_pllclkin if pll is ussed
+ * Note that during PLL lock wait we are running on internal RC
+ * Note for M and P calculation :
+ *          FCCO must be between 156MHz and 320MHz
+ *          M ranges from 1 to 32, steps of 1, M = Freq_out / Freq_in 
+ *          P ranges from 1 to 8, P must be a power of two, FCCO = 2 * P * Freq_out
+ *          Freq_out < 100 MHz
+ *          Freq_in is between 10 and 25 MHz
+ *          M = Freq_out / Freq_in 
+ *
+ * freq_sel : set to one of the predefined values. See core/system.h
+ */
+void clock_config(uint32_t freq_sel)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+
+       lpc_disable_irq();
+       /* Turn on IRC */
+       sys_config->powerdown_run_cfg &= ~(LPC_POWER_DOWN_IRC);
+       sys_config->powerdown_run_cfg &= ~(LPC_POWER_DOWN_IRC_OUT);
+       /* Use IRC clock for main clock */
+       sys_config->main_clk_sel = LPC_MAIN_CLK_SRC_IRC_OSC;
+       lpc_private.need_IRC = 1;
+       /* Switch the main clock source */
+       sys_config->main_clk_upd_en = 0;
+       sys_config->main_clk_upd_en = 1;
+
+       /* Turn off / power off external crystal */
+       sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_SYS_OSC;
+       /* Set AHB clock divider : divide by one ... */
+       sys_config->sys_AHB_clk_div = 1;
+       /* power off PLL */
+       sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_SYSPLL;
+
+       /* If using only internal RC, we are done */
+       if (freq_sel == FREQ_SEL_IRC) {
+               lpc_private.main_clock = LPC_IRC_OSC_CLK;
+       } else {
+               uint32_t M = ((freq_sel >> 3) & 0xFF);
+               uint32_t N = 0; /* P = 2 ^ N */
+
+               /* Select value for N */
+               switch (freq_sel) {
+                       case 3: /* FREQ_SEL_36MHz */
+                       case 2: /* FREQ_SEL_24MHz */
+                               N = 2; /* P = 4 */
+                               break;
+                       default: /* 48MHz to 60 MHz */
+                               N = 1; /* P = 2 */
+                               break;
+               }
+               lpc_private.main_clock = (((freq_sel >> 3) & 0xFF) * 12 * 1000 * 1000);
+               /* Setup PLL dividers */
+               sys_config->sys_pll_ctrl = (((M - 1) & 0x1F) | (N << 5));  /* 5 is PSEL shift */
+               /* Set sys_pll_clk to internal RC */
+               sys_config->sys_pll_clk_sel = LPC_PLL_CLK_SRC_IRC_OSC;
+               sys_config->sys_pll_clk_upd_en = 0;  /* SYSPLLCLKUEN must go from LOW to HIGH */
+               sys_config->sys_pll_clk_upd_en = 1;
+               /* Power-up PLL */
+               sys_config->powerdown_run_cfg &= ~(LPC_POWER_DOWN_SYSPLL);
+               /* Wait Until PLL Locked */
+               while (!(sys_config->sys_pll_status & 0x01));
+               /* Use PLL as main clock */
+               sys_config->main_clk_sel = LPC_MAIN_CLK_SRC_PLL_OUT;
+               /* Switch the main clock source */
+               sys_config->main_clk_upd_en = 0;
+               sys_config->main_clk_upd_en = 1;
+       }
+
+       /* And call all clock updaters */
+       propagate_main_clock();
+       /* Turn interrupts on once again*/
+       lpc_enable_irq();
+}
+
+uint32_t get_main_clock(void)
+{
+       return lpc_private.main_clock;
+}
+
+/***************************************************************************** */
+/*                     Peripheral Clocks                                       */
+/***************************************************************************** */
+void Dummy_Clk_Updater(void) {
+       do { } while (0);
+}
+
+void uart_clk_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater")));
+void i2c_clock_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater")));
+void ssp_clk_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater")));
+void adc_clk_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater")));
+
+static void propagate_main_clock(void)
+{
+       uart_clk_update();
+       i2c_clock_update();
+       ssp_clk_update();
+       adc_clk_update();
+}
+
+/***************************************************************************** */
+/*                    CLK Out                                                  */
+/***************************************************************************** */
+/* This is mainly a debug feature, but can be used to provide a clock to an
+ * external peripheral */
+/* Note that PIO0_12 is the only pin possible for CLK_Out, and is multiplexed
+ * with ISP mode selection on reset.
+ * The pin must be enabled using a pio table passed to the set_pins() function.
+ */
+
+void clkout_on(uint32_t src, uint32_t div)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+
+       /* Select clk_out clock source */
+       sys_config->clk_out_src_sel = (src & 0x03);
+       /* Activate clk_out */
+       sys_config->clk_out_div = (div & 0xFF);
+       sys_config->clk_out_upd_en = 0;
+       sys_config->clk_out_upd_en = 1;
+}
+void clkout_off(void)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       sys_config->clk_out_div = 0; /* Disable CLKOUT */
+       sys_config->clk_out_upd_en = 0;
+       sys_config->clk_out_upd_en = 1;
+}
+
+
+/***************************************************************************** */
+/*                    Default sleep function                                   */
+/***************************************************************************** */
+/* Note that if the systick core functions are used these will be overridden */
+
+/* This "msleep" is a simple wait routine which is close to a millisecond sleep
+ * whith a CPU Clock of 24MHz, but has no exact relation to time.
+ * It is highly dependent to CPU clock speed anyway.
+ * Note : This is an active sleep !
+ */
+static void def_msleep(uint32_t ms)
+{
+       volatile uint32_t dec = ms * 2667;
+       while (dec--);
+}
+
+/* Something that's not too far from a microsecond sleep at 24MHz CPU Clock
+ * Note : This is an active sleep !
+ */
+static inline void def_usleep(uint32_t us)
+{
+       volatile uint32_t dec = us * 2;
+       while (dec--);
+}
+
+void msleep(uint32_t ms) __attribute__ ((weak, alias ("def_msleep")));
+void usleep(uint32_t us) __attribute__ ((weak, alias ("def_usleep")));
+
diff --git a/core/systick.c b/core/systick.c
new file mode 100644 (file)
index 0000000..3f7310e
--- /dev/null
@@ -0,0 +1,364 @@
+/****************************************************************************
+ *  core/systick.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+/***************************************************************************** */
+/*               System Tick Timer                                             */
+/***************************************************************************** */
+
+/* Driver for the internal systick timer of the LPC82x.
+ * Refer to the LPC82x documentation (UM10800.pdf) for more information
+ */
+
+#include "core/system.h"
+#include "core/systick.h"
+#include "lib/errno.h"
+
+
+/* Static variables */
+static volatile uint32_t sleep_count = 0;
+static volatile uint32_t tick_ms = 0;
+static volatile uint32_t systick_running = 0;
+static volatile uint32_t tick_reload = 0;
+static uint32_t usleep_us_count = 0;
+
+/* Wraps every 50 days or so with a 1ms tick */
+static volatile uint32_t global_wrapping_system_ticks = 0;
+/* The systick cycles run at get_main_clock(), and would wrap more often! */
+static volatile uint32_t global_wrapping_system_clock_cycles = 0;
+
+
+struct systick_callback {
+       void (*callback) (uint32_t);
+       uint16_t period;
+       uint16_t countdown;
+};
+static volatile struct systick_callback cbs[MAX_SYSTICK_CALLBACKS] = {};
+
+/* System Tick Timer Interrupt Handler */
+void SysTick_Handler(void)
+{
+       int i = 0;
+       global_wrapping_system_ticks++;
+       global_wrapping_system_clock_cycles += tick_reload;
+       if (sleep_count != 0) {
+               sleep_count--;
+       }
+       for (i = 0; i < MAX_SYSTICK_CALLBACKS; i++) {
+               if (cbs[i].callback != NULL) {
+                       cbs[i].countdown--;
+                       if (cbs[i].countdown == 0) {
+                               cbs[i].countdown = cbs[i].period;
+                               cbs[i].callback(global_wrapping_system_ticks);
+                       }
+               }
+       }
+}
+
+
+/* Register a callback to be called every 'period' system ticks.
+ * returns the callback number if registration was OK.
+ * returns negative value on error.
+ * The callback will get the "global_wrapping_system_ticks" as argument, which wraps every 50 days
+ *   or so with a 1ms tick
+ */
+int add_systick_callback(void (*callback) (uint32_t), uint16_t period)
+{
+       int i = 0;
+       if (period == 0) {
+               return -EINVAL;
+       }
+       for (i = 0; i < MAX_SYSTICK_CALLBACKS; i++) {
+               if (cbs[i].callback == NULL) {
+                       cbs[i].callback = callback;
+                       cbs[i].period = period;
+                       cbs[i].countdown = period;
+                       return i;
+               }
+       }
+       return -EBUSY;
+}
+
+int remove_systick_callback(void (*callback) (uint32_t))
+{
+       int i = 0;
+       for (i = 0; i < MAX_SYSTICK_CALLBACKS; i++) {
+               if (cbs[i].callback == callback) {
+                       cbs[i].callback = NULL;
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+/***************************************************************************** */
+/* systick timer control function */
+
+/* Start the system tick timer
+ * Starting the systick timer also resets the internal tick counters.
+ * If you need a value that goes beyond one start/stop cycle and accross resets,
+ *    then it's up to you to keep track of this using systick_get_tick_count() and/or
+ *    systick_get_clock_cycles().
+ */
+void systick_start(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       systick->value = 0;
+       systick_running = 1;
+       global_wrapping_system_ticks = 0;
+       global_wrapping_system_clock_cycles = tick_reload;
+       systick->control |= LPC_SYSTICK_CTRL_ENABLE;
+}
+/* Stop the system tick timer */
+void systick_stop(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       systick->control &= ~(LPC_SYSTICK_CTRL_ENABLE);
+       systick_running = 0;
+       systick->value = 0;
+}
+/* Reset the system tick timer, making it count down from the reload value again
+ * Reseting the systick timer also resets the internal tick counters.
+ * If you need a value that goes beyond one start/stop cycle and accross resets,
+ *    then it's up to you to keep track of this using systick_get_tick_count() and/or
+ *    systick_get_clock_cycles().
+ */
+void systick_reset(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       systick->value = 0;
+       global_wrapping_system_ticks = 0;
+       global_wrapping_system_clock_cycles = tick_reload;
+}
+
+/* Get system tick timer current value (counts at get_main_clock() !)
+ * systick_get_timer_val returns a value between 0 and systick_get_timer_reload_val()
+ */
+uint32_t systick_get_timer_val(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       return systick->value;
+}
+/* Get system tick timer reload value */
+uint32_t systick_get_timer_reload_val(void)
+{
+       return tick_reload;
+}
+
+/* Check if systick is running (return 1) or not (return 0) */
+uint32_t is_systick_running(void)
+{
+       return systick_running;
+}
+
+/* Get the system tick period in ms
+ * A vaue of 0 means the system tick timer has not been configured.
+ * Note : calls to msleep() or usleep() will configure the system tick timer
+ *        with a value of 1ms if it was not configured yet.
+ */
+uint32_t systick_get_tick_ms_period(void)
+{
+       return tick_ms;
+}
+
+/* Get the "timer wrapped" indicator.
+ * Used in usleep() function.
+ * Note : the first to call this function will get the right information.
+ * All subsequent calls will get wrong indication.
+ * Thus this function is not exported to user space, user should compare global
+ * ticks values or tick counter values. */
+static uint32_t systick_counted_to_zero(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       return (systick->control & LPC_SYSTICK_CTRL_COUNTFLAG);
+}
+
+
+/* Get the number of system ticks ... since last wrapping of the counter, which
+ * is about 50 days with a 1ms system tick. */
+uint32_t systick_get_tick_count(void)
+{
+       return global_wrapping_system_ticks;
+}
+
+/* Get the number of clock cycles ... since last wrapping of the counter. */
+uint32_t systick_get_clock_cycles(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       /* global_wrapping_system_clock_cycles has been initialised to reload value, thus there is
+        * no need to add it here, making the call quicker */
+       return global_wrapping_system_clock_cycles - systick->value;
+}
+
+/***************************************************************************** */
+/* Power up the system tick timer.
+ * ms is the interval between system tick timer interrupts. If set to 0, the default
+ *     value is used, which should provide a 1ms period.
+ */
+void systick_timer_on(uint32_t ms)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       uint32_t reload; /* The reload value for the counter */
+
+       /* Set the reload value */
+       if (ms != 0) {
+               reload = ((get_main_clock() / 1000) * ms) - 1;
+       } else {
+               reload = (get_main_clock() / 1000) - 1;
+               ms = 1;
+       }
+       /* For the LPC82x the system tick clock is fixed to half the frequency of the system clock */
+       reload = reload >> 1; /* Divide by 2 */
+       systick->reload_val = (reload & 0xffffff);
+       tick_ms = ms;
+       tick_reload = systick->reload_val;
+
+       /* Start counting from the reload value, writting anything would do ... */
+       systick->value = reload;
+       /* Consider we already counted one cycle, making further reading of this count easier */
+       global_wrapping_system_clock_cycles = tick_reload;
+
+       /* And enable counter interrupt */
+       systick->control = LPC_SYSTICK_CTRL_TICKINT;
+       systick_running = 0;
+
+       /* Perform this division now for the usleep function. */
+       usleep_us_count = get_main_clock() / (1000 * 1000);
+       /* For the LPC82x the system tick clock is fixed to half the frequency of the system clock */
+       usleep_us_count = (usleep_us_count >> 1); /* Divide by two */
+
+       /* FIXME : document this */
+       NVIC_SetPriority(SYSTICK_IRQ, ((1 << LPC_NVIC_PRIO_BITS) - 1));
+}
+
+/* Removes the main clock from the selected timer block */
+void systick_timer_off(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       systick->control = 0;
+       systick->reload_val = 0;
+       tick_ms = 0;
+       tick_reload = 0;
+       systick_running = 0;
+}
+
+
+/***************************************************************************** */
+/* Sleeping functions */
+
+/* Set the sleep countdown value
+ * A sleep will end when this value reaches 0
+ * Note that calls to this function while a sleep() has been initiated will change the
+ *   sleep duration ....
+ */
+static inline void set_sleep(uint32_t ticks)
+{
+       sleep_count = ticks;
+}
+
+/* Actual sleep function, checks that system tick counter is configured to generate
+ * an interrupt and to move sleep_count down to 0
+ */
+#define SYSTICK_CAN_SLEEP   (LPC_SYSTICK_CTRL_TICKINT | LPC_SYSTICK_CTRL_ENABLE)
+static uint32_t sleep(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       if ((systick->control & SYSTICK_CAN_SLEEP) != SYSTICK_CAN_SLEEP) {
+               return -1;
+       }
+       do { } while (sleep_count != 0);
+       return 0;
+}
+
+/* This msleep sleeps less than the required amount of time as it forgets about
+ * the already elapsed time of the systick timer since last tick. */
+void msleep(uint32_t ms)
+{
+       uint32_t ticks = 0;
+
+       if (tick_ms == 0) {
+               systick_timer_on(1);
+               ticks = ms;
+       } else {
+               ticks = ms / tick_ms;
+       }
+       set_sleep(ticks);
+       if (systick_running == 0) {
+               systick_start();
+       }
+       sleep();
+}
+
+/* This usleep function tries to sleep at most the required amount of time.
+ * The setup is so long that it cannot sleep for less than 10us when running at 48MHz
+ */
+void usleep(uint32_t us)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       uint32_t start = systick->value; /* Grab the starting (call time) value now */
+       uint32_t count = 0;
+       uint32_t end = 0;
+
+       end = systick_counted_to_zero(); /* erase loop indicator */
+       if (us > 1000) {
+               msleep(us / 1000);
+               us = us % 1000;
+       } else {
+               if (systick_running == 0) {
+                       if (tick_ms == 0) {
+                               systick_timer_on(1);
+                       }
+                       systick_start();
+               }
+       }
+       count = usleep_us_count * us;
+        /* Remember that systick is a decrementing counter */
+       if (count > start) {
+               end = (systick->reload_val - (count - start));
+               do { } while (systick_counted_to_zero() == 0); /* Wait for timer loop */
+               do { } while (systick->value > end); /* Wait for remaining part of sleep duration */
+       } else {
+               end = start - count;
+               /* Wait for sleep duration.
+                * If the counter looped, it means we already waited too much */
+               do { } while ((systick->value > end) && (systick_counted_to_zero() == 0));
+       }
+}
+
+void usleep_short(uint32_t us)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       uint32_t start = systick->value; /* Grab the starting (call time) value now */
+       uint32_t count = usleep_us_count * us;
+       uint32_t end = systick_counted_to_zero(); /* Erase loop indicator */
+
+        /* Remember that systick is a decrementing counter */
+       if (count > start) {
+               end = (systick->reload_val - (count - start));
+               do { } while (systick_counted_to_zero() == 0); /* Wait for timer loop */
+               do { } while (systick->value > end); /* Wait for remaining part of sleep duration */
+       } else {
+               end = start - count;
+               /* Wait for sleep duration.
+                * If the counter looped, it means we already waited too much */
+               do { } while ((systick->value > end) && (systick_counted_to_zero() == 0));
+       }
+}
+
diff --git a/core/watchdog.c b/core/watchdog.c
new file mode 100644 (file)
index 0000000..5553fa8
--- /dev/null
@@ -0,0 +1,205 @@
+/****************************************************************************
+ *   core/watchdog.c
+ *
+ * Watchdog support
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/*
+ * This file implements support of the Windowed Watchdog (WWDT)
+ */
+
+#include "core/system.h"
+#include "core/watchdog.h"
+
+
+
+/***************************************************************************** */
+void watchdog_feed(void)
+{
+       struct lpc_watchdog* wdt = LPC_WDT;
+       lpc_disable_irq();
+       wdt->feed_seqence = 0xAA;
+       wdt->feed_seqence = 0x55;
+       lpc_enable_irq();
+}
+
+static void (*wdt_callback)(void) = NULL;
+
+
+/* With no callback, the watchdog interupt may be used to wake up by generating an interrupt */
+void WDT_Handler(void)
+{
+       struct lpc_watchdog* wdt = LPC_WDT;
+       wdt->mode |= LPC_WDT_INTR_FLAG;
+       /* Call user callback if the user registered one */
+       if (wdt_callback != NULL) {
+               wdt_callback();
+       }
+}
+
+
+/* Lock the watchdog clock source power.
+ * Once locked, writes to the current watchdog clock power bits in powerdown_*_cfg will
+ *   have no effect.
+ * It is still possible to switch the watchdog clock source and turn of the clock if the
+ *   watchdog clock source has not been locked yet.
+ */
+void watchdog_lock_clk_src_power(void)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       struct lpc_watchdog* wdt = LPC_WDT;
+
+       sys_config->powerdown_sleep_cfg &= ~(LPC_POWER_DOWN_WDT_OSC);
+       sys_config->powerdown_wake_cfg &= ~(LPC_POWER_DOWN_WDT_OSC);
+
+       wdt->mode |= LPC_WDT_CLK_POWER_LOCK;
+}
+
+/* Lock the watchdog timer value */
+void watchdog_lock_timer_val(void)
+{
+       struct lpc_watchdog* wdt = LPC_WDT;
+       wdt->mode |= LPC_WDT_TIMER_VAL_PROTECT;
+}
+
+/* Change the watchdog timer value, if not protected */
+void watchdog_set_timer_val(uint32_t nb_clk)
+{
+       struct lpc_watchdog* wdt = LPC_WDT;
+
+       if (!(wdt->mode & LPC_WDT_TIMER_VAL_PROTECT)) {
+               wdt->timer_const = ((nb_clk >> 2) & LPC_WDT_TIMER_MAX);
+       }
+}
+
+/* Lock the watchdog and all related features.
+ * Calls all the other watchdog_lock_* functions (clk_src, clk_src_power, timer_val, enable).
+ */
+void watchdog_lock_full(void)
+{
+       watchdog_lock_timer_val();
+       watchdog_lock_clk_src_power();
+}
+
+/*
+ * Configure the watchdog.
+ * clk_sel is either 0 (IRC) or 1 (WDTCLK). The corresponding clock source will be powered on.
+ * Note : only WDTCLK is running in deep power down mode
+ * Note : protecting the clock source power will prevent turning off the IRC for power saving
+ *   if it is selected as main clock source.
+ */
+void watchdog_config(const struct wdt_config* wd_conf)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       struct lpc_watchdog* wdt = LPC_WDT;
+
+       NVIC_DisableIRQ(WDT_IRQ);
+       /* Power wadchdog block before changing it's configuration */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_Watchdog, 1);
+       /* Configure watchdog timeout for normal operation */
+       wdt->timer_const = ((wd_conf->nb_clk >> 2) & LPC_WDT_TIMER_MAX);
+       /* If intr_mode_only is set, a watchdog timeout will trigger an interrupt instead of a reset */
+       if (wd_conf->intr_mode_only == 1) {
+               wdt->mode = LPC_WDT_EN;
+       } else {
+               wdt->mode = LPC_WDT_EN | LPC_WDT_RESET_ON_TIMEOUT;
+       }
+       /* Register the callback for the interrupt */
+       wdt_callback = wd_conf->callback;
+       /* Power ON Watchdog clock */
+       sys_config->powerdown_run_cfg &= ~(LPC_POWER_DOWN_WDT_OSC);
+       /* Use the windows functionnality ? */
+       if (wd_conf->wdt_window > 0x100) {
+               wdt->window_compare = (wd_conf->wdt_window & LPC_WDT_TIMER_MAX);
+       } else {
+               wdt->window_compare = LPC_WDT_TIMER_MAX;
+       }
+       /* Warning interrupt ? */
+       if (wd_conf->wdt_warn != 0) {
+               if (wd_conf->wdt_warn > LPC_WDT_WARNINT_MAXVAL) {
+                       wdt->warning_int_compare = LPC_WDT_WARNINT_MAXVAL;
+               } else {
+                       wdt->warning_int_compare = wd_conf->wdt_warn;
+               }
+       }
+       /* Protect any of the watchdog functions now ? */
+       if (wd_conf->locks != 0) {
+               uint32_t mode = wdt->mode;
+               if (wd_conf->locks & WDT_CLK_POWER_LOCK) {
+                       mode |= LPC_WDT_CLK_POWER_LOCK;
+               }
+               if (wd_conf->locks & WDT_TIMER_VAL_LOCK) {
+                       mode |= LPC_WDT_TIMER_VAL_PROTECT;
+               }
+               wdt->mode = mode;
+       }
+       /* Feed sequence to validate the configuration */
+       watchdog_feed();
+       NVIC_EnableIRQ(WDT_IRQ);
+}
+
+
+/*
+ * Stop the watchdog
+ * This function can be used during system operation to stop the watchdog if it has not
+ *   been locked or protected against clock source modification, for example when entering
+ *   sleep or deep sleep.
+ * Return 0 if a solution has been found to stop the watchdog, or -1 if watchdog is still
+ *   running after this call.
+ * TODO : Check this function
+ */
+int stop_watchdog(void)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       struct lpc_watchdog* wdt = LPC_WDT;
+
+       if (wdt->mode & LPC_WDT_CLK_POWER_LOCK) {
+               return -1;
+       }
+       NVIC_DisableIRQ(WDT_IRQ);
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_Watchdog, 1);
+       sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_WDT_OSC;
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_Watchdog, 0);
+       return 0;
+}
+
+
+
+/*
+ * Disable the watchdog
+ * This function can be used upon system startup to disable watchdog operation
+ */
+void startup_watchdog_disable(void)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       struct lpc_watchdog* wdt = LPC_WDT;
+
+       /* Power wadchdog block before changing it's configuration */
+       sys_config->sys_AHB_clk_ctrl |= LPC_SYS_ABH_CLK_CTRL_Watchdog;
+       /* Stop watchdog */
+       wdt->mode = 0;
+       watchdog_feed();
+       /* And power it down */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_Watchdog, 0);
+       sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_WDT_OSC;
+       NVIC_DisableIRQ(WDT_IRQ);
+}
+
+
diff --git a/drivers/adc.c b/drivers/adc.c
new file mode 100644 (file)
index 0000000..bae9d88
--- /dev/null
@@ -0,0 +1,292 @@
+/****************************************************************************
+ *  drivers/adc.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+
+/***************************************************************************** */
+/*                Analog to Digital Converter (ADC)                            */
+/***************************************************************************** */
+
+/* ADC driver for the integrated ADC module of the LPC82x.
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+
+#include "core/system.h"
+#include "drivers/adc.h"
+
+/* ADC Clock should be as near to 30MHz as possible */
+#define adc_clk_Val  (30 * 1000 * 1000)
+
+
+
+/***************************************************************************** */
+/* Generic ADC handler */
+void (*adc_int_callback)(uint32_t) = NULL;
+void ADC_Handler(void)
+{
+       volatile struct lpc_adc* adc = LPC_ADC;
+       uint32_t flags = adc->flags;
+
+       if (adc_int_callback != NULL) {
+               adc_int_callback(flags);
+       }
+}
+void ADC_SEQA_Handler(void) __attribute__ ((alias ("ADC_Handler")));
+void ADC_SEQB_Handler(void) __attribute__ ((alias ("ADC_Handler")));
+void ADC_THCMP_Handler(void) __attribute__ ((alias ("ADC_Handler")));
+void ADC_OVR_Handler(void) __attribute__ ((alias ("ADC_Handler")));
+
+/* Read the conversion from the given channel
+ * This function reads the conversion value directly in the data register and
+ * always returns a value.
+ * Return 0 if the value is a new one and no overrun occured.
+ * Return -1 if channel does not exist
+ * Retuen 1 if the value is an old one
+ * Return 2 if an overrun occured
+ */
+int adc_get_value(uint16_t * val, unsigned int channel)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t save_reg = 0;
+
+       if (channel > NB_ADC_CHANNELS)
+               return -1;
+
+       /* Save the whole register as some bits are cleared when register is read */
+       save_reg = adc->data[channel];
+       *val = ((save_reg >> LPC_ADC_RESULT_SHIFT) & LPC_ADC_RESULT_MASK);
+       /* Has this conversion value been already read ? */
+       if (! (save_reg & LPC_ADC_CONV_DONE)) {
+               return 1;
+       }
+       if (save_reg & LPC_ADC_OVERRUN) {
+               return 2;
+       }
+       return 0;
+}
+
+/* Start a conversion on the given channel (0 to 7) */
+void adc_start_convertion_once(unsigned int channel, uint8_t seq_num, int use_int)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t reg_val = 0;
+
+       if (channel >= NB_ADC_CHANNELS) {
+               return;
+       }
+       if (seq_num >= NB_ADC_SEQUENCES) {
+               return;
+       }
+       
+       /* Set conversion channel bit */
+       reg_val = LPC_ADC_CHANNEL(channel);
+
+       /*  Use of interrupts for the specified channel ? */
+       if (use_int) {
+               /* Set interrupt Bit */
+               adc->int_en = LPC_ADC_CHANNEL(channel);
+       } else {
+               adc->int_en = 0;
+       }
+
+       /* Start conversion */
+       reg_val |= (LPC_ADC_START_CONV_NOW | LPC_ADC_SEQ_EN);
+       adc->seqctrl[seq_num] = reg_val;
+}
+
+
+/* Start burst conversions.
+ * channels is a bit mask of requested channels.
+ * Use LPC_ADC_CHANNEL(x) (x = 0 .. 7) for channels selection.
+ */
+void adc_start_burst_conversion(uint16_t channels, uint8_t seq_num)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t reg_val = 0;
+
+       if (seq_num >= NB_ADC_SEQUENCES) {
+               return;
+       }
+       
+       /* Set conversion channel bits and burst mode */
+       reg_val = (channels & LPC_ADC_CHANNEL_MASK);
+       reg_val |= LPC_ADC_BURST;
+
+       /*  Do not use of interrupts in burst mode. */
+       /* If you need to, then you should also use DMA for data transfer, and make sure your code is
+        * able to handle the load */
+       if (seq_num == LPC_ADC_SEQA) {
+               adc->int_en &= ~(LPC_ADC_SEQA_INTEN);
+       } else {
+               adc->int_en &= ~(LPC_ADC_SEQB_INTEN);
+       }
+
+       /* Start conversion */
+       adc->seqctrl[seq_num] = (reg_val | LPC_ADC_SEQ_EN);
+}
+void adc_stop_burst_conversion(uint8_t seq_num)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       if (seq_num >= NB_ADC_SEQUENCES) {
+               return;
+       }
+       adc->seqctrl[seq_num] &= ~LPC_ADC_BURST;
+}
+
+
+/* This should be used to configure conversion start on falling or rising edges of
+ * some signals, or on timer for burst conversions.
+ */
+void adc_prepare_conversion_on_event(uint16_t channels, uint8_t event, uint8_t seq_num,
+                                                                               int use_int, uint32_t mode)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t reg_val = 0;
+
+       if (seq_num >= NB_ADC_SEQUENCES) {
+               return;
+       }
+
+       /* Set conversion channel bits and burst mode */
+       reg_val |= (channels & LPC_ADC_CHANNEL_MASK);
+       /* Set conversion condition bits */
+       switch (event) {
+               case LPC_ADC_START_CONV_ADC_PINTRIG_0:
+               case LPC_ADC_START_CONV_ADC_PINTRIG_1:
+               case LPC_ADC_START_CONV_SCT0_OUT3:
+               case LPC_ADC_START_CONV_ACMP_OUT:
+               case LPC_ADC_START_CONV_ARM_TXEV:
+                       reg_val |= LPC_ADC_START_CONV_EVENT(event);
+                       break;
+               default:
+               case LPC_ADC_START_CONV_SOFT:
+                       /* Trigger = 0 : already OK */
+                       break;
+       }
+       if (mode != 0) {
+                reg_val |= (mode & LPC_ADC_ADDITIONAL_MODE_MASK);
+       }
+
+       /*  Use of interrupts for the specified channel ? */
+       if (use_int) {
+               if (seq_num == LPC_ADC_SEQA) {
+                       adc->int_en = LPC_ADC_SEQA_INTEN;
+               } else {
+                       adc->int_en = LPC_ADC_SEQB_INTEN;
+               }
+       } else {
+               adc->int_en = 0;
+       }
+
+       /* Enable conversion on selected event */
+       adc->seqctrl[seq_num] = (reg_val | LPC_ADC_SEQ_EN);
+}
+
+/* Software trigger of the given configured sequence */
+void adc_trigger_sequence_conversion(uint8_t seq_num)
+{
+       struct lpc_adc* adc = LPC_ADC;
+
+       if (seq_num >= NB_ADC_SEQUENCES) {
+               return;
+       }
+
+       adc->seqctrl[seq_num] |= (LPC_ADC_START_CONV_NOW);
+}
+
+
+/***************************************************************************** */
+/*   ADC Setup : private part : Clocks, Power and Mode   */
+
+/* When lowpower_en is not 0 the ADC low power mode is selected, which adds a 15ADC clock delay
+ * before each set of consecutive conversions (but not between consecutive conversions)
+ */
+void adc_set_low_power(int lowpower_en)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       if (lowpower_en) {
+               adc->ctrl |= LPC_ADC_LOW_POWER_EN;
+       } else {
+               adc->ctrl &= ~(LPC_ADC_LOW_POWER_EN);
+       }
+}
+
+void adc_clk_update(void)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t main_clock = get_main_clock();
+       uint32_t clkdiv = 0;
+
+       /* Configure ADC clock to get the 9MHz sample clock */
+       clkdiv = (main_clock / adc_clk_Val);
+       adc->ctrl &= ~LPC_ADC_CLK_MASK;
+       adc->ctrl |= LPC_ADC_CLK_DIV(clkdiv);
+}
+
+
+void adc_on(void (*adc_callback)(uint32_t))
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       struct lpc_adc* adc = LPC_ADC;
+
+       /* Disable ADC Interrupts */
+       NVIC_DisableIRQ(ADC_SEQA_IRQ);
+       NVIC_DisableIRQ(ADC_SEQB_IRQ);
+       NVIC_DisableIRQ(ADC_THCMP_IRQ);
+       NVIC_DisableIRQ(ADC_OVR_IRQ);
+
+       /* Power-up ADC */
+       sys_config->powerdown_run_cfg &= ~LPC_POWER_DOWN_ADC;
+       /* Provide clock to ADC */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_ADC, 1);
+       adc->ctrl = 0;
+       adc_clk_update();
+
+       /* Prevent unconfigured conversion start */
+       adc->seqctrl[0] = 0;
+       adc->seqctrl[1] = 0;
+
+       /* Remove the default global interrupt enabled setting */
+       adc->int_en = 0;
+       /* Register a possible calback */
+       adc_int_callback = adc_callback;
+
+       /* Enable ADC Interrupts */
+       NVIC_EnableIRQ(ADC_SEQA_IRQ);
+       NVIC_EnableIRQ(ADC_SEQB_IRQ);
+       NVIC_EnableIRQ(ADC_THCMP_IRQ);
+       NVIC_EnableIRQ(ADC_OVR_IRQ);
+}
+
+void adc_off(void)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+
+       /* Disable ADC Interrupts */
+       NVIC_DisableIRQ(ADC_SEQA_IRQ);
+       NVIC_DisableIRQ(ADC_SEQB_IRQ);
+       NVIC_DisableIRQ(ADC_THCMP_IRQ);
+       NVIC_DisableIRQ(ADC_OVR_IRQ);
+       /* Power Down ADC */
+       sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_ADC;
+       /* Remove clock from ADC block */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_ADC, 0);
+}
+
diff --git a/drivers/gpio.c b/drivers/gpio.c
new file mode 100644 (file)
index 0000000..0b3a8b2
--- /dev/null
@@ -0,0 +1,184 @@
+/****************************************************************************
+ *  drivers/gpio.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/***************************************************************************** */
+/*                GPIOs and GPIO Interrupts                                    */
+/***************************************************************************** */
+
+/* Driver for GPIO configuration and access (including GPIO interrupts) on the LPC82x.
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+
+
+#include "core/system.h"
+#include "core/pio.h"
+#include "drivers/gpio.h"
+#include "lib/errno.h"
+
+
+
+/***************************************************************************** */
+/*   GPIO setup   */
+
+void gpio_on(void)
+{
+       /* Provide power to GPIO control blocks */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_GPIO, 1);
+}
+void gpio_off(void)
+{
+       /* Remove power from GPIO control blocks */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_GPIO, 0);
+}
+
+/*
+ * This function calls the config_pio() function for the gpio with the given
+ * mode, configures the direction of the pin and sets the initial state.
+ */
+void config_gpio(const struct pio* gpio, uint32_t mode, uint8_t dir, uint8_t ini_val)
+{
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(0);
+
+       /* Configure as GPIO */
+       config_pio(gpio, NULL, mode);
+
+       if (dir == GPIO_DIR_IN) {
+               gpio_port->data_dir &= ~(1 << gpio->pin);
+       } else {
+               gpio_port->data_dir |= (1 << gpio->pin);
+               if (ini_val == 0) {
+                       gpio_port->clear = (1 << gpio->pin);
+               } else {
+                       gpio_port->set = (1 << gpio->pin);
+               }
+       }
+}
+
+/***************************************************************************** */
+/* GPIO Interrupts Callbacks */
+#define NB_PININT_INTERRUPTS   8
+static void (*gpio_callbacks[NB_PININT_INTERRUPTS]) (uint32_t) = {0};
+
+/* Return the pin interrupt number if OK, or a negative value in case of error */
+int set_gpio_callback(void (*callback) (uint32_t), const struct pio* gpio, uint8_t sense)
+{
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(0);
+       struct lpc_pin_int* pinint = LPC_GPIO_INTERRUPTS;
+       struct lpc_sys_config* sys_conf = LPC_SYS_CONFIG;
+       uint32_t irq = 0;
+
+       /* Register the callback */
+       if (gpio->pin >= PORT0_NB_PINS)
+               return -EINVAL;
+
+       /* Get the next available interrupt */
+       for (irq = 0; irq < NB_PININT_INTERRUPTS; irq++) {
+               if (gpio_callbacks[irq] == NULL) {
+                       gpio_callbacks[irq] = callback;
+                       break;
+               }
+       }
+       /* If not found, return. */
+       if (irq == NB_PININT_INTERRUPTS) {
+               return -1;
+       }
+
+       /* Power on the Pin interrupt subsystem */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_GPIO, 1);
+
+       /* Configure the pin as interrupt source */
+       gpio_port->data_dir &= ~(1 << gpio->pin); /* Input */
+       config_pio(gpio, NULL, 0);
+       sys_conf->pin_int_sel[irq] = gpio->pin;
+
+       /* Setup the înint as requested */
+       switch (sense) {
+               case EDGES_BOTH:
+                       pinint->mode &= ~(0x01 << irq);
+                       pinint->lvl_rising_set_en = (0x01 << irq);
+                       pinint->lvl_falling_set_en = (0x01 << irq);
+                       break;
+               case EDGE_RISING:
+                       pinint->mode &= ~(0x01 << irq);
+                       pinint->lvl_rising_set_en = (0x01 << irq);
+                       pinint->lvl_falling_clr_en = (0x01 << irq);
+                       break;
+               case EDGE_FALLING:
+                       pinint->mode &= ~(0x01 << irq);
+                       pinint->lvl_rising_clr_en = (0x01 << irq);
+                       pinint->lvl_falling_set_en = (0x01 << irq);
+                       break;
+               case LEVEL_LOW:
+                       pinint->mode |= (0x01 << irq);
+                       pinint->lvl_rising_set_en = (0x01 << irq);
+                       pinint->lvl_falling_clr_en = (0x01 << irq); /* Active low */
+                       break;
+               case LEVEL_HIGH:
+                       pinint->mode |= (0x01 << irq);
+                       pinint->lvl_rising_set_en = (0x01 << irq);
+                       pinint->lvl_falling_set_en = (0x01 << irq); /* Active high */
+                       break;
+               default: /* Not handled, do not activate the interrupt */
+                       return -EINVAL;
+       }
+       NVIC_EnableIRQ(irq + PININT0_IRQ);
+       return irq;
+}
+
+void remove_gpio_callback(unsigned int irq)
+{
+       struct lpc_pin_int* pinint = LPC_GPIO_INTERRUPTS;
+       struct lpc_sys_config* sys_conf = LPC_SYS_CONFIG;
+
+       /* Remove the handler */
+       if (irq > NB_PININT_INTERRUPTS)
+               return;
+       gpio_callbacks[irq] = NULL;
+
+       /* And disable the interrupt */
+       sys_conf->pin_int_sel[irq] = 0xFF;
+       pinint->mode &= ~(0x01 << irq);
+       pinint->lvl_rising_clr_en = (0x01 << irq);
+       pinint->lvl_falling_clr_en = (0x01 << irq);
+
+       NVIC_DisableIRQ(irq + PININT0_IRQ);
+}
+
+
+/* Interrupt Handlers */
+#define DECLARE_PIO_INT_HANDLER(x) \
+       void PININT_ ## x ## _Handler(void) \
+       { \
+               struct lpc_pin_int* pinint = LPC_GPIO_INTERRUPTS; \
+               if (gpio_callbacks[x] != NULL) { \
+                       gpio_callbacks[x](x); \
+               } \
+               pinint->status = (0x01 << x); \
+       }
+
+DECLARE_PIO_INT_HANDLER(0);
+DECLARE_PIO_INT_HANDLER(1);
+DECLARE_PIO_INT_HANDLER(2);
+DECLARE_PIO_INT_HANDLER(3);
+DECLARE_PIO_INT_HANDLER(4);
+DECLARE_PIO_INT_HANDLER(5);
+DECLARE_PIO_INT_HANDLER(6);
+DECLARE_PIO_INT_HANDLER(7);
+
diff --git a/drivers/i2c.c b/drivers/i2c.c
new file mode 100644 (file)
index 0000000..2178b1d
--- /dev/null
@@ -0,0 +1,550 @@
+/****************************************************************************
+ *   drivers/i2c.c
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+/**************************************************************************** */
+/*                      I2C                                                   */
+/**************************************************************************** */
+
+/* I2C driver for the I2C bus integrated module of the LPC82x.
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+
+#include "lib/stdint.h"
+
+#include "core/lpc_regs.h"
+#include "core/lpc_core.h"
+#include "core/system.h"
+#include "lib/string.h"
+#include "lib/errno.h"
+#include "drivers/i2c.h"
+
+
+/*
+ * I2C Bus structure
+ *
+ * clock : current i2c clock.
+ * state : global state of the i2c engine.
+ * master_status : status returned by i2c block as found in "status" register.
+ *
+ * ctrl_buf : This buffer, if used, must have the SAME size as out_buff.
+ *           Then, instead of simply moving to the next byte, the corresponding condition
+ *           will be executed : I2C_CONT, I2C_DO_REPEATED_START, I2C_DO_STOP_START or I2C_STOP.
+ */
+struct i2c_bus {
+       volatile struct lpc_i2c* regs;
+       uint8_t irq;
+       uint8_t mode;
+       uint32_t reset_bit;
+       uint32_t power_bit;
+       volatile uint32_t clock;
+       volatile uint32_t state;
+       volatile uint32_t master_status;
+       volatile uint32_t slave_status;
+
+       volatile const char* out_buff;
+       volatile const char* ctrl_buf;
+       volatile uint32_t write_length;
+       volatile uint32_t write_index;
+
+       volatile char* in_buff;
+       volatile uint32_t read_length;
+       volatile uint32_t read_index;
+};
+
+
+static struct i2c_bus i2c_buses[NB_I2C_BUSSES] = {
+       {
+               .regs = (struct lpc_i2c*)LPC_I2C0,
+               .irq = I2C0_IRQ,
+               .reset_bit = LPC_I2C0_RESET_N,
+               .power_bit = LPC_SYS_ABH_CLK_CTRL_I2C0,
+               .state = I2C_OK,
+       },
+       {
+               .regs = (struct lpc_i2c*)LPC_I2C1,
+               .irq = I2C1_IRQ,
+               .reset_bit = LPC_I2C1_RESET_N,
+               .power_bit = LPC_SYS_ABH_CLK_CTRL_I2C1,
+               .state = I2C_OK,
+       },
+       {
+               .regs = (struct lpc_i2c*)LPC_I2C2,
+               .irq = I2C2_IRQ,
+               .reset_bit = LPC_I2C2_RESET_N,
+               .power_bit = LPC_SYS_ABH_CLK_CTRL_I2C2,
+               .state = I2C_OK,
+       },
+       {
+               .regs = (struct lpc_i2c*)LPC_I2C3,
+               .irq = I2C3_IRQ,
+               .reset_bit = LPC_I2C3_RESET_N,
+               .power_bit = LPC_SYS_ABH_CLK_CTRL_I2C3,
+               .state = I2C_OK,
+       },
+};
+
+
+/* FIXME : Should add a field "what to do on addr NACK" to i2c_bus structure, and use
+   it with the timeout to create a retry mechanism */
+/* FIXME : For case 58 ... What would be the use of a restart ?? perform periodic reads ? */
+/* FIXME : Implement Slave when arbitration lost ? */
+
+
+
+/* I2C Interrupt handler */
+/* Actual version will stop on NACKs */
+/* See LPC1764 user's manual UM10360 on page 457 (19.9.5) for details on I2C State machine */
+void I2C_Handler(uint32_t bus_num)
+{
+       uint8_t status = 0;
+       uint8_t condition = I2C_CONT;
+       struct i2c_bus* i2c = &(i2c_buses[bus_num]);
+
+       /* This handler deals with master read and master write only */
+       i2c->master_status = i2c->regs->status; /* Store current status */
+       i2c->slave_status = i2c->regs->status;
+       status = (i2c->regs->status & 0xFF);
+
+       /* I2C State Machine ! */
+       switch (status) {
+
+       /* Errors */
+               case 0x00: /* Should never happen */
+                       i2c->regs->int_en_clr = I2C_ST_MASTER_PENDING;
+                       i2c->state = I2C_ERROR_UNKNOWN;
+                       break;
+
+               case 0x10:
+               case 0x11: /* Arbitration lost. We don't deal with multiple master situation */
+                       /* FIXME : We have two option :
+                        *  - do nothing, which will release the bus.
+                        *      This options allows handling of multiple master topologies.
+                        *  - Set start flag, and a start condition will be transmitted when bus becomes free.
+                        */
+                       /* We choose to do nothing. User code should retry later. */
+                       i2c->state = I2C_ARBITRATION_LOST;
+                       break;
+
+               case 0x40:
+               case 0x41: /* Start/Stop error. */
+                       /* A start or stop condition has been detected while it was not allowed by the I2C
+                        *  specification. The master interface has stoped driving the bus and is in idle state.
+                        * We have three option :
+                        *  - Do nothing.
+                        *  - Set start flag, and a start condition will be transmitted when bus becomes free.
+                        *  - Try to detect whether the I2C bus has stalled (?? how ?)
+                        */
+                       /* We choose to do nothing. User code should retry later. */
+                       i2c->state = I2C_BUS_ERROR;
+                       break;
+
+       /* NACKs */
+               case 0x07:  /* NACK on Address */
+               case 0x09:  /* NACK on Data byte */
+                       /* Send a STOP condition will end transactions and let the driver retry later. */
+                       i2c->regs->master_ctrl = I2C_MASTER_STOP;
+                       i2c->state = I2C_NACK;
+                       break;
+
+       /* Rx */
+               case 0x02:
+               case 0x03:  /* Receive ready. Data byte has been received */
+                       if (i2c->in_buff != NULL) {
+                               i2c->in_buff[i2c->read_index] = i2c->regs->master_data;
+                       }
+                       i2c->read_index++;
+                       if (i2c->read_index < i2c->read_length) {
+                               /* Send ACK (tells the slave to continue) */
+                               i2c->regs->master_ctrl = I2C_MASTER_CONTINUE;
+                       } else {
+                               /* Send a NACK (tells the slave this was the last byte)
+                                * FIXME : We have two other options : Repeated START or STOP + START,
+                                *    but what for ? periodic reads ?
+                                */
+                               i2c->regs->master_ctrl = I2C_MASTER_STOP;
+                               i2c->state = I2C_OK;
+                       }
+                       break;
+
+       /* Tx */
+               case 0x04:
+               case 0x05:  /* Transmit ready. */
+                       if (i2c->write_length <= 1) { /* Nothing more to send, we must stop. */
+                               /* This one is used to probe devices, or wait for completion */
+                               i2c->regs->master_ctrl = I2C_MASTER_STOP;
+                               i2c->state = I2C_NO_DATA;
+                               break;
+                       }
+                       
+                       if (i2c->ctrl_buf) {
+                               condition = i2c->ctrl_buf[i2c->write_index];
+                       }
+                       i2c->write_index++;
+
+                       switch (condition) {
+                               case I2C_DO_STOP_START: /* Send STOP / START condition */
+                                       i2c->regs->master_ctrl = I2C_MASTER_STOP;
+                               case I2C_DO_REPEATED_START: /* Send repeated start condition */
+                               case I2C_CONT: /* Send next data byte */
+                                       if (i2c->write_index < i2c->write_length) {
+                                               i2c->regs->master_data = i2c->out_buff[i2c->write_index];
+                                       } else {
+                                               /* We should have data to send ! Stop the controller. */
+                                               i2c->regs->master_ctrl = I2C_MASTER_STOP;
+                                               i2c->state = I2C_NO_DATA;
+                                               break;
+                                       }
+                                       if (condition == I2C_CONT) {
+                                               i2c->regs->master_ctrl = I2C_MASTER_CONTINUE;
+                                       } else {
+                                               i2c->regs->master_ctrl = I2C_MASTER_START;
+                                       }
+                                       break;
+                               case I2C_STOP: /* Send STOP condition */
+                                       i2c->regs->master_ctrl = I2C_MASTER_STOP;
+                                       i2c->state = I2C_OK;
+                                       break;
+                       }
+                       break;
+
+               default:
+                       i2c->state = I2C_ERROR_UNKNOWN;
+                       break;
+       }
+
+       /* When communication is over, disable the idle/pending interrupt */
+       if (i2c->state != I2C_BUSY) {
+               i2c->regs->int_en_clr = I2C_ST_MASTER_PENDING;
+       }
+       /* Clear interrupt flag. This has to be done last. */
+       i2c->regs->status = I2C_ST_CLEAR_ALL;
+       return;
+}
+
+
+void I2C_0_Handler(void)
+{
+       I2C_Handler(0);
+}
+void I2C_1_Handler(void)
+{
+       I2C_Handler(1);
+}
+void I2C_2_Handler(void)
+{
+       I2C_Handler(2);
+}
+void I2C_3_Handler(void)
+{
+       I2C_Handler(3);
+}
+
+
+
+/***************************************************************************** */
+/*                        I2C access                                           */
+/***************************************************************************** */
+static int i2c_perform_data_transfer(struct i2c_bus* i2c)
+{   
+       int ret = 0;
+
+       if (i2c->mode != I2C_MASTER) {
+               return -EINVAL;
+       }
+
+       /* FIXME : This test is only valid for master */
+       if ((i2c->regs->status & 0x0F) != 0x01) {
+               return -EBUSY;
+       }
+       /* Start the process */
+       i2c->state = I2C_BUSY;
+       i2c->write_index = 0;
+       i2c->read_index = 0;
+       i2c->regs->master_data = i2c->out_buff[0];
+       i2c->regs->master_ctrl = I2C_MASTER_START;
+       i2c->regs->int_en_set = (I2C_ST_MASTER_PENDING | I2C_ST_MASTER_ARB_LOSS | I2C_ST_MASTER_STERR);
+
+       /* Wait for process completion */
+       do {} while (i2c->state == I2C_BUSY); /* FIXME : OS should schedule here */
+
+       /* Handle returned state (errors or OK) */
+       switch (i2c->state) {
+               case I2C_OK:
+               case I2C_NO_DATA:
+                       /* Return 0 : success */
+                       break;
+               case I2C_NACK:
+                       ret = -EREMOTEIO;
+                       break;
+               case I2C_ARBITRATION_LOST:
+                       ret = -EBUSY;
+                       break;
+               case I2C_BUS_ERROR: /* This one is bad ... */
+               case I2C_ERROR_UNKNOWN:
+               default:
+                       ret = -EIO;
+                       break;
+       }
+
+       /* Force device to release the bus :
+        *    send a START followed by a STOP (initiate transmission with nul write_length) */
+       i2c->state = I2C_BUSY;
+       i2c->write_length = 0;
+       i2c->regs->master_data = 0;
+       i2c->regs->master_ctrl = I2C_MASTER_START;
+       i2c->regs->int_en_set = I2C_ST_MASTER_PENDING;
+       do {} while (i2c->state == I2C_BUSY); /* FIXME : OS should schedule here */
+       i2c->state = I2C_OK;
+       
+       /* Done with the Bus, Disable the interrupts */ 
+       i2c->regs->int_en_clr = (I2C_ST_MASTER_PENDING | I2C_ST_MASTER_ARB_LOSS | I2C_ST_MASTER_STERR);
+
+       return ret;
+}
+
+/* Read
+ * Performs a non-blocking read on the module's i2c bus.
+ *   bus_num : I2C bus number to use.
+ *   cmd_buf : buffer containing all control byte to be sent on the i2c bus
+ *   cmd_size : size of the cmd_buf command buffer
+ *   ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
+ *         if not NULL, ctrl_buf has the same size as cmd_buf
+ *   inbuff : the buffer where read data will be put. May be NULL if count is 0.
+ *   count : the number of bytes to be read.
+ * RETURN VALUE
+ *   Upon successfull completion, returns the number of bytes read. On error, returns a negative
+ *   integer equivalent to errors from glibc.
+ *   -EBADFD : Device not initialized (-77)
+ *   -EBUSY : Device or ressource Busy or Arbitration lost (-16)
+ *   -EAGAIN : Device already in use (-11)
+ *   -EINVAL : Invalid argument (no cmd_buf, or no inbuff when count > 0) (-22)
+ *   -EREMOTEIO : Device did not acknowledge (-121)
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine (-5)
+ */
+int i2c_read(uint8_t bus_num, const void *cmd_buf, size_t cmd_size, const void* ctrl_buf, void* inbuff, size_t count)
+{
+       int ret = 0;
+       struct i2c_bus* i2c = NULL;
+
+       if (bus_num >= NB_I2C_BUSSES) {
+               return -EINVAL;
+       }
+       i2c = &(i2c_buses[bus_num]);
+
+       /* Checks */
+       if (i2c->clock == 0)
+               return -EBADFD;
+       if (cmd_buf == NULL)
+               return -EINVAL;
+       if ((inbuff == NULL) && (count > 0))
+               return -EINVAL;
+
+       if (i2c->state == I2C_BUSY) {
+               return -EBUSY;
+       }
+       if (i2c->state != I2C_OK) {
+               /* What should we do ??? someone failed to reset status ? */
+       }
+
+       /* Set up i2c for read operation */
+       /* command (write) buffer */
+       i2c->out_buff = cmd_buf;
+       i2c->write_length = cmd_size;
+       /* Control buffer, if any.
+        * Used to control operations on i2C bus to simplify the interface */
+       i2c->ctrl_buf = ctrl_buf;
+       /* Read buffer */
+       i2c->in_buff = inbuff;
+       i2c->read_length = count;
+       i2c->read_index = 0;
+
+       ret = i2c_perform_data_transfer(i2c);
+       if (ret == 0) {
+               return i2c->read_index;
+       }
+       return ret;
+}
+
+/* Write
+ * Performs a non-blocking write on the module's i2c bus.
+ *   bus_num : I2C bus number to use.
+ *   buf : buffer containing all byte to be sent on the i2c bus,
+ *         including conrtol bytes (address, offsets, ...)
+ *   count : the number of bytes to be sent, including address bytes and so on.
+ *   ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
+ *         FIXME : note that STOP + START conditions are not allowed, the STOP would lead to sending
+ *         the first bytes of buf, creating an infinite loop.
+ * RETURN VALUE
+ *   Upon successfull completion, returns the number of bytes written. On error, returns a negative
+ *   integer equivalent to errors from glibc.
+ *   -EBADFD : Device not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EAGAIN : Device already in use
+ *   -EINVAL : Invalid argument (buf)
+ *   -EREMOTEIO : Device did not acknowledge
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+int i2c_write(uint8_t bus_num, const void *buf, size_t count, const void* ctrl_buf)
+{
+       int ret = 0;
+       struct i2c_bus* i2c = NULL;
+
+       if (bus_num >= NB_I2C_BUSSES) {
+               return -EINVAL;
+       }
+       i2c = &(i2c_buses[bus_num]);
+
+       /* Checks */
+       if (i2c->clock == 0)
+               return -EBADFD;
+       if (buf == NULL)
+               return -EINVAL;
+
+       if (i2c->state == I2C_BUSY) {
+               return -EBUSY;
+       }
+       if (i2c->state != I2C_OK) {
+               /* What should we do ??? someone failed to reset status ? */
+       }
+
+       /* Clear read information to prevent entering master receiver states */
+       i2c->read_length = 0;
+       i2c->in_buff = NULL;
+       /* Set up i2c for write operation */
+       i2c->out_buff = buf;
+       i2c->write_length = count;
+       /* Control buffer, if any.
+        * Used to control operations on i2C bus to simplify the interface */
+       i2c->ctrl_buf = ctrl_buf;
+
+       ret = i2c_perform_data_transfer(i2c);
+       if (ret == 0) {
+               return count;
+       }
+       return ret;
+}
+
+
+int i2c_set_timeout(uint8_t bus_num, uint16_t timeout)
+{
+       struct i2c_bus* i2c = NULL;
+
+       if (bus_num >= NB_I2C_BUSSES) {
+               return -EINVAL;
+       }
+       i2c = &(i2c_buses[bus_num]);
+       i2c->regs->timeout = timeout;
+
+       return 0;
+}
+
+/***************************************************************************** */
+/*                I2C Init                                                     */
+/***************************************************************************** */
+
+static void i2c_clock_on(struct i2c_bus* i2c)
+{
+       uint32_t main_clock = get_main_clock();
+       uint32_t scl_div = 0;
+
+       /* Setup I2C clock */
+       scl_div = (main_clock / (i2c->clock * 4));  /* Two clocks low and two clocks high -> divide by 4 */
+       i2c->regs->clkdiv = (scl_div - 1);
+       i2c->regs->master_timing = 0; /* Two clocks low and two clocks high */
+}
+
+/* I2C on / off
+ *   bus_num : I2C bus number to use.
+ *   i2c_clk_freq : I2C clock freqeuncy in Hz
+ *   mode is one of I2C_MASTER, I2C_SLAVE or I2C_MONITOR.
+ */
+int i2c_on(uint8_t bus_num, uint32_t i2c_clk_freq, uint8_t mode)
+{
+       struct i2c_bus* i2c = NULL;
+
+       if (bus_num >= NB_I2C_BUSSES) {
+               return -EINVAL;
+       }
+       i2c = &(i2c_buses[bus_num]);
+
+       NVIC_DisableIRQ(i2c->irq);
+       /* Power on I2C block */
+       subsystem_power(i2c->power_bit, 1);
+       subsystem_reset(i2c->reset_bit);
+       /* Set clock */
+       i2c->clock = i2c_clk_freq;
+       i2c_clock_on(i2c);
+       /* Disable all interrupt condition */
+       i2c->regs->int_en_clr = ~(0UL);
+       i2c->mode = mode;
+       /* Enable I2C */
+       switch (mode) {
+               case I2C_MASTER:
+                       i2c->regs->config = I2C_MASTER_EN;
+                       break;
+               case I2C_SLAVE:
+                       i2c->regs->config = I2C_SLAVE_EN;
+                       break;
+               case I2C_MONITOR:
+               default:
+                       i2c->regs->config = I2C_MONITOR_EN;
+                       break;
+       }
+       /* And enable interrupts */
+       NVIC_EnableIRQ(i2c->irq);
+
+       return 0;
+}
+
+int i2c_off(uint8_t bus_num)
+{
+       struct i2c_bus* i2c = NULL;
+
+       if (bus_num >= NB_I2C_BUSSES) {
+               return -EINVAL;
+       }
+       i2c = &(i2c_buses[bus_num]);
+
+       NVIC_DisableIRQ(i2c->irq);
+       subsystem_power(i2c->power_bit, 0);
+       i2c->clock = 0;
+
+       return 0;
+}
+
+/* Allow system to propagate main clock */
+void i2c_clock_update(void)
+{
+       int i = 0;
+
+       for (i = 0; i < NB_I2C_BUSSES; i++) {
+               if (! subsystem_powered(i2c_buses[i].power_bit)) {
+                       continue;
+               }
+               if (i2c_buses[i].clock != 0) {
+               /* FIXME : we should stop I2C transfers, disable I2C interrupts and stop I2C clock. */
+                       i2c_clock_on(&(i2c_buses[i]));
+               }
+       }
+}
+
diff --git a/drivers/serial.c b/drivers/serial.c
new file mode 100644 (file)
index 0000000..ecc6bbe
--- /dev/null
@@ -0,0 +1,451 @@
+/****************************************************************************
+ *  drivers/serial.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+
+/***************************************************************************** */
+/*                UARTs                                                        */
+/***************************************************************************** */
+/* UART driver for the integrated UARTs of the LPC82x.
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+
+/* All three UARTs are available, UART numbers are in the range 0 - 2 */
+
+#include "core/system.h"
+#include "core/pio.h"
+#include "lib/string.h"
+#include "lib/utils.h"
+#include "lib/errno.h"
+#include "drivers/serial.h"
+
+
+struct uart_device
+{
+       struct lpc_usart* regs;
+       uint32_t baudrate;
+       uint32_t config;
+       uint8_t num;
+       uint8_t capabilities;
+       uint8_t current_mode;
+
+       /* Output buffer */
+       volatile char out_buff[SERIAL_OUT_BUFF_SIZE];
+       volatile uint32_t sending; /* Actual sending position in out buffer */
+       /* This lock only prevents multiple calls to serial_write() to execute simultaneously */
+       volatile uint32_t out_lock;
+       volatile uint32_t out_length; /* actual position to add in out buffer */
+
+       /* Input */
+       void (*rx_callback)(uint8_t); /* Possible RX callback */
+};
+
+#define NUM_UARTS 3
+static struct uart_device uarts[NUM_UARTS] = {
+       {
+               .num = 0,
+               .regs = (struct lpc_usart*)LPC_UART_0,
+               .baudrate = 0,
+               .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
+               .out_buff = {0},
+               .sending = 0,
+               .out_lock = 0,
+               .rx_callback = NULL,
+               .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_RS485),
+               .current_mode = SERIAL_MODE_UART,
+       },
+       {
+               .num = 1,
+               .regs = (struct lpc_usart*)LPC_UART_1,
+               .baudrate = 0,
+               .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
+               .out_buff = {0},
+               .sending = 0,
+               .out_lock = 0,
+               .rx_callback = NULL,
+               .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_RS485),
+               .current_mode = SERIAL_MODE_UART,
+       },
+       {
+               .num = 2,
+               .regs = (struct lpc_usart*)LPC_UART_2,
+               .baudrate = 0,
+               .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
+               .out_buff = {0},
+               .sending = 0,
+               .out_lock = 0,
+               .rx_callback = NULL,
+               .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_RS485),
+               .current_mode = SERIAL_MODE_UART,
+       },
+};
+
+static void uart_check_rx(struct uart_device* uart, uint32_t intr)
+{
+       if (intr & LPC_UART_ST_RX_READY) {
+               uint8_t data = uart->regs->rx_data;
+               if (uart->rx_callback != NULL) {
+                       /* Call the Rx callback */
+                       uart->rx_callback(data);
+               } else {
+                       /* Echo */
+                       uart->regs->tx_data = data;
+               }
+       }
+       /* FIXME : handle erors */
+}
+
+static void uart_check_tx(struct uart_device* uart, uint32_t intr)
+{
+       /* We are currently sending, send next char */
+       if (intr & LPC_UART_ST_TX_READY) {
+               if (uart->out_buff && uart->sending && (uart->out_length > uart->sending)) {
+                       uart->regs->tx_data = uart->out_buff[uart->sending];
+                       uart->sending++;
+               } else {
+                       uart->sending = 0;
+                       uart->regs->inten_clear = LPC_UART_ST_TX_READY;
+               }
+       }
+}
+
+/* Generic UART handler */
+static void UART_Handler(struct uart_device* uart)
+{
+       uint32_t intr = uart->regs->status;
+
+       uart_check_rx(uart, intr);
+       uart_check_tx(uart, intr);
+       /* Clear all flags */
+       uart->regs->status = LPC_UART_ST_CLEAR;
+}
+
+
+/* Handlers */
+void UART_0_Handler(void)
+{
+       UART_Handler(&uarts[0]);
+}
+void UART_1_Handler(void)
+{
+       UART_Handler(&uarts[1]);
+}
+void UART_2_Handler(void)
+{
+       UART_Handler(&uarts[2]);
+}
+
+
+/* Start sending buffer content */
+static void uart_start_sending(uint32_t uart_num)
+{
+       struct uart_device* uart = &uarts[uart_num];
+
+       if (!uart->sending && (uart->out_length != 0)) {
+               uart->sending++;
+               uart->regs->tx_data = uart->out_buff[0];
+               /* Activate only LPC_UART_ST_TX_READY in order to prevent multiple calls to
+                * the interrupt handler, which will cause data loss */
+               uart->regs->inten_set = (LPC_UART_ST_TX_READY);
+       }
+}
+
+
+/****************************************************************************** */
+/*    Serial send byte - quick function with almost no tests.
+ * If the uart is not sending, the byte is placed directly in the data buffer and
+ * the call returns 0.
+ * Else, the call returns -EBUSY and nothing is sent.
+ */
+int serial_send_quickbyte(uint32_t uart_num, uint8_t data)
+{
+       struct uart_device* uart = &uarts[uart_num];
+       if (!uart->sending) {
+               uart->regs->tx_data = data;
+               return 0;
+       } else {
+               return -EBUSY;
+       }
+}
+
+/***************************************************************************** */
+/*    Serial Write
+ *
+ * Try to send at most "length" characters from "buf" on the requested uart.
+ * Returns a negative value on error, or number of characters copied into output buffer,
+ * witch may be less than requested "length"
+ * Possible errors: requested uart does not exists (-EINVAL) or unable to acquire uart
+ * lock (-EBUSY).
+ *
+ * Warning for Real Time : This implementation will block if there's already a
+ * transmission ongoing.
+ */
+int serial_write(uint32_t uart_num, const char *buf, uint32_t length)
+{
+       struct uart_device* uart = NULL;
+
+       if (uart_num >= NUM_UARTS)
+               return -EINVAL;
+
+       uart = &uarts[uart_num];
+       /* Lock acquire */
+       if (sync_lock_test_and_set(&uart->out_lock, 1) == 1) {
+               return -EBUSY;
+       }
+
+       /* If UART is sending wait for buffer empty */
+       /* FIXME : be smart for OS, call scheduler or return */
+       while (uart->sending != 0) {
+               /* If interrupt are masked, check for tx ourselves */
+               if (get_priority_mask() != 0) {
+                       uart_check_tx(uart, uart->regs->status);
+               }
+       }
+
+       if (length > SERIAL_OUT_BUFF_SIZE) {
+               length = SERIAL_OUT_BUFF_SIZE;
+       }
+       memcpy((char*)uart->out_buff, buf, length);
+       uart->out_length = length;
+
+       /* Turn output on */
+       uart_start_sending(uart_num);
+
+       /* Release the lock */
+       sync_lock_release(&uart->out_lock);
+
+       return length;
+}
+
+
+/***************************************************************************** */
+/*    Serial Flush
+ *
+ * Wait until all characters have been sent
+ * Returns -EINVAL on error, 0 on success.
+ * Possible errors: requested uart does not exists or unable to acquire uart lock.
+ *
+ * Warning for Real Time : This implementation will block if there's already a
+ * transmission ongoing.
+ */
+int serial_flush(uint32_t uart_num)
+{
+       struct uart_device* uart = NULL;
+
+       if (uart_num >= NUM_UARTS)
+               return -EINVAL;
+
+       uart = &uarts[uart_num];
+
+       /* Active wait for message to be sent. If interrupts are
+        * disabled, call the UART handler while waiting. */
+       while (uart->sending) {
+               if (get_priority_mask() == 0) {
+                       uart_check_tx(uart, uart->regs->status);
+               }
+       }
+
+       return 0;
+}
+
+
+/***************************************************************************** */
+/*   UART Setup : private part : Clocks, Pins, Power and Mode   */
+
+/* UART Clock Setup */
+/* Note : for all uarts we use full peripheral clock.
+ * The common uart clock is the main_clock divided by UARTCLKDIV (which we set to 1)
+ * The uart pclk (U_PCLK) is common uart clock divided by (1 + mult/div)
+ *   - Documentation states that div must be 256 (uart_common_fclk_div = 0xFF)
+ *   - In order to get the closest value for 115200 bauds, the mult value is 22, which
+ *     provides a 11050360 Hz clock with a 12Mhz system clock (ideal value would be
+ *     11059200 Hz). Then the uart specific baud rate generator divisor can be set to 6
+ *     (BRGVAL = 5) in order to get the 1843200 Hz clock which is 16x the 115200 baud
+ *     rate (oversampling of 16).
+ *     Depending on the main clock frequency, other values can be achieved by selecting
+ *     the right baud rate generator divisor (BRGVAL).
+ *   - In order to get the closest value for 1500000 bauds (1.5Mbauds) the mult value
+*      should be 128 and the main clock set to 36MHz, which gives a 24MHz uart pclk.
+ *     A baud rate generator divisor of 1 (BRGVAL = 0) would then provide a 1.5MHz baudrate
+ *     with 16x oversampling.
+ */
+enum uart_speed_types {
+       LPC_UART_CLK_NONE,
+       LPC_UART_CLK_COMMON,
+       LPC_UART_CLK_HIGH_SPEED,
+};
+static uint8_t uart_speed_type = LPC_UART_CLK_NONE;
+static int uart_clk_on(uint32_t uart_num, uint32_t baudrate)
+{
+       struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
+       struct lpc_usart* uart_regs = uarts[uart_num].regs; /* Get the right registers */
+       uint32_t div = 0;
+       /* clk_mult is the 12MHz multiplier which gives the main clock freq */
+       uint8_t clk_mult = (get_main_clock() / (12 * 1000 * 1000));
+
+       /* Save baudrate value */
+       uarts[uart_num].baudrate = baudrate;
+
+       /* Configure common UART clock */
+       sys_config->uart_clk_div = 0x01; /* Do not divide peripheral clock for uarts */
+       sys_config->uart_common_fclk_div = 0xFF; /* divider value must be 256 */
+       if (baudrate <= 230400) {
+               if (uart_speed_type == LPC_UART_CLK_HIGH_SPEED) {
+                       return -1;
+               }
+               sys_config->uart_common_fclk_mult = 22; /* Closest value to get 115200 baudrate */
+               /* Get the divider value */
+               div = (691200 * clk_mult) / baudrate; /* 691200 is (11059200 / 16) */
+               uart_regs->baudrate_gen = (div - 1);
+               uart_speed_type = LPC_UART_CLK_COMMON;
+       } else {
+               if (uart_speed_type == LPC_UART_CLK_COMMON) {
+                       return -EINVAL;
+               }
+               sys_config->uart_common_fclk_mult = 128; /* Value to get 1500000 baudrate */
+               uart_speed_type = LPC_UART_CLK_HIGH_SPEED;
+               uart_regs->baudrate_gen = 0;
+       }
+       return 0;
+}
+static void uart_clk_off(uint32_t uart_num)
+{
+       /* Erase saved baudrate */
+       uarts[uart_num].baudrate = 0;
+}
+
+static void uart_setup(uint32_t uart_num)
+{
+       struct lpc_usart* uart_regs = uarts[uart_num].regs; /* Get the right registers */
+       /* Set up UART mode */
+       uart_regs->config = (uarts[uart_num].config | LPC_UART_ENABLE);
+       uart_regs->control = 0;
+       /* Clear the Status Register */
+       uart_regs->status = LPC_UART_ST_CLEAR;
+       /* Enable UART Interrupt */
+       uart_regs->inten_set = LPC_UART_ST_RX_READY;
+}
+
+/* Change UART configuration (number of data, parity and stop bits).
+ * config is usually a mask of LPC_UART_xBIT (x = 5..8), LPC_UART_xSTOP (x = 1..2)
+ *   and one of LPC_UART_NO_PAR, LPC_UART_ODD_PAR or LPC_UART_EVEN_PAR.
+ */
+int uart_set_config(uint8_t uart_num, uint32_t config)
+{
+       struct uart_device* uart = NULL;
+
+       if (uart_num >= NUM_UARTS)
+               return -EINVAL;
+       uart = &uarts[uart_num];
+       uart->config = config;
+       return 0;
+}
+
+struct uart_def
+{
+       uint32_t irq;
+       uint32_t power_offset;
+};
+static struct uart_def uart_defs[NUM_UARTS] = {
+       { UART0_IRQ, LPC_SYS_ABH_CLK_CTRL_UART0 },
+       { UART1_IRQ, LPC_SYS_ABH_CLK_CTRL_UART1 },
+       { UART2_IRQ, LPC_SYS_ABH_CLK_CTRL_UART2 },
+};
+
+/***************************************************************************** */
+/*   Public access to UART setup   */
+
+/* Allow any change to the main clock to be forwarded to us */
+void uart_clk_update(void)
+{
+       int i = 0;
+       for (i = 0; i < NUM_UARTS; i++) {
+               if (uarts[i].baudrate != 0) {
+                       uart_clk_on(i, uarts[i].baudrate);
+               }
+       }
+}
+
+/* Change uart mode to RS485
+ * return -ENODEV when the device does not support RS485 mode.
+ */
+int uart_set_mode_rs485(uint32_t uart_num, uint32_t control, uint8_t addr, uint8_t delay)
+{
+       struct uart_device* uart = NULL;
+       struct lpc_usart* uart_regs = NULL;
+       if (uart_num >= NUM_UARTS)
+               return -EINVAL;
+       uart = &uarts[uart_num];
+       uart_regs = uart->regs; /* Get the right registers */
+
+       if (!(uart->capabilities & SERIAL_CAP_RS485)) {
+               return -ENODEV;
+       }
+
+       /* Set current mode */
+       uart->current_mode = SERIAL_MODE_RS485;
+       uart_regs->config = 0; /* FIXME */
+       uart_regs->control = 0; /* FIXME */
+       uart_regs->address = LPC_RS485_ADDR(addr);
+       return 0;
+}
+
+
+/* Do we need to allow setting of other parameters ? (Other than 8n1) */
+int uart_on(uint32_t uart_num, uint32_t baudrate, void (*rx_callback)(uint8_t))
+{
+       struct uart_def* uartdef = NULL;
+       uint32_t status = 0;
+
+       if (uart_num >= NUM_UARTS)
+               return -EINVAL;
+       uartdef = &uart_defs[uart_num];
+       uarts[uart_num].rx_callback = rx_callback;
+
+       NVIC_DisableIRQ( uartdef->irq );
+       /* Turn On power */
+       subsystem_power(uartdef->power_offset, 1);
+       /* Setup clock acording to baudrate */
+       status = uart_clk_on(uart_num, baudrate);
+       /* Setup */
+       uart_setup(uart_num);
+       /* Enable interrupts back on */
+       NVIC_EnableIRQ( uartdef->irq );
+
+       return status;
+}
+
+void uart_off(uint32_t uart_num)
+{
+       struct uart_def* uartdef = NULL;
+       if (uart_num >= NUM_UARTS)
+               return;
+       uartdef = &uart_defs[uart_num];
+
+       NVIC_DisableIRQ( uartdef->irq );
+       uart_clk_off(uart_num);
+       /* Turn Off power */
+       subsystem_power(uartdef->power_offset, 0);
+       uarts[uart_num].rx_callback = NULL;
+       uarts[uart_num].regs->config = 0;
+}
+
+
+
diff --git a/extdrv/tmp101_temp_sensor.c b/extdrv/tmp101_temp_sensor.c
new file mode 100644 (file)
index 0000000..81af7f5
--- /dev/null
@@ -0,0 +1,191 @@
+/****************************************************************************
+ *   extdrv/tmp101_temp_sensor.c
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include "lib/stdint.h"
+
+#include "core/lpc_core.h"
+#include "core/system.h"
+#include "lib/errno.h"
+#include "drivers/i2c.h"
+#include "extdrv/tmp101_temp_sensor.h"
+
+
+/***************************************************************************** */
+/*          Support for TMP101 temperature sensors from Texas Instrument       */
+/***************************************************************************** */
+/* This driver is made for the TMP101 version of the chip, though there's few
+ * diferences between the TMP100 and TMP101 version.
+ * This driver does not handle the SMBus Alert command.
+ */
+
+
+enum tmp10x_internal_reg_numbers {
+       TMP_REG_TEMPERATURE = 0,
+       TMP_REG_CONFIG,
+       TMP_REG_ALERT_LOW,
+       TMP_REG_ALERT_HIGH,
+};
+
+
+/* Aditional defines, not exported to userspace */
+/* Mode config */
+#define TMP_SHUTDOWN_MODE_ON            (1 << 0)
+#define TMP_THERMOSTAT_COMPARATOR_MODE  (0 << 1)
+#define TMP_THERMOSTAT_INTERRUPT_MODE   (1 << 1)
+/* Alert signal polarity */
+#define TMP_ALERT_POLARITY_LOW          (0 << 2)
+#define TMP_ALERT_POLARITY_HIGH         (1 << 2)
+/* One-shot measurement trigger */
+#define TMP_ONE_SHOT_TRIGGER            (1 << 7)
+
+
+
+/* Check the sensor presence, return 1 if sensor was found.
+ * This is a basic check, it could be anything with the same address ...
+ * addr : the sensor address on most significant bits.
+ */
+int tmp101_probe_sensor(struct tmp101_sensor_config* conf)
+{
+       char cmd_buf = (conf->addr | I2C_READ_BIT);
+
+       /* Did we already probe the sensor ? */
+       if (conf->probe_ok != 1) {
+               conf->probe_ok = i2c_read(conf->bus_num, &cmd_buf, 1, NULL, NULL, 0);
+       }
+       return conf->probe_ok;
+}
+
+/* Convert raw temperature data (expressed as signed value of 16 times the
+ * actual temperature in the twelve higher bits of a sixteen bits wide value)
+ * into a decimal integer value of ten times the actual temperature.
+ * The value returned is thus in tenth of degrees centigrade.
+ */
+int tmp101_convert_to_deci_degrees(uint16_t raw)
+{
+       return (((int16_t)raw * 10) >> 8);
+}
+
+/* Temp Read
+ * Performs a non-blocking read of the temperature from the sensor.
+ * 'raw' and 'deci_degrees' : integer addresses for conversion result, may be NULL.
+ * Return value(s):
+ *   Upon successfull completion, returns 0 and the temperature read is placed in the
+ *   provided integers. On error, returns a negative integer equivalent to errors from glibc.
+ *   -EBADFD : I2C not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EINVAL : Invalid argument (buf)
+ *   -ENODEV : No such device
+ *   -EREMOTEIO : Device did not acknowledge : Any device present ?
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+#define CMD_BUF_SIZE 3
+int tmp101_sensor_read(struct tmp101_sensor_config* conf, uint16_t* raw, int* deci_degrees)
+{
+       int ret = 0;
+       uint16_t temp = 0;
+       char cmd_buf[CMD_BUF_SIZE] = { conf->addr, TMP_REG_TEMPERATURE, (conf->addr | I2C_READ_BIT), };
+       char ctrl_buf[CMD_BUF_SIZE] = { I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
+
+       if (tmp101_probe_sensor(conf) != 1) {
+               return -ENODEV;
+       }
+
+       /* Read the requested data */
+       if (conf->last_accessed_register == TMP_REG_TEMPERATURE) {
+               /* No need to switch back to temperature register */
+               ret = i2c_read(conf->bus_num, (cmd_buf + 2), 1, (ctrl_buf + 2), (char*)&temp, 2);
+       } else {
+               /* Send (write) temperature register address to TMP101 internal pointer */
+               ret = i2c_read(conf->bus_num, cmd_buf, CMD_BUF_SIZE, ctrl_buf, (char*)&temp, 2);
+               conf->last_accessed_register = TMP_REG_TEMPERATURE;
+       }
+
+       if (ret == 2) {
+               if (raw != NULL) {
+                       *raw = byte_swap_16(temp);
+               }
+               if (deci_degrees != NULL) {
+                       *deci_degrees = tmp101_convert_to_deci_degrees(byte_swap_16(temp));
+               }
+               return 0;
+       }
+       return ret;
+}
+
+
+/* Sensor config
+ * Performs default configuration of the temperature sensor.
+ * The sensor is thus placed in shutdown mode, the thermostat is in interrupt mode,
+ * and the polarity is set to active high.
+ * Return value :
+ *   Upon successfull completion, returns 0. On error, returns a negative integer
+ *   equivalent to errors from glibc.
+ *   -EBADFD : I2C not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EINVAL : Invalid argument (buf)
+ *   -ENODEV : No such device
+ *   -EREMOTEIO : Device did not acknowledge : Any device present ?
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+#define CONF_BUF_SIZE 4
+int tmp101_sensor_config(struct tmp101_sensor_config* conf)
+{
+       int ret = 0;
+       char cmd[CONF_BUF_SIZE] = { conf->addr, TMP_REG_CONFIG, };
+
+       if (tmp101_probe_sensor(conf) != 1) {
+               return -ENODEV;
+       }
+
+       /* Store the new configuration */
+       conf->actual_config = (TMP_SHUTDOWN_MODE_ON | TMP_THERMOSTAT_INTERRUPT_MODE | TMP_ALERT_POLARITY_HIGH);
+       conf->actual_config |= (conf->resolution & (0x03 << 5));
+       cmd[2] = conf->actual_config;
+       ret = i2c_write(conf->bus_num, cmd, 3, NULL);
+       conf->last_accessed_register = TMP_REG_CONFIG;
+       if (ret == 3) {
+               return 0; /* Config success */
+       }
+       return ret;
+}
+
+/* Start a conversion when the sensor is in shutdown mode. */
+int tmp101_sensor_start_conversion(struct tmp101_sensor_config* conf)
+{
+       int ret = 0;
+       char cmd[CONF_BUF_SIZE] = { conf->addr, TMP_REG_CONFIG, };
+
+       if (tmp101_probe_sensor(conf) != 1) {
+               return -ENODEV;
+       }
+
+       cmd[2] = conf->actual_config;
+       cmd[2] |= TMP_ONE_SHOT_TRIGGER;
+       ret = i2c_write(conf->bus_num, cmd, 3, NULL);
+       conf->last_accessed_register = TMP_REG_CONFIG;
+       if (ret == 3) {
+               return 0; /* Conversion start success */
+       }
+       return ret;
+}
+
+
diff --git a/extdrv/ws2812.c b/extdrv/ws2812.c
new file mode 100644 (file)
index 0000000..2f1f4f0
--- /dev/null
@@ -0,0 +1,179 @@
+/****************************************************************************
+ *   extdrv/ws2812.c
+ *
+ *
+ * Copyright 2013 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/*
+ * Support for the WS2812 Chainable RGB Leds
+ *
+ * WS2812 protocol can be found here : https://www.adafruit.com/datasheets/WS2812.pdf
+ *
+ */
+
+#include "lib/stdint.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "drivers/gpio.h"
+#include "lib/string.h"
+#include "extdrv/ws2812.h"
+
+
+static struct pio ws2812_gpio = LPC_GPIO_0_0;
+
+/* Configure Selected GPIO as output. */
+void ws2812_config(const struct pio* gpio)
+{
+       struct pin_matrix_entry mat = LPC_GPIO;
+       config_pio(gpio, &mat, LPC_IO_MODE_PULL_UP);
+       pio_copy(&ws2812_gpio, gpio);
+       gpio_dir_out(ws2812_gpio);
+}
+
+static uint8_t led_data[NB_LEDS * 3];
+static uint16_t max_led = 0;
+static uint32_t nb_bytes = 0;
+
+
+static void ws2812_bit_sender(void)
+{
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(ws2812_gpio.port);
+       uint32_t gpio_bit = (1 << ws2812_gpio.pin);
+       uint32_t byte_idx = 0;
+       uint8_t bit_idx = 7;
+       uint8_t bit = 0;
+
+       lpc_disable_irq();
+
+       /* Send data */
+       while (byte_idx < nb_bytes) {
+               bit = (led_data[byte_idx] & (0x01 << bit_idx));
+
+               if (bit == 0) {
+                       /* "high" time : 350ns */
+                       gpio_port->set = gpio_bit;
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       /* "low" time : 800ns */
+                       gpio_port->clear = gpio_bit;
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+               } else {
+                       /* "high" time : 700ns */
+                       gpio_port->set = gpio_bit;
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       nop();
+                       /* "high" time : 600ns */
+                       gpio_port->clear = gpio_bit;
+                       nop();
+                       nop();
+               }
+
+               /* Move to the next bit */
+               if (bit_idx == 0) {
+                       bit_idx = 7;
+                       byte_idx++;
+               } else {
+                       bit_idx--;
+               }
+       }
+
+       lpc_enable_irq();
+}
+
+/* Send led data from internal buffer (set leds to the selected color).
+ * If nb_leds is 0 then all led data set using ws2812_set_pixel() since the last call
+ *   to ws2812_clear_buffer(), ws2812_clear() or ws2812_stop() will be sent.
+ * Call to this function will disable interrupts due to timming restrictions during
+ *   the call to ws2812_bit_sender().
+ */
+int ws2812_send_frame(uint16_t nb_leds)
+{
+       if (nb_leds > NB_LEDS) {
+               return -1;
+       }
+       if (nb_leds == 0) {
+               nb_leds = max_led;
+       }
+       nb_bytes = (nb_leds + 1) * 3;
+       ws2812_bit_sender();
+       /* Reset delay */
+       usleep(60);
+       return 0;
+}
+
+/* Set a pixel (led) color in the data buffer */
+int ws2812_set_pixel(uint16_t pixel_num, uint8_t red, uint8_t green, uint8_t blue)
+{
+       if (pixel_num >= NB_LEDS) {
+               return -1;
+       }
+       led_data[ ((pixel_num * 3) + 0) ] = green;
+       led_data[ ((pixel_num * 3) + 1) ] = red;
+       led_data[ ((pixel_num * 3) + 2) ] = blue;
+       if (max_led < pixel_num) {
+               max_led = pixel_num;
+       }
+       return 0;
+}
+
+/* Clear the internal data buffer. */
+void ws2812_clear_buffer(void)
+{
+       memset(led_data, 0, (NB_LEDS * 3));
+       max_led = 0;
+}
+
+/* Clear the internal data buffer and send it to the Leds, turning them all off */
+void ws2812_clear(void)
+{
+       /* Start at first led and send all leds off */
+       ws2812_clear_buffer();
+       ws2812_send_frame(NB_LEDS);
+       max_led = 0;
+}
+
+void ws2812_stop(void) __attribute__ ((alias ("ws2812_clear")));
+
diff --git a/include/core/iap.h b/include/core/iap.h
new file mode 100644 (file)
index 0000000..69d39c7
--- /dev/null
@@ -0,0 +1,87 @@
+/****************************************************************************
+ *   core/iap.h
+ *
+ * Copyright 2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef CORE_IAP_H
+#define CORE_IAP_H
+
+#include "lib/stdint.h"
+
+
+/*******************************************************************************/
+/*            In Application Programming ROM based routines                    */
+/*******************************************************************************/
+
+/* Provide access to IAP ROM based routines.
+ * This is the only access to User information block, and allows in-application re-programming
+ *   of the micro-controller (for bootloaders, drivers, loadable RTOS tasks, ....)
+ */
+
+
+
+/* Prepare sectors from the programm flash memory for erasing or writting
+ * Sectors numbers start at 0. A flash sector size is 4kB (0x1000 bytes)
+ * Provide the same sector number as start and end to prepare a single sector.
+ * Of course, end sector number MUST be higher than (or equal to) start sector number.
+ */
+int iap_prepare_flash(uint32_t start_sector, uint32_t end_sector);
+
+/* Erase full flash sectors from the programm memory
+ * Sectors numbers start at 0. A flash sector size is 4kB (0x1000 bytes)
+ * Provide the same sector number as start and end to erase a single sector.
+ * Of course, end sector number MUST be higher than (or equal to) start sector number.
+ * Use iap_erase_flash_pages() to erase a single page within a sector.
+ * A sector must be prepared for writing before the erase operation.
+ * Interrputs are disabled during this operation.
+ */
+int iap_erase_flash_sectors(uint32_t start_sector, uint32_t end_sector);
+
+/* Erase pages  from the programm memory
+ * Page numbers start at 0. A flash page size is 512 bytes.
+ * Provide the same page number as start and end to erase a single page.
+ * Of course, end page number MUST be higher than (or equal to) start page number.
+ * There is no way to erase only parts of a page.
+ * The sector in which the page reside must be prepared for writing before the page erase
+ *    operation.
+ * Interrputs are disabled during this operation.
+ */
+int iap_erase_flash_pages(uint32_t start_page, uint32_t end_page);
+
+
+/* Copy some data from RAM to Flash.
+ * When writting to the programm flash memory, the sectors must be prepared for writing
+ *   before the copy operation.
+ * Both dest and src parameters must be aligned to 4 bytes boundary and size must be a
+ *   multiple of 4.
+ * dest is the destination address and must be the address of some flash memory.
+ * ser is the source address and must be the address of some RAM memory.
+ * The sector or page in dest must have been erased before writing and no writing operation
+ *   performed between (dest) and (dest+size) addresses. (Writting in other parts of the
+ *   page or sector is OK)
+ * Interrputs are disabled during this operation.
+ */
+int iap_copy_ram_to_flash(uint32_t dest, uint32_t src, uint32_t size);
+
+
+/* Return the part ID */
+uint32_t iap_read_part_id(void);
+
+
+#endif /* CORE_IAP_H */
+
diff --git a/include/core/lpc_core.h b/include/core/lpc_core.h
new file mode 100644 (file)
index 0000000..6439a1e
--- /dev/null
@@ -0,0 +1,497 @@
+/****************************************************************************
+ *   core/lpc_core.h
+ *
+ * Helper functions to access some registers and Cortex M0 core functionalities.
+ *
+ *
+ * Some of the code from here comes from CMSIS. Should this be rewritten ?
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef LPC_CORE_H
+#define LPC_CORE_H
+
+#include "lib/stdint.h"
+#include "core/lpc_regs.h"
+
+
+
+/***************************************************************************** */
+/*                    Cortex-M0 System Control Block                           */
+/***************************************************************************** */
+/* Cortex-M0 System Control Block Registers */
+struct syst_ctrl_block_regs {
+       volatile const uint32_t cpuid; /* 0x000 : CPU ID Base Register (R/ ) */
+       volatile uint32_t icsr;        /* 0x004 : Interrupt Control State Register (R/W) */
+       uint32_t reserved_0;
+       volatile uint32_t aircr;       /* 0x00C : Application Interrupt / Reset Control Register (R/W) */
+       volatile uint32_t scr;         /* 0x010 : System Control Register (R/W) */
+       volatile uint32_t ccr;         /* 0x014 : Configuration Control Register (R/W) */
+       uint32_t reserved_1;
+       volatile uint32_t shp[2];      /* 0x01C : System Handlers Priority Registers. [0] is reserved_ (R/W) */
+};
+#define LPC_SCB       ((struct syst_ctrl_block_regs *) LPC_SCB_BASE) /* SCB configuration struct */
+
+/* SCB CPUID Register Definitions */
+#define SCB_CPUID_IMPLEMENTER      (0xFFUL << 24)     /* SCB CPUID: IMPLEMENTER Mask */
+#define SCB_CPUID_VARIANT          (0xFUL << 20)      /* SCB CPUID: VARIANT Mask */
+#define SCB_CPUID_ARCHITECTURE     (0xFUL << 16)      /* SCB CPUID: ARCHITECTURE Mask */
+#define SCB_CPUID_PARTNO           (0xFFFUL << 4)     /* SCB CPUID: PARTNO Mask */
+#define SCB_CPUID_REVISION         (0xFUL << 0)       /* SCB CPUID: REVISION Mask */
+
+/* SCB Interrupt Control State Register Definitions */
+#define SCB_ICSR_NMIPENDSET        (1UL << 31)        /* SCB ICSR: NMIPENDSET Mask */
+#define SCB_ICSR_PENDSVSET         (1UL << 28)        /* SCB ICSR: PENDSVSET Mask */
+#define SCB_ICSR_PENDSVCLR         (1UL << 27)        /* SCB ICSR: PENDSVCLR Mask */
+#define SCB_ICSR_PENDSTSET         (1UL << 26)        /* SCB ICSR: PENDSTSET Mask */
+#define SCB_ICSR_PENDSTCLR         (1UL << 25)        /* SCB ICSR: PENDSTCLR Mask */
+#define SCB_ICSR_ISRPREEMPT        (1UL << 23)        /* SCB ICSR: ISRPREEMPT Mask */
+#define SCB_ICSR_ISRPENDING        (1UL << 22)        /* SCB ICSR: ISRPENDING Mask */
+#define SCB_ICSR_VECTPENDING       (0x1FFUL << 12)    /* SCB ICSR: VECTPENDING Mask */
+#define SCB_ICSR_VECTACTIVE        (0x1FFUL << 0)     /* SCB ICSR: VECTACTIVE Mask */
+
+/* SCB Application Interrupt and Reset Control Register Definitions */
+#define SCB_AIRCR_VECTKEY_OFFSET   16
+#define SCB_AIRCR_VECTKEY          (0xFFFFUL << 16)   /* SCB AIRCR: VECTKEY Mask */
+#define SCB_AIRCR_VECTKEYSTAT      (0xFFFFUL << 16)   /* SCB AIRCR: VECTKEYSTAT Mask */
+#define SCB_AIRCR_ENDIANESS        (1UL << 15)        /* SCB AIRCR: ENDIANESS Mask */
+#define SCB_AIRCR_SYSRESETREQ      (1UL << 2)         /* SCB AIRCR: SYSRESETREQ Mask */
+#define SCB_AIRCR_VECTCLRACTIVE    (1UL << 1)         /* SCB AIRCR: VECTCLRACTIVE Mask */
+
+/* SCB System Control Register Definitions */
+#define SCB_SCR_SEVONPEND          (1UL << 4)         /* SCB SCR: SEVONPEND Mask */
+#define SCB_SCR_SLEEPDEEP          (1UL << 2)         /* SCB SCR: SLEEPDEEP Mask */
+#define SCB_SCR_SLEEPONEXIT        (1UL << 1)         /* SCB SCR: SLEEPONEXIT Mask */
+
+/* SCB Configuration Control Register Definitions */
+#define SCB_CCR_STKALIGN           (1UL << 9)         /* SCB CCR: STKALIGN Mask */
+#define SCB_CCR_UNALIGN_TRP        (1UL << 3)         /* SCB CCR: UNALIGN_TRP Mask */
+
+
+
+/*******************************************************************************/
+/*                Core Instructions                                            */
+/*******************************************************************************/
+/* NOP */
+#define nop() __asm volatile ("nop" : : : "memory")
+/* SEV : Send Event */
+#define sev() __asm volatile ("sev" : : : "memory")
+/* WFE : Wait For Event */
+#define wfe() __asm volatile ("wfe" : : : "memory")
+/* WFI : Wait For Interrupt */
+#define wfi() __asm volatile ("wfi" : : : "memory")
+
+
+/* Synchronization */
+/* Instruction Synchronization Barrier : Flushes pipeline */
+#define isb() __asm volatile ("isb" : : : "memory")
+/* Data Synchronization Barrier : All explicit memory access completed */
+#define dsb() __asm volatile ("dsb" : : : "memory")
+/* Data Memory Barrier : Ensures apparent order but not completion */
+#define dmb() __asm volatile ("dmb" : : : "memory")
+
+
+
+/* Access to the Application Program Status Register (APSR). */
+static inline uint32_t get_APSR(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, apsr" : "=r" (r)); return (r);
+}
+#define APSR_SATURATION  (get_APSR() & (0x1 << 27))  /* bit 27  Saturation condition flag */
+#define APSR_OVERFLOW    (get_APSR() & (0x1 << 28))  /* bit 28  Overflow condition code flag */
+#define APSR_CARRY       (get_APSR() & (0x1 << 29))  /* bit 29  Carry condition code flag */
+#define APSR_ZERO        (get_APSR() & (0x1 << 30))  /* bit 30  Zero condition code flag */
+#define APSR_NEGATIVE    (get_APSR() & (0x1 << 31))  /* bit 31  Negative condition code flag */
+
+
+/* Access the Interrupt Program Status Register (IPSR). */
+static inline uint32_t get_IPSR(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, ipsr" : "=r" (r)); return (r);
+}
+#define IPSR      (get_IPSR() & 0x1FF)  /* bit:  0..8  Exception number */
+#define IPSR_IRQ0 16
+#define IRQ_NUM   (IPSR - IPSR_IRQ0)
+
+
+/* Control Register */
+static inline uint32_t get_CONTROL(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, control" : "=r" (r)); return (r);
+}
+static inline void set_CONTROL(uint32_t control)
+{
+       __asm volatile ("msr control, %0" : : "r" (control));
+}
+
+
+/* Process Stack Pointer */
+static inline uint32_t get_process_stack_pointer(void)
+{
+       register uint32_t r; __asm volatile ("mrs %0, psp" : "=r" (r)); return (r);
+}
+static inline void set_process_stack_pointer(uint32_t top_of_stack)
+{
+       __asm volatile ("msr psp, %0" : : "r" (top_of_stack));
+}
+
+
+/* Main Stack Pointer */
+static inline uint32_t get_main_stack_pointer(void)
+{
+       register uint32_t r; __asm volatile ("mrs %0, msp" : "=r" (r)); return (r);
+}
+static inline void set_main_stack_pointer(uint32_t top_of_stack)
+{
+       __asm volatile ("msr msp, %0" : : "r" (top_of_stack));
+}
+
+
+/* Priority Mask */
+static inline uint32_t get_priority_mask(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, primask" : "=r" (r)); return (r);
+}
+static inline void set_priority_mask(uint32_t mask)
+{
+       __asm volatile ("msr primask, %0" : : "r" (mask));
+}
+
+
+/* Base Priority */
+static inline uint32_t get_base_priority(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, basepri_max" : "=r" (r)); return (r);
+}
+static inline void set_base_priority(uint32_t prio)
+{
+       __asm volatile ("msr basepri, %0" : : "r" (prio));
+}
+
+
+/* Fault Mask */
+static inline uint32_t get_fault_mask(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, faultmask" : "=r" (r)); return (r);
+}
+static inline void set_fault_mask(uint32_t mask)
+{
+       __asm volatile ("msr faultmask, %0" : : "r" (mask));
+}
+
+
+
+/*******************************************************************************/
+/*            Byte swap instructions                                           */
+/*******************************************************************************/
+/* Swap bytes of each 16-bit halfword in a 32-bit word, keeping halfword order */
+static inline uint32_t double_byte_swap_16(volatile uint32_t value)
+{
+       uint32_t result = 0;
+       __asm volatile ("rev16 %0, %1" : "=l" (result) : "l" (value));
+       return result;
+}
+/* Change endianness of a 16-bit halfword */
+static inline uint32_t byte_swap_16(volatile uint16_t value)
+{
+       uint32_t result = 0;
+       __asm volatile ("rev16 %0, %1" : "=l" (result) : "l" (value));
+       return (result & 0xFFFF);
+}
+/* Change endianness of a 32-bit word */
+static inline uint32_t byte_swap_32(volatile uint32_t value)
+{
+       uint32_t result = 0;
+       __asm volatile ("rev %0, %1" : "=l" (result) : "l" (value));
+       return result;
+}
+
+
+
+
+
+/*******************************************************************************/
+/*            Interrupts                                                       */
+/*******************************************************************************/
+
+/* Cortex-M0 Processor Exceptions Numbers */
+/* Note : entry 0 is "end stack pointer" */
+#define RESET_IRQ       ( -15 ) /*  1 - Reset ... not an interrupt ... */
+#define NMI_IRQ         ( -14 ) /*  2 - Non Maskable Interrupt */
+#define HARD_FAULT_IRQ  ( -13 ) /*  3 - Cortex-M0 Hard Fault Interrupt */
+/* Note : entry 7 is the 2’s complement of the check-sum of the previous 7 entries */
+#define SV_CALL_IRQ     (  -5 ) /* 11 - Cortex-M0 Supervisor Call Interrupt */
+#define PEND_SV_IRQ     (  -2 ) /* 14 - Cortex-M0 Pend SV Interrupt */
+#define SYSTICK_IRQ     (  -1 ) /* 15 - Cortex-M0 System Tick Interrupt */
+/* LPC82x Specific Interrupt Numbers */
+#define SSP0_IRQ       0
+#define SSP1_IRQ       1
+/* No IRQ 2 */
+#define UART0_IRQ      3
+#define UART1_IRQ      4
+#define UART2_IRQ      5
+/* No IRQ 6 */
+#define I2C1_IRQ       7
+#define I2C0_IRQ       8
+#define SCT_IRQ        9
+#define MRT_IRQ       10
+#define CMP_IRQ       11
+#define WDT_IRQ       12
+#define BOD_IRQ       13
+#define FLASH_IRQ     14
+#define WKT_IRQ       15
+#define ADC_SEQA_IRQ  16
+#define ADC_SEQB_IRQ  17
+#define ADC_THCMP_IRQ 18
+#define ADC_OVR_IRQ   19
+#define SDMA_IRQ      20
+#define I2C2_IRQ      21
+#define I2C3_IRQ      22
+/* No IRQ 23 */
+#define PININT0_IRQ   24
+#define PININT1_IRQ   25
+#define PININT2_IRQ   26
+#define PININT3_IRQ   26
+#define PININT4_IRQ   28
+#define PININT5_IRQ   28
+#define PININT6_IRQ   30
+#define PININT7_IRQ   31
+
+
+/* Enable IRQ Interrupts
+  Enables IRQ interrupts by clearing the I-bit in the CPSR.
+  Can only be executed in Privileged modes.
+ */
+static inline void lpc_enable_irq(void)
+{
+       __asm volatile ("cpsie i");
+}
+
+/* Disable IRQ Interrupts
+  Disables IRQ interrupts by setting the I-bit in the CPSR.
+  Can only be executed in Privileged modes.
+ */
+static inline void lpc_disable_irq(void)
+{
+       __asm volatile ("cpsid i");
+}
+
+
+/*******************************************************************************/
+/*                Hardware Abstraction Layer : NVIC Functions                  */
+/*******************************************************************************/
+
+/* Cortex-M0 NVIC Registers */
+struct nvic_regs {
+       volatile uint32_t int_set_enable;  /* 0x000 : Interrupt Set Enable Register (R/W) */
+       uint32_t reserved_0[31];
+       volatile uint32_t int_clear_enable;  /* 0x080 : Interrupt Clear Enable Register (R/W) */
+       uint32_t reserved_1[31];
+       volatile uint32_t int_set_pending;  /* 0x100 : Interrupt Set Pending Register (R/W) */
+       uint32_t reserved_2[31];
+       volatile uint32_t int_clear_pending;  /* 0x180 : Interrupt Clear Pending Register (R/W) */
+       uint32_t reserved_3[31];
+       volatile uint32_t int_active_bit; /* 0x200 : Interrupt Active Bit Register (R/-) */
+       uint32_t reserved_4[63];
+       volatile uint32_t int_priority[8]; /* 0x300 to 0x31C : Interrupt Priority Register (R/W) */
+};
+#define LPC_NVIC      ((struct nvic_regs *) LPC_NVIC_BASE)        /* NVIC configuration struct */
+
+
+
+/*  Enable External Interrupt
+  This function enables a device specific interrupt in the NVIC interrupt controller.
+  The interrupt number cannot be a negative value.
+  IRQ : Number of the external interrupt to enable
+ */
+static inline void NVIC_EnableIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       nvic->int_set_enable = (1 << (IRQ & 0x1F));
+}
+
+/*  Disable External Interrupt
+  This function disables a device specific interupt in the NVIC interrupt controller.
+  The interrupt number cannot be a negative value.
+  IRQ : Number of the external interrupt to disable
+ */
+static inline void NVIC_DisableIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       nvic->int_clear_enable = (1 << (IRQ & 0x1F));
+}
+
+/*  Get Pending Interrupt
+  This function reads the pending register in the NVIC and returns the pending bit
+       for the specified interrupt.
+  IRQ : Number of the interrupt for get pending
+  return :
+        0  Interrupt status is not pending
+        1  Interrupt status is pending
+ */
+static inline uint32_t NVIC_GetPendingIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       return (uint32_t)((nvic->int_set_pending & (1 << (IRQ & 0x1F)))?1:0);
+}
+
+/*  Set Pending Interrupt
+  This function sets the pending bit for the specified interrupt.
+  The interrupt number cannot be a negative value.
+  IRQ : Number of the interrupt for set pending
+ */
+static inline void NVIC_SetPendingIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       nvic->int_set_pending = (1 << (IRQ & 0x1F));
+}
+
+/*  Clear Pending Interrupt
+  This function clears the pending bit for the specified interrupt.
+  The interrupt number cannot be a negative value.
+  IRQ : Number of the interrupt for clear pending
+ */
+static inline void NVIC_ClearPendingIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       nvic->int_clear_pending = (1 << (IRQ & 0x1F));
+}
+
+
+/* The following MACROS handle generation of the register offset and byte masks */
+#define LPC_NVIC_PRIO_BITS  5  /* Number of Bits used for Priority Levels */
+#define LPC_IRQ_BIT_SHIFT(IRQ) (((uint32_t)(IRQ) & 0x03) * 8)
+#define LPC_IRQ_SHP_IDX(IRQ)   ((((int32_t)(IRQ) + 16) >> 2) - 1)
+#define LPC_IRQ_IP_IDX(IRQ)    ((uint32_t)(IRQ) >> 2)
+
+/*  Set Interrupt Priority
+  This function sets the priority for the specified interrupt. The interrupt
+       number can be positive to specify an external (device specific)
+       interrupt, or negative to specify an internal (core) interrupt.
+  Note: The priority cannot be set for every core interrupt.
+  IRQ : Number of the interrupt for set priority
+  priority : Priority to set
+ */
+static inline void NVIC_SetPriority(uint32_t IRQ, uint32_t priority)
+{
+       if ((int32_t)IRQ < 0) {
+               if ((int32_t)IRQ > (-12)) {
+                       struct syst_ctrl_block_regs* scb = LPC_SCB;
+                       scb->shp[LPC_IRQ_SHP_IDX(IRQ)] = (scb->shp[LPC_IRQ_SHP_IDX(IRQ)] & ~(0xFF << LPC_IRQ_BIT_SHIFT(IRQ))) |
+                               (((priority << (8 - LPC_NVIC_PRIO_BITS)) & 0xFF) << LPC_IRQ_BIT_SHIFT(IRQ));
+               }
+       } else if (LPC_IRQ_IP_IDX(IRQ) < 8) {
+               struct nvic_regs* nvic = LPC_NVIC;
+               nvic->int_priority[LPC_IRQ_IP_IDX(IRQ)] = (nvic->int_priority[LPC_IRQ_IP_IDX(IRQ)] & ~(0xFF << LPC_IRQ_BIT_SHIFT(IRQ))) |
+                       (((priority << (8 - LPC_NVIC_PRIO_BITS)) & 0xFF) << LPC_IRQ_BIT_SHIFT(IRQ));
+       }
+}
+
+
+/*  Get Interrupt Priority
+  This function reads the priority for the specified interrupt. The interrupt
+       number can be positive to specify an external (device specific)
+       interrupt, or negative to specify an internal (core) interrupt.
+  The returned priority value is automatically aligned to the implemented
+       priority bits of the microcontroller.
+  IRQ : Number of the interrupt for get priority
+  return : Interrupt Priority
+ */
+static inline uint32_t NVIC_GetPriority(uint32_t IRQ)
+{
+       if ((int32_t)IRQ < 0) {
+               if ((int32_t)IRQ > (-12)) {
+                       struct syst_ctrl_block_regs* scb = LPC_SCB;
+                       /* Get priority for Cortex-M0 system interrupts */
+                       return ((uint32_t)((scb->shp[LPC_IRQ_SHP_IDX(IRQ)] >> LPC_IRQ_BIT_SHIFT(IRQ) ) >> (8 - LPC_NVIC_PRIO_BITS)));
+               }
+       } else if (LPC_IRQ_IP_IDX(IRQ) < 8) {
+               struct nvic_regs* nvic = LPC_NVIC;
+               /* Get priority for device specific interrupts */
+               return ((uint32_t)((nvic->int_priority[LPC_IRQ_IP_IDX(IRQ)] >> LPC_IRQ_BIT_SHIFT(IRQ) ) >> (8 - LPC_NVIC_PRIO_BITS)));
+       }
+}
+
+
+/*  System Reset
+  This function initiate a system reset request to reset the MCU.
+ */
+static inline void NVIC_SystemReset(void)
+{
+       struct syst_ctrl_block_regs* scb = LPC_SCB;
+       dsb(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */
+       scb->aircr = ((0x5FA << SCB_AIRCR_VECTKEY_OFFSET) | SCB_AIRCR_SYSRESETREQ);
+       dsb();  /* Ensure completion of memory access */
+       while (1); /* wait until reset */
+}
+
+
+
+/*******************************************************************************/
+/*            Sync lock                                                        */
+/*******************************************************************************/
+/* NOTE : There is no syncro instructions on Cortex-M0 */
+
+/* IRQ released version : IRQ are enabled upon return
+ * Returns the old value after the new value has been set.
+ */
+static inline uint32_t sync_lock_test_and_set(volatile uint32_t *addr, uint32_t value)
+{
+       uint32_t oldval;
+       lpc_disable_irq();
+       dsb();
+       oldval = *addr;
+       *addr = value;
+       dsb();
+       lpc_enable_irq();
+       return oldval;
+}
+/* Remove the lock */
+static inline void sync_lock_release(volatile uint32_t *addr)
+{
+       *addr = 0;
+       dsb();
+}
+
+/* IRQ disabled version : If lock is acquired (old value is 0) IRQ are
+ *     disabled when the call returns
+ * Returns the old value after the new value has been set.
+ */
+static inline uint32_t irq_sync_lock_test_and_set(volatile uint32_t *addr, uint32_t value)
+{
+       uint32_t oldval;
+       lpc_disable_irq();
+       dsb();
+       oldval = *addr;
+       *addr = value;
+       dsb();
+       if (oldval) {
+               lpc_enable_irq();
+       }
+       return oldval;
+}
+/* Remove the lock */
+static inline void irq_sync_lock_release(volatile uint32_t *addr)
+{
+       *addr = 0;
+       dsb();
+       lpc_enable_irq();
+}
+
+
+#endif /* LPC_CORE_H */
+
diff --git a/include/core/lpc_regs.h b/include/core/lpc_regs.h
new file mode 100644 (file)
index 0000000..3665689
--- /dev/null
@@ -0,0 +1,229 @@
+/****************************************************************************
+ *   core/lpc_regs.h
+ *
+ * Cortex-M0 Core Registers definitions
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+#ifndef LPC_REGS_H
+#define LPC_REGS_H
+
+#include "lib/stdint.h"
+#include "lib/stddef.h"
+
+
+
+/***************************************************************************** */
+/*                          Memory Map                                         */
+/***************************************************************************** */
+/* Base addresses */
+#define LPC_FLASH_BASE        (0x00000000UL)
+#define LPC_RAM_BASE          (0x10000000UL)
+#define LPC_APB_BASE          (0x40000000UL)
+#define LPC_CRC_BASE          (0x50000000UL)
+#define LPC_SCT_PWM_BASE      (0x50004000UL)
+#define LPC_DMA_BASE          (0x50008000UL)
+#define LPC_GPIO_BASE         (0xA0000000UL)
+#define LPC_GPIO_INTR_BASE    (0xA0004000UL)
+
+/* Memory mapping of Cortex-M0 Hardware */
+#define LPC_SCS_BASE        (0xE000E000UL)         /* System Control Space Base Address */
+#define LPC_COREDEBUG_BASE  (0xE000EDF0UL)         /* Core Debug Base Address */
+#define LPC_SYSTICK_BASE    (LPC_SCS_BASE + 0x0010UL)  /* SysTick Base Address */
+#define LPC_NVIC_BASE       (LPC_SCS_BASE + 0x0100UL)  /* NVIC Base Address */
+#define LPC_SCB_BASE        (LPC_SCS_BASE + 0x0D00UL)  /* System Control Block Base Address */
+
+/* APB0 peripherals */
+#define LPC_WDT_BASE           (LPC_APB_BASE + 0x00000)
+#define LPC_MRT_BASE           (LPC_APB_BASE + 0x04000)
+#define LPC_SWT_BASE           (LPC_APB_BASE + 0x08000)
+#define LPC_SWITCH_MATRIX_BASE (LPC_APB_BASE + 0x0C000)
+#define LPC_ADC_BASE           (LPC_APB_BASE + 0x1C000)
+#define LPC_PMU_BASE           (LPC_APB_BASE + 0x20000)
+#define LPC_ACMP_BASE          (LPC_APB_BASE + 0x24000)
+#define LPC_DMA_TRIG_MUX_BASE  (LPC_APB_BASE + 0x28000)
+#define LPC_IMUX_BASE          (LPC_APB_BASE + 0x2C000)
+#define LPC_FLASH_CONFIG_BASE  (LPC_APB_BASE + 0x40000)
+#define LPC_IOCON_BASE         (LPC_APB_BASE + 0x44000)
+#define LPC_SYSCON_BASE        (LPC_APB_BASE + 0x48000)
+#define LPC_I2C0_BASE          (LPC_APB_BASE + 0x50000)
+#define LPC_I2C1_BASE          (LPC_APB_BASE + 0x54000)
+#define LPC_SSP0_BASE          (LPC_APB_BASE + 0x58000)
+#define LPC_SSP1_BASE          (LPC_APB_BASE + 0x5C000)
+#define LPC_USART0_BASE        (LPC_APB_BASE + 0x64000)
+#define LPC_USART1_BASE        (LPC_APB_BASE + 0x68000)
+#define LPC_USART2_BASE        (LPC_APB_BASE + 0x6C000)
+#define LPC_I2C2_BASE          (LPC_APB_BASE + 0x70000)
+#define LPC_I2C3_BASE          (LPC_APB_BASE + 0x74000)
+
+
+
+
+
+/***************************************************************************** */
+/*                     Power Management Unit                                   */
+/***************************************************************************** */
+/* Power Management Unit (PMU) */
+struct lpc_pm_unit
+{
+       volatile uint32_t power_ctrl;  /* 0x000 : Power control Register (R/W) */
+       volatile uint32_t gp_data[4];  /* 0x004 to 0x010 : General purpose Register 0 to 3 (R/W) */
+       volatile uint32_t system_config; /* 0x014 : System configuration register (R/W) */
+                                                       /* (RTC clock control and hysteresis of the WAKEUP pin) */
+};
+#define LPC_PMU   ((struct lpc_pm_unit *) LPC_PMU_BASE)
+
+/* System config register */
+#define LPC_WAKEUP_PIN_HYST_MASK    (0x01 << 10)
+#define LPC_RTC_CLK_SRC_SHIFT       11
+#define LPC_RTC_CLK_SRC_MASK        (0x0F << LPC_RTC_CLK_SRC_SHIFT)
+/* See RTC section above for RTC Clock source selection bits */
+
+
+
+/***************************************************************************** */
+/*                     Synchronous Serial Communication                        */
+/***************************************************************************** */
+/* Synchronous Serial Communication (SSP) */
+struct lpc_ssp
+{
+       volatile uint32_t ctrl_0;        /* 0x000 : Control Register 0 (R/W) */
+       volatile uint32_t ctrl_1;        /* 0x004 : Control Register 1 (R/W) */
+       volatile uint32_t data;          /* 0x008 : Data Register (R/W) */
+       volatile const uint32_t status;  /* 0x00C : Status Registe (R/-) */
+       volatile uint32_t clk_prescale;  /* 0x010 : Clock Prescale Register (R/W) */
+       volatile uint32_t int_mask;      /* 0x014 : Interrupt Mask Set and Clear Register (R/W) */
+       volatile uint32_t raw_int_status;     /* 0x018 : Raw Interrupt Status Register (R/-) */
+       volatile uint32_t masked_int_status;  /* 0x01C : Masked Interrupt Status Register (R/-) */
+       volatile uint32_t int_clear;     /* 0x020 : SSPICR Interrupt Clear Register (-/W) */
+       volatile uint32_t dma_ctrl;      /* 0x024 : DMA Control Register (R/W) */
+};
+#define LPC_SSP0        ((struct lpc_ssp *) LPC_SSP0_BASE)
+
+/* SSP Control 0 register */
+#define LPC_SSP_DATA_WIDTH(x)    (((x) - 1) & 0x0F) /* Use 4 for 4 bits, 5 for 5 bits, .... */
+#define LPC_SSP_FRAME_SPI        (0x00 << 4)
+#define LPC_SSP_FRAME_TI         (0x01 << 4)
+#define LPC_SSP_FRAME_MICROWIRE  (0x02 << 4)
+#define LPC_SSP_SPI_CLK_LOW      (0x00 << 6)
+#define LPC_SSP_SPI_CLK_HIGH     (0x01 << 6)
+#define LPC_SSP_SPI_CLK_FIRST    (0x00 << 7)
+#define LPC_SSP_SPI_CLK_LAST     (0x01 << 7)
+#define LPC_SSP_SPI_CLK_RATE_DIV(x) (((x) & 0xFF) << 8)
+/* SSP Control 1 register */
+#define LPC_SSP_LOOPBACK_MODE      (0x01 << 0)
+#define LPC_SSP_ENABLE             (0x01 << 1)
+#define LPC_SSP_MASTER_MODE        (0x00 << 2)
+#define LPC_SSP_SLAVE_MODE         (0x01 << 2)
+#define LPC_SSP_SLAVE_OUT_DISABLE  (0x01 << 3)
+
+/* SSP Status register */
+#define LPC_SSP_ST_TX_EMPTY      (0x01 << 0)
+#define LPC_SSP_ST_TX_NOT_FULL   (0x01 << 1)
+#define LPC_SSP_ST_RX_NOT_EMPTY  (0x01 << 2)
+#define LPC_SSP_ST_RX_FULL       (0x01 << 3)
+#define LPC_SSP_ST_BUSY          (0x01 << 4)
+
+/* SSP Interrupt Mask, Raw, Status, Clear */
+#define LPC_SSP_INTR_RX_OVERRUN      (0x01 << 0)
+#define LPC_SSP_INTR_RX_TIMEOUT      (0x01 << 1)
+#define LPC_SSP_INTR_RX_HALF_FULL    (0x01 << 2)
+#define LPC_SSP_INTR_TX_HALF_EMPTY   (0x01 << 3)
+
+/* SSP DMA Control */
+#define LPC_SSP_RX_DMA_EN   (0x01 << 0)
+#define LPC_SSP_TX_DMA_EN   (0x01 << 1)
+
+
+
+/***************************************************************************** */
+/*                     Timer                                                   */
+/***************************************************************************** */
+/* Timer (TMR) */
+struct lpc_timer
+{
+       volatile uint32_t int_reg;        /* 0x000 : Interrupt Register (R/W) */
+       volatile uint32_t timer_ctrl;     /* 0x004 : Timer Control Register (R/W) */
+       volatile uint32_t timer_counter;  /* 0x008 : Timer Counter Register (R/W) */
+       volatile uint32_t prescale;       /* 0x00C : Prescale Register (R/W) */
+       volatile uint32_t prescale_counter;  /* 0x010 : Prescale Counter Register (R/W) */
+       volatile uint32_t match_ctrl;     /* 0x014 : Match Control Register (R/W) */
+       volatile uint32_t match_reg[4];    /* 0x018 : Match Register 0 to 3 (R/W) */
+       volatile uint32_t capture_ctrl;   /* 0x028 : Capture Control Register (R/W) */
+       volatile const uint32_t capture_reg[4]; /* 0x02C : Capture Register 0 to 3 (R/ ) */
+       volatile uint32_t external_match; /* 0x03C : External Match Register (R/W) */
+       uint32_t reserved_2[12];
+       volatile uint32_t count_ctrl;     /* 0x070 : Count Control Register (R/W) */
+       volatile uint32_t pwm_ctrl;       /* 0x074 : PWM Control Register (R/W) */
+};
+#define LPC_TMR16B0     ((struct lpc_timer *) LPC_TIMER0_BASE)
+#define LPC_TMR16B1     ((struct lpc_timer *) LPC_TIMER1_BASE)
+#define LPC_TMR32B0     ((struct lpc_timer *) LPC_TIMER2_BASE)
+#define LPC_TMR32B1     ((struct lpc_timer *) LPC_TIMER3_BASE)
+#define LPC_TIMER_REGS(x)  ((struct lpc_timer *) (LPC_TIMER0_BASE + ((x) * 0x4000)))
+
+#define LPC_TIMER_COUNTER_ENABLE (1 << 0) /* CEN */
+#define LPC_TIMER_COUNTER_RESET  (1 << 1) /* CRST */
+
+/* Match internal configuration */
+#define LPC_TIMER_INTERRUPT_ON_MATCH   0x01
+#define LPC_TIMER_RESET_ON_MATCH       0x02
+#define LPC_TIMER_STOP_ON_MATCH        0x04
+#define LPC_TIMER_MATCH_ERASE(x)       (0x07 << (((x) & 0x03) * 3))
+#define LPC_TIMER_MATCH_SHIFT(x)       (((x) & 0x03) * 3)
+/* Capture internal configuration */
+#define LPC_TIMER_CAP_ON_RISING_EDGE   0x01
+#define LPC_TIMER_CAP_ON_FALLING_EDGE  0x02
+#define LPC_TIMER_INTERRUPT_ON_CAPTURE 0x04
+#define LPC_TIMER_CAPTURE_ERASE(x)     (0x07 << (((x) & 0x03) * 3))
+#define LPC_TIMER_CAPTURE_SHIFT(x)     (((x) & 0x03) * 3)
+/* Match external configuration */
+#define LPC_TIMER_NOTHING_ON_MATCH     0x00
+#define LPC_TIMER_CLEAR_ON_MATCH       0x01
+#define LPC_TIMER_SET_ON_MATCH         0x02
+#define LPC_TIMER_TOGGLE_ON_MATCH      0x03
+#define LPC_TIMER_EXT_MATCH0_SHIFT     4
+#define LPC_TIMER_EXT_MATCH1_SHIFT     6
+#define LPC_TIMER_EXT_MATCH2_SHIFT     8
+#define LPC_TIMER_EXT_MATCH3_SHIFT     10
+/* Counter */
+#define LPC_COUNTER_IS_TIMER           0x00
+#define LPC_COUNTER_INC_ON_RISING      0x01
+#define LPC_COUNTER_INC_ON_FALLING     0x02
+#define LPC_COUNTER_INC_ON_BOTH        0x03
+#define LPC_COUNTER_INC_INPUT_SHIFT    2
+#define LPC_COUNTER_INC_INPUT(x)       (((x) & 0x03) << LPC_COUNTER_INC_INPUT_SHIFT)
+#define LPC_COUNTER_CLEAR_ON_EVENT_EN  (0x01 << 4)
+#define LPC_COUNTER_CLEAR_ON_EVENT_SHIFT  5
+#define LPC_COUNTER_CLEAR_ON_CHAN0_RISE   0x00
+#define LPC_COUNTER_CLEAR_ON_CHAN0_FALL   0x01
+#define LPC_COUNTER_CLEAR_ON_CHAN1_RISE   0x02
+#define LPC_COUNTER_CLEAR_ON_CHAN1_FALL   0x03
+#define LPC_COUNTER_CLEAR_ON_CHAN2_RISE   0x04
+#define LPC_COUNTER_CLEAR_ON_CHAN2_FALL   0x05
+#define LPC_COUNTER_CLEAR_ON_CHAN3_RISE   0x06
+#define LPC_COUNTER_CLEAR_ON_CHAN3_FALL   0x07
+/* PWM */
+#define LPC_PWM_CHANNEL_ENABLE(x)    (0x01 << ((x) & 0x03))
+
+
+
+
+
+
+#endif  /* LPC_REGS_H */
diff --git a/include/core/pio.h b/include/core/pio.h
new file mode 100644 (file)
index 0000000..1f6f284
--- /dev/null
@@ -0,0 +1,305 @@
+/****************************************************************************
+ *  core/pio.h
+ *
+ * Copyright 2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+#ifndef CORE_PIO_H
+#define CORE_PIO_H
+
+/* The "PIO" module gives access to the configuration of all the pins of the
+ * micro-controller, whatever the function of the pin.
+ * It has nothing related to the GPIO function of the pins.
+ */
+
+#include <core/lpc_regs.h>
+
+
+
+/* Define a pin for the switch matrix fixed functions or GPIO
+ * When used for a GPIO or movable function the bit 7 of offset0 must be 1. Then both
+ *    offset0 and offset1 will be used to disable the corresponding fixed functions if any.
+ * When used for a fixed-pin function the bit 7 of offset0 must be 0. Then the offset0
+ *    field holds the fixed function to activate, and the offset1 field holds the fixed
+ *    function to disable, if any.
+ */
+struct pio {
+       uint8_t port; /* 0xFF indicates the end of a pin array */
+       uint8_t pin;  /* 0xFF indicates the end of a pin array */
+       uint8_t offset0; /* 0xFF indicates no fixed function on this pin */
+       uint8_t offset1; /* "" */
+};
+
+#define ARRAY_LAST_PIN   {0xFF, 0xFF, 0xFF, 0xFF}
+#define PIO_LAST   ARRAY_LAST_PIN
+
+struct pin_matrix_entry {
+       uint8_t reg_offset;
+       uint8_t bit_shift;
+};
+
+struct pio_config {
+       struct pio pio;
+       struct pin_matrix_entry matrix;
+       uint16_t mode;
+};
+#define ARRAY_LAST_PIO  { PIO_LAST, {0xFF, 0xFF}, 0 }
+
+
+#define PORT0_NB_PINS 29
+
+/* Simple copy function. */
+void pio_copy(struct pio* dst, const struct pio* src);
+
+/* Configure the pin in the requested function and mode. */
+void config_pio(const struct pio* pp, const struct pin_matrix_entry* matrix, uint16_t mode);
+
+/* Configure a set (array) of pins in a single loop */
+void set_pins(const struct pio_config* pins);
+
+
+/***************************************************************************** */
+/*                     Pins configuration                                      */
+/***************************************************************************** */
+
+/****************************************************************************/
+/* Defines for struct pio */
+
+/*  GPIO Pins  */
+#define LPC_GPIO_0_0  {0,  0, (0x80 |  0), 0xFF}
+#define LPC_GPIO_0_1  {0,  1, (0x80 |  1), 9}
+#define LPC_GPIO_0_2  {0,  2, (0x80 |  5), 0xFF}
+#define LPC_GPIO_0_3  {0,  3, (0x80 |  4), 0xFF}
+#define LPC_GPIO_0_4  {0,  4, (0x80 | 24), 0xFF}
+#define LPC_GPIO_0_5  {0,  5, (0x80 |  8), 0xFF}
+#define LPC_GPIO_0_6  {0,  6, (0x80 | 10), 14}
+#define LPC_GPIO_0_7  {0,  7, (0x80 | 13), 0xFF}
+#define LPC_GPIO_0_8  {0,  8, (0x80 |  6), 0xFF}
+#define LPC_GPIO_0_9  {0,  9, (0x80 |  7), 0xFF}
+#define LPC_GPIO_0_10 {0, 10, (0x80 | 12), 0xFF}
+#define LPC_GPIO_0_11 {0, 11, (0x80 | 11), 0xFF}
+#define LPC_GPIO_0_12 {0, 12, (0x80 | 0xFF), 0xFF}
+#define LPC_GPIO_0_13 {0, 13, (0x80 | 23), 0xFF}
+#define LPC_GPIO_0_14 {0, 14, (0x80 |  2), 15}
+#define LPC_GPIO_0_15 {0, 15, (0x80 | 0xFF), 0xFF}
+#define LPC_GPIO_0_16 {0, 16, (0x80 | 0xFF), 0xFF}
+#define LPC_GPIO_0_17 {0, 17, (0x80 | 22), 0xFF}
+#define LPC_GPIO_0_18 {0, 18, (0x80 | 21), 0xFF}
+#define LPC_GPIO_0_19 {0, 19, (0x80 | 20), 0xFF}
+#define LPC_GPIO_0_20 {0, 20, (0x80 | 19), 0xFF}
+#define LPC_GPIO_0_21 {0, 21, (0x80 | 18), 0xFF}
+#define LPC_GPIO_0_22 {0, 22, (0x80 | 17), 0xFF}
+#define LPC_GPIO_0_23 {0, 23, (0x80 |  3), 16}
+#define LPC_GPIO_0_24 {0, 24, (0x80 | 0xFF), 0xFF}
+#define LPC_GPIO_0_25 {0, 25, (0x80 | 0xFF), 0xFF}
+#define LPC_GPIO_0_26 {0, 26, (0x80 | 0xFF), 0xFF}
+#define LPC_GPIO_0_27 {0, 27, (0x80 | 0xFF), 0xFF}
+#define LPC_GPIO_0_28 {0, 28, (0x80 | 0xFF), 0xFF}
+
+/* FIXED functions */
+/*  Comparator Pins  */
+#define LPC_ACMP_I1_PIO_0_0   {0,  0,  0, 0xFF}
+#define LPC_ACMP_I2_PIO_0_1   {0,  1,  1, 9}
+#define LPC_ACMP_I3_PIO_0_14  {0, 14,  2, 15}
+#define LPC_ACMP_I4_PIO_0_23  {0, 23,  3, 16}
+#define LPC_VDDCMP_PIO_0_6    {0,  6, 10, 14}
+/*  ADC Pins  */ 
+#define LPC_ADC_AD0_PIO_0_7   {0,  7, 13, 0xFF}
+#define LPC_ADC_AD1_PIO_0_6   {0,  6, 14, 10}
+#define LPC_ADC_AD2_PIO_0_14  {0, 14, 15, 2}
+#define LPC_ADC_AD3_PIO_0_23  {0, 23, 16, 3}
+#define LPC_ADC_AD4_PIO_0_22  {0, 22, 17, 0xFF}
+#define LPC_ADC_AD5_PIO_0_21  {0, 21, 18, 0xFF}
+#define LPC_ADC_AD6_PIO_0_20  {0, 20, 19, 0xFF}
+#define LPC_ADC_AD7_PIO_0_19  {0, 19, 20, 0xFF}
+#define LPC_ADC_AD8_PIO_0_18  {0, 18, 21, 0xFF}
+#define LPC_ADC_AD9_PIO_0_17  {0, 17, 22, 0xFF}
+#define LPC_ADC_AD10_PIO_0_13 {0, 13, 23, 0xFF}
+#define LPC_ADC_AD11_PIO_0_4  {0,  4, 24, 0xFF}
+/*  CLK and Reset Pin  */
+#define LPC_XTALIN_PIO_0_8  {0,  8, 6, 0xFF}
+#define LPC_XTALOUT_PIO_0_9 {0,  9, 7, 0xFF}
+#define LPC_CLKIN_PIO_0_1   {0,  1, 9, 1}
+#define LPC_RESET_PIO_0_5   {0,  5, 8, 0xFF}
+/*  SWD (Debug) pins */
+#define LPC_SWD_SWCLK_PIO_0_3  {0,  3, 4, 0xFF}
+#define LPC_SWD_SWDIO_PIO_0_2  {0,  2, 5, 0xFF}
+/*  I2C Pins  */
+#define LPC_I2C0_SCL_PIO_0_10 {0, 10, 12, 0xFF}
+#define LPC_I2C0_SDA_PIO_0_11 {0, 11, 11, 0xFF}
+
+
+/****************************************************************************/
+/* Defines for struct pin_matrix_entry : MOVABLE functions */
+
+#define LPC_GPIO        {0xFF, 0xFF}
+#define LPC_FIXED       {0xFF, 0xFF}
+
+/*  CLKOUT Pin  */
+#define LPC_CLKOUT      {11, 16}
+
+/* Patern match */
+#define LPC_PATTERN_MATCH  {11, 24}
+
+/*  UART Pins  */
+/* UART0 Pins  */
+#define LPC_UART0_TX    {0,  0}
+#define LPC_UART0_RX    {0,  8}
+#define LPC_UART0_RTS   {0, 16}
+#define LPC_UART0_CTS   {0, 24}
+#define LPC_UART0_SCLK  {1,  0}
+/*  UART1 Pins  */
+#define LPC_UART1_TX    {1,  8}
+#define LPC_UART1_RX    {1, 16}
+#define LPC_UART1_RTS   {1, 24}
+#define LPC_UART1_CTS   {2,  0}
+#define LPC_UART1_SCLK  {2,  8}
+/*  UART2 Pins  */
+#define LPC_UART2_TX    {2, 16}
+#define LPC_UART2_RX    {2, 24}
+#define LPC_UART2_RTS   {3,  0}
+#define LPC_UART2_CTS   {3,  8}
+#define LPC_UART2_SCLK  {3, 16}
+
+/*  SPI Pins  */
+/* SSP 0 */
+#define LPC_SSP0_SCLK   {3, 24}
+#define LPC_SSP0_MOSI   {4,  0}
+#define LPC_SSP0_MISO   {4,  8}
+#define LPC_SSP0_SSEL0  {4, 16}
+#define LPC_SSP0_SSEL1  {4, 24}
+#define LPC_SSP0_SSEL2  {5,  0}
+#define LPC_SSP0_SSEL3  {5,  8}
+/* SSP 1 */
+#define LPC_SSP1_SCLK   {5, 16}
+#define LPC_SSP1_MOSI   {5, 24}
+#define LPC_SSP1_MISO   {6,  0}
+#define LPC_SSP1_SSEL0  {6,  8}
+#define LPC_SSP1_SSEL1  {6, 16}
+
+/*  I2C Pins  */
+/* I2C1 */
+#define LPC_I2C1_SDA    {9,  8}
+#define LPC_I2C1_SCL    {9, 16}
+/* I2C2 */
+#define LPC_I2C2_SDA    {9, 24}
+#define LPC_I2C2_SCL   {10,  0}
+/* I2C3 */
+#define LPC_I2C3_SDA   {10,  8}
+#define LPC_I2C3_SCL   {10, 16}
+
+/*  ADC Pins  */
+#define LPC_ADC_PINTRIG0  {10, 24}
+#define LPC_ADC_PINTRIG1  {11,  0}
+#define LPC_ACMP_OUT      {11,  8}
+
+/*  Timer Pins  */
+/* State configurable Timer */
+#define LPC_SCT_PIN0    {6, 24}
+#define LPC_SCT_PIN1    {7,  0}
+#define LPC_SCT_PIN2    {7,  8}
+#define LPC_SCT_PIN3    {7, 16}
+#define LPC_SCT_POUT0   {7, 24}
+#define LPC_SCT_POUT1   {8,  0}
+#define LPC_SCT_POUT2   {8,  8}
+#define LPC_SCT_POUT3   {8, 16}
+#define LPC_SCT_POUT4   {8, 24}
+#define LPC_SCT_POUT5   {9,  0}
+
+
+/***************************************************************************** */
+/*                     Switch matrix                                           */
+/***************************************************************************** */
+/* pin switch matrix (SWM) : configure fixed and movable functions */
+#define LPC_MATRIX_NB_PIN_ASSIGN   12
+struct lpc_switch_matrix
+{
+       volatile uint32_t pin_assign[LPC_MATRIX_NB_PIN_ASSIGN];  /* 0x000 to 0x02C : PINASSIGN0 to PINASSIGN11 (R/W) */
+       uint32_t reserved_0[100];
+       volatile uint32_t pin_enable[1];   /* 0x1C0 : Enabme fixed-pin functions */
+};
+#define LPC_SWITCH_MATRIX   ((struct lpc_switch_matrix *) LPC_SWITCH_MATRIX_BASE)
+
+
+                                                            
+/***************************************************************************** */
+/*                     IO Control                                              */
+/***************************************************************************** */
+/* Pin Connect Block (IOCON) */
+struct lpc_io_control
+{
+       volatile uint32_t pio0_17;   /* 0x000 : I/O configuration for pin pio0_17 (R/W) */
+       volatile uint32_t pio0_13;   /* 0x004 : I/O configuration for pin pio0_13 (R/W) */
+       volatile uint32_t pio0_12;   /* 0x008 : I/O configuration for pin pio0_12 (R/W) */
+       volatile uint32_t pio0_5;    /* 0x00C : I/O configuration for pin pio0_5 (R/W) */
+       volatile uint32_t pio0_4;    /* 0x010 : I/O configuration for pin pio0_4 (R/W) */
+       volatile uint32_t pio0_3;    /* 0x014 : I/O configuration for pin pio0_3 (R/W) */
+       volatile uint32_t pio0_2;    /* 0x018 : I/O configuration for pin pio0_2 (R/W) */
+       volatile uint32_t pio0_11;   /* 0x01C : I/O configuration for pin pio0_11 (R/W) */
+       volatile uint32_t pio0_10;   /* 0x020 : I/O configuration for pin pio0_10 (R/W) */
+       volatile uint32_t pio0_16;   /* 0x024 : I/O configuration for pin pio0_16 (R/W) */
+       volatile uint32_t pio0_15;   /* 0x028 : I/O configuration for pin pio0_15 (R/W) */
+       volatile uint32_t pio0_1;    /* 0x02C : I/O configuration for pin pio0_1 (R/W) */
+       uint32_t reserved0;    /* 0x030 */
+       volatile uint32_t pio0_9;    /* 0x034 : I/O configuration for pin pio0_9 (R/W) */
+       volatile uint32_t pio0_8;    /* 0x038 : I/O configuration for pin pio0_8 (R/W) */
+       volatile uint32_t pio0_7;    /* 0x03C : I/O configuration for pin pio0_7 (R/W) */
+       volatile uint32_t pio0_6;    /* 0x040 : I/O configuration for pin pio0_6 (R/W) */
+       volatile uint32_t pio0_0;    /* 0x044 : I/O configuration for pin pio0_0 (R/W) */
+       volatile uint32_t pio0_14;   /* 0x048 : I/O configuration for pin pio0_14 (R/W) */
+       uint32_t reserved1;    /* 0x04C */
+       volatile uint32_t pio0_28;    /* 0x050 : I/O configuration for pin pio0_28 (R/W) */
+       volatile uint32_t pio0_27;    /* 0x054 : I/O configuration for pin pio0_27 (R/W) */
+       volatile uint32_t pio0_26;    /* 0x058 : I/O configuration for pin pio0_26 (R/W) */
+       volatile uint32_t pio0_25;    /* 0x05C : I/O configuration for pin pio0_25 (R/W) */
+       volatile uint32_t pio0_24;    /* 0x060 : I/O configuration for pin pio0_24 (R/W) */
+       volatile uint32_t pio0_23;    /* 0x064 : I/O configuration for pin pio0_23 (R/W) */
+       volatile uint32_t pio0_22;    /* 0x068 : I/O configuration for pin pio0_22 (R/W) */
+       volatile uint32_t pio0_21;    /* 0x06C : I/O configuration for pin pio0_21 (R/W) */
+       volatile uint32_t pio0_20;    /* 0x070 : I/O configuration for pin pio0_20 (R/W) */
+       volatile uint32_t pio0_19;    /* 0x074 : I/O configuration for pin pio0_19 (R/W) */
+       volatile uint32_t pio0_18;    /* 0x078 : I/O configuration for pin pio0_18 (R/W) */
+
+};
+#define LPC_IO_CONTROL  ((struct lpc_io_control *) LPC_IOCON_BASE)
+
+
+#define LPC_IO_MODE_INACTIVE  (0x00 << 3)
+#define LPC_IO_MODE_PULL_DOWN (0x01 << 3)
+#define LPC_IO_MODE_PULL_UP   (0x02 << 3)
+#define LPC_IO_MODE_REPEATER  (0x03 << 3)
+
+#define LPC_IO_HYSTERESIS_EN  (0x01 << 5)
+
+#define LPC_IO_INVERTED       (0x01 << 6)
+
+#define LPC_IO_I2CMODE_STD    (0x00 << 8)
+#define LPC_IO_I2CMODE_GPIO   (0x01 << 8)
+#define LPC_IO_I2CMODE_FPLUS  (0x02 << 8)
+
+#define LPC_IO_OPEN_DRAIN_ENABLE (0x01 << 10)
+
+#define LPC_IO_SAMPLE_MODE_BYP    (0x00 << 11)
+#define LPC_FILTER_ONE_CLK    1
+#define LPC_FILTER_TWO_CLK    2
+#define LPC_FILTER_THREE_CLK  3
+#define LPC_IO_SAMPLE_MODE(x)     ((x & 0x03) << 11)
+
+#define LPC_IO_SAMPLE_CLK_DIV(x)  ((x & 0x07) << 13)
+
+
+#endif /* CORE_PIO_H */
diff --git a/include/core/system.h b/include/core/system.h
new file mode 100644 (file)
index 0000000..fe75606
--- /dev/null
@@ -0,0 +1,276 @@
+/****************************************************************************
+ *   core/system.h
+ *
+ * All low-level functions for clocks configuration and switch, system
+ *  power-up, reset, and power-down.
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef CORE_SYSTEM_H
+#define CORE_SYSTEM_H
+
+#include "lib/stdint.h"
+
+#include "core/lpc_regs.h"
+#include "core/lpc_core.h"
+
+
+
+/***************************************************************************** */
+/*                       Power up defaults                                     */
+/***************************************************************************** */
+/* Change reset power state to our default, removing power from unused
+ * interfaces */
+void system_set_default_power_state(void);
+
+/***************************************************************************** */
+/*                       Power                                                 */
+/***************************************************************************** */
+void enter_deep_sleep(void);
+
+/* Power on or off a subsystem */
+void subsystem_power(uint32_t power_bit, uint32_t on_off);
+/* Check whether a subsystem is powered or not */
+uint8_t subsystem_powered(uint32_t power_bit);
+
+/* Reset a subsystem */
+void subsystem_reset(uint32_t reset_bit);
+void subsystem_reset_hold(uint32_t reset_bit);
+void subsystem_reset_release(uint32_t reset_bit);
+
+/* Configure the brown-out detection. */
+void system_brown_out_detection_config(uint32_t level);
+
+/***************************************************************************** */
+/*                      System Clock                                           */
+/***************************************************************************** */
+/* A clock frequency is defined as the integer value in MHz divided by 12, shifted
+ * by 3.
+ */
+/* PLL may fail to lock for frenquencies above 60MHz */
+#define FREQ_SEL_60MHz   (5 << 3)
+#define FREQ_SEL_48MHz   (4 << 3)
+#define FREQ_SEL_36MHz   (3 << 3)
+#define FREQ_SEL_24MHz   (2 << 3)
+#define FREQ_SEL_12MHz   (1 << 3)
+#define FREQ_SEL_IRC  FREQ_SEL_12MHz
+
+/* Main clock config
+ * We use internal RC and PLL0
+ * Note that during PLL lock wait we are running on internal RC
+ */
+void clock_config(uint32_t freq_sel);
+
+/* return current main clock in HZ */
+uint32_t get_main_clock(void);
+
+
+/* This is mainly a debug feature, but can be used to provide a clock to an
+ * external peripheral */
+void clkout_on(uint32_t src, uint32_t div);
+void clkout_off(void);
+
+
+/***************************************************************************** */
+/* Sleeping functions : these use systick if the systick code is kept. Otherwise
+ *   it will use a decrementing while loop which is (badly) calibrated for a 24MHz
+ *   main clock.
+ */
+void msleep(uint32_t ms);
+void usleep(uint32_t us);
+
+
+
+/***************************************************************************** */
+/*                     System Configuration                                    */
+/***************************************************************************** */
+/* System Configuration (SYSCON) */
+struct lpc_sys_start_logic_ctrl
+{
+       volatile uint32_t edge_ctrl;  /* 0x00 : edge control Register 0 (R/W) */
+       volatile uint32_t signal_en;  /* 0x04 : signal enable Register 0 (R/W) */
+       volatile uint32_t reset;      /* 0x08 : reset Register 0  (-/W) */
+       volatile uint32_t status;     /* 0x0C : status Register 0 (R/-) */
+};
+struct lpc_sys_config
+{
+       volatile uint32_t sys_mem_remap;   /* 0x000 System memory remap (R/W) */
+       volatile uint32_t peripheral_reset_ctrl; /* 0x004 Peripheral reset control (R/W) */
+       volatile uint32_t sys_pll_ctrl;    /* 0x008 System PLL control (R/W) */
+       volatile uint32_t sys_pll_status;  /* 0x00C System PLL status (R/ ) */
+       uint32_t reserved_0[4];
+
+       volatile uint32_t sys_osc_ctrl;    /* 0x020 : System oscillator control (R/W) */
+       volatile uint32_t WDT_osc_ctrl;    /* 0x024 : Watchdog oscillator control (R/W) */
+       volatile uint32_t IRC_ctrl;        /* 0x028 : IRC control (R/W) */
+       uint32_t reserved_1[1];
+       volatile uint32_t sys_reset_status;    /* 0x030 : System reset status Register (R/ ) */
+       uint32_t reserved_2[3];
+       volatile uint32_t sys_pll_clk_sel;     /* 0x040 : System PLL clock source select (R/W) */
+       volatile uint32_t sys_pll_clk_upd_en;  /* 0x044 : System PLL clock source update enable (R/W) */
+       uint32_t reserved_3[10];
+
+       volatile uint32_t main_clk_sel;     /* 0x070 : Main clock source select (R/W) */
+       volatile uint32_t main_clk_upd_en;  /* 0x074 : Main clock source update enable (R/W) */
+       volatile uint32_t sys_AHB_clk_div;  /* 0x078 : System AHB clock divider (R/W) */
+       uint32_t reserved_4[1];
+
+       volatile uint32_t sys_AHB_clk_ctrl; /* 0x080 : System AHB clock control (R/W) */
+       uint32_t reserved_5[4];
+
+       volatile uint32_t uart_clk_div;   /* 0x094 : USART clock divider (R/W) */
+       uint32_t reserved_6[18];
+
+       volatile uint32_t clk_out_src_sel; /* 0x0E0 : CLKOUT clock source select (R/W) */
+       volatile uint32_t clk_out_upd_en;  /* 0x0E4 : CLKOUT clock source update enable (R/W) */
+       volatile uint32_t clk_out_div;     /* 0x0E8 : CLKOUT clock divider (R/W) */
+       uint32_t reserved_7[1];
+       volatile uint32_t uart_common_fclk_div;  /* 0x0F0 : USART 1-4 common fractional gen divider (R/W) */
+       volatile uint32_t uart_common_fclk_mult; /* 0x0F4 : USART 1-4 common fractional gen multiplier  (R/W) */
+       uint32_t reserved_8[1];
+       volatile uint32_t ext_trace_buffer_cmd;  /* 0x0FC : External trace buffer command (R/W) */
+
+       volatile uint32_t por_captured_io_status_0;  /* 0x100 : POR captured PIO status 0 (R/ ) */
+       uint32_t reserved_9[12];
+
+       volatile uint32_t IO_config_clk_div[7]; /* 0x134 - 0x14C : Peripheral clocks 6 to 0 for glitch filter */
+
+       volatile uint32_t BOD_ctrl;      /* 0x150 : BOD control (R/W) */
+       volatile uint32_t sys_tick_cal;  /* 0x154 : System tick counter calibration (R/W) */
+       uint32_t reserved_10[6];
+       volatile uint32_t irq_latency;   /* 0x170 : IRQ delay, alloxs trade-off bw latency and determinism */
+       volatile uint32_t int_nmi_cfg;   /* 0x174 : NMI interrupt source configuration control */
+       volatile uint32_t pin_int_sel[8]; /* 0x178 - 0x194 : Pin interrupt Select registers (R/W) */
+       uint32_t reserved_11[26];
+
+       struct lpc_sys_start_logic_ctrl start_log_ctrl[2]; /* 0x200 to 0x20C and 0x210 to 0x21C :
+                                                    Start logic 0 and Start logic 1/peripheral interrupts */
+       uint32_t reserved_12[4];
+
+       volatile uint32_t powerdown_sleep_cfg;  /* 0x230 : Power-down states in Deep-sleep mode (R/W) */
+       volatile uint32_t powerdown_wake_cfg;  /* 0x234 : Power-down states after wake-up (R/W) */
+       volatile uint32_t powerdown_run_cfg;        /* 0x238 : Power-down configuration Register (R/W) */
+       uint32_t reserved_13[110];
+       volatile const uint32_t device_id;  /* 0x3F4 : Device ID (R/ ) */
+};
+
+#define LPC_SYS_CONFIG ((struct lpc_sys_config *) LPC_SYSCON_BASE)
+
+
+/* AHB control bits
+ *   0 (System (cortexM0, syscon, PMU, ...)) is a read only bit (system cannot be disabled)
+ */
+#define LPC_SYS_ABH_CLK_CTRL_SYSTEM     (1 <<  0) /* Read only */
+#define LPC_SYS_ABH_CLK_CTRL_ROM        (1 <<  1)
+#define LPC_SYS_ABH_CLK_CTRL_RAM        (1 <<  2)
+#define LPC_SYS_ABH_CLK_CTRL_FLASH_REG  (1 <<  3)
+#define LPC_SYS_ABH_CLK_CTRL_FLASH      (1 <<  4)
+#define LPC_SYS_ABH_CLK_CTRL_I2C0       (1 <<  5)
+#define LPC_SYS_ABH_CLK_CTRL_GPIO       (1 <<  6)
+#define LPC_SYS_ABH_CLK_CTRL_SWM        (1 <<  7)
+#define LPC_SYS_ABH_CLK_CTRL_SCT        (1 <<  8)
+#define LPC_SYS_ABH_CLK_CTRL_WKT        (1 <<  9)
+#define LPC_SYS_ABH_CLK_CTRL_MRT        (1 << 10)
+#define LPC_SYS_ABH_CLK_CTRL_SSP0       (1 << 11)
+#define LPC_SYS_ABH_CLK_CTRL_SSP1       (1 << 12)
+#define LPC_SYS_ABH_CLK_CTRL_CRC        (1 << 13)
+#define LPC_SYS_ABH_CLK_CTRL_UART0      (1 << 14)
+#define LPC_SYS_ABH_CLK_CTRL_UART1      (1 << 15)
+#define LPC_SYS_ABH_CLK_CTRL_UART2      (1 << 16)
+#define LPC_SYS_ABH_CLK_CTRL_Watchdog   (1 << 17)
+#define LPC_SYS_ABH_CLK_CTRL_IO_CONFIG  (1 << 18)
+#define LPC_SYS_ABH_CLK_CTRL_ACMP       (1 << 19)
+#define LPC_SYS_ABH_CLK_CTRL_I2C1       (1 << 21)
+#define LPC_SYS_ABH_CLK_CTRL_I2C2       (1 << 22)
+#define LPC_SYS_ABH_CLK_CTRL_I2C3       (1 << 23)
+#define LPC_SYS_ABH_CLK_CTRL_ADC        (1 << 24)
+#define LPC_SYS_ABH_CLK_CTRL_MTB        (1 << 26)
+#define LPC_SYS_ABH_CLK_CTRL_DMA        (1 << 29)
+/* Helper */
+#define LPC_SYS_ABH_CLK_CTRL_MEM_ALL    0x0000001F
+
+/* Peripheral reset */
+#define LPC_SSP0_RESET_N        (1 << 0)
+#define LPC_SSP1_RESET_N        (1 << 1)
+#define LPC_UART_CLK_RESET_N    (1 << 2)
+#define LPC_UART0_RESET_N       (1 << 3)
+#define LPC_UART1_RESET_N       (1 << 4)
+#define LPC_UART2_RESET_N       (1 << 5)
+#define LPC_I2C0_RESET_N        (1 << 6)
+#define LPC_MRT_RESET_N         (1 << 7)
+#define LPC_SCT_RESET_N         (1 << 8)
+#define LPC_WKT_RESET_N         (1 << 9)
+#define LPC_GPIO_RESET_N        (1 << 10)
+#define LPC_FLASH_RESET_N       (1 << 11)
+#define LPC_ACMP_RESET_N        (1 << 12)
+#define LPC_I2C1_RESET_N        (1 << 14)
+#define LPC_I2C2_RESET_N        (1 << 15)
+#define LPC_I2C3_RESET_N        (1 << 16)
+
+/* Peripheral power down */
+#define LPC_POWER_DOWN_IRC_OUT      (1 << 0)
+#define LPC_POWER_DOWN_IRC          (1 << 1)
+#define LPC_POWER_DOWN_FLASH        (1 << 2)
+#define LPC_POWER_DOWN_BOD          (1 << 3)
+#define LPC_POWER_DOWN_ADC          (1 << 4)
+#define LPC_POWER_DOWN_SYS_OSC      (1 << 5)
+#define LPC_POWER_DOWN_WDT_OSC      (1 << 6)
+#define LPC_POWER_DOWN_SYSPLL       (1 << 7)
+#define LPC_POWER_DOWN_COPARATOR    (1 << 15)
+
+#define LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_ON  0x0000FFF7
+#define LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_OFF 0x0000FFFF
+
+#define LPC_MAIN_CLK_SRC_IRC_OSC       0x00
+#define LPC_MAIN_CLK_SRC_PLL_IN        0x01
+#define LPC_MAIN_CLK_SRC_WATCHDOG_OSC  0x02
+#define LPC_MAIN_CLK_SRC_PLL_OUT       0x03
+
+#define LPC_PLL_CLK_SRC_IRC_OSC        0x00
+#define LPC_PLL_CLK_SRC_EXT_OSC        0x01
+#define LPC_PLL_CLK_SRC_CLKIN          0x03
+
+#define LPC_CLKOUT_SRC_IRC_OSC       0x00
+#define LPC_CLKOUT_SRC_XTAL_OSC      0x01
+#define LPC_CLKOUT_SRC_WATCHDOG_OSC  0x02
+#define LPC_CLKOUT_SRC_MAIN_CLK      0x03
+
+#define LPC_WDT_DIVSEL(x)  (((x) / 2) - 1)
+#define LPC_WDT_FREQSEL_600KHz  (0x01 << 5)
+
+/* Pin interrupt wakeup enable */
+#define LPC_PINT_WAKEUP_EN(x)   (1 << (x))
+
+/***************************************************************************** */
+/*                  Flash Control                                              */
+/***************************************************************************** */
+/* Flash configuration */
+struct lpc_flash_control
+{
+       uint32_t reserved_0[10];
+       volatile uint32_t flash_cfg; /* 0x028 Flash configuration (R/W) */
+};
+#define LPC_FLASH_CONTROL ((struct lpc_flash_control *) LPC_FLASH_CONFIG_BASE)
+#define LPC_FLASH_CFG_MASK   0x03
+#define LPC_FLASH_CFG_SHIFT  0
+
+
+
+
+#endif /* CORE_SYSTEM_H */
diff --git a/include/core/systick.h b/include/core/systick.h
new file mode 100644 (file)
index 0000000..78b7873
--- /dev/null
@@ -0,0 +1,141 @@
+/****************************************************************************
+ *   core/systick.h
+ *
+ * System tick timer control
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef CORE_SYSTICK_H
+#define CORE_SYSTICK_H
+
+#include "core/lpc_regs.h"
+
+/***************************************************************************** */
+/*               System Tick Timer                                             */
+/***************************************************************************** */
+
+/* Driver for the internal systick timer of the LPC82x.
+ * Refer to the LPC82x documentation (UM10800.pdf) for more information
+ */
+
+
+/* Start the system tick timer
+ * Starting the systick timer also resets the internal tick counters.
+ * If you need a value that goes beyond one start/stop cycle and accross resets,
+ *    then it's up to you to keep track of this using systick_get_tick_count() and/or
+ *    systick_get_clock_cycles().
+ */
+void systick_start(void);
+
+/* Stop the system tick timer */
+void systick_stop(void);
+
+/* Reset the system tick timer, making it count down from the reload value again
+ * Reseting the systick timer also resets the internal tick counters.
+ * If you need a value that goes beyond one start/stop cycle and accross resets,
+ *    then it's up to you to keep track of this using systick_get_tick_count() and/or
+ *    systick_get_clock_cycles().
+ */
+void systick_reset(void);
+
+/* Get system tick timer current value (counts at get_main_clock() !)
+ * systick_get_timer_val returns a value between 0 and systick_get_timer_reload_val()
+ */
+uint32_t systick_get_timer_val(void);
+
+/* Get system tick timer reload value */
+uint32_t systick_get_timer_reload_val(void);
+
+/* Check if systick is running (return 1) or not (return 0) */
+uint32_t is_systick_running(void);
+
+/* Get the system tick period in ms
+ * A vaue of 0 means the system tick timer has not been configured.
+ * Note : calls to msleep() or usleep() will configure the system tick timer
+ *        with a value of 1ms if it was not configured yet.
+ */
+uint32_t systick_get_tick_ms_period(void);
+
+/* Get the number of system ticks ... since last wrapping of the counter, which
+ * is about 50 days with a 1ms system tick. */
+uint32_t systick_get_tick_count(void);
+
+/* Get the number of clock cycles ... since last wrapping of the counter. */
+uint32_t systick_get_clock_cycles(void);
+
+/* Power up the system tick timer.
+ * ms is the interval between system tick timer interrupts. If set to 0, the default
+ *     value is used, which should provide a 1ms period.
+ */
+void systick_timer_on(uint32_t ms);
+
+/* Removes the main clock from the selected timer block */
+void systick_timer_off(void);
+
+/* Register a callback to be called every 'period' system ticks.
+ * returns the callback number if registration was OK.
+ * returns negative value on error.
+ * The callback will get the "global_wrapping_system_ticks" as argument, which wraps every 50 days
+ *   or so with a 1ms tick
+ */
+#define MAX_SYSTICK_CALLBACKS  4
+int add_systick_callback(void (*callback) (uint32_t), uint16_t period);
+/* Remove a registered callback, given the callback address used to register it. */
+int remove_systick_callback(void (*callback) (uint32_t));
+
+
+
+/* This function can be used when you are absolutly certain that systick timer is running, and when
+ * you need to sleep less than 1000us (1ms)
+ */
+void usleep_short(uint32_t us);
+
+
+/***************************************************************************** */
+/*                    Cortex-M0 System Timer                                   */
+/***************************************************************************** */
+/* Cortex-M0 System Timer Registers */
+struct lpc_system_tick {
+       volatile uint32_t control;     /* 0x000 : SysTick Control and Status Register (R/W) */
+       volatile uint32_t reload_val;  /* 0x004 : SysTick Reload Value Register (R/W) */
+       volatile uint32_t value;       /* 0x008 : SysTick Current Value Register (R/W) */
+       volatile const uint32_t calibration;  /* 0x00C : SysTick Calibration Register (R/ ) */
+};
+#define LPC_SYSTICK  ((struct lpc_system_tick*) LPC_SYSTICK_BASE) /* SysTick configuration struct */
+
+/* SysTick Control / Status Register Definitions */
+#define LPC_SYSTICK_CTRL_COUNTFLAG  (1UL << 16)   /* SysTick CTRL: COUNTFLAG Mask */
+#define LPC_SYSTICK_CTRL_CLKSOURCE  (1UL << 2)    /* SysTick CTRL: CLKSOURCE Mask */
+#define LPC_SYSTICK_CTRL_TICKINT    (1UL << 1)    /* SysTick CTRL: TICKINT Mask */
+#define LPC_SYSTICK_CTRL_ENABLE     (1UL << 0)    /* SysTick CTRL: ENABLE Mask */
+
+/* SysTick Reload Register Definitions */
+#define LPC_SYSTICK_LOAD_RELOAD     (0xFFFFFFUL)  /* SysTick LOAD: RELOAD Mask */
+
+/* SysTick Current Register Definitions */
+#define LPC_SYSTICK_VAL_CURRENT     (0xFFFFFFUL)  /* SysTick VAL: CURRENT Mask */
+
+/* SysTick Calibration Register Definitions */
+#define LPC_SYSTICK_CALIB_NOREF     (1UL << 31)   /* SysTick CALIB: NOREF Mask */
+#define LPC_SYSTICK_CALIB_SKEW      (1UL << 30)   /* SysTick CALIB: SKEW Mask */
+#define LPC_SYSTICK_CALIB_TENMS     (0xFFFFFFUL)  /* SysTick CALIB: TENMS Mask */
+
+
+
+#endif /* CORE_SYSTICK_H */
diff --git a/include/core/watchdog.h b/include/core/watchdog.h
new file mode 100644 (file)
index 0000000..6c8ce93
--- /dev/null
@@ -0,0 +1,140 @@
+/****************************************************************************
+ *   core/watchdog.h
+ *
+ * Watchdog support
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/*
+ * This file implements support of the Windowed Watchdog (WWDT)
+ */
+
+
+#ifndef CORE_WATCHDOG_H
+#define CORE_WATCHDOG_H
+
+#include "lib/stdint.h"
+#include "core/lpc_regs.h"
+
+
+#define WDT_CLK_POWER_LOCK  (0x01 << 0)
+#define WDT_EN_LOCK         (0x01 << 1)
+#define WDT_TIMER_VAL_LOCK  (0x01 << 2)
+
+struct wdt_config {
+       int intr_mode_only; /* If set to 1, a watchdog timeout will trigger an interrupt instead of a reset */
+       void (*callback)(void);
+       uint32_t locks; /* Bitfield from WDT_*_LOCK defined in watchdog.h */
+       /* Number of clk_src clocks before the watchdog timer times out. Will be divided by 4 to give
+        *   the watchdog reload value */
+       uint32_t nb_clk;  /* 0x3FF to 0x03FFFFFF */
+       /* The next two values are relative to the timer value, not the number of clk_src clocks. */
+       uint32_t wdt_window; /* Watchdog window value : 0x100 to 0x00FFFFFF */
+       uint16_t wdt_warn; /* 0x00 to 0x3FF */
+};
+
+/***************************************************************************** */
+void watchdog_feed(void);
+
+
+/* Lock the watchdog clock source power.
+ * Once locked, writes to the current watchdog clock power bits in powerdown_*_cfg will
+ *   have no effect.
+ * It is still possible to switch the watchdog clock source and turn of the clock if the
+ *   watchdog clock source has not been locked yet.
+ */
+void watchdog_lock_clk_src_power(void);
+
+/* Lock the watchdog timer value */
+void watchdog_lock_timer_val(void);
+
+/* Change the watchdog timer value, if not protected */
+void watchdog_set_timer_val(uint32_t nb_clk);
+
+/* Lock the watchdog and all related features.
+ * Calls all the other watchdog_lock_* functions (clk_src, clk_src_power, timer_val, enable).
+ */
+void watchdog_lock_full(void);
+
+/*
+ * Configure the watchdog.
+ * clk_sel is either 0 (IRC) or 1 (WDTCLK). The corresponding clock source will be powered on.
+ * Note : only WDTCLK is running in deep power down mode
+ * Note : protecting the clock source power will prevent turning off the IRC for power saving
+ *   if it is selected as main clock source.
+ */
+void watchdog_config(const struct wdt_config* wd_conf);
+
+
+/*
+ * Stop the watchdog
+ * This function can be used during system operation to stop the watchdog if it has not
+ *   been locked or protected against clock source modification, for example when entering
+ *   sleep or deep sleep.
+ * It will also try to power-down the oscilators if not used for main clock.
+ * Return 0 if a solution has been found to stop the watchdog, or -1 if watchdog is still
+ *   running after this call.
+ * TODO : Check this function, and implement the missing cases
+ */
+int stop_watchdog(void);
+
+
+/*
+ * Disable the watchdog
+ * This function can be used upon system startup to disable watchdog operation
+ */
+void startup_watchdog_disable(void);
+
+
+
+
+/***************************************************************************** */
+/*                     Watchdog Timer                                          */
+/***************************************************************************** */
+/* Watchdog Timer (WDT) */
+struct lpc_watchdog
+{   
+    volatile uint32_t mode;          /* 0x000 : Watchdog mode register (R/W) */
+    volatile uint32_t timer_const;   /* 0x004 : Watchdog timer constant register (R/W) */
+    volatile uint32_t feed_seqence;  /* 0x008 : Watchdog feed sequence register ( /W) */
+    volatile const uint32_t timer_value;  /* 0x00C : Watchdog timer value register (R/ ) */
+    uint32_t reserved0;      /* 0x010 */
+    volatile uint32_t warning_int_compare; /* 0x014 : Watchdog Warning Interrupt compare value. */
+    volatile uint32_t window_compare;      /* 0x018 : Watchdog Window compare value. */
+};
+#define LPC_WDT         ((struct lpc_watchdog *) LPC_WDT_BASE)
+
+#define LPC_WDT_TIMER_MAX  0xFFFFFF
+
+/* Mode register */
+#define LPC_WDT_EN                  (0x01 << 0)
+#define LPC_WDT_RESET_ON_TIMEOUT    (0x01 << 1)
+#define LPC_WDT_TIMEOUT_FLAG        (0x01 << 2)
+#define LPC_WDT_INTR_FLAG           (0x01 << 3)
+#define LPC_WDT_TIMER_VAL_PROTECT   (0x01 << 4) /* WDPROTECT */
+#define LPC_WDT_CLK_POWER_LOCK      (0x01 << 5) /* WDLOCKCLK */
+
+/* Warning Interupt */
+#define LPC_WDT_WARNINT_CMPVAL(x)  ((x) & 0x3FF)
+#define LPC_WDT_WARNINT_MAXVAL     0x3FF
+
+
+
+
+#endif /* CORE_WATCHDOG_H */
diff --git a/include/drivers/adc.h b/include/drivers/adc.h
new file mode 100644 (file)
index 0000000..7590732
--- /dev/null
@@ -0,0 +1,169 @@
+/****************************************************************************
+ *  drivers/adc.h
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef DRIVERS_ADC_H
+#define DRIVERS_ADC_H
+
+
+#include "lib/stdint.h"
+#include "core/lpc_regs.h"
+
+/***************************************************************************** */
+/*                Analog to Digital Converter (ADC)                            */
+/***************************************************************************** */
+
+/* ADC driver for the integrated ADC module of the LPC82x.
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+
+#define NB_ADC_CHANNELS  12
+#define NB_ADC_SEQUENCES 2
+
+#define LPC_ADC_SEQ(x)  (x)
+#define LPC_ADC_SEQA    0
+#define LPC_ADC_SEQB    1
+
+/* Read the conversion from the given channel
+ * This function reads the conversion value directly in the data register and
+ * always returns a value.
+ * Return 0 if the value is a new one and no overrun occured.
+ * Return -1 if channel does not exist
+ * Return 1 if the value is an old one.
+ * Return 2 if an overrun occured
+ */
+int adc_get_value(uint16_t * val, unsigned int channel);
+
+/* Start a conversion on the given channel (0 to 7)
+ * Unsupported yet : Set use_int to 1 to have your interrupt callback called upon conversion done.
+ */
+void adc_start_convertion_once(unsigned int channel, uint8_t seq_num, int use_int);
+
+/* Start burst conversions.
+ * channels is a bit mask of requested channels.
+ * Use LPC_ADC_CHANNEL(x) (x = 0 .. 7) for channels selection.
+ */
+void adc_start_burst_conversion(uint16_t channels, uint8_t seq_num);
+void adc_stop_burst_conversion(uint8_t seq_num);
+
+
+enum lpc_adc_start_conv_events {
+       LPC_ADC_START_CONV_SOFT = 0,
+       LPC_ADC_START_CONV_ADC_PINTRIG_0,
+       LPC_ADC_START_CONV_ADC_PINTRIG_1,
+       LPC_ADC_START_CONV_SCT0_OUT3,
+       LPC_ADC_START_CONV_ACMP_OUT,
+       LPC_ADC_START_CONV_ARM_TXEV,
+};
+/* This should be used to configure conversion start on falling or rising edges of
+ * some signals, or on timer for burst conversions.
+ */
+void adc_prepare_conversion_on_event(uint16_t channels, uint8_t seq_num, uint8_t event,
+                                                                               int use_int, uint32_t mode);
+
+/* Software trigger of the given configured sequence */
+void adc_trigger_sequence_conversion(uint8_t seq_num);
+
+/***************************************************************************** */
+/*   ADC Setup   */
+
+/* When lowpower_en is not 0 the ADC low power mode is selected, which adds a 15ADC clock delay
+ * before each set of consecutive conversions (but not between consecutive conversions)
+ */
+void adc_set_low_power(int lowpower_en);
+
+/* Power on/off the ADC block */
+void adc_on(void (*adc_callback)(uint32_t));
+void adc_off(void);
+
+
+
+
+/***************************************************************************** */
+/*                     Analog-to-Digital Converter                             */
+/***************************************************************************** */
+/* Analog-to-Digital Converter (ADC) */
+struct lpc_adc
+{
+       volatile uint32_t ctrl;         /* 0x000 : A/D Control Register (R/W) */
+       uint32_t reserved_0;
+       volatile uint32_t seqctrl[2];      /* 0x008 - 0x00C : A/D Conversion sequence A and B control register (R/W) */
+       volatile uint32_t global_data[2]; /* 0x010 - 0x014 : A/D sequence A and B Global Data Register (R/W) */
+       uint32_t reserved_1[2];
+       volatile uint32_t data[NB_ADC_CHANNELS]; /* Offset: 0x020-0x04C A/D Channel 0..11 Data Register (R/-) */
+       volatile uint32_t threshold_low[2];   /* 0x050 - 0x054 : A/D Low Compare Threshold Register 0 and 1 (R/W) */
+       volatile uint32_t threshold_high[2];  /* 0x058 - 0x05C : A/D High Compare Threshold Register 0 and 1 (R/W) */
+       volatile uint32_t chan_threshold_sel; /* 0x060 : A/D Channel Threshold select Register (R/W) */
+       volatile uint32_t int_en;       /* 0x064 : A/D Interrupt Enable Register (R/W) */
+       volatile const uint32_t flags;  /* 0x068 : A/D Flags Register (R/ ) */
+       volatile uint32_t trim;         /* 0x06C : A/D Trim Register (R/W) */
+};
+#define LPC_ADC         ((struct lpc_adc *) LPC_ADC_BASE)
+
+/* ADC Control register bits */
+#define LPC_ADC_CLK_MASK      0x0FF
+#define LPC_ADC_CLK_DIV(x)    ((x) & LPC_ADC_CLK_MASK)
+#define LPC_ADC_LOW_POWER_EN  (0x01 << 10)
+#define LPC_ADC_CALIBRATION   (0x01 << 30)
+
+/* LPC_ADC_CHANNEL_* are also used for interrupt register */
+#define LPC_ADC_CHANNEL_MASK (0xFFF << 0)
+#define LPC_ADC_CHANNEL(x)  (0x01 << (x))
+#define LPC_ADC_START_CONV_EVENT(x) (((x) & 0x7) << 12)
+#define LPC_ADC_START_EDGE_FALLING  (0x0 << 18)
+#define LPC_ADC_START_EDGE_RISING   (0x1 << 18)
+#define LPC_ADC_SYNC_TRIG_BYPASS    (0x1 << 19)
+#define LPC_ADC_START_CONV_NOW      (0x01 << 26)
+#define LPC_ADC_BURST               (0x01 << 27)
+#define LPC_ADC_SINGLESTEP          (0x01 << 28)
+#define LPC_ADC_LOW_PRIORITY        (0x01 << 29)
+#define LPC_ADC_INT_MODE_END_OF_SEQ (0x01 << 30)
+#define LPC_ADC_SEQ_EN              (0x01 << 31)
+#define LPC_ADC_ADDITIONAL_MODE_MASK  ((0x0 << 18) | (0x1 << 19) | (0x01 << 28) | (0x01 << 29) | (0x01 << 30))
+
+
+/* ADC Data register bits */
+#define LPC_ADC_RESULT_MASK   0xFFF
+#define LPC_ADC_RESULT_SHIFT  4
+#define LPC_ADC_RESULT(x)     (((x) & LPC_ADC_RESULT_MASK) >> LPC_ADC_RESULT_SHIFT)
+#define LPC_ADC_THRESHOLD_CMP_RANGE(x) (((x) & 0x03) >> 16)
+#define LPC_ADC_THRESHOLD_CMP_CROSS(x) (((x) & 0x03) >> 18)
+#define LPC_ADC_RES_CHAN(x)   (((x) & 0x0F) >> 26)
+#define LPC_ADC_OVERRUN    (0x01 << 30)
+#define LPC_ADC_CONV_DONE  (0x01 << 31)
+
+/* ADC Threshold register bits */
+#define LPC_ADC_THRESHOLD(x)  (((x) & LPC_ADC_RESULT_MASK) << LPC_ADC_RESULT_SHIFT)
+#define LPC_ADC_THRESHOLD_LEVEL_0  0
+#define LPC_ADC_THRESHOLD_LEVEL_1  1
+
+/* For more readability when selecting a channel number */
+#define LPC_ADC_NUM(x)    (x)
+
+
+
+/* ADC Interrupt Register */
+#define LPC_ADC_SEQA_INTEN   (0x01 << 0)
+#define LPC_ADC_SEQB_INTEN   (0x01 << 1)
+/* TODO : Define other bits */
+
+
+
+#endif /* DRIVERS_ADC_H */
+
diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h
new file mode 100644 (file)
index 0000000..65cbbf3
--- /dev/null
@@ -0,0 +1,175 @@
+/****************************************************************************
+ *  drivers/gpio.h
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/***************************************************************************** */
+/*                GPIOs and GPIO Interrupts                                    */
+/***************************************************************************** */
+
+/* Driver for GPIO configuration and access (including GPIO interrupts) on the LPC82x.
+ * Refer to LPC82x documentation (UM10800.pdf) for more information.
+ */
+
+#ifndef DRIVERS_GPIO_H
+#define DRIVERS_GPIO_H
+
+
+#include "lib/stdint.h"
+#include "core/lpc_regs.h"
+#include "core/pio.h"
+
+
+/***************************************************************************** */
+/*   Public access to GPIO setup   */
+
+
+enum gpio_interrupt_senses {
+       EDGES_BOTH = 0,
+       EDGE_FALLING,
+       EDGE_RISING,
+       LEVEL_HIGH,
+       LEVEL_LOW,
+};
+
+#define GPIO_DIR_IN 0
+#define GPIO_DIR_OUT 1
+
+/* GPIO Interrupts */
+/* Add a callback on a GPIO interrupt.
+ * This call will configure the GPIO (call to config_pio()), set it as input and
+ * activate the interrupt on the given 'sense' event. use the gpio_interrupt_senses
+ * enum for 'sense' values.
+ * The callback will receive the irq number as argument.
+ * Returns the interrupt number if OK, or a negative value in case of error.
+ */
+int set_gpio_callback(void (*callback) (uint32_t), const struct pio* gpio, uint8_t sense);
+void remove_gpio_callback(unsigned int irq);
+
+
+
+/* GPIO Activation */
+void gpio_on(void);
+void gpio_off(void);
+
+#define gpio_dir_in(gpio) \
+{ \
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(0); \
+       gpio_port->dir_clear = (1 << gpio.pin);\
+}
+
+#define gpio_dir_out(gpio) \
+{ \
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(0); \
+       gpio_port->dir_set = (1 << gpio.pin);\
+}
+
+
+#define gpio_set(gpio) \
+{ \
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(0); \
+       gpio_port->set = (1 << gpio.pin);\
+}
+
+#define gpio_clear(gpio) \
+{ \
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(0); \
+       gpio_port->clear = (1 << gpio.pin);\
+}
+
+#define gpio_toggle(gpio) \
+{ \
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(0); \
+       gpio_port->toggle = (1 << gpio.pin);\
+}
+
+
+/* GPIO Configuration
+ * This function calls the config_pio() function for the gpio with the given
+ * mode, configures the direction of the pin and sets the initial state.
+ * Use GPIO_DIR_IN or GPIO_DIR_OUT for the direction "dir", and 0 or 1 for the initial
+ * value "ini_val".
+ */
+void config_gpio(const struct pio* gpio, uint32_t mode, uint8_t dir, uint8_t ini_val);
+
+
+
+/***************************************************************************** */
+/*                     General Purpose Input/Output                            */
+/***************************************************************************** */
+/* General Purpose Input/Output (GPIO) */
+struct lpc_gpio
+{
+       volatile uint8_t  bval[32];   /* 0x0000 - 0x001C : Pin value of each pin on a byte for quick access */
+       uint32_t reserved_0[1016];
+       volatile uint32_t wval[32];   /* 0x1000 - 0x1074 : Pin value of each pin on a 32bits word for quick access */
+       uint32_t reserved_1[992];
+       volatile uint32_t data_dir;   /* 0x2000 : Data direction Register (R/W) */
+       uint32_t reserved_2[31];
+       volatile uint32_t mask;       /* 0x2080 : Pin mask, affects data, out, set, clear and invert */
+       uint32_t reserved_3[31];
+       volatile uint32_t val;        /* 0x2100 : Port data Register (R/W) */
+       uint32_t reserved_4[31];
+       volatile uint32_t mval;       /* 0x2180 : Port masked data Register (R/W) */
+       uint32_t reserved_5[31];
+       volatile uint32_t set;        /* 0x2200 : Port output set Register (-/W) */
+       uint32_t reserved_6[31];
+       volatile uint32_t clear;      /* 0x2280 : Port output clear Register (-/W) */
+       uint32_t reserved_7[31];
+       volatile uint32_t toggle;     /* 0x2300 : Port output invert Register (-/W) */
+       uint32_t reserved_8[31];
+       volatile uint32_t dir_set;    /* 0x2380 : Port direction set (set as output) Register (-/W) */
+       uint32_t reserved_9[31];
+       volatile uint32_t dir_clear;  /* 0x2400 : Port direction clear (set as input) Register (-/W) */
+       uint32_t reserved_10[31];
+       volatile uint32_t dir_toggle; /* 0x2480 : Port direction toggle Register (-/W) */
+};
+#define LPC_GPIO_0      ((struct lpc_gpio *) LPC_GPIO_BASE)
+#define LPC_GPIO_REGS(x)  ((struct lpc_gpio *) (LPC_GPIO_BASE))
+
+
+
+
+
+/***************************************************************************** */
+/*                    Pin interrupts and patern interrupts                     */
+/***************************************************************************** */
+/* Pin and pattern interrupts */
+struct lpc_pin_int
+{
+       volatile uint32_t mode;  /* 0x000 : Pin interrupt mode (R/W) */
+       volatile uint32_t lvl_rising_enable; /* 0x004 : Pin interrupt level or rising edge int enable (R/W) */
+       volatile uint32_t lvl_rising_set_en; /* 0x008 : Pin interrupt level or rising edge int set (-/W) */
+       volatile uint32_t lvl_rising_clr_en; /* 0x00C : Pin interrupt level or rising edge int clear (-/W) */
+       volatile uint32_t lvl_falling_enable; /* 0x010 : Pin interrupt active level or falling edge int enable (R/W) */
+       volatile uint32_t lvl_falling_set_en; /* 0x014 : Pin interrupt active level or falling edge int set (-/W) */
+       volatile uint32_t lvl_falling_clr_en; /* 0x018 : Pin interrupt active level or falling edge int clear (-/W) */
+       volatile uint32_t rising;  /* 0x01C : Pin interrupt rising edge register (R/W) */
+       volatile uint32_t falling; /* 0x020 : Pin interrupt falling edge register (R/W) */
+       volatile uint32_t status;  /* 0x024 : Pin interrupt status register (R/W) */
+       volatile uint32_t pmatch_ctrl;  /* 0x028 : Pattern match interrupt control (R/W) */
+       volatile uint32_t pmatch_bitslice_src;   /* 0x02C : Pattern match interrupt bit-slice source (R/W) */
+       volatile uint32_t pmatch_bitslice_config;  /* 0x030 : Pattern match interrupt bit-slice configuration (R/W) */
+};
+#define LPC_GPIO_INTERRUPTS ((struct lpc_pin_int *) LPC_GPIO_INTR_BASE)
+
+
+
+
+
+#endif /* DRIVERS_GPIO_H */
diff --git a/include/drivers/i2c.h b/include/drivers/i2c.h
new file mode 100644 (file)
index 0000000..b67c96d
--- /dev/null
@@ -0,0 +1,249 @@
+/****************************************************************************
+ *   drivers/i2c.h
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/**************************************************************************** */
+/*                      I2C                                                   */
+/**************************************************************************** */
+
+/* I2C driver for the I2C bus integrated module of the LPC1224.
+ * Refer to LPC1224 documentation (UM10441.pdf) for more information.
+ */
+
+#ifndef DRIVERS_I2C_H
+#define DRIVERS_I2C_H
+
+#include "lib/stdint.h"
+
+
+#define NB_I2C_BUSSES   4
+
+#define I2C_CLK_100KHz  (100*1000)
+#define I2C_CLK_400KHz  (400*1000)
+
+#define I2C_READ_BIT 0x01
+#define I2C_WRITE_BIT 0x00
+
+#define I2C0  0
+#define I2C1  1
+#define I2C2  2
+#define I2C3  3
+
+
+enum i2c_type {
+       I2C_MASTER = 0,
+       I2C_SLAVE,
+       I2C_MONITOR,
+};
+
+enum i2c_conditions {
+       I2C_CONT = 0,
+       I2C_DO_REPEATED_START,
+       I2C_DO_STOP_START,
+       I2C_STOP,
+};
+
+enum i2c_states {
+       /* Must be set before starting the state machine to be able to wait for completion. */
+       I2C_BUSY = 0,
+       I2C_OK, /* All right, default state after init has been done. */
+       /* Sent slave address and it got ACK'ed, but no data.
+        *  Used to probe or wait for completion. */
+       I2C_NO_DATA,
+       I2C_NACK, /* NACK received */
+       I2C_TIME_OUT,
+       I2C_ARBITRATION_LOST, /* Another master took the I2C Bus from us ... */
+       I2C_BUS_ERROR, /* Illegal start or stop (status of 0x00) */
+       I2C_ERROR_UNKNOWN,
+};
+
+enum i2c_state_machine_states {
+       /* Error states */
+       I2C_ILLEGAL = 0x00, /* Illegal start or stop */
+       I2C_ARBIT_LOST = 0x38,
+       /* Start condition states */
+       I2C_STARTED = 0x08,
+       I2C_RESTARTED, /* Unused, should be set when restarting (STOP+START) after a NACK */
+       I2C_REPEATED_START = 0x10,
+       /* Transmitter states */
+       I2C_ACK_ON_ADDRESS_W = 0x18,
+       I2C_NACK_ON_ADDRESS_W = 0x20,
+       I2C_ACK_ON_DATA_W = 0x28,
+       I2C_NACK_ON_DATA_W = 0x30,
+       /* Receiver states */
+       I2C_ACK_ON_ADDRESS_R = 0x40,
+       I2C_NACK_ON_ADDRESS_R = 0x48,
+       I2C_DATA_ACK = 0x50,
+       I2C_DATA_NACK = 0x58,
+};
+
+
+
+
+/***************************************************************************** */
+/*                Modules I2C access                                           */
+/***************************************************************************** */
+/* I2C Read
+ * Performs a non-blocking read on the i2c bus.
+ *   cmd_buf : buffer containing all control byte to be sent on the i2c bus
+ *   cmd_size : size of the cmd_buf command buffer
+ *   ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
+ *         ctrl_buf has the same size as cmd_buf
+ *   inbuff : the buffer where read data will be put.
+ *   count : the number of bytes to be read.
+ * RETURN VALUE
+ *   Upon successfull completion, returns the number of bytes read. On error, returns a negative
+ *   integer equivalent to errors from glibc.
+ *   -EBADFD : Device not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EAGAIN : Device already in use
+ *   -EINVAL : Invalid argument (buf)
+ *   -EREMOTEIO : Device did not acknowledge
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+int i2c_read(uint8_t bus_num, const void *cmd_buf, size_t cmd_size, const void* ctrl_buf, void* inbuff, size_t count);
+
+/* I2C Write
+ * Performs a non-blocking write on the i2c bus.
+ *   buf : buffer containing all byte to be sent on the i2c bus,
+ *         including conrtol bytes (address, offsets, ...)
+ *   count : the number of bytes to be sent, including address bytes and so on.
+ *   ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
+ *         ctrl_buf has the same size as cmd_buf
+ *         FIXME : note that STOP + START conditions are not allowed, the STOP would lead to sending
+ *         the first bytes of buf, creating an infinite loop.
+ * RETURN VALUE
+ *   Upon successfull completion, returns the number of bytes written. On error, returns a negative
+ *   integer equivalent to errors from glibc.
+ *   -EBADFD : Device not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EAGAIN : Device already in use
+ *   -EINVAL : Invalid argument (buf)
+ *   -EREMOTEIO : Device did not acknowledge
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+int i2c_write(uint8_t bus_num, const void *buf, size_t count, const void* ctrl_buf);
+
+
+
+int i2c_set_timeout(uint8_t bus_num, uint16_t timeout);
+
+
+/***************************************************************************** */
+/*                I2C Init                                                     */
+/***************************************************************************** */
+int i2c_on(uint8_t bus_num, uint32_t i2c_clk_freq, uint8_t mode);
+int i2c_off(uint8_t bus_num);
+/* Allow system to propagate main clock */
+void i2c_clock_update(void);
+
+
+/***************************************************************************** */
+/*                     Inter-Integrated Circuit                                */
+/***************************************************************************** */
+/* Inter-Integrated Circuit (I2C) */
+struct lpc_i2c
+{
+       volatile uint32_t config;        /* 0x000 : I2C Configuration of shared functions (R/W) */
+       volatile uint32_t status;        /* 0x004 : I2C Status Register (R/W) */
+       volatile uint32_t int_en_set;    /* 0x008 : I2C Interrupt Enable Set and Read (R/W) */
+       volatile uint32_t int_en_clr;    /* 0x00C : I2C Interrupt Enable Clear (-/W) */
+       volatile uint32_t timeout;       /* 0x010 : I2C Timeout Value (R/W) */
+       volatile uint32_t clkdiv;        /* 0x014 : I2C Clock pre-divider */
+       volatile uint32_t int_status;    /* 0x018 : I2C Interrupt Status (R/-) */
+       uint32_t reserved0;
+       volatile uint32_t master_ctrl;   /* 0x020 : I2C Master Control Register (R/W) */
+       volatile uint32_t master_timing; /* 0x024 : I2C Master Timing Configuration (R/W) */
+       volatile uint32_t master_data;   /* 0x028 : I2C Master Data Register (R/W) */
+       uint32_t reserved1[5];
+       volatile uint32_t slave_ctrl;    /* 0x040 : I2C Slave Control Register (R/W) */
+       volatile uint32_t slave_data;    /* 0x044 : I2C Slave Data Register (R/W) */
+       volatile uint32_t slave_addr_0;  /* 0x048 : I2C Slave Address Register 0 (R/W) */
+       volatile uint32_t slave_addr_1;  /* 0x04C : I2C Slave Address Register 1 (R/W) */
+       volatile uint32_t slave_addr_2;  /* 0x050 : I2C Slave Address Register 2 (R/W) */
+       volatile uint32_t slave_addr_3;  /* 0x054 : I2C Slave Address Register 3 (R/W) */
+       volatile uint32_t slave_a0_qual; /* 0x058 : I2C Slave Address 0 Qualification (R/W) */
+       uint32_t reserved2[9];
+       volatile const uint32_t monitor_data;  /* 0x080 : Monitor receiver Data register (R/-) */
+};
+#define LPC_I2C0         ((struct lpc_i2c *) LPC_I2C0_BASE)
+#define LPC_I2C1         ((struct lpc_i2c *) LPC_I2C1_BASE)
+#define LPC_I2C2         ((struct lpc_i2c *) LPC_I2C2_BASE)
+#define LPC_I2C3         ((struct lpc_i2c *) LPC_I2C3_BASE)
+
+/* Config Register */
+#define I2C_MASTER_EN    (0x01 << 0)
+#define I2C_SLAVE_EN     (0x01 << 1)
+#define I2C_MONITOR_EN   (0x01 << 2)
+#define I2C_TIMEOUT_EN   (0x01 << 3)
+#define I2C_MONITOR_CLK_STRETCH   (0x01 << 4)
+
+/* Status and Interrupt Registers */
+/* Master status */
+#define I2C_ST_MASTER_PENDING     (0x01 << 0)
+#define I2C_ST_MASTER_STATE_MASK  (0x07 << 1)
+#define I2C_ST_MASTER_STATE_SHIFT  1
+#define I2C_ST_MASTER_STATE(x)    (((x) & I2C_ST_MASTER_STATE_MASK) >> I2C_ST_MASTER_STATE_SHIFT)
+#define I2C_ST_MASTER_ARB_LOSS    (0x01 << 4)
+#define I2C_ST_MASTER_STERR       (0x01 << 6)
+/* Slave status */
+#define I2C_ST_SLAVE_PENDING      (0x01 << 8)
+#define I2C_ST_SLAVE_STATE_MASK   (0x03 << 9)
+#define I2C_ST_SLAVE_STATE_SHIFT   9
+#define I2C_ST_SLAVE_STATE        (((x) & I2C_ST_SLAVE_STATE_MASK) >> I2C_ST_SLAVE_STATE_SHIFT)
+#define I2C_ST_SLAVE_NO_STRETCH   (0x01 << 11)
+#define I2C_ST_SLAVE_IDX_MASK     (0x03 << 12)
+#define I2C_ST_SLAVE_IDX_SHIFT     12
+#define I2C_ST_SLAVE_IDX(x)       (((x) & I2C_ST_SLAVE_IDX_MASK) >> I2C_ST_SLAVE_IDX_SHIFT)
+#define I2C_ST_SLAVE_SELECTED     (0x01 << 14)
+#define I2C_ST_SLAVE_DESELECTED   (0x01 << 15)
+/* Monitor */
+#define I2C_ST_MONITOR_READY      (0x01 << 16)
+#define I2C_ST_MONITOR_OVERRUN    (0x01 << 17)
+#define I2C_ST_MONITOR_ACTIVE     (0x01 << 18)
+#define I2C_ST_MONITOR_IDLE       (0x01 << 19)
+/* Events */
+#define I2C_ST_EVENT_TIMEOUT      (0x01 << 24)
+#define I2C_ST_SCL_TIMEOUT        (0x01 << 25)
+
+#define I2C_ST_CLR_MASTER         (I2C_ST_MASTER_ARB_LOSS | I2C_ST_MASTER_STERR)
+#define I2C_ST_CLR_SLAVE          (I2C_ST_SLAVE_DESELECTED)
+#define I2C_ST_CLR_MON            (I2C_ST_MONITOR_OVERRUN | I2C_ST_MONITOR_IDLE)
+#define I2C_ST_CLR_EVT            (I2C_ST_EVENT_TIMEOUT | I2C_ST_SCL_TIMEOUT)
+#define I2C_ST_CLEAR_ALL          (I2C_ST_CLR_MASTER | I2C_ST_CLR_SLAVE | I2C_ST_CLR_MON | I2C_ST_CLR_EVT)
+
+/* Master Control Register */
+#define I2C_MASTER_CONTINUE    (0x01 << 0)
+#define I2C_MASTER_START       (0x01 << 1)
+#define I2C_MASTER_STOP        (0x01 << 2)
+#define I2C_MASTER_DMA         (0x01 << 3)
+
+
+#define I2C_ASSERT_ACK   (0x01 << 2)
+#define I2C_INTR_FLAG    (0x01 << 3)
+#define I2C_STOP_FLAG    (0x01 << 4)
+#define I2C_START_FLAG   (0x01 << 5)
+#define I2C_ENABLE_FLAG  (0x01 << 6)
+
+
+
+
+#endif /* DRIVERS_I2C_H */
diff --git a/include/drivers/serial.h b/include/drivers/serial.h
new file mode 100644 (file)
index 0000000..6b0e973
--- /dev/null
@@ -0,0 +1,210 @@
+/****************************************************************************
+ *  drivers/serial.h
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/***************************************************************************** */
+/*                UARTs                                                        */
+/***************************************************************************** */
+/* UART driver for the integrated UARTs.
+ * Refer to micro-controller documentation for more information.
+ */
+
+/* All three UARTs are available, UART numbers are in the range 0 - 2 */
+
+#ifndef DRIVERS_SERIAL_H
+#define DRIVERS_SERIAL_H
+
+
+#include "lib/stdint.h"
+
+
+#define UART0  0
+#define UART1  1
+#define UART2  2
+#define UART3  3
+
+
+#define SERIAL_CAP_UART   (1 << 0)
+#define SERIAL_CAP_RS485  (1 << 1)
+
+#define SERIAL_MODE_UART  SERIAL_CAP_UART
+#define SERIAL_MODE_RS485 SERIAL_CAP_RS485
+
+
+/* This buffer size is the maximum write size for a serial_printf or a uprintf call.
+ * Previously this value was 64, but it is often too short, so I set it to 96, which
+ *    should be OK for most cases. In need of a bigger write buffer, change this value
+ *    or perform multiple write calls (better).
+ */
+#define SERIAL_OUT_BUFF_SIZE 96
+
+
+/***************************************************************************** */
+/*    Serial Write
+ *
+ * Try to send at most "length" characters from "buf" on the requested uart.
+ * Returns a negative value on error, or number of characters copied into output buffer,
+ * witch may be less than requested "length"
+ * Possible errors: requested uart does not exists (-EINVAL) or unable to acquire uart
+ * lock (-EBUSY).
+ *
+ * Warning for Real Time : This implementation will block if there's already a
+ * transmission ongoing.
+ */
+int serial_write(uint32_t uart_num, const char *buf, uint32_t length);
+
+/***************************************************************************** */
+/*    Serial Flush
+ *
+ * Wait until all characters have been sent
+ * Returns -EINVAL on error, 0 on success.
+ * Possible errors: requested uart does not exists or unable to acquire uart lock.
+ *
+ * Warning for Real Time : This implementation will block if there's already a
+ * transmission ongoing.
+ */
+int serial_flush(uint32_t uart_num);
+
+
+/****************************************************************************** */
+/*    Serial send byte - quick function with almost no tests.
+ * If the uart is not sending, the byte is placed directly in the data buffer and
+ * the call returns 0.
+ * Else, the call returns -EBUSY and nothing is sent.
+ */
+int serial_send_quickbyte(uint32_t uart_num, uint8_t data);
+
+
+/***************************************************************************** */
+/*   Public access to UART setup   */
+
+
+/* Change UART configuration (number of data, parity and stop bits).
+ * config is usually a mask of LPC_UART_xBIT (x = 5..8), LPC_UART_xSTOP (x = 1..2)
+ *   and one of LPC_UART_NO_PAR, LPC_UART_ODD_PAR or LPC_UART_EVEN_PAR.
+ */
+int uart_set_config(uint8_t uart_num, uint32_t config);
+
+/* Change uart mode to RS485
+ * return -ENODEV when the device does not support RS485 mode.
+ */
+int uart_set_mode_rs485(uint32_t uart_num, uint32_t control, uint8_t addr, uint8_t delay);
+
+/* Change uart mode to IRDA
+ * return -ENODEV when the device does not support IrDA mode.
+ */
+int uart_set_mode_irda(uint32_t uart_num, uint32_t control, uint16_t pulse_width);
+
+/* Allow any change to the main clock to be forwarded to us */
+void uart_clk_update(void);
+
+/* Do we need to allow setting of other parameters ? (Other than 8n1) */
+int uart_on(uint32_t uart_num, uint32_t baudrate, void (*rx_callback)(uint8_t));
+
+void uart_off(uint32_t uart_num);
+
+
+/***************************************************************************** */
+/*              Universal Synchronous or Asynchronous Receiver Transmitter     */
+/***************************************************************************** */
+/* Universal Synchronous or Asynchronous Receiver Transmitter (USART) */
+struct lpc_usart
+{
+       volatile uint32_t config;      /* 0x000 : USART configuration register (R/W) */
+       volatile uint32_t control;     /* 0x004 : USART control register (R/W) */
+       volatile uint32_t status;      /* 0x008 : USART status register (R/W) */
+       volatile uint32_t inten_set;   /* 0x00C : Interupt enable set / read (R/W) */
+       volatile uint32_t inten_clear; /* 0x010 : Interupt enable clear (-/W) */
+       volatile uint32_t rx_data;     /* 0x014 : Receiver Data register (R/-) */
+       volatile uint32_t rx_datstat;  /* 0x018 : Receiver Data with status register (R/-) */
+       volatile uint32_t tx_data;     /* 0x01C : Transmit Data register (R/W) */
+       volatile uint32_t baudrate_gen;  /* 0x020 : Baud Rate Generator register (R/W) */
+       volatile uint32_t int_status;  /* 0x024 : Interrupt status register (R/-) */
+       volatile uint32_t oversample_sel;  /* 0x028 : Oversample selection register (R/W) */
+       volatile uint32_t address;     /* 0x02C : Address register (R/W) */
+};
+#define LPC_UART_0        ((struct lpc_usart *) LPC_USART0_BASE)
+#define LPC_UART_1        ((struct lpc_usart *) LPC_USART1_BASE)
+#define LPC_UART_2        ((struct lpc_usart *) LPC_USART2_BASE)
+
+/* Configuration Register */
+#define LPC_UART_ENABLE        (0x01 << 0)
+#define LPC_UART_7BIT          (0x00 << 2)
+#define LPC_UART_8BIT          (0x01 << 2)
+#define LPC_UART_9BIT          (0x02 << 2)
+#define LPC_UART_NO_PAR        (0x00 << 4)
+#define LPC_UART_EVEN_PAR      (0x02 << 4)
+#define LPC_UART_ODD_PAR       (0x03 << 4)
+#define LPC_UART_1STOP         (0x00 << 6)
+#define LPC_UART_2STOP         (0x01 << 6)
+#define LPC_UART_CTS_EN        (0x01 << 9)
+#define LPC_UART_LOOPBACK      (0x01 << 15)
+#define LPC_UART_RX_POL_INVERT (0x01 << 22)
+#define LPC_UART_TX_POL_INVERT (0x01 << 23)
+/* Configuration for synchronous mode */
+#define LPC_UART_SYNCHRONOUS   (0x01 << 11)
+#define LPC_UART_CLK_POL_FALL  (0x00 << 12)
+#define LPC_UART_CLK_POL_RISE  (0x01 << 12)
+#define LPC_UART_SYNC_SLAVE    (0x00 << 14)
+#define LPC_UART_SYNC_MASTER   (0x01 << 14)
+/* Configuration for RS485 mode */
+#define LPC_RS485_OE_TURNAROUND_EN  (0x01 << 18)
+#define LPC_RS485_AUTO_ADDR_EN (0x01 << 19)
+#define LPC_RS485_ENABLE       (0x01 << 20)
+#define LPC_RS485_DIR_CTRL_INV (0x01 << 21)
+
+/* Control Register */
+#define LPC_UART_TX_BREAK_EN   (0x01 << 1)
+#define LPC_UART_ADDR_DETECT   (0x01 << 2)
+#define LPC_UART_TX_DISABLE    (0x01 << 6)
+#define LPC_UART_CONT_CLK      (0x01 << 8)
+#define LPC_UART_RX_CONT_CLK_CLR  (0x01 << 9)
+#define LPC_UART_AUTOBAUD      (0x01 << 16)
+
+/* Status, Interrupt Enable, and Interrupt clear Register definition */
+#define LPC_UART_ST_RX_READY   (0x01 << 0)
+#define LPC_UART_ST_RX_IDLE    (0x01 << 1)
+#define LPC_UART_ST_TX_READY   (0x01 << 2)
+#define LPC_UART_ST_TX_IDLE    (0x01 << 3)
+#define LPC_UART_ST_CTS        (0x01 << 4)
+#define LPC_UART_ST_CTS_CHANGE (0x01 << 5)
+#define LPC_UART_ST_TX_DISABLE (0x01 << 6)
+#define LPC_UART_ST_OVERRUN    (0x01 << 8)
+#define LPC_UART_ST_RX_BREAK   (0x01 << 10)
+#define LPC_UART_ST_BRK_CHANGE (0x01 << 11)
+#define LPC_UART_ST_START      (0x01 << 12)
+#define LPC_UART_ST_FRAME_ERR  (0x01 << 13)
+#define LPC_UART_ST_PAR_ERR    (0x01 << 14)
+#define LPC_UART_ST_NOISE_ERR  (0x01 << 15)
+#define LPC_UART_ST_AUTOBAUD_ERR  (0x01 << 16)
+/* Status helpers */
+#define LPC_UART_ST_CLEAR      (0x1F920)
+#define LPC_UART_ERR_FLAGS     (LPC_UART_ST_FRAME_ERR | LPC_UART_ST_PAR_ERR | LPC_UART_ST_NOISE_ERR)
+
+/* Baud rate generator divisor */
+#define LPC_UART_BRG_DIV(x)   (((x) - 1) & 0xFFFF)
+/* Oversampling register */
+#define LPC_UART_OVERSAMPLING(x)  (((x) - 1) & 0x0F)
+
+/* RS485 or UART address */
+#define LPC_RS485_ADDR(x)  ((x) & 0xFF)
+#define LPC_UART_ADDR(x)  ((x) & 0xFF)
+
+
+#endif /* DRIVERS_SERIAL_H */
diff --git a/include/extdrv/tmp101_temp_sensor.h b/include/extdrv/tmp101_temp_sensor.h
new file mode 100644 (file)
index 0000000..72101d6
--- /dev/null
@@ -0,0 +1,126 @@
+/****************************************************************************
+ *   extdrv/tmp101_temp_sensor.h
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef EXTDRV_TEMP_H
+#define EXTDRV_TEMP_H
+
+#include "lib/stdint.h"
+
+
+/***************************************************************************** */
+/*          Support for TMP101 temperature sensors from Texas Instrument       */
+/***************************************************************************** */
+/* This driver is made for the TMP101 version of the chip, though there's few
+ * diferences between the TMP100 and TMP101 version.
+ * This driver does not handle the SMBus Alert command.
+ */
+
+
+/* Faulty mesures required to trigger alert */
+#define TMP_FAULT_ONE       ((0x00 & 0x03) << 3)
+#define TMP_FAULT_TWO       ((0x01 & 0x03) << 3)
+#define TMP_FAULT_FOUR      ((0x02 & 0x03) << 3)
+#define TMP_FAULT_SIX       ((0x03 & 0x03) << 3)
+
+/* Temp mesurement resolution bits */            /* conversion time */
+#define TMP_RES_NINE_BITS   ((0x00 & 0x03) << 5)   /*  40ms */
+#define TMP_RES_TEN_BITS    ((0x01 & 0x03) << 5)   /*  80ms */
+#define TMP_RES_ELEVEN_BITS ((0x02 & 0x03) << 5)   /* 160ms */
+#define TMP_RES_TWELVE_BITS ((0x03 & 0x03) << 5)   /* 320ms */
+
+
+/* TMP101 sensor instance data.
+ * Use one of this for each sensor you want to access.
+ * - addr is the sensor address on most significant bits.
+ * - last_accessed_register is used to keep track of the last register accessed to
+ * prevent sending the pointer register again if we want to read the same register again.
+ * - resolution is one of the above resolution defined values.
+ */
+struct tmp101_sensor_config {
+       uint8_t addr;
+       uint8_t bus_num;
+       uint8_t probe_ok;
+       uint8_t actual_config;
+       int last_accessed_register;
+       uint32_t resolution;
+};
+
+
+/* Check the sensor presence, return 1 if found
+ * This is a basic check, it could be anything with the same address ...
+ * addr: the sensor address on most significant bits.
+ */
+int tmp101_probe_sensor(struct tmp101_sensor_config* conf);
+
+
+/* Convert raw temperature data (expressed as signed value of 16 times the
+ * actual temperature in the twelve higher bits of a sixteen bits wide value)
+ * into a decimal interger value of ten times the actual temperature.
+ * The value returned is thus in tenth of degrees centigrade.
+ */
+int tmp101_convert_to_deci_degrees(uint16_t raw);
+
+
+/* Temp Read
+ * Performs a non-blocking read of the temperature from the sensor.
+ * addr: the sensor address on most significant bits.
+ * 'raw' and 'deci_degrees': integer addresses for conversion result, may be NULL.
+ * Return value(s):
+ *   Upon successfull completion, returns 0 and the temperature read is placed in the
+ *   provided integer(s). On error, returns a negative integer equivalent to errors from
+ *   glibc.
+ *   -EBADFD : I2C not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EINVAL : Invalid argument (buf)
+ *   -ENODEV : No such device
+ *   -EREMOTEIO : Device did not acknowledge : Any device present ?
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+int tmp101_sensor_read(struct tmp101_sensor_config* conf, uint16_t* raw, int* deci_degrees);
+
+
+/* Sensor config
+ * Performs default configuration of the temperature sensor.
+ * The sensor is thus placed in shutdown mode, the thermostat is in interrupt mode,
+ * and the polarity is set to active high.
+ * The conversion resolution is set to the provided "resolution".
+ * addr: the sensor address on most significant bits.
+ * Return value:
+ *   Upon successfull completion, returns 0. On error, returns a negative integer
+ *   equivalent to errors from glibc.
+ *   -EBADFD : I2C not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EINVAL : Invalid argument (buf)
+ *   -ENODEV : No such device
+ *   -EREMOTEIO : Device did not acknowledge : Any device present ?
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+int tmp101_sensor_config(struct tmp101_sensor_config* conf);
+
+/* Start a conversion when the sensor is in shutdown mode.
+ * addr : the sensor address on most significant bits.
+ */
+int tmp101_sensor_start_conversion(struct tmp101_sensor_config* conf);
+
+
+#endif /* EXTDRV_TEMP_H */
+
diff --git a/include/extdrv/ws2812.h b/include/extdrv/ws2812.h
new file mode 100644 (file)
index 0000000..755886e
--- /dev/null
@@ -0,0 +1,98 @@
+/****************************************************************************
+ *   extdrv/ws2812.h
+ *
+ *
+ * Copyright 2013 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/*
+ * Support for the WS2812 Chainable RGB Leds
+ *
+ * WS2812 protocol can be found here : https://www.adafruit.com/datasheets/WS2812.pdf
+ *
+ */
+
+/*
+ * Preliminary notice :
+ * This driver will only function with a clock frequency of 48MHz (or close to) due to
+ *   the use of nop() to get the right timmings.
+ *
+ * Internal data buffer :
+ * This driver uses an internal buffer for NB_LEDS leds or "pixels". The buffer
+ *   size is (3 * NB_LEDS) bytes.
+ * The buffer is set pixel per pixel using the ws2812_set_pixel() function.
+ * The buffer is then sent to the led strip using ws2812_send_frame().
+ *
+ * Driving several led strips :
+ * It is possible to drive several led strips using this driver by calling the config
+ *   function ws2812_config() between each ws2812_send_frame() call, and setting the led
+ *   data again using the ws2812_set_pixel() function for each new led.
+ * This solution is not the most adapted for several led strips, and the driver should be
+ *   modified to use an external buffer which address is either passed to each function or
+ *   set using a modified version of the ws2812_config() function.
+ *   In this case, the timmings should be checked and updated as access to the data may
+ *   require more instructions.
+ *
+ * Note : ws2812_send_frame() will call lpc_disable_irq() to disable all interrupts
+ *   when entering the timming critical section.
+ *   Use of timers and interrupts have been tried but timmings are too short even
+ *   whith the micro-controller running at 48MHz and direct access to the timer and
+ *   GPIO registers.
+ *   Instead the function uses a few nop() to get the right timmings.
+ *   
+ */
+
+#include "lib/stdint.h"
+#include "core/pio.h"
+
+
+/* Size of the internal buffer.
+ * Change the value to the number of leds of your led strip.
+ */
+#define NB_LEDS  60
+
+
+/* Configure the pin for the led data signal. */
+void ws2812_config(const struct pio* gpio);
+
+/* Send led data from internal buffer using the configured GPIO pin. (Set leds to the
+ *   selected color).
+ * If no pin have been configured, GPIO_0_0 will be used.
+ * If nb_leds is 0 then all led data set using ws2812_set_pixel() since the last call
+ *   to ws2812_clear_buffer(), ws2812_clear() or ws2812_stop() will be sent.
+ * Call to this function will disable interrupts due to timming restrictions.
+ * Return -1 on error (nb_leds above NB_LEDS), or 0 on success.
+ */
+int ws2812_send_frame(uint16_t nb_leds);
+
+/* Set a pixel (led) color in the data buffer (frame)
+ * The pixel number 'pixel_num' is the led offset in the led strip.
+ * 'red', 'green' and 'blue' are the color values of the pixel. A value of 0 is off,
+ *   while a value of 0xFF (255) is full brightness.
+ * Return -1 on error (pixel_num above NB_LEDS), or 0 on success.
+ */
+int ws2812_set_pixel(uint16_t pixel_num, uint8_t red, uint8_t green, uint8_t blue);
+
+/* Clear the internal data buffer. */
+void ws2812_clear_buffer(void);
+
+/* Clear the internal data buffer and send it to the Leds, turning them all off */
+void ws2812_clear(void);
+/*     Alias for ws2812_clear */
+void ws2812_stop(void);
+
diff --git a/include/lib/errno.h b/include/lib/errno.h
new file mode 100644 (file)
index 0000000..8d563eb
--- /dev/null
@@ -0,0 +1,43 @@
+/****************************************************************************
+ *   lib/errno.h
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef LIB_ERRNO_H
+#define LIB_ERRNO_H
+
+/* Error Values, from glibc errno.h and errno-base.h */
+#define EIO          5 /* Bad one: Input or Output error. */
+#define E2BIG        7 /* Argument list too long or Data size beyond buffer size */
+#define EAGAIN      11 /* Device already in use */
+#define EFAULT      14 /* Address error */
+#define EBUSY       16 /* Device or ressource Busy */
+#define ENODEV      19 /* No such device */
+#define EINVAL      22 /* Invalid argument */
+#define EBADFD      77 /* Device not initialized */
+#define EREMOTEIO  121 /* Device did not acknowledge */
+
+/* Note on error values for I2C :
+ *  EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ *  EFAULT : address above eeprom size
+ *  EBUSY : Device or ressource Busy or Arbitration lost
+ *  EREMOTEIO : Device did not acknowledge
+ */
+
+
+#endif /* LIB_ERRNO_H */
diff --git a/include/lib/font.h b/include/lib/font.h
new file mode 100644 (file)
index 0000000..3473f5e
--- /dev/null
@@ -0,0 +1,38 @@
+/************************************************************************
+ * lib/font.h
+ *
+ * Copyright (C) Lisa Milne 2014 <lisa@ltmnet.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ ************************************************************************/
+
+/*
+ * The font has been found on opengameart.org:
+ * http://opengameart.org/content/8x8-ascii-bitmap-font-with-c-source
+ */
+
+#ifndef LIB_FONT_H
+#define LIB_FONT_H
+
+/*
+ * The values in this array are a 8x8 bitmap font for ascii characters
+ * As memory is a very precious ressource on a micro-controller all chars
+ * before "space" (0x20) have been removed.
+ */
+#define NB_FONT_TILES 95
+extern uint8_t first_font_char;
+extern uint64_t font[NB_FONT_TILES];
+
+#endif /* LIB_FONT_H */
diff --git a/include/lib/list.h b/include/lib/list.h
new file mode 100644 (file)
index 0000000..1baab39
--- /dev/null
@@ -0,0 +1,262 @@
+/**
+ *  lib/list.h
+ *
+ * Circular linked list implementation
+ * Using the linked list code from linux
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+#ifndef LIB_LIST_H
+#define LIB_LIST_H
+
+#include "lib/stddef.h"
+
+struct list_head {
+       struct list_head* next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+    struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head* list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head* new, struct list_head* prev, struct list_head* next)
+{
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head* new, struct list_head* head)
+{
+       __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head* new, struct list_head* head)
+{
+       __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head* prev, struct list_head* next)
+{
+       next->prev = prev;
+       prev->next = next;
+}
+
+static inline void list_del(struct list_head* entry)
+{
+       __list_del(entry->prev, entry->next);
+       entry->next = NULL;
+       entry->prev = NULL;
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head* list, const struct list_head* head)
+{
+       return list->next == head;
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head* list,
+                                  struct list_head* head)
+{
+       list_del(list);
+       list_add_tail(list, head);
+}
+
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head* head)
+{
+       return head->next == head;
+}
+
+/**
+ * list_rotate_left - rotate the list to the left
+ * @head: the head of the list
+ */
+static inline void list_rotate_left(struct list_head* head)
+{
+       struct list_head* first;
+
+       if (!list_empty(head)) {
+               first = head->next;
+               list_move_tail(first, head);
+       }
+}
+
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:    the &struct list_head pointer.
+ * @type:   the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+    container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:    the list head to take the element from.
+ * @type:   the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+    list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each    -   iterate over a list
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @head:   the head for your list.
+ */
+#define list_for_each(pos, head) \
+    for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev   -   iterate over a list backwards
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @head:   the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+    for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @n:      another &struct list_head to use as temporary storage
+ * @head:   the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+    for (pos = (head)->next, n = pos->next; pos != (head); \
+        pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos:    the &struct list_head to use as a loop cursor.
+ * @n:      another &struct list_head to use as temporary storage
+ * @head:   the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+    for (pos = (head)->prev, n = pos->prev; \
+         pos != (head); \
+         pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry  -   iterate over list of given type
+ * @pos:    the type * to use as a loop cursor.
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)              \
+    for (pos = list_entry((head)->next, typeof(*pos), member);  \
+         &pos->member != (head);    \
+         pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:    the type * to use as a loop cursor.
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)          \
+    for (pos = list_entry((head)->prev, typeof(*pos), member);  \
+         &pos->member != (head);    \
+         pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:    the type * to use as a loop cursor.
+ * @n:      another type * to use as temporary storage
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)          \
+    for (pos = list_entry((head)->next, typeof(*pos), member),  \
+        n = list_entry(pos->member.next, typeof(*pos), member); \
+         &pos->member != (head);                    \
+         pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ * @pos:    the type * to use as a loop cursor.
+ * @n:      another type * to use as temporary storage
+ * @head:   the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)      \
+    for (pos = list_entry((head)->prev, typeof(*pos), member),  \
+        n = list_entry(pos->member.prev, typeof(*pos), member); \
+         &pos->member != (head);                    \
+         pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+
+
+
+#endif /* LIB_LIST_H */
+
diff --git a/include/lib/protocols/dtplug/defs.h b/include/lib/protocols/dtplug/defs.h
new file mode 100644 (file)
index 0000000..188a5b1
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * lib/protocols/dtplug/defs.h
+ *
+ *
+ * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef LIB_PROTOCOLS_DTPLUG_DEFS_H
+#define LIB_PROTOCOLS_DTPLUG_DEFS_H
+
+
+#include "lib/stdint.h"
+
+/******************************************************************************/
+/* These structures define the packets used to transfer data over the serial link
+ *    between the dtplug (or domotab or any computing platform) and a module
+ */
+
+/* The header is included in each and every packet we need to transfer
+ * It holds information about the message type and content and provides checksum
+ * information of the header and the data part of the packet if any.
+ *
+ * Checksums information :
+ *    The header checksum is a value such that the sum of all bytes of the header
+ *        modulo 256 is equal to 0. (Use a mask with 0xFF to get the modulo)
+ *    The data checksum the sum of all data bytes modulo 256.
+ *
+ * Sequence numbers, data checksums and error codes
+ *    The sequence number is on the 6 least significant bits of the sequence number field.
+ *      this gives 64 sequence numbers which is more than enough.
+ *    When the most significant bit (bit 7) of the sequence number field (seq_num) is set
+ *      in a request (master to slave), the slave MUST send an acknowledge packet or a reply
+ *      with the same sequence number.
+ *      This may help checking which packet triggered the reply and packet losses.
+ *    When bit 7 is set in a reply, it indicates that the packet is an error packet and that
+ *      the union holds error information (error code and aditional error information.
+ *      No data should be present in the packet.
+ *    When set, bit 6 of the sequence number indicates that the union holds 'quick_data'.
+ *      This bit cannot be used for error packets.
+ *      A packet with "quick-data" cannot have additional data.
+ *    When bit 6 is not set, and the packet is not an error packet, the union holds a
+ *      'data_information' structure whith the packet data 'size' (if any) and 'data_checksum'
+ *      for the packet data part.
+ *
+ * Data size and big (continued) data packets
+ *    When a packet does not have enough room for the whole data the most significant bit
+ *      (bit 7) of the data size is set to mark a packet whose data will be continued in a
+ *      subsequent PKT_TYPE_CONTINUED_DATA packet.
+ *      this bit must be set in all but the last one of a continued data packet serie.
+*/
+
+/* Normal packets 'sel' field information : holds information about the data part.
+ * A 'size' of 0 indicates that there is no data part.
+ */
+struct data_information {
+       uint8_t size;  /* Size of the data part. The header size is fixed, so not included */
+       uint8_t checksum;  /* Checksum for the data part */
+} __attribute__ ((__packed__));
+/* Error packet 'sel' field */
+struct error_information {
+       uint8_t error_code;
+       uint8_t info;
+} __attribute__ ((__packed__));
+
+/* Packet header */
+struct header {
+       char start;    /* Start of paquet indicator */
+       uint8_t type;  /* Packet type, used to provide information on the data structure */
+       uint8_t checksum;  /* Header checksum */
+       uint8_t seq_num; /* Packet sequence number on bits 0:5, error indicator on bit 7 */
+       union {
+               struct data_information data;
+               struct error_information err;
+               uint8_t quick_data[2];
+       };
+} __attribute__ ((__packed__));
+
+#define FIRST_PACKET_CHAR  '#'
+/* Sequence byte decoding */
+#define PACKET_NEEDS_REPLY (0x01 << 7) /* Host to slave */
+#define PACKET_IS_ERROR    (0x01 << 7) /* Slave to host */
+#define QUICK_DATA_PACKET  (0x01 << 6)
+#define SEQUENCE_MASK  (0x3F)
+/* Data size decoding */
+#define BIG_DATA_PKT       (0x01 << 7) /* The total data size is above PACKET_DATA_SIZE, the packet will be continued. */
+#define PKT_SIZE_MASK  (0x7F)
+
+/* The following struct defines a generic packet.
+ * Specific packets should be defined in specific structures.
+ */
+#define PACKET_DATA_SIZE  64
+struct packet {
+       struct header info;  /* Packet header */
+       uint8_t data[PACKET_DATA_SIZE];   /* packet data */
+} __attribute__ ((__packed__));
+
+
+
+enum packet_types {
+       /* Common packet types, must be handled by all the slaves */
+       PKT_TYPE_RESET = 0, /* Soft reset of board */
+       PKT_TYPE_PING, /* Reply with no data or urgent data */
+       PKT_TYPE_GET_BOARD_INFO, /* Return board name, version, module version, and programm version. */
+       PKT_TYPE_SET_TIME, /* Set current time for events timestamping */
+       PKT_TYPE_GET_NUM_PACKETS, /* Get the number of packets received since system start */
+       PKT_TYPE_GET_ERRORS, /* Ask the slave to return any active error code in the data */
+       PKT_TYPE_GET_NUM_ERRORS, /* Get the number of errors since system start */
+       PKT_TYPE_SET_USER_INFO, /* Change the current board user information (and reset board) */
+
+       /* Config */
+       PKT_TYPE_ADD_GPIO, /* Configure one of the GPIO or ADC as GPIO */
+       PKT_TYPE_ADD_CS,   /* Configure one of the GPIO or ADC as SPI Chip select */
+       /* ADC config specifies :
+        *   the channel number,
+        *   periodicity of sample (from on request up to continuous),
+        *   and number of values for the continuous average computation
+        */
+       PKT_TYPE_ADD_ADC,  /* Configure one of the ADC as ADC */
+       /* PWM config specifies :
+        *   the channel number,
+        *   the PWM period,
+        *   the channel duty cycle,
+        */
+       PKT_TYPE_ADD_PWM,  /* Configure one of the PWM capable GPIO as PWM */
+
+       /* Continued data. Use for protocols with data size that goes beyond PACKET_DATA_SIZE */
+       PKT_TYPE_CONTINUED_DATA,
+
+       /* Temperature packets */
+       PKT_TYPE_START_TEMP_CONVERSION, /* Requiered to update the temperature value */
+       PKT_TYPE_GET_TEMPERATURE, /* Get temprature values */
+
+       /* ADC, PWM and GPIO packets */
+       PKT_TYPE_START_ADC_CONVERSION,
+       PKT_TYPE_GET_ADC_VALUE,
+       PKT_TYPE_SET_GPIO,
+       PKT_TYPE_GET_GPIO,
+       PKT_TYPE_SET_PWM_CHAN,
+
+       /* Communication */
+       SEND_ON_BUS,
+};
+
+/* Error / status codes */
+enum reply_statuses {
+       NO_ERROR = 0,
+       GOT_MANY_ERRORS, /* This one is returned when there's not only one error */
+       ERROR_PKT_NOT_HANDLED,
+       ERROR_LAST_PKT_IN_PROCESS,
+       ERROR_IN_PKT_STRUCTURE,
+       ERROR_IN_DATA_CHECKSUM,
+       ERROR_IN_DATA_VALUES,
+       ERROR_IN_DATA_SIZE, /* To many data */
+       ERROR_IN_UART_TX,  /* This one is critical if received, and much more critical when it occurs and cannot be sent. */
+       /* Temperature */
+       ERROR_NO_TEMP_SENSOR,
+       ERROR_TEMP_CONVERSION,
+       TEMPERATURE_ALERT,
+       /* Configuration problem */
+       ERROR_FLASH_ERASE, /* Error, unable to erase the user information block */
+       ERROR_FLASH_WRITE, /* Error, unable to write the user information block */
+       /* RF */
+       RF_RX_QUEUE_EMPTY, /* Na RX packet in RX queue */
+       ERROR_IN_RF_RX,
+       ERROR_IN_RF_TX,
+       /* Last error number ... must not be above 255 */
+       LAST_ERROR_NUM,  /* This one is here to get the value of the last enum. */
+};
+
+
+
+/******************************************************************************/
+/* Other information on the protocol */
+
+/* When a packet is received and requires an ACK but no particular data, the slave replies
+ *    using a PING packet, with the sequence field set to the sequence number of the last received packet).
+ *    When the slave has urgent data to send (either errors or alerts), it uses the corresponding bits in
+ *    the sequence byte and places the 'appropriate data (error_information or quick_dtaa) in the 'sel' field.
+ */
+
+/* Multiple-bytes data are sent in Big Endian (network endian) !!!!
+ * This is the usual way to send data over a network, and even if most of our boards and computers are little endian
+ *   there are very little multi-byte information in our protocol so it's OK
+ * The endianness transformation may be done before or after the checksum control, it has no influence on the
+ *   checksum algorithm we chose.
+ */
+
+/* What to do on error, and error recovery procedure.
+ * When a slave has an internal error, it has two options.
+ * Either it's the first one, and the master requested a reply. The slave can then send the error
+ *   code in the reply.
+ * Or it's not the first one or the master did not ask for a reply or ACK. Then the slave stores the
+ *   error code for future transmission.
+ *   If the master asked for a reply and the slave has many errors, the slave send "GOT_MANY_ERRORS" as error code.
+ * When the master receives the "GOT_MANY_ERRORS" error code, it must send a "PKT_TYPE_GET_ERRORS" request.
+ * The slave then replies with a list of all errors in the packet data with a header which does not indicate an
+ *   error packet (this is the normal reply to a PKT_TYPE_GET_ERRORS request.
+ * A slave cannot store more than 8 error codes, if the count is 8, consider that there is a BIG problem !
+ */
+
+
+
+
+#endif /* LIB_PROTOCOLS_DTPLUG_DEFS_H */
diff --git a/include/lib/protocols/dtplug/slave.h b/include/lib/protocols/dtplug/slave.h
new file mode 100644 (file)
index 0000000..94ee66e
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * lib/protocols/dtplug/slave.h
+ *
+ *
+ * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef LIB_PROTOCOLS_DTPLUG_SLAVE_H
+#define LIB_PROTOCOLS_DTPLUG_SLAVE_H
+
+
+#include "lib/stdint.h"
+#include "lib/protocols/dtplug/defs.h"
+
+
+/******************************************************************************/
+/* DTPlug (or DomoTab, PC, ...) Communication */
+
+#define DTPP_MAX_ERROR_STORED 8
+
+struct dtplug_protocol_handle {
+       /* Store two packets, one being received, one being used */
+       struct packet packets[2];
+       struct packet* rx_packet;
+       volatile struct packet* packet_ok;
+
+       uint32_t packet_count;
+
+       uint32_t errors_count;
+       uint8_t error_storage[(DTPP_MAX_ERROR_STORED * 2)];
+       uint8_t num_errors_stored;
+
+       /* Set to 1 when the packet is handled to tell the decoder we can handle a new one.
+        * MUST be initialised to 1 or the handle will think we have a valid packet to handle upon
+        * system startup */
+       uint8_t done_with_old_packet;
+       uint8_t uart;
+};
+
+
+/* Setup the UART used for communication with the host / master (the module is slave) */
+void dtplug_protocol_set_dtplug_comm_uart(uint8_t uart_num, struct dtplug_protocol_handle* handle);
+
+
+/* Tell the receive routine that the "packet_ok" packet is no more in use and that
+ *  we are ready to handle a new one */
+void dtplug_protocol_release_old_packet(struct dtplug_protocol_handle* handle);
+
+
+/* Get a pointer to the new packet received.
+ * Return NULL when no new packet were received since last packet was released.
+ */
+struct packet* dtplug_protocol_get_next_packet_ok(struct dtplug_protocol_handle* handle);
+
+
+/* When a packet has not been handled we must not count it as acknowledged
+ * On the next ping request the master will then see wich packet caused the problem.
+ */
+void dtplug_protocol_add_error_to_list(struct dtplug_protocol_handle* handle, struct header* info, uint8_t error_code);
+
+
+/* This function handle sending replies when requested by the host.
+ * When there is an error but the host did not request a reply, this function stores the error for
+ *    future request.
+ * When a reply is effectively sent, the PACKET_NEEDS_REPLY bit is removed from the sequence filed
+ *   packet handling code will know if there is still a PING request to be answered.
+ */
+void dtplug_protocol_send_reply(struct dtplug_protocol_handle* handle,
+                                                                       struct packet* question, uint8_t error, int size, uint8_t* data);
+
+
+
+#endif /* LIB_PROTOCOLS_DTPLUG_SLAVE_H */
diff --git a/include/lib/stddef.h b/include/lib/stddef.h
new file mode 100644 (file)
index 0000000..ec72897
--- /dev/null
@@ -0,0 +1,53 @@
+/****************************************************************************
+ *   lib/stddef.h
+ *
+ * Copyright 2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ r
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef LIB_STDDEF_H
+#define LIB_STDDEF_H
+
+
+#undef __SIZE_TYPE__
+#define __SIZE_TYPE__ long unsigned int
+typedef __SIZE_TYPE__ size_t;
+
+#define NULL ((void *)0)
+
+
+/**
+ * offsetof - return the offset of a member in the containing structure.
+ */
+#ifdef __builtin_offsetof
+ #define offsetof(type, member)  __builtin_offsetof (type, member)
+#else
+ #define offsetof(type, member) ((size_t) &((type *)0)->member)
+#endif
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:        the pointer to the member.
+ * @type:       the type of the container struct this is embedded in.
+ * @member:     the name of the member within the struct.
+ */
+#define container_of(ptr, type, member) ({                      \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+#endif /* LIB_STDDEF_H */
diff --git a/include/lib/stdint.h b/include/lib/stdint.h
new file mode 100644 (file)
index 0000000..3b5318d
--- /dev/null
@@ -0,0 +1,107 @@
+/****************************************************************************
+ *   lib/"lib/stdint.h"
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ r
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef LIB_STDINT_H
+#define LIB_STDINT_H
+
+/* Signed */
+typedef signed char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
+__extension__
+typedef long long int int64_t;
+/* Small types - Signed */
+typedef signed char int_least8_t;
+typedef short int int_least16_t;
+typedef int int_least32_t;
+__extension__
+typedef long long int int_least64_t;
+/* Fast types - Signed */
+typedef signed char int_fast8_t;
+typedef int int_fast16_t;
+typedef int int_fast32_t;
+__extension__
+typedef long long int int_fast64_t;
+
+
+/* Unsigned */
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+__extension__
+typedef unsigned long long int uint64_t;
+/* Small types - Unsigned */
+typedef unsigned char uint_least8_t;
+typedef unsigned short int uint_least16_t;
+typedef unsigned int uint_least32_t;
+__extension__
+typedef unsigned long long int uint_least64_t;
+/* Fast types - Unsigned */
+typedef unsigned char uint_fast8_t;
+typedef unsigned int uint_fast16_t;
+typedef unsigned int uint_fast32_t;
+__extension__
+typedef unsigned long long int uint_fast64_t;
+
+typedef long unsigned int size_t;
+
+
+/* Types for `void *' pointers.  */
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+
+/* Largest integral types.  */
+__extension__
+typedef long long int intmax_t;
+__extension__
+typedef unsigned long long int uintmax_t;
+
+#  define __INT64_C(c)  c ## LL
+#  define __UINT64_C(c) c ## ULL
+
+
+/* Limits of integral types.  */
+
+/* Minimum of signed integral types.  */
+#define INT8_MIN       (-128)
+#define INT16_MIN      (-32767-1)
+#define INT32_MIN      (-2147483647-1)
+#define INT64_MIN      (-__INT64_C(9223372036854775807)-1)
+/* Maximum of signed integral types.  */
+#define INT8_MAX       (127)
+#define INT16_MAX      (32767)
+#define INT32_MAX      (2147483647)
+#define INT64_MAX      (__INT64_C(9223372036854775807))
+
+/* Maximum of unsigned integral types.  */
+#define UINT8_MAX      (255)
+#define UINT16_MAX     (65535)
+#define UINT32_MAX     (4294967295U)
+#define UINT64_MAX     (__UINT64_C(18446744073709551615))
+
+
+#define SIZE_MAX     (4294967295UL)
+
+#define __WORDSIZE  32
+
+
+#endif /* LIB_STDINT_H */
diff --git a/include/lib/stdio.h b/include/lib/stdio.h
new file mode 100644 (file)
index 0000000..a3547f7
--- /dev/null
@@ -0,0 +1,39 @@
+/****************************************************************************
+ *  lib/stdio.h
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef LIB_STDIO_H
+#define LIB_STDIO_H
+
+#include <stdarg.h>
+#include "lib/stdint.h"
+#include "lib/string.h"
+
+
+/* */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+/* */
+int snprintf(char* buf, size_t size, const char *format, ...);
+
+/* */
+int uprintf(int uart_num, const char *format, ...);
+
+
+#endif /* LIB_STDIO_H */
diff --git a/include/lib/stdlib.h b/include/lib/stdlib.h
new file mode 100644 (file)
index 0000000..9ae275d
--- /dev/null
@@ -0,0 +1,34 @@
+/****************************************************************************
+ *  lib/stdlib.h
+ *
+ * Copyright 2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef LIB_STDLIB_H
+#define LIB_STDLIB_H
+
+#include "lib/stdint.h"
+
+/* Simple strtoul implementation.
+ * Returns the value converted from the given string.
+ * Does not check that the base is respected aside for the use of letters in
+ *   number representation.
+ */
+uint32_t strtoul(const char* str, char** end, uint8_t base);
+
+#endif /* LIB_STDLIB_H */
+
diff --git a/include/lib/string.h b/include/lib/string.h
new file mode 100644 (file)
index 0000000..5866b49
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  lib/string.h
+ *
+ * From linux/lib/string.h :
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ */
+
+#ifndef LIB_STRING_H
+#define LIB_STRING_H
+
+#include <lib/stddef.h>
+#include "lib/stdint.h"
+
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ */
+void * memcpy(void *dest, const void *src, size_t count);
+
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ */
+void * memset(void * s, int c, size_t count);
+
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+char * strcpy(char * dest, const char *src);
+
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
+ * However, the result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ */
+char * strncpy(char * dest, const char *src, size_t count);
+
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
+int strcmp(const char * cs, const char * ct);
+
+/**
+ * strncmp - Compare two length-limited strings
+ * @cs: One string
+ * @ct: Another string
+ * @count: The maximum number of bytes to compare
+ */
+int strncmp(const char * cs, const char * ct, size_t count);
+
+/**
+ * strchr - Find the first occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char * strchr(const char * s, int c);
+
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char * s);
+
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char * strrchr(const char * s, int c);
+
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char * s, size_t count);
+
+
+#endif /* LIB_STRING_H */
diff --git a/include/lib/time.h b/include/lib/time.h
new file mode 100644 (file)
index 0000000..be9bbc7
--- /dev/null
@@ -0,0 +1,95 @@
+/****************************************************************************
+ *   lib/time.h
+ *
+ *
+ *
+ * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+#ifndef LIB_TIME_H
+#define LIB_TIME_H
+
+
+#include "lib/stdint.h"
+
+
+/******************************************************************************/
+/* Common parts for time handling for LPC Boards with or without RTC */
+
+/* Notes on time tracking using this library :
+ *
+ * - Unless there is some known good time source used to set time (using set_time()) the time is
+ *     counted from the system power ON or RTC power ON as origin.
+ *
+ * - This code relies on systick timer configured with a 1ms period (systick_timer_on(1)) for whole
+ *     time on systems without a RTC oscilator and on systick timer for mili-seconds only on systems
+ *     with a 32.768 KHz external oscilator for the RTC.
+ *
+ * - When used with systick only, the time tracking is far from the precision time one should
+ *     obtain using the RTC with an external 32.768 KHz cristal. It uses the 12MHz internal RC
+ *     Oscilator, which is at 1% accuracy.
+ *     Thus the time error may be as much as 1s every 100 seconds !
+ */
+
+struct time_spec {
+       uint32_t seconds;
+       uint16_t msec;
+};
+
+
+/* Call this to set the time from a known good time source. */
+void set_time(struct time_spec* new_time);
+
+
+/* Call this to set the time from a known good time source.
+ * This function returns the time difference in the given time_spec.
+ */
+void set_time_and_get_difference(struct time_spec* new_time, struct time_spec* diff);
+
+
+/* Put a time struct in a buffer, swapping both fields to network endian. */
+void time_to_buff_swapped(uint8_t* buf, struct time_spec* src_time);
+
+
+/* Get a snapshot of the time when this is called.
+ * When in interrupt, use get_time_in_interrupt(). It will get called anyway, but it
+ *   will be longer.
+ */
+void get_time(struct time_spec* save_time);
+
+/* Get a snapshot of the time when this is called
+ * It is safe to call this one in interrupt.
+ */
+void get_time_in_interrupt(struct time_spec* save_time);
+
+
+/* Must be called once to register the systick callback.
+ * Can be called anytime, will just return if it has already been called.
+ */
+void time_init(void);
+
+
+/* Compute a time difference
+ * Return 0 if both times are the same, 1 if (t1 > t2), -1 if (t1 < t2)
+ */
+int get_time_diff(const struct time_spec* t1, const struct time_spec* t2, struct time_spec* diff);
+
+
+
+#endif /* LIB_TIME_H */
+
diff --git a/include/lib/utils.h b/include/lib/utils.h
new file mode 100644 (file)
index 0000000..838e24d
--- /dev/null
@@ -0,0 +1,52 @@
+/****************************************************************************
+ *  lib/utils.h
+ *
+ * Copyright 2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef LIB_UTILS_H
+#define LIB_UTILS_H
+
+/***************************************************************************** */
+/* Library routines                                                            */
+/***************************************************************************** */
+
+#include "lib/stdint.h"
+
+
+/***************************************************************************** */
+/* Bit twidling hacks.
+ * http://graphics.stanford.edu/~seander/bithacks.html
+ */
+
+/* Counting consecutive trailing or leading zero bits (or finding bit indices)
+ * The ARM Cortex M0 core does not have the __builtin_clz() and __builtin_ctz()
+ * instructions.
+ */
+
+/* Count leading zeroes
+ * The following function is an effitient way to implement __builtin_clz().
+ */
+uint8_t clz(uint32_t x);
+
+/* Count traling zeroes
+ * The following function is an effitient way to implement __builtin_ctz().
+ */
+uint8_t ctz(uint32_t x);
+
+#endif /* LIB_UTILS_H */
+
diff --git a/lib/font.c b/lib/font.c
new file mode 100644 (file)
index 0000000..b98c544
--- /dev/null
@@ -0,0 +1,132 @@
+/************************************************************************
+ * lib/font.c
+ *
+ * Copyright (C) Lisa Milne 2014 <lisa@ltmnet.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ ************************************************************************/
+
+/*
+ * The font has been found on opengameart.org:
+ * http://opengameart.org/content/8x8-ascii-bitmap-font-with-c-source
+ */
+
+#include "lib/stdint.h"
+#include "lib/font.h"
+
+/*
+ * The values in this array are a 8x8 bitmap font for ascii characters
+ * As memory is a very precious ressource on a micro-controller all chars
+ * before "space" (0x20) have been removed.
+ */
+uint8_t first_font_char = 0x20;
+uint64_t font[NB_FONT_TILES] = {
+       0x0000000000000000, /* (space) */  /* 0x20 */
+       0x0808080800080000, /* ! */
+       0x2828000000000000, /* " */
+       0x00287C287C280000, /* # */
+       0x081E281C0A3C0800, /* $ */
+       0x6094681629060000, /* % */
+       0x1C20201926190000, /* & */
+       0x0808000000000000, /* ' */
+       0x0810202010080000, /* ( */
+       0x1008040408100000, /* ) */
+       0x2A1C3E1C2A000000, /* * */
+       0x0008083E08080000, /* + */
+       0x0000000000081000, /* , */
+       0x0000003C00000000, /* - */
+       0x0000000000080000, /* . */
+       0x0204081020400000, /* / */
+       0x1824424224180000, /* 0 */ /*x30 */
+       0x08180808081C0000, /* 1 */
+       0x3C420418207E0000, /* 2 */
+       0x3C420418423C0000, /* 3 */
+       0x081828487C080000, /* 4 */
+       0x7E407C02423C0000, /* 5 */
+       0x3C407C42423C0000, /* 6 */
+       0x7E04081020400000, /* 7 */
+       0x3C423C42423C0000, /* 8 */
+       0x3C42423E023C0000, /* 9 */
+       0x0000080000080000, /* : */
+       0x0000080000081000, /* ; */
+       0x0006186018060000, /* < */
+       0x00007E007E000000, /* = */
+       0x0060180618600000, /* > */
+       0x3844041800100000, /* ? */
+       0x003C449C945C201C, /* @ */ /* 0x40 */
+       0x1818243C42420000, /* A */
+       0x7844784444780000, /* B */
+       0x3844808044380000, /* C */
+       0x7844444444780000, /* D */
+       0x7C407840407C0000, /* E */
+       0x7C40784040400000, /* F */
+       0x3844809C44380000, /* G */
+       0x42427E4242420000, /* H */
+       0x3E080808083E0000, /* I */
+       0x1C04040444380000, /* J */
+       0x4448507048440000, /* K */
+       0x40404040407E0000, /* L */
+       0x4163554941410000, /* M */
+       0x4262524A46420000, /* N */
+       0x1C222222221C0000, /* O */
+       0x7844784040400000, /* P */ /* 0x50 */
+       0x1C222222221C0200, /* Q */
+       0x7844785048440000, /* R */
+       0x1C22100C221C0000, /* S */
+       0x7F08080808080000, /* T */
+       0x42424242423C0000, /* U */
+       0x8142422424180000, /* V */
+       0x4141495563410000, /* W */
+       0x4224181824420000, /* X */
+       0x4122140808080000, /* Y */
+       0x7E040810207E0000, /* Z */
+       0x3820202020380000, /* [ */
+       0x4020100804020000, /* \ */
+       0x3808080808380000, /* ] */
+       0x1028000000000000, /* ^ */
+       0x00000000007E0000, /* _ */
+       0x1008000000000000, /* ` */ /* 0x60 */
+       0x003C023E463A0000, /* a */
+       0x40407C42625C0000, /* b */
+       0x00001C20201C0000, /* c */
+       0x02023E42463A0000, /* d */
+       0x003C427E403C0000, /* e */
+       0x0018103810100000, /* f */
+       0x0000344C44340438, /* g */
+       0x2020382424240000, /* h */
+       0x0800080808080000, /* i */
+       0x0800180808080870, /* j */
+       0x20202428302C0000, /* k */
+       0x1010101010180000, /* l */
+       0x0000665A42420000, /* m */
+       0x00002E3222220000, /* n */
+       0x00003C42423C0000, /* o */
+       0x00005C62427C4040, /* p */ /* 0x70 */
+       0x00003A46423E0202, /* q */
+       0x00002C3220200000, /* r */
+       0x001C201804380000, /* s */
+       0x00103C1010180000, /* t */
+       0x00002222261A0000, /* u */
+       0x0000424224180000, /* v */
+       0x000081815A660000, /* w */
+       0x0000422418660000, /* x */
+       0x0000422214081060, /* y */
+       0x00003C08103C0000, /* z */
+       0x1C103030101C0000, /* { */
+       0x0808080808080800, /* | */
+       0x38080C0C08380000, /* } */
+       0x000000324C000000, /* ~ */
+};
+
diff --git a/lib/protocols/dtplug/slave.c b/lib/protocols/dtplug/slave.c
new file mode 100644 (file)
index 0000000..c6b5714
--- /dev/null
@@ -0,0 +1,488 @@
+/****************************************************************************
+ *   lib/protocol/dtplug/slave.c
+ *
+ *
+ * Copyright 2013-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+#include "lib/stdint.h"
+#include "core/system.h"
+#include "core/iap.h"
+#include "drivers/serial.h"
+#include "lib/stdio.h"
+#include "lib/string.h"
+#include "lib/time.h"
+
+#include "lib/protocols/dtplug/defs.h"
+#include "lib/protocols/dtplug/slave.h"
+
+/******************************************************************************/
+/* DTPlug (or DomoTab, PC, ...) Communication */
+
+#define DTPP_MAX_HANDLERS 2
+static struct dtplug_protocol_handle* dtpp_handles[DTPP_MAX_HANDLERS] = {0};
+
+
+
+static void dtplug_protocol_decode(struct dtplug_protocol_handle* handle, uint8_t c);
+
+static void dtplug_protocol_decoder_0(uint8_t c)
+{
+       dtplug_protocol_decode(dtpp_handles[0], c);
+}
+static void dtplug_protocol_decoder_1(uint8_t c)
+{
+       dtplug_protocol_decode(dtpp_handles[1], c);
+}
+
+
+/* Setup the UART used for communication with the host / master (the module is slave) */
+void dtplug_protocol_set_dtplug_comm_uart(uint8_t uart_num, struct dtplug_protocol_handle* handle)
+{
+       void* decoder = dtplug_protocol_decoder_0;
+
+       /* Basic parameter checks */
+       if (uart_num >= DTPP_MAX_HANDLERS) {
+               return;
+       }
+       if (handle == NULL) {
+               return;
+       }
+
+       /* Configure and register handle and configure uart */
+       handle->rx_packet = handle->packets;
+       handle->packet_ok = NULL;
+       handle->done_with_old_packet = 1;
+       handle->uart = uart_num;
+       dtpp_handles[uart_num] = handle;
+       switch (uart_num) {
+               case 1:
+                       decoder = dtplug_protocol_decoder_1;
+                       break;
+               case 0:
+               default:
+                       break;
+       }
+       uart_on(uart_num, 115200, decoder);
+}
+
+
+/* Tell the receive and decode routine that the "handle->packet_ok" packet is no more in use and that
+ *  we are ready to handle a new one.
+ */
+void dtplug_protocol_release_old_packet(struct dtplug_protocol_handle* handle)
+{
+       handle->packet_ok = NULL;
+       handle->done_with_old_packet = 1;
+}
+
+
+
+/* When a packet has not been handled we must not count it as acknowledged
+ * On the next ping request the master will then see wich packet caused the problem.
+ */
+void dtplug_protocol_add_error_to_list(struct dtplug_protocol_handle* handle, struct header* info, uint8_t error_code)
+{
+       if (handle->num_errors_stored < (DTPP_MAX_ERROR_STORED * 2)) {
+               if (error_code == NO_ERROR) {
+                       error_code = ERROR_PKT_NOT_HANDLED;
+               }
+               handle->error_storage[handle->num_errors_stored++] = error_code;
+               handle->error_storage[handle->num_errors_stored++] = (info->seq_num & SEQUENCE_MASK);
+       }
+}
+
+
+/* Handle packet reception, including checksums */
+/* 'sum' is used to sum all the received characters, and if the last byte of sum is 0 for each
+ *   part (header and data) then the packet is valid.
+ * 'full_size' is the size of the whole packet, including header, updated as soon as the header
+ *   is checked and valid
+ */
+static void dtplug_protocol_decode(struct dtplug_protocol_handle* handle, uint8_t c)
+{
+       static uint8_t rx_ptr = 0;
+       static uint8_t sum = 0;
+       static uint8_t full_size = 0;
+       static struct header* info = NULL;
+
+       /* Do not start reception before receiving the packet start character */
+       if ((rx_ptr == 0) && (c != FIRST_PACKET_CHAR)) {
+               return;
+       }
+
+       /* Store the new byte in the packet */
+       if (rx_ptr < sizeof(struct packet)) {
+               ((uint8_t*)handle->rx_packet)[rx_ptr++] = c;
+               sum += c;
+       } else {
+               goto next_packet;
+       }
+
+       /* Is this packet valid ? (at end of header reception) */
+       if (rx_ptr == sizeof(struct header)) {
+               if (sum != 0) {
+                       goto next_packet;
+               }
+               /* Start the new checksum for data (if any) */
+               sum = 0;
+
+               info = (struct header*)handle->rx_packet;
+               full_size = sizeof(struct header);
+               if (!(info->seq_num & QUICK_DATA_PACKET)) {
+                       /* Do not care about big data packets here */
+                       full_size += (info->data.size & PKT_SIZE_MASK);
+               }
+       }
+
+       /* Did we receive the whole packet ? */
+       if (rx_ptr == full_size) {
+               /* From here on, the packet is valid, we can provide some feedback */
+               /* Check data checksum */
+               if (!(info->seq_num & QUICK_DATA_PACKET) && (sum != info->data.checksum)) {
+                       dtplug_protocol_add_error_to_list(handle, info, ERROR_IN_DATA_CHECKSUM);
+                       handle->errors_count++;
+                       goto next_packet;
+               }
+               /* Warning, if we are still using the old packet there's a problem */
+               if (handle->done_with_old_packet == 0) {
+                       /* FIXME : what to do then ? inform the master ? ignore the new packet ? */
+                       dtplug_protocol_add_error_to_list(handle, info, ERROR_LAST_PKT_IN_PROCESS);
+                       handle->errors_count++;
+                       goto next_packet;
+               }
+               /* Count received packets */
+               handle->packet_count++;
+               /* Mark packet as OK : switch pointers */
+               handle->packet_ok = handle->rx_packet;
+               handle->done_with_old_packet = 0;
+               /* Switch our receiving buffer (do not overide the last received packet !) */
+               if (handle->rx_packet == handle->packets) {
+                       handle->rx_packet = handle->packets + 1;
+               } else {
+                       handle->rx_packet = handle->packets;
+               }
+               /* And get ready to receive the next packet */
+               goto next_packet;
+       }
+
+       return;
+
+next_packet:
+#ifdef DEBUG
+       if (handle->done_with_old_packet != 0) {
+               uprintf(handle->uart, "Rx:%d, f:%d, cnt:%d\n", rx_ptr, full_size, handle->packet_count);
+               if (rx_ptr >= sizeof(struct header)) {
+                       struct header* h = &(handle->rx_packet->info);
+                       uprintf(handle->uart, "P: type:%03d, seq:%d, e:%d, q:%d\n", h->type, h->seq_num,
+                                                               (h->seq_num & PACKET_IS_ERROR), (h->seq_num & QUICK_DATA_PACKET));
+               }
+       }
+#endif
+       /* Wether the packet was OK or not doesn't matter, go on for a new one :) */
+       full_size = 0;
+       rx_ptr = 0;
+       sum = 0;
+}
+
+/* This function handle sending replies when requested by the host.
+ * When there is an error but the host did not request a reply, store the error for future request.
+ * When a reply is effectively sent, the PACKET_NEEDS_REPLY bit is removed from the sequence number so the
+ *   packet handling code will know if there is still a PING request to be answered.
+ */
+void dtplug_protocol_send_reply(struct dtplug_protocol_handle* handle,
+                                                                       struct packet* question, uint8_t error, int size, uint8_t* data)
+{
+       struct packet reply;
+       struct header* tx_info = &(reply.info);
+       int i = 0, sent = 0, len = 0;
+       uint8_t sum = 0;
+       int data_send_size = size, data_sent = 0;
+       uint8_t* data_src = data;
+       uint8_t type = question->info.type;
+
+       if (error != NO_ERROR) {
+               handle->errors_count++;
+       }
+       /* If no reply requested : we were called thus there have been an error. We should store the error and return. */
+       if (!(question->info.seq_num & PACKET_NEEDS_REPLY)) {
+               /* If we still have some room for the error, then keep track of it (if any),
+                * otherwise ... drop it, we don't have that much memory to keep track of hundreds of errors */
+               if (error != NO_ERROR) {
+                       dtplug_protocol_add_error_to_list(handle, &(question->info), error);
+               }
+               return;
+       }
+
+       /* Remove the PACKET_NEEDS_REPLY bit as the reply is being built to prevent multiple replies to the
+        *   same packet. (do it now to prevent the mask when building the type field of the reply) */
+       question->info.seq_num &= ~(PACKET_NEEDS_REPLY);
+
+       /* If any error stored, send "got many errors" reply and store the error, but if
+        *    the host is reading the error table, no need to say there is an error table.
+        *    Rather send any possible new error.
+        */
+       if (handle->num_errors_stored != 0) {
+               /* Store the new error if any */
+               if (error != NO_ERROR) {
+                       dtplug_protocol_add_error_to_list(handle, &(question->info), error);
+               }
+               /* The master wants to get all errors, give them even if there is an error in the sequence number */
+               if (question->info.type == PKT_TYPE_GET_ERRORS) {
+                       data_send_size = handle->num_errors_stored;
+                       size = handle->num_errors_stored;
+                       data_src = handle->error_storage;
+                       handle->num_errors_stored = 0;
+               } else {
+                       error = GOT_MANY_ERRORS;
+                       data_send_size = 0;
+                       size = 0;
+               }
+       }
+
+       do {
+               /* Does the data fit in the message ? */
+               if (data_send_size > PACKET_DATA_SIZE) {
+                       data_send_size = PACKET_DATA_SIZE;
+               }
+
+               /* Build the reply */
+               tx_info->start = FIRST_PACKET_CHAR;
+               tx_info->type = type;
+               tx_info->seq_num = question->info.seq_num;
+
+               len = sizeof(struct header); /* At least, send header on serial link */
+               if (error) {
+                       tx_info->seq_num |= PACKET_IS_ERROR;
+                       tx_info->err.error_code = error;
+                       if (error == GOT_MANY_ERRORS) {
+                               tx_info->err.info = handle->num_errors_stored;
+                       }
+               } else {
+                       /* Append possible data */
+                       if ((data_src != NULL) && (data_send_size != 0)) {
+                               /* Can we send a quick data packet ? */
+                               if (size && (size <= 2)) {
+                                       tx_info->seq_num |= QUICK_DATA_PACKET;
+                                       tx_info->quick_data[0] = data_src[0];
+                                       tx_info->quick_data[1] = data_src[1];
+                               } else {
+                                       /* Copy data, compute checksum (also OK for a data_send_size of 0) */
+                                       sum = 0;
+                                       for (i = 0; i < data_send_size; i++) {
+                                               reply.data[i] = data_src[i];
+                                               sum += data_src[i]; /* Build checksum */
+                                       }
+                                       /* And update header information */
+                                       tx_info->data.size = data_send_size;
+                                       /* Will this packet be continued in the following one ? */
+                                       if (data_send_size < (size - data_sent)) {
+                                               tx_info->data.size |= BIG_DATA_PKT;
+                                       }
+                                       tx_info->data.checksum = sum;
+                                       /* Update length of data to send on serial link */
+                                       len += data_send_size;
+                               }
+                       }
+               }
+
+               /* Compute header checksum */
+               sum = 0;
+               tx_info->checksum = 0;
+               for (i = 0; i < sizeof(struct header); i++) {
+                       sum += ((uint8_t*)tx_info)[i];
+               }
+               tx_info->checksum = ((uint8_t)(256 - sum));
+
+               /* And send the reply */
+               sent = 0;
+               while (sent < len) {
+                       int ret = serial_write(handle->uart, (((char*)(&reply)) + sent), (len - sent));
+                       if (ret >= 0) {
+                               sent += ret;
+                       } else {
+                               /* Store a sending error, though it may never be sent ... */
+                               dtplug_protocol_add_error_to_list(handle, &(question->info), ERROR_IN_UART_TX);
+                               handle->errors_count++;
+                               return;
+                       }
+                       /* The serial baud rate is 115200, which means 64 bytes are sent in a little less than 6 ms.
+                        * When there is not enougth place in the buffer, the return value should be 64, meaning 64 byte
+                        *   were stored for transmission. Sleep for 6ms and try sending the next part.
+                        */
+                       if (sent < len) {
+                               msleep(5);
+                       }
+               }
+               data_sent += data_send_size;
+
+               /* Need to send more ? */
+               if (data_sent < size) {
+                       /* Move data pointer */
+                       data_src += data_send_size;
+                       /* Update size to send. check against PACKET_DATA_SIZE is done at beginning of loop */
+                       data_send_size = (size - data_sent);
+                       /* Set packet type to continued data packet for following packets */
+                       type = PKT_TYPE_CONTINUED_DATA;
+               }
+       } while (data_sent < size);
+}
+
+
+/******************************************************************************/
+/* User information block re-programming
+ * Make sure that data is aligned on 4 bytes boundary, and that size is a multiple of 4.
+ */
+/* FIXME : erase the last flash page instead ! */
+#if 0
+static int dtplug_protocol_user_flash_update(struct dtplug_protocol_handle* handle,
+                                                                                        struct packet* question, void* data, int size)
+{
+       int ret = 0;
+       /* Erase the user flash information pages */
+       ret = iap_erase_info_page(0, 2);
+       if (ret != 0) {
+               dtplug_protocol_send_reply(handle, question, ERROR_FLASH_ERASE, 0, NULL);
+               return -1;
+       }
+       ret = iap_copy_ram_to_flash((uint32_t)get_user_info(), (uint32_t)data, size);
+       if (ret != 0) {
+               dtplug_protocol_send_reply(handle, question, ERROR_FLASH_WRITE, 0, NULL);
+               return -1;
+       }
+       return 0;
+}
+#endif
+
+
+/******************************************************************************/
+/* Common packets handlers.
+ * Return 1 when packet has been handled, or 0 if the type is not a common one and some
+ *   board or application specific code should take care of it.
+ */
+static int dtplug_protocol_common_handles(struct dtplug_protocol_handle* handle, struct packet* question)
+{
+       uint32_t tmp_val_swap = 0;
+       /* These we can always handle */
+       switch (question->info.type) {
+               case PKT_TYPE_PING:
+                       question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */
+                       dtplug_protocol_send_reply(handle, question, NO_ERROR, 0, NULL); /* A ping needs no aditional data */
+                       dtplug_protocol_release_old_packet(handle);
+                       break;
+               case PKT_TYPE_RESET:
+                       /* Software reset of the board. No way out. */
+                       NVIC_SystemReset();
+                       break;
+               case PKT_TYPE_SET_TIME:
+                       {
+                               struct time_spec new_time, time_diff;
+                               uint32_t* seconds = (uint32_t*)question->data;
+                               uint16_t* msec = (uint16_t*)&(question->data[4]);
+                               uint8_t time_buff[6];
+                               if (question->info.seq_num & QUICK_DATA_PACKET) {
+                                       dtplug_protocol_send_reply(handle, question, ERROR_IN_PKT_STRUCTURE, 0, NULL);
+                                       break;
+                               }
+                               if (question->info.data.size != 6) {
+                                       dtplug_protocol_send_reply(handle, question, ERROR_IN_DATA_VALUES, 0, NULL);
+                                       break;
+                               }
+                               new_time.seconds = byte_swap_32(*seconds);
+                               new_time.msec = (uint16_t)byte_swap_16(*msec);
+                               if (!(question->info.seq_num & PACKET_NEEDS_REPLY)) {
+                                       set_time(&new_time);
+                               } else {
+                                       set_time_and_get_difference(&new_time, &time_diff);
+                                       time_to_buff_swapped(time_buff, &time_diff);
+                                       dtplug_protocol_send_reply(handle, question, NO_ERROR, 6, time_buff);
+                               }
+                       }
+                       dtplug_protocol_release_old_packet(handle);
+                       break;
+/* FIXME : erase the last flash page instead ! */
+#if 0
+               case PKT_TYPE_SET_USER_INFO:
+                       {
+                               uint8_t tmp_data[sizeof(struct user_info)] __attribute__ ((__aligned__(4))) = {};
+                               uint8_t offset = question->data[0];
+                               uint8_t size = question->data[1];
+                               if (question->info.seq_num & QUICK_DATA_PACKET) {
+                                       dtplug_protocol_send_reply(handle, question, ERROR_IN_PKT_STRUCTURE, 0, NULL);
+                                       break;
+                               }
+                               /* Check that amount of data provided is OK and does not go beyond user_info structure end */
+                               if ((question->info.data.size != (size + 2)) || ((offset + size) > sizeof(struct user_info))) {
+                                       dtplug_protocol_send_reply(handle, question, ERROR_IN_DATA_VALUES, 0, NULL);
+                                       break;
+                               }
+                               /* Copy all board data before flash erase */
+                               memcpy(tmp_data, get_user_info(), sizeof(struct user_info));
+                               /* Update information in the copy */
+                               memcpy(&(tmp_data[offset]), &(question->data[2]), size);
+                               /* Update the user flash information pages */
+                               if (dtplug_protocol_user_flash_update(handle, question, tmp_data, sizeof(struct user_info)) != 0) {
+                                       /* Reply got sent, if return value is not 0 */
+                                       break;
+                               }
+                       }
+                       /* Software reset of the board. No way out. */
+                       NVIC_SystemReset();
+                       break;
+#endif
+               case PKT_TYPE_GET_NUM_PACKETS:
+                       question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */
+                       tmp_val_swap = byte_swap_32(handle->packet_count);
+                       dtplug_protocol_send_reply(handle, question, NO_ERROR, 4, (uint8_t*)(&tmp_val_swap));
+                       dtplug_protocol_release_old_packet(handle);
+                       break;
+               case PKT_TYPE_GET_ERRORS:
+                       question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */
+                       dtplug_protocol_send_reply(handle, question, NO_ERROR, 0, NULL); /* Error handling code will take care of filling the message */
+                       dtplug_protocol_release_old_packet(handle);
+                       break;
+               case PKT_TYPE_GET_NUM_ERRORS:
+                       question->info.seq_num |= PACKET_NEEDS_REPLY; /* Make sure the reply will be sent */
+                       tmp_val_swap = byte_swap_32(handle->errors_count);
+                       dtplug_protocol_send_reply(handle, question, NO_ERROR, 4, (uint8_t*)(&tmp_val_swap));
+                       dtplug_protocol_release_old_packet(handle);
+                       break;
+               default:
+                       /* We do not handle this type, it must be a board specific one */
+                       return 0;
+       }
+       /* Packet handled */
+       return 1;
+}
+
+
+/* Get a pointer to the new packet received.
+ * Return NULL when no new packet were received since last packet was released.
+ * If a new packet is present, call the common handles first.
+ */
+struct packet* dtplug_protocol_get_next_packet_ok(struct dtplug_protocol_handle* handle)
+{
+       if (handle->packet_ok != NULL) {
+               struct packet* pkt_tmp = (struct packet*)handle->packet_ok;
+               if (dtplug_protocol_common_handles(handle, pkt_tmp) == 0) {
+                       return pkt_tmp;
+               }
+       }
+       return NULL;
+}
+
diff --git a/lib/stdlib.c b/lib/stdlib.c
new file mode 100644 (file)
index 0000000..c37dd56
--- /dev/null
@@ -0,0 +1,55 @@
+/****************************************************************************
+ *  lib/stdlib.c
+ *
+ * Copyright 2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include "lib/stdint.h"
+#include "lib/stddef.h"
+
+/* Simple strtoul implementation.
+ * Returns the value convertes from the given string.
+ * Does not check that the base is respected aside for the use of letters in
+ *   number representation.
+ */
+uint32_t strtoul(const char* str, char** end, uint8_t base)
+{
+       uint32_t val = 0;
+       while (*str != '\0') {
+               if (*str >= '0' && *str <= '9') {
+                       val = (val * base) + ((*str) - '0');
+                       str++;
+                       continue;
+               }
+               if (*str >= 'A' && *str <= 'F' && base > 10) {
+                       val = (val * base) + ((*str) - 'A' + 10);
+                       str++;
+                       continue;
+               }
+               if (*str >= 'a' && *str <= 'f' && base > 10) {
+                       val = (val * base) + ((*str) - 'a' + 10);
+                       str++;
+                       continue;
+               }
+               break;
+       }
+       if (end != NULL) {
+               *end = str;
+       }
+       return val;
+}
+
diff --git a/lib/string.c b/lib/string.c
new file mode 100644 (file)
index 0000000..834e514
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ */
+
+#include <lib/stddef.h>
+#include "lib/stdint.h"
+
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ */
+void* memcpy(void* dest, const void* src, size_t count)
+{
+       unsigned long* dl = (unsigned long*)dest, *sl = (unsigned long*)src;
+       char *d8, *s8;
+
+       if (src == dest)
+               return dest;
+
+       /* while all data is aligned (common case), copy a word at a time */
+       if ( (((uint32_t)dest | (uint32_t)src) & (sizeof(*dl) - 1)) == 0) {
+               while (count >= sizeof(*dl)) {
+                       *dl++ = *sl++;
+                       count -= sizeof(*dl);
+               }
+       }
+       /* copy the rest one byte at a time */
+       d8 = (char *)dl;
+       s8 = (char *)sl;
+       while (count--) {
+               *d8++ = *s8++;
+       }
+       return dest;
+}
+
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ */
+void* memset(void* s, int c, size_t count)
+{
+       unsigned long* sl = (unsigned long*) s;
+       unsigned long cl = 0;
+       char* s8;
+       int i;
+
+       /* do it one word at a time (32 bits or 64 bits) while possible */
+       if ( ((uint32_t)s & (sizeof(*sl) - 1)) == 0) {
+               for (i = 0; i < sizeof(*sl); i++) {
+                       cl <<= 8;
+                       cl |= c & 0xff;
+               }
+               while (count >= sizeof(*sl)) {
+                       *sl++ = cl;
+                       count -= sizeof(*sl);
+               }
+       }
+       /* fill 8 bits at a time */
+       s8 = (char*)sl;
+       while (count--) {
+               *s8++ = c;
+       }
+       return s;
+}
+
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+char* strcpy(char* dest, const char* src)
+{
+       char* tmp = dest;
+
+       while ((*dest++ = *src++) != '\0') {
+               /* nothing */;
+       }
+       return tmp;
+}
+
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
+ * However, the result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ */
+char* strncpy(char* dest, const char* src, size_t count)
+{
+       char* tmp = dest;
+
+       while (count-- && (*dest++ = *src++) != '\0') {
+               /* nothing */;
+       }
+       return tmp;
+}
+
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
+int strcmp(const char* cs, const char* ct)
+{
+       register signed char __res;
+
+       while (1) {
+               if ((__res = *cs - *ct++) != 0 || !*cs++) {
+                       break;
+               }
+       }
+       return __res;
+}
+
+/**
+ * strncmp - Compare two length-limited strings
+ * @cs: One string
+ * @ct: Another string
+ * @count: The maximum number of bytes to compare
+ */
+int strncmp(const char* cs, const char* ct, size_t count)
+{
+       register signed char __res = 0;
+
+       while (count) {
+               if ((__res = *cs - *ct++) != 0 || !*cs++) {
+                       break;
+               }
+               count--;
+       }
+
+       return __res;
+}
+
+/**
+ * strchr - Find the first occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char* strchr(const char* s, int c)
+{
+       for(; *s != (char) c; ++s) {
+               if (*s == '\0') {
+                       return NULL;
+               }
+       }
+       return (char *) s;
+}
+
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char* s)
+{
+       const char* sc;
+
+       for (sc = s; *sc != '\0'; ++sc) {
+               /* nothing */;
+       }
+       return sc - s;
+}
+
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char* strrchr(const char* s, int c)
+{
+       const char* p = s + strlen(s);
+       do {
+               if (*p == (char)c) {
+                       return (char *)p;
+               }
+       } while (--p >= s);
+       return NULL;
+}
+
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char* s, size_t count)
+{
+       const char* sc;
+
+       for (sc = s; count-- && *sc != '\0'; ++sc) {
+               /* nothing */;
+       }
+       return sc - s;
+}
diff --git a/lib/time.c b/lib/time.c
new file mode 100644 (file)
index 0000000..deb4bad
--- /dev/null
@@ -0,0 +1,207 @@
+/****************************************************************************
+ *   lib/time.c
+ *
+ *
+ * Copyright 2013-2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+#include "lib/stdint.h"
+#include "core/lpc_core.h"
+#include "core/system.h"
+#include "core/systick.h"
+#include "lib/time.h"
+#include "lib/string.h"
+
+
+/******************************************************************************/
+/* Common parts for time handling for LPC Boards with or without RTC */
+
+/* Notes on time tracking using this library :
+ *
+ * - Unless there is some known good time source used to set time (using set_time()) the time is
+ *     counted from the system power ON or RTC power ON as origin.
+ *
+ * - This code relies on systick timer configured with a 1ms period (systick_timer_on(1)) for whole
+ *     time on systems without a RTC oscilator and on systick timer for mili-seconds only on systems
+ *     with a 32.768 KHz external oscilator for the RTC.
+ *
+ * - When used with systick only, the time tracking is far from the precision time one should
+ *     obtain using the RTC with an external 32.768 KHz cristal. It uses the 12MHz internal RC
+ *     Oscilator, which is at 1% accuracy.
+ *     Thus the time error may be as much as 1s every 100 seconds !
+ */
+
+static volatile struct time_spec time = { 0, 0, };
+static volatile uint32_t time_lock = 0;;
+
+/* Interupt routine which keeps track of the time */
+void time_track(uint32_t ms)
+{
+    /* This lock may have us miss one ms when time is changed, but this is perfectly OK, time is
+     *    being changed !
+     * Anyway, we are in interrupt context, we MUST NOT loop or sleep !
+     */
+    if (sync_lock_test_and_set(&time_lock, 1) == 1) {
+        return;
+    }
+    time.msec++;
+    if (time.msec >= 1000) {
+        time.msec = 0;
+        time.seconds++;
+    }
+    sync_lock_release(&time_lock);
+}
+
+/* Call this to set the time from a known good time source. */
+void set_time(struct time_spec* new_time)
+{
+    /* We are not in interrupt context, we can wait for the lock to be released */
+    while (sync_lock_test_and_set(&time_lock, 1) == 1) {};
+    time.seconds = new_time->seconds;
+    time.msec = new_time->msec;
+    sync_lock_release(&time_lock);
+}
+
+/* Call this to set the time from a known good time source.
+ * This function returns the time difference in the given time_spec.
+ */
+void set_time_and_get_difference(struct time_spec* new_time, struct time_spec* diff)
+{
+       struct time_spec tmp_old;
+       if (new_time == NULL) {
+               return;
+       }
+    /* We are not in interrupt context, we can wait for the lock to be released */
+    while (sync_lock_test_and_set(&time_lock, 1) == 1) {};
+       /* Save the old time */
+       tmp_old.seconds = time.seconds;
+       tmp_old.msec = time.msec;
+       /* Set the time as soon as possible */
+    time.seconds = new_time->seconds;
+    time.msec = new_time->msec;
+    sync_lock_release(&time_lock);
+
+       /* And now compute the time difference */
+       if (diff == NULL) {
+               return;
+       }
+       if (new_time->seconds == tmp_old.seconds) {
+               diff->msec = new_time->msec - tmp_old.msec;
+       } else {
+               diff->seconds = new_time->seconds - tmp_old.seconds;
+               if (new_time->seconds > tmp_old.seconds) {
+                       diff->msec = (1000 - tmp_old.msec) + new_time->msec;
+               } else {
+                       diff->msec = (1000 - new_time->msec) + tmp_old.msec;
+               }
+               if (diff->msec > 1000) {
+                       diff->msec -= 1000;
+               } else {
+                       diff->seconds -= 1;
+               }
+       }
+}
+
+
+/* Put a time struct in a buffer, swapping both fields to network endian. */
+void time_to_buff_swapped(uint8_t* buf, struct time_spec* src_time)
+{
+       struct time_spec time; /* Warning, this one will hold time in network endian ! */
+       time.seconds = byte_swap_32(src_time->seconds);
+       time.msec = (uint16_t)byte_swap_16(src_time->msec);
+       memcpy(buf, &(time.seconds), 4);
+       memcpy((buf + 4), &(time.msec), 2);
+}
+
+
+/* Get a snapshot of the time when this is called.
+ * It is unsafe to call this one when in interrupt, use get_time_in_interrupt()
+ */
+void get_time(struct time_spec* save_time)
+{
+       /* FIXME : Check that we are not in interrupt ... */
+       if (get_priority_mask() == 0) {
+               get_time_in_interrupt(save_time);
+               return;
+       }
+    /* We are not in interrupt context, we can wait for the lock to be released */
+    while (sync_lock_test_and_set(&time_lock, 1) == 1) {};
+       save_time->seconds = time.seconds;
+       save_time->msec = time.msec;
+    sync_lock_release(&time_lock);
+}
+
+/* Get a snapshot of the time when this is called
+ * It is safe to call this one in interrupt.
+ */
+void get_time_in_interrupt(struct time_spec* save_time)
+{
+    /* We are in interrupt context, we can't wait for the lock to be released */
+       save_time->seconds = time.seconds;
+       save_time->msec = time.msec;
+}
+
+/* Must be called once to register the systick callback. */
+static uint8_t time_configured = 0;
+void time_init(void)
+{
+       if (time_configured != 0) {
+               return;
+       }
+       time_configured = 1;
+       add_systick_callback(time_track, 1); /* callback, period (ms) */
+}
+
+
+/* Compute a time difference
+ * Return 0 if both times are the same, 1 if (t1 > t2), -1 if (t1 < t2)
+ */
+int get_time_diff(const struct time_spec* t1, const struct time_spec* t2, struct time_spec* diff)
+{
+       if (t1->seconds < t2->seconds) {
+               diff->seconds = (t2->seconds - t1->seconds - 1);
+               diff->msec = ((t2->msec + 1000) - t1->msec);
+               if (diff->msec >= 1000) {
+                       diff->msec -= 1000;
+                       diff->seconds++;
+               }
+               return -1;
+       } else if (t1->seconds == t2->seconds) {
+               diff->seconds = 0;
+               if (t1->msec < t2->msec) {
+                       diff->msec = t2->msec - t1->msec;
+                       return -1;
+               } else if (t1->msec == t2->msec) {
+                       diff->msec = 0;
+                       return 0;
+               } else {
+                       diff->msec = t1->msec - t2->msec;
+                       return 1;
+               }
+       } else {
+               diff->seconds = (t1->seconds - t2->seconds - 1);
+               diff->msec = ((t1->msec + 1000) - t2->msec);
+               if (diff->msec >= 1000) {
+                       diff->msec -= 1000;
+                       diff->seconds++;
+               }
+               return 1;
+       }
+}
+
+
diff --git a/lib/uprintf.c b/lib/uprintf.c
new file mode 100644 (file)
index 0000000..064bcfb
--- /dev/null
@@ -0,0 +1,45 @@
+/****************************************************************************
+ *  lib/uprintf.c
+ *
+ * UART printf
+ * 
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include <stdarg.h>
+#include "lib/stdint.h"
+#include "drivers/serial.h"
+#include "lib/string.h"
+#include "lib/stdio.h"
+
+
+int uprintf(int uart_num, const char* format, ...)
+{
+       char printf_buf[SERIAL_OUT_BUFF_SIZE];
+       va_list args;
+       int r;
+
+       va_start(args, format);
+    r = vsnprintf(printf_buf, SERIAL_OUT_BUFF_SIZE, format, args);
+    va_end(args);
+
+       serial_write(uart_num, printf_buf, r);
+
+    return r;
+}
+
+
diff --git a/lib/utils.c b/lib/utils.c
new file mode 100644 (file)
index 0000000..c6899eb
--- /dev/null
@@ -0,0 +1,103 @@
+/****************************************************************************
+ *  lib/utils.c
+ *
+ * Copyright 2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include "lib/stdint.h"
+
+
+/***************************************************************************** */
+/* Bit twidling hacks.
+ * http://graphics.stanford.edu/~seander/bithacks.html
+ */
+
+/* Counting consecutive trailing or leading zero bits (or finding bit indices)
+ * The ARM Cortex M0 core does not have the __builtin_clz() and __builtin_ctz()
+ * instructions.
+ */
+
+
+
+/* Count leading zeroes
+ * The following function is an efficient way to implement __builtin_clz(),
+ * or at least a good compromize between memory usage and speed.
+ */
+uint8_t clz(uint32_t x)
+{
+       static const uint8_t bval_clz[] = {0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4};
+       unsigned int r = 32;
+       if (x >= 0x10000) { /* Quicker than (x & 0xFFFF0000) on a 32bit arm arch */
+               r -= 16;
+               x >>= 16;
+       }
+       if (x & 0xFF00) {
+               r -= 8;
+               x >>= 8;
+       }
+       if (x & 0xF0) {
+               r -= 4;
+               x >>= 4;
+       }
+       return r - bval_clz[x];
+}
+
+/* Count traling zeroes
+ * The following function is an efficient way to implement __builtin_ctz(),
+ * or at least a good compromize between memory usage and speed.
+ */
+uint8_t ctz(uint32_t x)
+{
+       static const uint8_t bval_ctz[] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
+       unsigned int r = 0;
+       if (x & 0x1) {
+               /* special case for odd value (assumed to happen half of the time) */
+               return r;
+       }
+       if ((x & 0xFFFF) == 0) {
+               r += 16;
+               x >>= 16;
+       }
+       if ((x & 0xFF) == 0) {
+               r += 8;
+               x >>= 8;
+       }
+       if ((x & 0xF) == 0) {
+               r += 4;
+               x >>= 4;
+       }
+       return r + bval_ctz[(x & 0x0F)];
+}
+
+/* Count bits set
+ *
+ */
+uint8_t bits_set(uint32_t x)
+{
+       static const uint8_t bval_bsets[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
+       uint8_t r = 0; /* Accumulator for the total bits set in x */
+       
+       r = bval_bsets[x & 0xFF];
+       x >>= 8;
+       r += bval_bsets[x & 0xFF];
+       x >>= 8;
+       r += bval_bsets[x & 0xFF];
+       x >>= 8;
+       r += bval_bsets[x & 0xFF];
+
+       return r;
+}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
new file mode 100644 (file)
index 0000000..138f681
--- /dev/null
@@ -0,0 +1,218 @@
+/****************************************************************************
+ *  lib/vsprintf.c
+ *
+ * Code based on lib/vsprintf.c from linux kernel.
+ * 
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include <stdarg.h>
+#include "lib/stdint.h"
+#include "lib/string.h"
+
+#define ZEROPAD   (1 <<  0)  /* pad with zero */
+#define SIGNED    (1 <<  1)  /* unsigned/signed long */
+#define SIGN      (1 <<  2)  /* show plus */
+#define SPACE     (1 <<  3)  /* space if plus */
+#define LEFT      (1 <<  4)  /* left justified */
+#define LOWERCASE (1 <<  5)  /* use lowercase in hex (must be 32 == 0x20) */
+#define SPECIAL   (1 <<  6)  /* prefix hex with "0x", octal with "0" */
+#define HEXA      (1 <<  7)  /* output hexa-decimal */
+
+/* In our case, anything that does not fit in 20 chars does not fit in an unsigned int. */
+#define TMP_NUM_BUF_SIZE 20
+static int convert(char* buf, char* end, uint32_t flags, uint32_t width, uint32_t num)
+{
+       static const char digits[16] = "0123456789ABCDEF";
+       char tmp[TMP_NUM_BUF_SIZE];
+       int i = 0, length = 0;
+       char sign = 0;
+
+       if (width > TMP_NUM_BUF_SIZE) {
+               width = TMP_NUM_BUF_SIZE;
+       }
+
+       /* Store sign, and convert to unsigned */
+       if (flags & SIGNED) {
+               if (width) {
+                       width--;
+               }
+               if ((signed long)num < 0) {
+                       sign = '-';
+                       num = -(signed long)num;
+               }
+       } /* Do we need to remove 2 to width in case of "SPECIAL" flag ? */
+
+       /* Generate full string in tmp[], in reverse order */
+       if (num == 0) {
+               tmp[i++] = '0';
+       } else if (flags & HEXA) {
+               /* low_case = 0 or 0x20. ORing digits or letters with 'low_case'
+                * produces same digits or (maybe lowercased) letters */
+               uint32_t low_case = (flags & LOWERCASE) ? 0x20 : 0;
+               do {
+                       tmp[i++] = (digits[num & 0x0F] | low_case);
+                       num = (num >> 4);
+               } while (num);
+       } else {
+               while (num) {
+                       tmp[i++] = (num % 10) + '0';
+                       num = num / 10;
+               }
+       }
+
+       /* Add sign, pad if reqiered */
+       if (flags & ZEROPAD) {
+               while (i < width) {
+                       tmp[i++] = '0';
+               }
+       }
+       if (sign) {
+               tmp[i++] = sign;
+       } else if (flags & SIGN) {
+               tmp[i++] = '+';
+       } else if (flags & SPACE) {
+               tmp[i++] = ' ';
+       } else if (flags & SPECIAL) {
+               tmp[i++] = 'x';
+               tmp[i++] = '0';
+       }
+       while (i < width) {
+               tmp[i++] = ' ';
+       }
+
+       /* And reverse string */
+       length = i;
+       while (i && (buf < end)) {
+               i--;
+               *(buf++) = tmp[i];
+       }
+       if (i)
+               return -i;
+
+       return length;
+}
+
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+    char* start = buf;
+    char* end = buf + size - 1; /* leave one char for terminating null byte */
+
+       /* Parse format string */
+       while ((buf < end) && *fmt) {
+       uint32_t flags = 0;
+       uint32_t width = 0;
+
+               if (*fmt != '%') {
+                       *buf++ = *fmt++;
+                       continue;
+               }
+
+               /* Do we have a conversion specifier ? */
+               fmt++;
+               if (*fmt == '%') {
+                       *buf++ = *fmt++;
+                       continue;
+               }
+               /* We got a conversion specifier, any modifier ? */
+               /* Note that '-' won't be handled */
+               while (1) {
+                       int found = 1;
+                       switch (*fmt) {
+                               case '-': flags |= LEFT;    break;
+                               case '+': flags |= SIGN;    break;
+                               case ' ': flags |= SPACE;   break;
+                               case '#': flags |= SPECIAL; break;
+                               case '0': flags |= ZEROPAD; break;
+                               default:  found = 0;
+                       }
+                       if (!found)
+                               break;
+                       fmt++;
+               }
+               /* Field width ? */
+               while ((*fmt >= '0') && (*fmt <= '9')) {
+                       width = (width * 10) + (*fmt - '0');
+                       fmt++;
+               }
+               /* We do not handle floats, floats have nothing to do with embeded systems */
+               /* Skip any precision */
+               if (*fmt == '.') {
+                       do {
+                               fmt++;
+                       } while ((*fmt >= '0') && (*fmt <= '9'));
+               }
+               /* Qualifier ? Should we really handle length modifiers ?
+                * The while loop is here to skip these. */
+               /* Handle conversion, if supported. Note that we may spend some time in here
+         * while waiting for the buffer to get available again  */
+               while (*fmt) {
+                       int found = 1;
+                       switch (*fmt) {
+                               /* signed */
+                               case 'd':
+                               case 'i':
+                                       flags |= SIGNED;
+                                       buf += convert(buf, end, flags, width, (uint32_t)va_arg(args, signed int));
+                                       break;
+                               /* unsigned */
+                               case 'x':
+                                       flags |= LOWERCASE;
+                               case 'X':
+                                       flags |= HEXA;
+                               case 'u':
+                                       buf += convert(buf, end, flags, width, (uint32_t)va_arg(args, unsigned int));
+                                       break;
+                               /* string */
+                               case 's': {
+                                       /* Copy string to buf */
+                                       char* tmp = va_arg(args, char *);
+                                       while ((buf < end) && *tmp) {
+                                               *buf++ = *tmp++;
+                                       }
+                                       break;
+                               }
+                               /* character */
+                               case 'c':
+                                       *buf++ = (char)va_arg(args, unsigned int);
+                                       break;
+                               default:
+                                       found = 0;
+                       }
+                       fmt++;
+                       if (found)
+                               break;
+               }
+       }
+       *buf = '\0';
+       return (buf - start);
+}
+
+
+int snprintf(char* buf, size_t size, const char *format, ...)
+{
+       va_list args;
+       int r;
+
+       va_start(args, format);
+    r = vsnprintf(buf, size, format, args);
+    va_end(args);
+
+    return r;
+}
+
+