First of all thanks for taking time to contribute to this project!
Here is a list of guidelines to contribute to Locha Mesh, and this time to the turpial-firmware.
Contributing to Turpial Firmware guidelines.
Please read our code of conduct.
We'll pleased to accept your patches and contributions to this project. There are some guidelines you need to follow.
If you have a question you can write to use using Twitter at @Locha_io, or through our website locha.io.
You can use our issue tracker to share your idea, it will be discussed by the Locha Mesh team members. If we all agree and makes sense to implement this feature, it will be kept opened.
You can open a new issue reporting a bug in our repository, please provide detailed information about the issues you're expecting.
You can contribute making a Pull-Request with the code you want to fix, or with the features that you would like to implement. It will follow a review process first, and after that it can be merged.
Before making modifications execute these git commands to start working on
your changes, this way you make sure you're up to date with the dev
branch.
git fetch --all
git checkout dev
# Synchronize with the origin branch.
git pull origin dev
# Create a branch for your feature.
git checkout -b featurebranch
# Push your changes to your fork, assuming pr is your remote.
git push pr featurebranch
Actually this project uses some parts of the
Google C++ styleguide and
we use a .clang-format
file to format the documents.
It's recommended to run clang-format
on the code you modify, so the review is
more easy.
The goals as we see them actually are based to optimize the code to be read efficiently; We expect the codebase to last long and we prioritize reading over writing.
-
We choose to explicitly optimize the user experience of the programmers reading the source code, maintaining and debugging the code in our codebase. We "leave a trace to the reader" to give a hint to who is reading by making the code very explicit about the intentions.
-
Be consistent with existing code. Actually having a common set of guidelines allows us to focus on other problems more important.
Commit messages should be always short, describing the changes. If the commit changes various files a more detailed (in other lines) description should be done describing the changes each one.
All header files should use include guards, there aren't exceptions to this rule. The format to create include guards is as follows:
// Example file: foo.h
#ifndef FOO_H
#define FOO_H
...
#endif // FOO_H
The #include
declarations should be positioned only in the top of the file
by default.
The header files should be included in the following order:
- C system headers.
- C++ standard library headers.
- Library headers.
- Project headers.
They should be put in descending order.
- Use a descriptive name and coherent with the code.
- All names should be in english.
Please don't define macros if you don't need really to. If you do it you can name them like this:
MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE
They should use uppercase letters and underscores.
// Examples:
#define ROUND(x) ...
#define PI_ROUNDED 3.0
#define LOW_NIBBLE(x) (x & 0xf)
- To separate words use underscores, variables should use
snake_case
naming. - Don't group variables by type.
- Private variables use a
m_
prefix. - Global variables use the
g_
prefix.
// GOOD, underscore
int rssi_level;
int snr_level;
// BAD, Grouped
int rssi_level, snr_level;
// BAD, CamelCase
int RssiLevel;
int SnrLevel;
// BAD, mixed case
int rssiLevel;
int snrLevel;
Local variables should be located the more closest possible to their usage location. Initialize the variables on their declaration.
int i;
i = f(); // Bad -- initialization separate from declaration.
int j = g(); // Good -- declaration has initialization.
std::vector<int> v;
v.push_back(1); // Prefer initializing using brace initialization.
v.push_back(2);
std::vector<int> v = {1, 2}; // Good -- v starts initialized.
Variables necessary for if
, while
and for
should be declared inside these statements. Example:
while (const char* p = strchr(str, '/')) str = p + 1;
- Use descriptive verbs.
- Names start with lowercase letters.
- If the name has various words the first letter of the word should be uppercase.
int getTotalNearestNodes();
void getData();
int getFirstItem();
- We use uppercase letters for every word of the class (
SnakeCase
).
class SomeClass {
public:
...
private:
int m_foo; // Private variables have the m_ prefix
};
- Always use brackets in the
if
/else
. - Put a space between
if
and()
.
// if-else or nested if-else statements ALWAYS put braces
if (foo)
{
if(foo == 1)
{
bar = UP;
}
else
{
bar = DOWN;
}
}
else
{
bar = MIDDLE;
}
// only if statement
if (foo) bar = UP;
- Put a space between
while
and()
.
// while statement
while (foo > 0)
{
++bar;
}
// do-while statement
do
{
++bar;
}
while (foo > 0);
Avoid using forward declarations, include the headers when possible.
- If using a function declared on a header file, include that file.
- When using template classes, obligatorily include the header file.
Only define inline functions when it's 10 lines or less.
Namespace provide a method to avoid name collisions in big codebases.
Namespaces should be used following these rules:
- All namespaces should be lowercase.
- Avoid colliding with other namespaces.
- Finish namespaces with a comment as shown below.
// In the .h file
namespace mynamespace {
// All declarations are within the namespace scope.
// Notice the lack of indentation.
class MyClass {
public:
...
void Foo();
};
} // namespace mynamespace
// In the .cc file
namespace mynamespace {
// Definition of functions is within scope of the namespace.
void MyClass::Foo() {
...
}
} // namespace mynamespace
Use structures only for objects that only have plain-old-data, everything else is a class.
-
Structures should be used for object that only carry data and have associated constants, but don't have any other functionality that isn't getting/setting the members. All fields should be public. Methods should only change the members value and not behaviour.
-
If you require more functionality, use a class.
-
Naming member variables on classes and structures have different rules. Structures don't use the
m_
prefix.
- Use the return value when possible, otherwise return through parameters using pointers.
- The input parameters go first, returns parameters go at the last position.
- We prefer short and concise functions.
- Somethings more large functions are needed and appropriate, if a function is over 40 lines, think if it can be broken in smaller pieces. Divide and conquer.
- Some functions are complex and big, don't be afraid to modify them if you need to suit your needs or to refactor it.
- All parameters passed by reference should use
const
. - If the parameter is modified use pointers instead.
- Use overloaded functions (constructors too) only if the reader looking at the call site can have a good idea of what is happening.
class MyClass {
public:
void analyze(const std::string &text);
void analyze(const char *text, size_t textlen);
};
- You can overload a function if the semantics between the variants are the same.
- Use C++ style castings:
static_cast<float>(double_value)
- Use brackets for arithmetic type conversions.
int64 y = int64 {1} << 42
- Don't use C style casts:
int y = (int) x
- Is preferred to put functions that aren't member functions on a namespace.
- Don't use a class to group static functions.
- We prefer to use the
const int *
, this form is used through all the codebase.
- Do not use tabs.
- Use 4 spaces as default indentation.
ToDo