aboutsummaryrefslogtreecommitdiffstats
path: root/source/libmaple/coding-standard.rst
diff options
context:
space:
mode:
Diffstat (limited to 'source/libmaple/coding-standard.rst')
-rw-r--r--source/libmaple/coding-standard.rst412
1 files changed, 412 insertions, 0 deletions
diff --git a/source/libmaple/coding-standard.rst b/source/libmaple/coding-standard.rst
new file mode 100644
index 0000000..23d20f8
--- /dev/null
+++ b/source/libmaple/coding-standard.rst
@@ -0,0 +1,412 @@
+.. _libmaple-coding-standard:
+
+Coding Standard
+===============
+
+This page documents the coding standard for :ref:`libmaple`. It's
+intended as a guide for how you should structure any code you would
+like included into the LeafLabs releases of libmaple.
+
+LeafLabs team members are required to follow these when producing new
+code. Community contributors to libmaple are strongly encouraged to
+do so; following these rules will greatly increase the probability
+that your patches will be folded in.
+
+In general, follow this guide unless there's a very good reason not
+to. Laziness doesn't count as a good reason. Most, if not all, of
+these decisions are entirely arbitrary, but it's important for
+readability that we be consistent. (If you notice an inconsistency,
+you should fix it).
+
+Note that the file ``.dir-locals.el`` in the libmaple root directory
+already ensures that many of these standards are followed by default
+in Emacs (but not on Windows, where it would need to be named
+``_dir_locals.el``, and no way, man). There's also some elisp
+scattered about this file which will provide you additional help.
+
+Vim customizations to do the same thing would be nice!
+
+.. contents:: Contents
+ :local:
+
+License
+-------
+
+.. highlight:: scheme
+
+Put an MIT license at the beginning of the file (look at any of our
+source files for an example). Copyright should go either to you or to
+LeafLabs, LLC.
+
+Emacs: if you don't like seeing the license, you should use elide-head
+(which will hide it for you). You can use the following::
+
+ (require 'elide-head)
+ (setq programming-mode-hooks '(c-mode-hook c++-mode-hook))
+ (add-to-list 'elide-head-headers-to-hide
+ '("The MIT License" . "DEALINGS IN\n [*] THE SOFTWARE"))
+ (add-to-list 'elide-head-headers-to-hide
+ '("The MIT License" . "DEALINGS IN THE\n...SOFTWARE"))
+ (dolist (hook programming-mode-hooks)
+ (add-hook hook (lambda () (elide-head))))
+
+Whitespace
+----------
+
+- 4 space indents (set in ``.dir-locals.el``).
+
+- Unix newlines. Some exceptions are currently grandfathered in; these
+ will go away in time.
+
+- No tab characters (set in ``.dir-locals.el``).
+
+- No trailing whitespace. For help getting this (and no tab
+ characters) done automatically in Emacs, you can use
+ `code-fascism.el <https://github.com/mbolivar/code-fascism>`_.
+
+- Files end in exactly one newline. The presence of a newline at EOF
+ is already done by ``c-require-final-newline`` in recent versions of
+ Emacs.
+
+- Exactly two newlines separate source paragraphs (you do separate
+ your code into paragraphs, don't you?).
+
+- The first line in a function is non-blank.
+
+.. highlight:: cpp
+
+- Exactly one space after ``if``, ``else``, ``for``, and ``while``,
+ before the following ``{`` or ``(``. One space before ``else``,
+ after the preceding ``}``. For example::
+
+ // This is good; we like this:
+ if (foo) {
+ while (quux) {
+ bar();
+ }
+ } else {
+ baz();
+ }
+
+ // THIS IS BAD! DON'T DO THIS:
+ if(foo){
+ while(quux){
+ bar();
+ }
+ }else{
+ baz();
+ }
+
+- Exactly one space in between binary arithmetic, logical, and
+ comparison operators and their operands. Examples::
+
+ // This is good:
+ int x = a + b * (c - d);
+ if (x != 0 && a > 7) {
+ SerialUSB.println(x);
+ }
+
+ // THIS IS BAD!
+ int x = a+b*(c-d);
+ if (x!=0 && a>7) {
+ SerialUSB.println(x);
+ }
+
+ // This is good:
+ uint32 adc_data = ADC1_BASE->DR;
+ SerialUSB.println(adc_data);
+
+ // THIS IS BAD!
+ uint32 adc_data = ADC1_BASE -> DR;
+ SerialUSB . println(adc_data);
+
+- No space between a unary operator and its operand. Examples::
+
+ // Good:
+ x++;
+
+ // BAD!
+ x ++;
+
+ // Good:
+ y = -x;
+
+ // BAD!
+ y = - x;
+
+- If you need to break up a long line:
+
+ * Prefer to break up long expressions after a binary operator. Example::
+
+ // Good:
+ if (some_really_long_conditional_wow_this_really_goes_on_forever ||
+ maybe_something_else_could_happen_too) {
+ ...
+ }
+
+ // BAD!
+ if (some_really_long_conditional_wow_this_really_goes_on_forever
+ || maybe_something_else_could_happen_too) {
+ ...
+ }
+
+ * When breaking up a function's arguments over multiple lines, align
+ the arguments on subsequent lines with the first argument.
+ Example::
+
+ // Good:
+ return_type value_i_got = function_with_a_really_long_name(argument1,
+ argument2,
+ argument3);
+
+ // BAD!
+ return_type value_i_got = function_with_a_really_long_name(argument1,
+ argument2,
+ argument3);
+
+ // BAD!
+ return_type value_i_got = function_with_a_really_long_name(argument1,
+ argument2,
+ argument3);
+
+- In function invocations, no space in between the function name and
+ the opening parenthesis. Example::
+
+ // Good:
+ SerialUSB.println("Hello, world!");
+
+ // BAD!
+ SerialUSB.println ("Hello, world!");
+
+- Don't indent C code within a conditionally-compiled ``extern "C"``
+ block. Example::
+
+ // Good:
+ #ifdef __cplusplus
+ extern "C"{
+ #endif
+
+ void some_c_function(void);
+
+ #ifdef __cplusplus
+ } // extern "C"
+ #endif
+
+ // BAD!
+ #ifdef __cplusplus
+ extern "C"{
+ #endif
+
+ void some_c_function(void);
+
+ #ifdef __cplusplus
+ } // extern "C"
+ #endif
+
+ Emacs does the "bad" behavior by default, which can be very
+ annoying. You can turn this off with ::
+
+ (defun c-mode-inextern-lang-hook ()
+ (setcdr (assq 'inextern-lang c-offsets-alist) '-))
+ (add-hook 'c-mode-hook c-mode-inextern-lang-hook)
+
+Comments
+--------
+
+.. highlight:: c++
+
+- Multi-line comments are pretty flexible. Any of these is fine::
+
+ /* Comment starts here.
+ * Continued lines have a '*' before them.
+ * The comment can end after the last line.
+ */
+
+ /* Comment starts here.
+ * The comment can end on the same line. */
+
+ /*
+ * You can also place a newline after the opening "/*".
+ */
+
+- Doxygen comments are multi-line comments that begin with ``/**``
+ instead.
+
+- Single-line comments are up to you.
+
+Braces
+------
+
+- Mostly `1TBS
+ <http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS>`_. The
+ only difference is that the opening brace of a function's definition
+ occurs exactly one space character after the closing parenthesis in
+ that function's parameter list. Example::
+
+ void func(void) {
+ ...
+ }
+
+Naming conventions
+------------------
+
+We'll handle the usual casing/underscore debate as follows.
+
+- First, ``Dont_Mix_Like_This``, because ``It_Looks_Really_Ugly``, ok?
+ [There's been some debate about this, and some exceptions are
+ already grandfathered in, so in order to settle it, let's call this
+ a "recommendation" instead of "requirement".]
+
+- Variables: Use underscores to separate words in C identifiers::
+
+ int some_example_name;
+
+ User-facing C++ variables should be camel cased
+ (``thisIsAnExample``, ``boardPWMPins``, etc.), for consistency with
+ the Arduino style. It's probably a good idea for you to case
+ non-user facing C++ variables in the C style; this will help
+ disambiguate what's part of the Wirish API and what's not.
+
+- Classes: Pascal case. So ``ThisIsAClassName``, but ``thisIsNot``,
+ ``this_is_not``, and ``Dont_You_DareTryANYTHING_STUPID``.
+
+- Functions: C functions are all lowercase, and words are separated by
+ underscores. C++ method names are camel cased.
+
+- Structs: Usually like variables (``adc_dev``, ``adc_reg_map``,
+ etc.), but it's not crucial. Don't feel obliged to put ``_t`` at
+ the end of the type name; we don't.
+
+- Macros and constants: all caps, separated by underscores. C++
+ variables with the ``const`` qualifier generally aren't considered
+ "constants" for the purposes of this rule; i.e., they are cased
+ according to the rules for variables. We make an exception for
+ ``PIN_MAP``, because it's the central Wirish data structure.
+
+- foo.h gets ``#ifdef``\ 'ed to ``_FOO_H_``.
+
+- Acronyms: The case of letters in an acronym is determined by the
+ case of the first letter in the acronym, which is determined by
+ following the above rules. Examples::
+
+ // Good:
+ void usb_func() { ... }
+ void frob_usb_disc() { ... }
+ class SomethingUSB {
+ void usbInit();
+ void initUSB();
+ };
+
+ // BAD:
+ class BadUsb { ... }; // say "GoodUSB" instead
+ void swizzle_USB_disc() { ... } // say "swizzle_usb_disc" instead
+
+Documentation
+-------------
+
+- Doxygen comments on every user-facing function and type.
+ Additionally, individually document the fields and enumerator values
+ of nontrivial user-facing structs and enums. See any register map
+ type's definition for an example.
+
+- For libmaple proper, you don't need comments for each register bit
+ definition, since that's just repeating information better obtained
+ by reading ST RM0008.
+
+- Doxygen comments generally only belong on types, functions,
+ etc. that are part of the public user-facing API. This generally
+ means that if there's ReST documentation for it under libmaple's
+ ``docs/source/``, it needs Doxygen comments, and that ReST should
+ use Breathe to pull that Doxygen comment out. (For more information
+ on this, see libmaple file ``docs/README``).
+
+ There are some exceptions to this rule since Breathe isn't totally
+ mature yet and Sphinx's C++ domain is still in flux. In these
+ cases, document the code "manually" in ReST.
+
+ This should be avoided if at all possible, since it creates a
+ maintenance burden of documenting things in two places at once, and
+ makes it easier for documentation to go stale.
+
+ If you do have to document something manually, put a comment in the
+ source file informing future maintainers about it, so they'll pay
+ extra attention when making changes.
+
+- When adding peripheral support, it would be nice if you put
+ longer-form comments into the libmaple ``notes/`` directory, with a
+ comment in the corresponding .h file referring to it. See the
+ :ref:`dac.h <libmaple-dac>` source for an example.
+
+ This lets us keep the source files relatively free of "introductory"
+ material, while allowing new readers a convenient starting point.
+ These longer-form notes also have a habit of turning into official,
+ user-facing documentation.
+
+- **For libmaple proper**, the convention is to document any
+ user-facing function at the point where it is defined. In
+ particular, this means you should document an externally-linked
+ function defined in a .c file in that .c file, not in the header
+ file where it is declared to the user.
+
+ **For Wirish**, the convention is to put the documentation in the
+ header file where the function is declared.
+
+General Formatting
+------------------
+
+.. highlight:: scheme
+
+- Keep it 80-column clean.
+
+ Emacs users: this means that the largest column number is 79. You
+ should turn on column number mode to help you out::
+
+ (column-number-mode 1)
+
+ You can get more help from `lineker-mode
+ <http://www.helsinki.fi/~sjpaavol/programs/lineker.el>`_. Just put
+ lineker.el somewhere in your load-path, and::
+
+ (require 'lineker)
+ (dolist (hook '(c-mode-hook c++-mode-hook))
+ (add-hook hook (lambda () (lineker-mode 1))))
+
+.. highlight:: cpp
+
+Language Features
+-----------------
+
+In libmaple proper, aim for C99 compatibility. Some GCC extensions
+are OK, but `don't get crazy <http://www.youtube.com/watch?v=jZkdcYlOn5M>`_.
+
+Explicitly approved GCC extensions:
+
+ * `asm volatile <http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html>`_
+
+ * `Nested functions <http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html>`_
+
+In Wirish, generally be very conservative when using C++ features that
+aren't part of C. We are forced to use C++ for Arduino compatibility
+(and the general Arduino style of conflating objects and libraries),
+but it's an angry beast, and we don't want to provoke it. **The
+mantra is "C with classes"**.
+
+Explicitly approved C++ features:
+
+ * Initializers that aren't constant; e.g. the ``gpio_dev*`` values
+ in a ``PIN_MAP``.
+
+ * Default arguments: e.g., the timeout argument in
+ :ref:`lang-waitforbuttonpress`.
+
+Explicitly forbidden C++ features:
+
+ * Templates
+
+Conditionally allowed C++ features:
+
+ * Operator overloading: Never allowed when it's just for style.
+ Probably fine when you're implementing a class that models a
+ mathematical structure, and you'd like to implement
+ e.g. ``operator+()``.
+