Developer Guide

From PaparazziUAV
Revision as of 12:20, 15 July 2016 by IHaveADrone (talk | contribs) (→‎MISRA-C Rules: removed random spaces inside of words)
Jump to navigation Jump to search

Introduction

By the time you land on this page, you probably want to enhance the Paparazzi project, that is really good for your karma and really appreciated by the Paparazzi community. We welcome contributions and improvements to the documentation.

FixIt

See also Doxygen for documentation close to the code.

Contributing

You would like to contribute, but are not sure how, then this is the page to visit

Code Editing

How to setup your IDE for use with the source code

Learning to Program

Improve your Paparazzi code in OCAML,C,C++ and Python

Aircraft build process and code generation

Description of the (rather complicated) build system and code generation regarding the airborne firmwares

Design Overview

Attempt at a longer walk through the airborne code architecture

Firmware Architecture

Attempt at brief overview of the firmware architecture with modules and subsystems

Communications

How telemetry and datalink is done

Communications (Proposed New system)

How the telemetry and datalink works

Server-GCS communications

How the Server and the Ground Control Station interact with each other

Values

A short walk through the system and how values are handled

Settings

Settings is the generic mechanism that allows to set and get the value of any variable of the embedded code.

Paparazzi Math Library

The custom Paparazzi math library written in C and how to use it in external programs

Reference/bootloader

All of the questions and answers about the bootloader, but were afraid to ask

LPC USB firmware

All of the answers to the Paparazzi USB bootloader of question you never dared to ask

Upload Bootloader for LPC21xx

