Skip to content

Latest commit

 

History

History
626 lines (445 loc) · 23.2 KB

CONTRIBUTING.md

File metadata and controls

626 lines (445 loc) · 23.2 KB

How to Contribute


Introduction

There are many ways to contribute to the OSCC project; support for additional vehicles can be added, diagrams can be made to look better, car systems can be better described, CAN frames can be better detailed, PCBs can be optimized or code could be refactored and improved.

The directory structure of the project is created in such a way that adding support for additional vehicles should be simple and intuitive.

All vehicle specific directories should be recreated for each additional vehicle. The naming convention is

<make>_<model>_<generational identifier>

Below is a sample of how additional vehicle directories should be created.

 .
├── firmware
│   ├── ...
│   ├── brake
│   │   ├──kia_soul_ps
│   │   ├──<my_new_car>       # Brake firmware for vehicle you're adding
│   ├── ...
├── vehicle_info
│   ├──kia_soul_ps
│   ├──<my_new_car>           # Vehicle specific information for vehicle you're adding
└── ...

Getting Started

  • Using the repo's Issues section, create a new issue and:
    • Clearly describe the issue including steps to reproduce when it is a bug
    • Create a branch using git fork in the repository on GitHub

Making Contributions

  • Do not work directly on the master branch; changes to the master branch will be removed

  • Create a topic branch from where you want to base your work

    • You'll likely fork from of the master branch
    • To quickly create a topic branch based on master:
    git checkout -b fix/master/my_contribution master
    
  • Write a good commit message.

Commit Messages

  • Use the present tense ("Add feature" not "Added feature")
  • Use the imperative mood ("Move resistor to..." not "Moves resistor to...")
  • Limit the first line to 72 characters or less
  • Reference issues and pull requests specifically
  • When changing documentation only, include [ci skip] in the commit description

Contributing Code

  • Code should conform to the coding standard (see below)
  • Push your changes to a topic branch in your branch of the repository
  • Submit a pull request to the repository in the PolySync organization
  • Update your github issue to mark that you have submitted code and are ready for it to be reviewed (Status: Ready for Merge)
    • Include a link to the pull request in the ticket
  • The PolySync team will review all pull requests on a weekly basis
  • Code contributed should include unit tests- that demonstrate the code functions as expected

Contributing a Diagram

  • The diagrams were created using the Eagle PCB Design tool
    • All board diagrams should use this tool
  • Modifications should include tests to demonstrate the the modified board works as expected

Submitting Enhancement Requests

