... | @@ -5,9 +5,9 @@ Following these rules is not *absolutely* necessary, and much of the existing co |
... | @@ -5,9 +5,9 @@ Following these rules is not *absolutely* necessary, and much of the existing co |
|
before we even decided them, but their use is definitely suggested.
|
|
before we even decided them, but their use is definitely suggested.
|
|
|
|
|
|
General Rules
|
|
General Rules
|
|
-------------
|
|
--------------
|
|
|
|
|
|
You can find some good rules for writing safety-critical code here: http://pixelscommander.com/wp-content/uploads/2014/12/P10.pdf.
|
|
You can find some good rules for writing safety-critical code here: <http://pixelscommander.com/wp-content/uploads/2014/12/P10.pdf>.
|
|
|
|
|
|
Here are some of them:
|
|
Here are some of them:
|
|
|
|
|
... | @@ -15,20 +15,7 @@ Here are some of them: |
... | @@ -15,20 +15,7 @@ Here are some of them: |
|
- Do not use dynamic memory allocation (`malloc` or `new`) after initialization
|
|
- Do not use dynamic memory allocation (`malloc` or `new`) after initialization
|
|
- No function should be longer than about 60 lines
|
|
- No function should be longer than about 60 lines
|
|
- The assertion density of the code should average to a minimum of two
|
|
- The assertion density of the code should average to a minimum of two
|
|
assertions per function.
|
|
assertions per function.[see [below](#Assertions)]
|
|
|
|
|
|
A typical use of an assertion would be as follows:
|
|
|
|
```c
|
|
|
|
if (!c_assert(p >= 0) == true) {
|
|
|
|
return ERROR;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
with the assertion defined as follows:
|
|
|
|
```c
|
|
|
|
#define c_assert(e) ((e) ? (true) : \
|
|
|
|
tst_debugging(”%s,%d: assertion ’%s’ failed\n”, \
|
|
|
|
__FILE__, __LINE__, #e), false)
|
|
|
|
```
|
|
|
|
- Data objects must be declared at the smallest possible level of scope
|
|
- Data objects must be declared at the smallest possible level of scope
|
|
- The return value of non-void functions must be checked by each calling
|
|
- The return value of non-void functions must be checked by each calling
|
|
function, and the validity of parameters must be checked inside each function
|
|
function, and the validity of parameters must be checked inside each function
|
... | @@ -37,198 +24,85 @@ simple macro definitions |
... | @@ -37,198 +24,85 @@ simple macro definitions |
|
- The use of pointers should be restricted. Specifically, no more than one level of
|
|
- The use of pointers should be restricted. Specifically, no more than one level of
|
|
dereferencing is allowed
|
|
dereferencing is allowed
|
|
|
|
|
|
Codestyle
|
|
Best Practices
|
|
-----------
|
|
-------------------
|
|
|
|
### Logging
|
|
For codestyle checking we use two main tools:
|
|
|
|
|
|
|
|
**Linter**
|
|
|
|
|
|
|
|
In the `scripts` folder you will find a linter which which warn you if the code contains
|
|
|
|
some common mistakes (and some more personal stuff, like having Matteo Michele Piazzolla
|
|
|
|
instead of Michele Piazzolla).
|
|
|
|
|
|
|
|
You should execute if from the main directory, like this:
|
|
|
|
|
|
|
|
```
|
|
|
|
cd skyward-boardcore
|
|
|
|
./scripts/linter.sh
|
|
|
|
```
|
|
|
|
|
|
|
|
Things that are being checked by the linter:
|
|
|
|
- Max 80 columns
|
|
|
|
- No triple \n\n\n
|
|
|
|
- Files without copyright
|
|
|
|
- Tab instead of spaces
|
|
|
|
- Matteo Michele Piazzolla
|
|
|
|
- Executes cppcheck and controls that there are no warnings
|
|
|
|
- No `using namespace` in header files (see below)
|
|
|
|
|
|
|
|
The software is a really simple collection of scripts, and it can produce false-positives.
|
|
|
|
|
|
|
|
**CLang-format**
|
|
|
|
|
|
|
|
Clang-format is a tool that helps mantaining the code clean and consistent with the chosen codestyle.
|
|
Per il logger, date un'occhiata [Log.cpp](https://the.al/share/_/pqyewIt6b4r.txt)
|
|
|
|
e [Log.h](https://the.al/share/_/pWoTjUhaN.txt)
|
|
|
|
|
|
There are many plugins out there for most of the IDEs (Vim, Visual Studio, Eclipse...).
|
|
Di pro rispetto a quello di gabriele c'è che non usa ostream, il quale ha un peso non
|
|
Otherwise you can run it from terminal:
|
|
indifferente sulla code size. L'idea sarebbe di riuscire a levare completamente
|
|
```
|
|
iostream e amici dalla code base.
|
|
cat source.cpp | clang-format > nice_style_source.cpp
|
|
|
|
```
|
|
|
|
or
|
|
|
|
```
|
|
|
|
clang-format -i source.cpp
|
|
|
|
```
|
|
|
|
or
|
|
|
|
```
|
|
|
|
find src/ -iname "*.cpp" -exec clang-format -i "{}" \;
|
|
|
|
```
|
|
|
|
(Remember the `src/`, otherwise the whole Miosix codebase will be formatted).
|
|
|
|
|
|
|
|
|
|
Altro pro del mio, si usa con la sintassi della printf, che personalmente
|
|
|
|
trovo 100k volte più comoda degli operatori << e >>. (lo so, non si può fare
|
|
|
|
l'overload per altre classi... si può sempre creare un metodo toString() :P)
|
|
|
|
|
|
Clang-format will search for a file called `.clang-format` in the working folder
|
|
Ultimo pro, LOG_DEBUG(), LOG_INFO(), ... son piu' veloce da scrivere rispetto a
|
|
or parent folders (in Boardcore it should be in the root folder).
|
|
Logger::Logger::Antani\<Antani::lol::blabla\>().
|
|
If it doesn't find it, a default format will be used (you can tell
|
|
|
|
it's using the default style if you see spaces between `()` ).
|
|
|
|
|
|
|
|
Sometimes it uses a strange indentation for enums. In general, if you don't want
|
|
|
|
a particular part of the code to be touched by clang-format, put it inside a:
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
// clang-format off
|
|
|
|
...codice da non toccare
|
|
|
|
// clang-format on
|
|
|
|
```
|
|
|
|
|
|
|
|
Files Stucture
|
|
### Debugging
|
|
-------------------
|
|
|
|
|
|
|
|
*TODO FILE NAMING CONVENTIONS*
|
|
Secondo me il modo migliore e fare una serie di macro in stile
|
|
|
|
|
|
Also, below you will find a description of how source files should be structured.
|
|
|
|
|
|
|
|
### Entrypoints Structure
|
|
|
|
|
|
|
|
*TODO COMMENT WITH \arg \returns ?*
|
|
|
|
|
|
|
|
#### 1) Copyrigth
|
|
|
|
|
|
|
|
You will find different Licence policies along the code: while Miosix's code was released unde the GPL license,
|
|
|
|
most of Boardcore has MIT License.
|
|
|
|
|
|
|
|
Anyway you want to licence your code, you should indeed put a copyright statement as a first thing in every file.
|
|
|
|
```Cpp
|
|
|
|
/* Copyright (c) 2015-2016 Skyward Experimental Rocketry
|
|
|
|
* Authors: ...
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
```
|
|
|
|
#### 2) Includes
|
|
|
|
```cpp
|
|
|
|
#include <Common.h>
|
|
|
|
#include "Miosix.h"
|
|
|
|
//...
|
|
|
|
```
|
|
|
|
💡 *Pro Tip*: In Common.h you will find many frequently used headers. Check it!
|
|
|
|
|
|
|
|
#### 3) Namespace
|
|
```C++
|
|
```cpp
|
|
#ifndef NDEBUG
|
|
using namespace std;
|
|
#define DEB(x) x
|
|
using namespace miosix;
|
|
#else
|
|
|
|
#define DEB(x)
|
|
|
|
#endif
|
|
```
|
|
```
|
|
|
|
|
|
⚠️ *WARNING*: Putting this in header files is bad practice and cancause trouble. To know more see <https://stackoverflow.com/questions/4872373/why-is-including-using-namespace-into-a-header-file-a-bad-idea-in-c>
|
|
da usare con `DEB(printf("..."))`
|
|
|
|
|
|
|
|
|
|
#### 4) Defines
|
|
O comunque usare questo metodo per usare il logger (come scritto ieri su slack)
|
|
```cpp
|
|
oppure per le assert. Tra l'altro son quasi sicuro che le assert non vengono
|
|
#define DEBUG
|
|
compilate se si usa -DNDEBUG.
|
|
```
|
|
|
|
⚠️ *WARNING*: DON'T abuse defines: they're difficult to read (and can create side effects).
|
|
|
|
|
|
|
|
Example of what you **DON'T** want to do (real life example):
|
|
Il problema di questo approccio e' che bisogna ricordarsi di non fare mai
|
|
```cpp
|
|
init dentro le assert:
|
|
#define SENSOR(NAME, CSPORT, CSPIN) \
|
|
|
|
typedef Gpio<GPIO##CSPORT##_BASE, CSPIN> CS_##NAME; \
|
|
|
|
typedef ProtocolSPI<busSPI1, CS_##NAME> spi##NAME
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 5) Typedefs and structs
|
|
|
|
```cpp
|
|
```cpp
|
|
typedef Gpio<GPIOA_BASE, 5> SomePin; //On a Discovery board, this would rapresent the PA5 pin
|
|
assert( init_blabla(...) == true ); // non viene invocata init_blabla
|
|
|
|
// se NDEBUG e' definito.
|
|
```
|
|
```
|
|
💡 *Pro Tip*: you can move gpio typedefs, constants defines and other configuration stuff
|
|
|
|
in an external config.h file (in the same directory) and then `#include` it here.
|
|
|
|
This will help someone else to change how you configured your object without touching the code.
|
|
|
|
|
|
|
|
#### 6) Global variables
|
|
|
|
```cpp
|
|
|
|
int _globalInt;
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 7) Functions prototypes
|
|
### Error Handling
|
|
```cpp
|
|
|
|
void useLongNames(int explicitArg);
|
|
|
|
```
|
|
|
|
#### 8) Main
|
|
|
|
|
|
|
|
```cpp
|
|
Per evitare inconsistenze, abbiamo fatto un csv con tutti i fault counters,
|
|
/*
|
|
descriizoni e altro (apribile tranquillamente con excel) e lanciando
|
|
Put a comment here that explains well how to setup/use the file.
|
|
./sbs -g, questo csv viene convertito in un header file che viene incluso
|
|
*/
|
|
nella cartella dei fault counter.
|
|
int main()
|
|
|
|
{
|
|
|
|
//Local variables declaration (all at the start of the function)
|
|
|
|
int localInt;
|
|
|
|
|
|
|
|
//DO STUFF
|
|
Durante la generazione il csv viene modificato; c'e 'Generated name' (colonna)
|
|
|
|
che viene impostata e non viene piu toccata se è gia scritta, questo implica
|
|
|
|
che se non vi piace un nome generato lo potete cambiare (todo: da verificare
|
|
|
|
se ho fatto veramente cosi lol)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 9) Functions bodies
|
|
### Assertions
|
|
|
|
|
|
```cpp
|
|
A typical use of an assertion would be as follows:
|
|
/*
|
|
```c
|
|
Put a comment before every function, telling what args they want and what they do.
|
|
if (!c_assert(p >= 0) == true) {
|
|
*/
|
|
return ERROR;
|
|
void useLongNames(int explicitArg)
|
|
|
|
{
|
|
|
|
//BODY of function
|
|
|
|
}
|
|
}
|
|
```
|
|
```
|
|
|
|
with the assertion defined as follows:
|
|
### Header Files Structure
|
|
```c
|
|
```cpp
|
|
#define c_assert(e) ((e) ? (true) : \
|
|
/*LICENSE*/
|
|
tst_debugging(”%s,%d: assertion ’%s’ failed\n”, \
|
|
#ifndef YOURHEADER_H
|
|
__FILE__, __LINE__, #e), false)
|
|
#define YOURHEADER_H
|
|
|
|
//Define stuff
|
|
|
|
#endif
|
|
|
|
```
|
|
```
|
|
|
|
|
|
TODO:
|
|
|
|
- name of objects, folders, ifdef miosix...
|
|
|
|
|
|
|
|
What's Next
|
|
What's Next
|
|
-------------
|
|
-------------
|
|
Once you've read these guidelines, you can check some [Best Practices](../wiki/Best-Practices) or
|
|
You will find more specific best practices in [Writing a Driver](../wiki/Writing-a-driver)
|
|
start [Writing a Driver](../wiki/Writing-a-Driver). |
|
and [Writing a Sensor](../wiki/Writing-a-Sensor), but before that maybe you should
|
|
\ No newline at end of file |
|
take a look at Boardcore's [Codestyle](../wiki/Codestyle). |
|
|
|
\ No newline at end of file |