How to [[upload the Bootloader to a LPC2148 processor based Autopilot board like the TWOG

Upload the luftboot bootloader

How to upload the Bootloader to a STM32 processor based Autopilot board like the Elle0 or Lisa/M

Upload with DFU (with native or custom dfu bootloader)

Using the native (embedded in ROM) or custom (e.g. Luftboot or KroozSD==) bootloader to upload Paparazzi code

Upload with STLink via SWD (without Bootloader)

General ST-LinkV2 page.

GDB OpenOCD Debug

Using GDB or OpenOCD to directly flash and debug Hardware

USB-Serial

Using a USB connection instead of UART for use with telemetry

ControlTheory

All information you are looking for about the harsh reality of Control Theory needed to let your aircraft fly

Altitude and Height

Altitude and Height demystified

AirBorne Interface ABI

Presentation of the airborne communication system

DevGuide/StateInterface

A stateinterface is a stateinterface is a stateinterface, poems aside read more about what the stateinterface entails here

RT_Paparazzi

Real Time Paparazzi how-to and guidelines

Continuous Integration builds

Info on the Continuous Integration builds (CI) server

MISRA-C Rules

And guidelines.

Directive 4.3

Assembly language shall be encapsulated an isolated

Where assembly language instructions are used they shall be encapsulated and isolated in:

  • Assembly language functions;
  • C functions ( inline functions preferred for C99 );
  • C macros.

Rationale

For reasons of efficiency it is sometimes necessary to embed simple assembly language instructions in-line, for example to enable and disable interrupts. If this is necessary, then it is recommended that it be achieved by using macros, or for C99, inline functions. Encapsulating assembly language is beneficial because:

  • It improves readability;
  • The name, and documentation, of the encapsulating macro or function makes the intent of the assembly language clear;
  • All uses of assembly language for a given purpose can share the same encapsulation which improves maintainability;
  • The assembly language can easily be substituted for a different target or for purposes of static analysis.

Note: the use of in-line assembly language is an extension to standard C, and therefore violates Rule 1.2.

Example

  #define NOP asm(" NOP")

Directive 4.10

Precautions shall be taken in order to prevent the contents of a header file being included more than once

Rationale

When a translation unit contains a complex hierarchy of nested header files, it is possible for a particular header file to be included more than once. This can be, at best, a source of confusion. If this multiple inclusion leads to multiple or conflicting definitions, then this can result in undefined or erroneous behaviour.

Example

  /* file.h */
  #ifndef FILE_H
  /* Non-co mpliant - does not #define FILE_H */
  #endif

In order to facilitate checking, the contents of the header should be protected from being included more than once using one of the following two forms:

  #if !defined ( identifier )
  #define identifier
    /* Contents of file */
  #endif
  #ifndef identifier
  #define identifier
    /* Contents of file */
  #endif

Note: the identifier used to test and record whether a given header file has already been included shall be unique across all header files in the project. Note: comments are permitted anywhere within these forms.


Rule 3.1

The character sequences /* and // shall not be used within a comment

Rationale

If a comment starting sequence, /* or //, occurs within a /* comment, is it quite likely to be caused by a missing */ comment ending sequence. If a comment starting sequence occurs within a // comment, it is probably because a region of code has been commented-out using //.

Exception

The sequence // is permitted within a // comment.

Example

Consider the following code fragment:

  /* some comment, end comment marker accidentally omitted
  >
  Perform_Critical_Safety_Function( X );
  /* this comment is non-compliant */

In reviewing the page containing the call to the function, the assumption is that it is executed code. Because of the accidental omission of the end comment marker, the call to the safety critical function will not be executed. In the following C99 example, the presence of // comments changes the meaning of the program:

  x = y // /*
        + z
        // */
      ;

This gives x = y + z; but would have been x = y; in the absence of the two // comment start sequences. See Also Dir 4.4


Rule 3.2

Line splicing shall not be used within // comments.

Amplification

Line-splicing occurs when the \ character is immediately followed by a new-line character. If the source file contains multibyte characters, they are converted to the source character set before any splicing occurs.

Rationale

If the source line containing a // comment ends with a \ character in the source character set, the next line becomes part of the comment. This may result in unintentional removal of code. Note: line-splicing is described in Section 5.1.1.2(2) of both C90 and C99.

Example

In the following non-compliant example, the physical line containing the if keyword is logically part of the previous line and is therefore a comment.

  extern bool_t b;
  void f ( void )
  {
    uint16_t x = 0; // comment 
    if ( b )
    {
      ++x; /* This is always executed */
    }
  }

See Also Dir 4.4

Rule 4.1

Octal and hexadecimal escape sequences shall be terminated

Amplification

An octal or hexadecimal escape sequence shall be terminated by either:

  • The start of another escape sequence, or
  • The end of the character constant or the end of a string literal.

Rationale

There is potential for confusion if an octal or hexadecimal escape sequence is followed by other characters. For example, the character constant '\x1f' consists of a single character whereas the character constant '\x1g' consists of the two characters '\x1' and 'g'. The manner in which multi-character constants are represented as integers is implementation-defined. The potential for confusion is reduced if every octal or hexadecimal escape sequence in a character constant or string literal is terminated.

Example

In this example, each of the strings pointed to by s1, s2 and s3 is equivalent to "Ag".

  const char *s1 = "\x41g";      /* Non-compliant */
  const char *s2 = "\x41" "g";   /* Compliant - terminated by end of literal */
  const char *s3 = "\x41\x67";  /* Compliant - terminated by another escape */
  int c1 = '\141t';              /* Non-compliant */
  int c2 = '\141\t';            /* Compliant - terminated by another escape */

See Also C90: Section 6.1.3.4, C99: Section 6.4.4.4


Rule 5.1

External identifiers shall be distinct

Amplification

This rule requires that different external identifiers be distinct within the limits imposed by the implementation. The definition of distinct depends on the implementation and on the version of the C language that is being used:

  • In C90 the minimum requirement is that the first 6 characters of external identifiers are significant but their case is not required to be significant;
  • In C99 the minimum requirement is that the first 31 characters of external identifiers are significant, with each universal character or corresponding extended source character occupying between 6 and 10 characters.

In practice, many implementations provide greater limits. For example it is common for external identifiers in C90 to be case-sensitive and for at least the first 31 characters to be significant.

Rationale

If two identifiers differ only in non-significant characters, the behaviour is undefined. If portability is a concern, it would be prudent to apply this rule using the minimum limits specified in The Standard. Long identifiers may impair the readability of code. While many automatic code generation systems produce long identifiers, there is a good argument for keeping identifier lengths well below this limit. Note: In C99, if an extended source character appears in an external identifier and that character does not have a corresponding universal character, The Standard does not specify how many characters it occupies.

Example

In the following example, the definitions all occur in the same translation unit. The implementation in question supports 31 significant case-sensitive characters in external identifiers.

  /*      1234567890123456789012345678901*********  Characters */
  int32_t engine_exhaust_gas_temperature_raw;
  int32_t engine_exhaust_gas_temperature_scaled;    /* Non-compliant */
  /*      1234567890123456789012345678901*********  Characters */
  int32_t engine_exhaust_gas_temp_raw;
  int32_t engine_exhaust_gas_temp_scaled;           /* Compliant */

In the following non-compliant example, the implementation supports 6 significant case-insensitive characters in external identifiers. The identifiers in the two translation units are different but are not distinct in their significant characters.

  /* file1.c */
  int32_t abc = 0;

  /* file2.c */
  int32_t ABC = 0;

See also: Dir 1.1, Rule 5.2, Rule 5.4, Rule 5.5

Rule 5.2

Identifiers declared in the same scope and name space shall be distinct

Amplification

This rule does not apply if both identifiers are external identifiers because this case is covered by Rule 5.1. This rule does not apply if either identifier is a macro identifier because this case is covered by Rule 5.4 and Rule 5.5. The definition of distinct depends on the implementation and on the version of the C language that is being used:

  • In C90 the minimum requirement is that the first 31 characters are significant;
  • In C99 the minimum requirement is that the first 63 characters are significant, with each universal character or extended source character counting as a single character.

Rationale

If two identifiers differ only in non-significant characters, the behaviour is undefined. If portability is a concern, it would be prudent to apply this rule using the minimum limits specified in The Standard. Long identifiers may impair the readability of code. While many automatic code generation systems produce long identifiers, there is a good argument for keeping identifier lengths well below this limit.

Example

In the following example, the implementation in question supports 31 significant case-sensitive characters inidentifiers that do not have external linkage. The identifier engine_exhaust_gas_temperature_local is compliant with this rule. Although it is not distinct from the identifier engine_exhaust_gas_temperature_raw, it is in a different scope. However, it is not compliant with Rule 5.3.

  /*             1234567890123456789012345678901*********    Characters */
  extern int32_t engine_exhaust_gas_temperature_raw;
  static int32_t engine_exhaust_gas_temperature_scaled; /*   Non-compliant */

  void f ( void )
  {
    /*      1234567890123456789012345678901*********         Characters */
    int32_t engine_exhaust_gas_temperature_local; /*         Compliant */
  }

  /*             1234567890123456789012345678901*********    Characters */
  static int32_t engine_exhaust_gas_temp_raw;
  static int32_t engine_exhaust_gas_temp_scaled;          /* Compliant */

See also Dir 1.1, Rule 5.1, Rule 5.3, Rule 5.4, Rule 5.5

Rule 5.3

An identifier declared in an inner scope shall not hide an identifier declared in an outer scope.

Amplification

An identifier declared in an inner scope shall be distinct from any identifier declared in an outer scope. The definition of distinct depends on the implementation and the version of the C language that is being used:

  • In C90 the minimum requirement is that the first 31 characters are significant;
  • In C99 the minimum requirement is that the first 63 characters are significant, with each universal character or extended source character counting as a single character.

Rationale

If two identifiers differ only in non-significant characters, the behaviour is undefined. If an identifier is declared in an inner scope but is not distinct from an identifier that already exists in an outer scope, then the inner-most declaration will “hide” the outer one. This may lead to developer confusion. Note: An identifier declared in one name space does not hide an identifier declared in a different name space. The terms outer and inner scope are defined as follows:

  • Identifiers that have file scope can be considered as having the outermost scope;
  • Identifiers that have block scope have a more inner scope;
  • Successive, nested blocks, introduce more inner scopes.

Example

  void fn1 ( void )
  {
    int16_t i;                            /* Declare an object "i" */
    {
      int16_t i;                          /* Non-compliant - hides previous "i " */
      i = 3;                              /* Could be confusing as to which "i" this refers */
    }
  }

  struct astruct
  {
    int16_t m;
  };

  extern void g ( struct astruct *p );

  int16_t xyz = 0; /* Declare an object "xyz" */

  void fn2 ( struct astruct xyz )         /* Non-compliant - outer "xyz" is
                                           * now hidden by parameter name */
    {
      g ( &xyz );
    }

  uint16_t speed;

  void fn3 ( void )
  {
    typedef float32_t speed;              /* Non-compliant - type hides object */
  }

See also: Rule 5.2, Rule 5.8