Enhancement suggestions are tracked as GitHub issues:

  • Use a clear and descriptive title for the issue to identify the suggestion
  • Provide a step-by-step description of the suggested enhancement in as many details as possible
  • Provide specific examples to demonstrate the steps
    • Include snippets in the examples as Markdown code blocks ( using the ``` format )
  • Describe the current behavior and how this enhancement improves or changes it
  • Explain why this enhancement is useful to most users
  • Specify which version of OSCC this change applies to
    • The versions can be found in the Releases tab on GitHub

Pull Request Labels

  • Fill in the required template
  • Follow the style guide
  • Code should be complete
    • Any changes should include unit tests for the submitted
  • End files with a new line
  • Changes should be located in the most appropriate directory
  • Please open an issue to suggest a new label.

Acceptance Tests

  • All submitted changes will go through a round of acceptance tests.
    • Acceptance includes:
      • Unit Tests to demonstrate the code works out of context
      • System Integration tests to demonstrate that the system works as intended
    • If there are specific or special test scenarios required for the change, they should be documented for any testing
    • PolySync will perform the acceptance testing periodically in order to get changes incorporated into the source
    • If the scope of the change is small enough that the modification is not visible from the system-level, a unit test alone may be acceptable.

Directory Contents

This information is also available in the README.

Directory Contents
3d_tools Technical drawings and 3D files for board enclosures and other useful parts
assets Diagrams and images used in the wiki
boards PCB schematics and board designs for control modules that are integrated with the vehicle, typically these are the throttle, steering and brake boards, but can include other items should they be contributed.
control User Space applications to provide mechanisms for the user to control the vehicle directly via something like a PC. Applications can be command-line or GUI based and include items like a joystick controller
firmware Arduino code for the throttle, steering and brake functionality. This directory also includes code for the CAN gateway module, which uses a stock Arduino board. The firmware should remain modular and portable to a a different Arduino board
vehicle_info Information on specific vehicles such as sensor outputs and wiring diagrams. Each additional vehicle should be in its own subdirectory

Diagrams

Adding diagrams for new boards or other components should be located in the directory most appropriate for their function:

  • A new enclosure should go in the 3d_models directory
  • A new board diagram should go in the boards directory
  • Any new vehicle information should reside in the vehicle_info directory

Existing diagrams should be edited using the Autodesk Eagle as mentioned above.

Building

To build the various components in the system, please see the README.md

Documentation

  • Documentation updates are welcome
  • Documentation should be located in the doc directory where it is most applicable (See the Directory descriptions above)
    • If the doc - directory does not exist, please create it as part of the submission
  • Documentation pull requests function in the same way as other pull requests
  • Documentation should be in markdown format

Helpful Links


OSCC Coding standard

As this is an automotive initiative, this coding standard is based on the MISRA C-2012 standard. The reasoning for the given rule or directive in the coding standard is not included in this as it would create much too large a document.

The MISRA standard is more exacting that the OSCC standard. It is not implied that compliance with this standard guarantees compliance with the MISRA standard.

1. Directives

  1. Implemented behavior must be documented and understood

  2. Comply with the C99 definition of the standard

  3. All source files must compile without errors

  4. Run-time failures must be limited

    1. All arithmetic operations must be checked (e.g. divide by zero)
    2. Pointer arithmetic must be checked
    3. Array bounds must be checked
    4. Parameter validity must be checked either before or inside a function call
    5. Pointer validity must be checked before dereference
    6. Avoid dynamic memory allocation
      1. If used, check validity of allocation
  5. Avoid assembly language usage.

    1. If used, then document, encapsulate and isolate all usage
  6. No “commented out” code

    1. C Style: /- ... */
    2. C++ Style: //
    3. Conditional Compilation Style: #if 0 .. #endif
  7. Prefer the use of types that define the size and signed value of the variable

    1. int8_t, int16_t, int32_t, int64_t
    2. uint8_t, uint16_t, uint32_t, uint64_t
    3. float32_t, float64_t, float128_t
    4. If abstract types are required, use the signed and size types to create the new type
    5. Exceptions:
      1. bool, char, unsigned char, float and double are acceptable for embedded code as they all have specific signs and sizes associated with them
      2. User space applications have more flexibility and can use the intrinsic types: long, unsigned long, int and unsigned int
  8. Prefer function calls to function-like macros

    1. Macros do not perform type-checking during compilation
    2. inline can be used, but is subject to compiler interpretation
  9. Prevent header files from being included more than once

    1. Use the #ifndef HEADER_FILE_H, #define HEADER_FILE_H ... #endif mechanism
  10. Check validity of parameters passed to library functions

    1. e.g. math calls and string calls
  11. Restrict dynamic memory allocation

    1. Allocate all required memory during initialization
    2. If the allocation fails, prevent the system from starting
  12. Sequence access to system resources appropriately

    1. File access - open, read/write, close
    2. Register access - atomic interaction
    3. Prefer to create a system object that manages the interaction (i.e. the singleton pattern)

2. Rules

1. Standard Environment

  1. Prefer to use only the language features that are available in the C99 standard.

2. Unused code

  1. A project should contain no unreachable or dead code
  2. A project should not have any unused type declarations
    1. Includes enumerations, unions, structures and native types
  3. A project should not contain any unused macros
  4. A project should not contain any unused labels
  5. A project should not contain any unused parameters
    1. Passing a parameter to another function constitutes usage

3. Comments

  1. Comments shall not contain C or C++ style comment markers

4. Identifiers

  1. Variables and functions in the same scope (and namespace) shall be distinguishable in the first 63 characters (by the C99 standard)

  2. Variables in an inner scope shall not hide a variable in an outer scope (e.g. do not use a local variable of the same name as a function parameter or a global variable)

  3. Macros must be distinct from variables

  4. Type definitions must be unique

  5. Structure, union, and enumeration tags must be unique

  6. Variable, macro and function naming should use “snake case”

    1. Variables and functions should use descriptive names which are all lowercase and separated by an underscore
      • variable: int32_t range_max;
      • function: int16_t send_can_frame( can_frame* transmit_frame );
    2. Macros should use descriptive names which are all uppercase and separated by an underscore
      • macro: #define TOGGLE_BIT( BIT, X ) ( ( X ) ^= ( 1 << ( BIT ) ) )
  7. All names (variable, macro, function or otherwise) should be human readable and avoid the use of abbreviations

    1. e.g. The macro name PEDAL_THRESHOLD should be used instead of PEDAL_THRESH

5. Types

  1. Prefer bit access macros to bit-field usage (see below)

    1. Bit fields must use an integer or unsigned integer type
    2. Single bit fields must use an unsigned integer type
    3. Bit fields are not necessarily portable as they are subject to compiler implementation and processor architecture
    4. Bit access Macros of the form BITX( 1 << X ) where X is in [ 0 .. variable width ] should be used
  2. String literals must be assigned to const char* variables

    1. This includes when being used as a parameter or return value
  3. Avoid type conversions between boolean values and other intrinsic types

  4. Operations should between objects of the same type (e.g. arithmetic operation should be performed on objects of the same type)

  5. Prefer to capture the result of an operation in an object type of the same size

    1. Exceptions exist when complying with a communication protocol or hardware register width
    2. Rule applies to both narrowing and widening the result of an operation
  6. Unions (overlapped storage) are only allowed when the items in the union are all the same size

// Example union is allowed because each element is 64 bits
union my_array_64bits
{
    char     char_array[8];
    int16_t  int_array[4];
    int32_t  int_array[2];
    float    float_array[2];
    double   double_array[1];
};

6. Declarations

  1. All types must be explicitly specified

    1. Leave nothing in a declaration to implication
    2. Objects
    3. Parameters
    4. Structure and union members
    5. Type definitions
    6. Function return types
  2. Functions should be in prototype form (as opposed to K & R style)

    1. It is acceptable to have an empty set of parentheses instead of a void declaration as in:

    int32_t my_function( );

    1. Prototype form means that the parameter types are included in the function parameter list as in:

    int32_t my_next_function( int32_t parameter1 );

  3. Externally available objects or functions shall be declared only once in one file

  4. Prefer the use of static keyword to limit access to functions and objects that are not accessible externally

  5. Prefer object declaration to be done at the block scope where it is used (e.g. local variables can be declared at the function or block scope)

  6. Arrays with external linkage should have their size explicitly stated

  7. Values for variables in enumerations must be unique

  8. Prefer the use of const pointer unless the pointer is to a value that is being modified

  9. The restrict keyword is not allowed

7. Initialization

  1. An automatic variable (e.g. a local variable) must not be read before it has been initialized

  2. Enclose initializations for array, structure or union variables with values enclosed in braces:

    1. int16_t my_array[ 4 ] = { 0, 1, 2, 3 };
    2. char Arrays may also be initialized with a string literal
    3. The stipulation is that the initializer must be internally consistent with the target array, structure or union
    4. If an array is statically initialized the size must be explicitly stated as in my_array[ 4 ] above
    5. Arrays shall not be partially initialized
  3. Static initialization shall not include any side effects (e.g. pointer dereference and increment which is allowed at run-time)

8. Pointers

  1. Pointer conversions are allowed when:

    1. The conversion is between a pointer and bool
    2. The conversion is from a void type and an intrinsic type
    3. The conversion is between compatible types
    4. The conversion is to a char or unsigned char so that the bytes of an object can be accessed directly
  2. Function pointers cannot be converted

  3. Pointer conversions between typed objects and integers are not allowed

  4. Problems with pointer conversions are mostly concerned with alignment problems and accessing beyond the bounds of the size of the object

  5. Always use the macro NULL to reference an invalid or uninitialized pointer

9. Expressions

  1. Always use parentheses to enforce explicit precedence

  2. For shift operations, the amount shifted must be >= 0 and < sizeof( value being shifted )

  3. Do not use the comma operator

    1. Multiple initialization on the same line
    2. For loops must iterate and act upon a single variable
  4. Always check for overflow on arithmetic operations on unsigned variables

10. Side Effects

  1. Initializer lists must not have side effects

    1. No modification of pointers during initialization
    2. Make all statements explicit
  2. Check macros to prevent side-effects in calls (e.g. What happens when you call DO_COPY_INDEX ( i++ )?)

#define DO_COPY_INDEX ( x ) ( a [ ( x ) ] = b [ ( x ) ] )
  1. Prefer that increment and decrement operators ( ++ and -- ) are explicit statements instead of integral in an operation, e.g.

    1. Macros
    2. Logical comparisons ( && and || )
    3. sizeof
  2. Do not use the result of an assignment operation as a variable or input into another statement

  3. Logical comparisons should not contain persistent side effects such as assignments

11. Control Statements

  1. Always use spaces instead of tabs

    1. Use 4 space as the standard indent
  2. Include a space after an opening parenthesis, brace or bracket and a space before the closing match.

    1. Parentheses: ( to_b || not_to_b )
    2. Brace: array[ 4 ] = { 0, 1, 2, 3 };
    3. Bracket: array[ 4 ] = { 0, 1, 2, 3 };
  3. Variable and function naming should use “snake case”, namely descriptive names which are all lowercase and separated by an underscore

    1. int32_t this_is_an_example_of_a_variable;
  4. if statements shall have the following form:

    int32_t sum;
    const static int32_t max = 25;
    
    if ( sum > max )
    {
        sum = max;
    }
  5. for loops shall have the following form:

    int32_t i;
    int32_t sum = 0;
    int32_t max = 25;
    
    for ( i = 0; i < max; i++ )
    {
        sum += i;
    }
  6. while loops shall have the following form:

    int32_t i = 0;
    int32_t sum = 0;
    int32_t max = 25;
    
    while ( i < max )
    {
        sum += i;
        i++;
    }
  7. do loops shall have the following form:

    int32_t i = 0;
    int32_t sum = 0;
    int32_t max = 25;
    
    do
    {
        sum += i;
        i++;
    } ( while i < max );
  8. Prefer that loops exit using control logic instead of a break statement

  9. Loop counter should not use a floating type as the iterator

  10. The control logic to exit a given loop must be controlled by a variable

    1. This prevents statements that are always true or always false
    2. Exceptions:
      1. for ( ; ; )
      2. while ( 1 ) or while ( true )
  11. The control logic for a statement used in if, for, while and do must resolve to a boolean expression

    1. Checking for the validity of a variable like an integer or pointer is not allowed (e.g. while ( i ) is not acceptable where while ( i != 0 ) is)

12. Control Flow

  1. Prefer to not use goto

    1. If goto is required, the goto label must be within the same function
  2. Prefer to limit the number of break statements to one for a given loop

  3. Functions should have a single point of exit at the end

    uint32_t example_function( uint32_t- pointer_parameter )
    {
        uint32_t return_code = 0;
    
        if ( pointer_parameter != NULL )
        {
            ...
            return_code = 1;
        }
        else
        {
            ...
            return_code = 10;
        }
        return ( return_code );
    }
  4. Prefer to keep functions as small as possible

  5. Duplicate code is not allowed

  6. Statements shall always use braces to delineate the scope of their operation

    1. As with a function, if, while, do, for, always use braces to scope the set of statements or other functions that the conditional controls
  7. All if, else if, trees shall be terminated with an else statement

13. Switch Statements

  1. Prefer if, else if, else construct to switch statements

    1. If the switch statement is required, it must be well-formed
    2. Each case is self-contained and must contain a break statement
    3. Falling through to the next case is only allowed when there is an empty case
    4. All switch statements must contain a final default case
    5. switch statements must contain at least 2 cases and a default
    uint32_t input_parameter;
    
    switch ( input_parameter )
    {
        case 1:
        ...
        break;
    
        case 2:
        case 3:
        {
            uint32_t local_scope_variable;
            ...
            break;
        }
    
        default:
        break;
    }

14. Functions

  1. Variable argument lists are not allowed (e.g. va_arg, va_start, va_end)

    1. printf or its equivalent is allowed for debug only
  2. Recursion is not allowed

  3. All functions require prototypes

  4. Prefer that return values from functions are used

15. Pointers and Arrays

  1. Check that pointer arithmetic does not go beyond the bounds of the array to which the pointer refers.

  2. Avoid pointer subtraction

    1. Pointer subtraction is only allowed for pointers that refer to the same array
  3. Avoid pointer comparison operations

    1. Pointer comparison can be used to determine if a pointer is in the bounds of the array that it refers to.
  4. Pointers should not go beyond two levels of nesting ( i.e. Pointers to pointers are allowed )

  5. Pointers should not be for stack variables or other objects with automatic storage

  6. Check that arrays of variable size are of positive size

16. Preprocessor Directives

  1. #include directives should be preceded only by comments or other preprocessor directives

  2. Macros shall not be named the same as a keyword

  3. Prefer that #undef is not used

  4. Macros should not contain preprocessor directives (side effects)

  5. Expressions from macro expansion should be surrounded by parentheses

  6. #if and #elif expressions should resolve as 0 or 1

  7. Prefer that the # and ## directives not be used

17. Standard Libraries

  1. Avoid #define and #undef on reserved identifiers or macros

  2. Avoid declaring a reserved identifier or macro

    1. e.g. do not create a variable called “float”
  3. Standard library usage is acceptable

18. Resources

  1. Free all allocated memory

  2. Do not open files for read and write at the same time, file access is read-only or write only

  3. Do not dereference a FILE object pointer

  4. Close all system resources before shutdown