Difference between revisions of "Developer Guide"
IHaveADrone (talk | contribs) m (typo) |
(Some of MISRAC directives) |
||
Line 83: | Line 83: | ||
==[[Builds|Continuous Integration builds]]== | ==[[Builds|Continuous Integration builds]]== | ||
Info on the [[Builds|Continuous Integration builds]] (CI) server | Info on the [[Builds|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 diff erent 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 ==== | |||
<source lang="c"> | |||
#define NOP asm(" NOP") | |||
</source> | |||
=== 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 ==== | |||
<source lang="c"> | |||
/* file.h */ | |||
#ifndef FILE_H | |||
/* Non-co mpliant - does not #define FILE_H */ | |||
#endif | |||
</source> | |||
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: | |||
<source lang="c"> | |||
#if !defined ( identifier ) | |||
#define identifier | |||
/* Contents of file */ | |||
#endif | |||
</source> | |||
<source lang="c"> | |||
#ifndef identifier | |||
#define identifier | |||
/* Contents of file */ | |||
#endif | |||
</source> | |||
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 sequen ce, /* 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 fr agment: | |||
<source lang="c"> | |||
/* some comment, end comment marker accidentally omitted | |||
> | |||
Perform_Critical_Safety_Function( X ); | |||
/* this comment is non-compliant */ | |||
</source> | |||
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: | |||
<source lang="c"> | |||
x = y // /* | |||
+ z | |||
// */ | |||
; | |||
</source> | |||
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 fi le 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 exampl e, the physical line containing the if keyword is logically part of the previous line and is therefore a comment. | |||
<source lang="c"> | |||
extern bool_t b; | |||
void f ( void ) | |||
{ | |||
uint16_t x = 0; // comment | |||
if ( b ) | |||
{ | |||
++x; /* This is always executed */ | |||
} | |||
} | |||
</source> | |||
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". | |||
<source lang="c"> | |||
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 */ | |||
</source> | |||
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 specifi ed 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. | |||
<source lang="c"> | |||
/* 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 */ | |||
</source> | |||
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. | |||
<source lang="c"> | |||
/* file1.c */ | |||
int32_t abc = 0; | |||
/* file2.c */ | |||
int32_t ABC = 0; | |||
</source> | |||
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 inidentifi ers 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. | |||
<source lang="c"> | |||
/* 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 */ | |||
</source> | |||
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 defi ned 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 ==== | |||
<source lang="c"> | |||
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 */ | |||
} | |||
</source> | |||
See also: Rule 5.2, Rule 5.8 | |||
[[Category:Developer_Documentation]] | [[Category:Developer_Documentation]] |
Revision as of 10:30, 13 July 2016
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.
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 diff erent 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 sequen ce, /* 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 fr agment:
/* 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 fi le 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 exampl e, 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 specifi ed 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 inidentifi ers 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 defi ned 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