Embedded C Coding Standards

Coding standards help keep the code clean, and consistent. The guidelines below also explain and cite the reasons why we should follow them, and certain ones will have references to ISO26262, which is a safety certification guideline for code.

Goals

Non-Goals

Any code you write, modify or generate should follow the coding standards. If you find any code that doesn't follow these rules, please take the initiative to fix it.

Follow the Boy Scout Rule

Leave the campground cleaner than you found it.


Best Practices

Principles are guiding rules to be more successful. You need to constantly keep these in mind and have them serve as a guardrail to keep you focused towards writing good, and clean software.

You should not learn of the following principles once and then forget them. A principle is a kind of rule, belief, or idea that guides you.

[Clean C++]

KISS


Keep It Simple and Stupid and less obscure. Keep the logic as simple as possible, and oftentimes as un-optimized as possible. Aim for code readability over creating fancy logic.

Very cool macro but could be deadly:

#define CRITICAL_SECTION() \
  for (int i = ISR_disable() | 1; i != 0; i=ISR_enable() & 0)

CRITICAL_SECTION() {
  ++x;
}

Violation of the KISS principle in an effort to "optimize":

uint8_t array[64];

// Do not do this
for (uint32_t i = 0; i < 64/8; i++) {
  *(uint64_t*)&array[i] = 0;
}

// Apply the KISS principle
uint8_t array[64] = { 0 };

Aim for extreme simplicity and write minimal amount of code. And remember my wise words:

It is not about how many lines of code you write, it is about how few.

-- Lockheed Martin (Preet)

DRY


Copy and paste is a design error.

-- David L. Parnas

Do not Repeat Yourself The extent of this even means not repeating yourself in comments. In general, whenever you believe a change in logic requires you to make the same fix somewhere else, then it is time to refactor the logic to avoid repeating yourself.

Do not repeat yourself in comments either

// The timeout is set to 100ms because ...
const uint32_t timeout_ms = 100;

// Instead, do this:

// The timeout value is chosen because ...
const uint32_t timeout_for_can_message_ms = 100;

But apart from this silly example, do not repeat your code in multiple places. Instead, refactor to a common function, and then re-use that. Effects of this includes:

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

-- The Pragmatic Programmer

YAGNI


You Ain't Gonna Need It This one is the most occurring theme among developers. We usually develop APIs that we think we will need one day. But the fact of the matter is that we can design the APIs when we really need it.

Here is a good one:

Do not do something today that you can do tomorrow, because tomorrow, you might not need to do it at all.

IBM Websphere Group (Preet)

Prefer to build software when you really need it, otherwise it is a waste. Avoid your impulses:

But at the same time, provisioning certain things towards the future is okay. For example, the TCP/IP stack provisioned for some reserved bytes and although the standard is largely unchanged, it did provide the roadway towards IPv6. Another example is that if you are developing a communication standard, it is okay to provision for an extra byte for a version that allows you to amend the standard in the future.

Other Best Practices


Here are some general Sibros guidelines for being a good, responsible engineer.

Modularize Code

Modularize code, and do not create God Objects. When you are dealing with a large problem, split the problem into smaller code modules and make the code only do one thing. This allows for the module to be implemented with simple logic thus improving the overall code readability as well as making it easier to test.

If we are creating an HTTP client, do not put all the code into a single module. Instead, consider splitting this problem into small code blocks, such as:

Reference this article for further inspiration.

Functions

if (constant == my_variable) { } // Good

if (my_variable == constant) { } // Bad

if (constant != my_variable) { } // Good

if (my_variable != constant) { } // Bad
const char *app__get_log_line(const *module_s); // Good 
bool app__is_id_ready(const *module_s, const size_t type_id); // Bad, const type_id is redundant

Validate Pointers

Assuming there is a heavy use of pointers, we want to balance the fundamental checks with those that may actually be useful and create a safer code-base.

C code modules are designed based on structs and the instances of these structs are then given to APIs. This mimics how C++ classes operate as the first parameter to functions is the module pointer itself which C++ refers to as the this pointer.

typedef struct {
  void * data;
} my_module_s;

void my_module__api(my_module_s *this_ptr);

There may be reasons for not checking the this_ptr, however, the safety aspects of the code outweigh the benefits. Here are some downsides that we did assess though:

void my_api(module_s *this_ptr, void *ptr) {
  if (NULL != this_ptr) {
    // Ensure that bad pointers do not execute an un-deterministic instruction
    if (NULL != ptr) {  
    }
  }
}

Pointer Validation Recommendation

Each pointer must be validated, and there are certain rules to follow in order to get past static analysis tools flagging your code, and preventing it from getting merged.

// DO NOT DO THIS
// CERT C will flag this as 'warning 613: potential use of null pointer
void foo(module_s *module, void *pointer) {
  const bool pointers_are_valid = (NULL != module) && (NULL != pointer);

  if (pointers_are_valid) {
    // ...
  }
}

// Explicitly check pointers
void foo(module_s *module, void *pointer) {
  if ((NULL != module) && (NULL != pointer)) {
    // ...
  }
}

If there are "private" (or static) functions, they do not need redundant checks as long as code structure guarantee that they will never be called unsafely. These are "forgiven" by PCLint or CERTC as long as they follow the coding standards of containing __private_ name. Here is an example:

static void module__private_do(module_s *module, void *pointer) {
  // No need to check 'if ((NULL != module) && (NULL != pointer))'
}

void module__do(module_s *module, void *pointer) {
  if ((NULL != module) && (NULL != pointer)) {
    module__private_do(module, pointer);
  }
}

Variables

Do not re-use variables, and avoid changing the variables passed as copy. You can opt to make the parameters const to enforce this.

sl_buffer_s sl_buffer__init(void *static_memory, size_t memory_size_bytes) {
  memory_size_bytes = (NULL == static_memory) ? 0U : memory_size_bytes;
}

// Do this instead
sl_buffer_s sl_buffer__init(void *static_memory, size_t memory_size_bytes) {
  const size_t sanity_checked_memory_size_bytes = (NULL == static_memory) ? 0U : memory_size_bytes;
}

Data Initialization

Globals

C standards call for initialization of all global memory to zero, and therefore, there is no need for explicit initialization. For any customer integration that fails to do this, we need to work with them to make sure that their startup code performs this necessary step.

int my_global;
struct_s my_struct;

Structs

Initialize the members by name. Use colon for C++ (it doesn’t support C dot initializer)

Example

const ecu_spi__channel_config_s ecu_spi__channel_configs[ECU_SPI__CHANNEL_COUNT] = {
  [ECU_SPI__CHANNEL_MOTOR] = { .master = true, .timing = FALLING_EDGE},
  [ECU_SPI__CHANNEL_HSD] = { .master = false, .timing = FALLING_EDGE},
  [ECU_SPI__CHANNEL_SBC] = { .master = true, .timing = RISING_EDGE},
};

For consistency reasons, when the dot initializer is not possible, then always use sl_utils__memset_zero(), then set the selected (or all) members appropriately.

void zero_struct_using_ptr(struct_s *s) {
  sl_utils__memset_zero(s, sizeof(*s));

  // Then
  s->foo = 1;
}

void instantiate_struct() {
  struct_s s;
  sl_utils__memset_zero(&s, sizeof(s));

  // Then
  s.foo = 1;
}

The reasons to use sl_utils__memset_zero() is that:

Do not confuse the struct initialization with array initialization which can use = {0}

Arrays/Maps

For constant arrays that map two sets of values and should contain a certain number of elements, use a static, compile-time assertion macro to validate the array size.

This ensures that the code will only compile when the number of elements in the map/array equals the number that is expected.

Example For an array that maps enums to strings:

static const sl_string_value_map_s image_type_string_map[] = {
    {"BOOTLOADER", SL_ECU_INFO__IMAGE_TYPE_BOOTLOADER},
    {"APP", SL_ECU_INFO__IMAGE_TYPE_APP},
    {"UPDATER", SL_ECU_INFO__IMAGE_TYPE_UPDATER},
    {"CALIBRATION_BLOCK", SL_ECU_INFO__IMAGE_TYPE_CALIBRATION_BLOCK},
};

Consider adding the following compile-time assertion:

COMPILE_TIME_ASSERT((size_t)SL_ECU_INFO__IMAGE_TYPE_COUNT == ARRAY_COUNT(image_type_string_map));

Safety and MISRA

    goto jump_over;
    int stack_corruption = 0;

    jump_over:
    stack_corruption = 123; // Oops, this was not allocated on the stack
      if (door_open) {   
        door_open = false;    
      }
      if (condition) {  
        // insert code here    
      } else if (second_condition) {
        // insert some more code  
      } else {  
      }
      // Do not do this
      *p++ = 1;
      byte[counter++] = 123;
      int b = a++;
      int c = ++a;
      if (++a > 5)
      if (a++ > 5)
      while (a++ > 6)

      // This is okay
      int okay = 5;
      okay++;
      okay = okay + 1;
      okay += 1;
      ++okay;

Documentation

Truth can only be found in one place: the code.

-- Robert C. Martin, Clean Code

This means that the names of the variables and functions etc should describe their purpose instead of having to rely on comments to understand the code. Spend extra time choosing your variable names, and your goal should be that you do not need to document your APIs. Note that in this code sample, we do not need to describe the parameters.

/**
 * Read up to 'bytes' number of bytes into the user provided memory
 * @returns number of bytes consumed
 */
size_t sl_data_carrier__consume(sl_data_carrier_s *data_carrier, void *input_buffer, size_t bytes);

Here is a bad example

uint32_t sl_crc32__compute(uint32_t crc, const uint8_t *data, size_t size, void (*callback)(void));

// But we can improve this by naming our variables that speak for the code itself
uint32_t sl_crc32__compute(uint32_t crc_initial_value, const uint8_t *data, size_t data_size_in_bytes,
                           void (*callback_during_computation)(void));
// This will call the close method and return
void close_file(file *file) {
  close(file);
}
if (...) {
  while (...) {
  }
} // if

Examples of good comments:

API documentation (doxygen style):

/**
 * A brief stating the purpose of the function.
 * @param some_parameter Explanation of parameter and it's value range.
 * @return Explanation of what the function returns and expected value range.
 */
uint32_t my_function(uint32_t some_parameter);
/** 
 * Struct documentation
 */
typedef struct {
  int member; /**< Documentation about this member */
} my_struct_s;

Lint exception:

/*lint !e9087 memcpy() requires void *. */

Implementation details that may not be obvious to other developers:

void mcu_reset__perform_reset(void) {
  /* Unlock is required before writing to the SCU registers to request reset */
  IfxScuWdt_clearSafetyEndinitInline(IfxScuWdt_getSafetyWatchdogPasswordInline());
  IfxCpu_triggerSwReset();
}

Commenting with ticket for future improvement:

void os_system_config__shutdown(os_system__shutdown_reason_e shutdown_reason) {
  (void)shutdown_reason; //TODO #1234: Need to update shared ram
}

Comments needing to be resolved before merging:

Temporary test code:

    // TESTING
    if (main_test.timeout > 0) {

An incomplete implementation (resolve before merging, otherwise provide ticket #):

void os_system_config__shutdown(os_system__shutdown_reason_e shutdown_reason) {
  (void)shutdown_reason; //TODO: Need to update shared ram
}

Balanced length for variables

Keep a balance between variable length and making the intent clear.

Avoid magic numbers

The definition of a magic number is when a hardcoded constant in code is obscure, and the developer's intent is not clear. In other words, readers may ask why was this specific constant chosen? And, what are the effects if I modify the constant?

Developers should avoid magic numbers by ensuring that the intent of any hardcoded constant is clear.

Timeout example

// Good: Timeout is some arbitrary whole unit (1 second)
const int tcp_connect_timeout_ms = 1000;
TCP_connect(&connection, tcp_connect_timeout_ms);

// Bad: This timeout is suspiciously specific
// Is it derived from a calibration? Or, is it random?
const int tcp_connect_timeout_ms = 3655;
TCP_connect(&connection, tcp_connect_timeout_ms);

Error code example

// Bad: What is the significance of 3? What about other constants like 2 or 4?
int error_code = TCP_connect(&connection, timeout_ms);
if (3 == error_code) {
    // Do error handling logic
}

// Good: Intent is clear; the if condition handles a timeout error
error_code_e error_code = TCP_connect(&connection, timeout_ms);
if (ERROR_CODE__TIMEOUT == error_code) {
    // Do error handling logic
}

Size example

/* 
 * Bad: Avoid using an auxiliary variable to define an array size (it's not necessary in this example)
 * While 65535 may seem obvious to some, it's still unnecessarily obscure
 */ 
#define BUFFER_SIZE 65535;
static uint8_t buffer[BUFFER_SIZE];
// Bad: Copy buffer mirrors buffer implicitly; this is prone to human error
static uint8_t copy_buffer[BUFFER_SIZE];

void test_read_buffer(void) {
    // Bad: The size of the buffer should be derived from the buffer itself (one source of truth)
    read_buffer(buffer, BUFFER_SIZE);

    // Simulate buffer overflow
    // Bad: 65536 is an obscure way of expressing larger than the buffer size
    // If the buffer size changes in the future, a maintainer may forget to update this constant
    read_buffer(buffer, 65536);
}

/*
 * Good: Prefer to use constants derived from existing constants
 * 65535 truly represents the max representation of 16 bits
 */
static uint8_t buffer[sizeof(uint16_t)];
// Good: Copy buffer mirrors buffer explicitly
static uint8_t copy_buffer[sizeof(buffer)];

void test_read_buffer(void) {
    // Good: Use `sizeof` on the array itself to get its size (one source of truth)
    read_buffer(buffer, sizeof(buffer));

    // Simulate buffer overflow
    /*
     * Good: Derived size clearly expresses 1 byte greater than actual size
     * Always derive numbers from some source of truth if buffer size changes in the future,
     * then there's no need to update this statement
     */
    read_buffer(buffer, sizeof(buffer) + 1);
}

Again, magic numbers are defined as obscure constants, so don’t do the obvious. For example, this statement is obvious and unnecessary:

const int zero = 0;

Avoid vague names

Avoid these:

// What operation?
void my_module__perform_operation();

// What type of info?
void my_module__update_info();

Use Relative Includes

Shown below are two ways to include a code module. We recommend going with Option 1 for the reasons mentioned below.

// Option 1
#include "sl_data_carrier.h"
// Option 2
#include "../buffers/sl_data_carrier.h"

Module Design

  void func1(void) {
    // NO STATIC VARIABLES INSIDE FUNCTIONS!
    static uint8_t local = 0;
  }

Software Layering

Whitespace & Code Format

Newer languages like Golang have whitespace rules, such as the brace positions built into the language. We chose to implement same idea by using clang-format, which auto formats the source code according to pre-set rules such that we focus our code reviews on the actual matter, and not the code format.

Sibros has clang-format set up to auto-format your code during git commit. Google C++ code whitespace formatting rules are used to format code during a post-commit hook. The only exception to the Google rules is that we use 120 character limit for lines instead of 80 characters.

Layers

There are two primary objectives for layering the code:

Shown below are two high level diagrams of the system/software architecture, as well as an explanation for each layer.

System Architecture

Software Architecture

The layers are:

Double Underscore

Double underscores are used to quickly distinguish what layer and module something belongs to. All functions, variables, structs, enums and unions in a file should match the file name. Please look at the diagram below and the explanations that follow afterwards.

c_code/
+ dev/
| + dev_file_io/
|   + dev_file_io.h
|   | + public header with API for dev_file_io
|   | + declares all dev_file_io__* functions
|   + littlefs/
|   | + dev_file_io.c
|   |   | + includes dev_file_io.h
|   |   | + all dev_file_io__* functions defined
|   |   | + includes dev_file_io_littlefs.h
|   |   | + includes dev_file_io_private.h
|   |   | + can make calls to dev_file_io_littlefs__* functions
|   | + dev_file_io_private.h
|   |   | + contains private information for dev_file_io.c
|   | + dev_file_io_littlefs.h
|   |   | + declares all littlefs specific functions that dev_file_io.c would need to call
|   | + dev_file_io_littlefs.c
|   |   | + includes dev_file_io_littlefs.h
|   |   | + defines all littlefs specific functions
|   |   | + makes all the actual calls to lfs_*
|   + lpc40xx/
|   | + Similar layout as littlefs folder
|   + posix/
|   | + Similar layout as littlefs folder

Observe the following:

Include Guard

Sibros initially went with #pragma once as an include guard. The thought process was that "most" compilers support this compiler pre-processor tag. Sibros, however, supports multitude of OEMs and a diverse set of compilers and we eventually ran into a Tasking compiler that would not recognize the pragma once and had to revise the strategy. Therefore, the include guard standard is:

#ifndef SIBROS__<FILE_NAME>_H
#define SIBROS__<FILE_NAME>_H

// ... code

#endif /* #ifndef SIBROS__<FILE_NAME>_H */

The reason to tag with SIBROS__ is that it guarantees that we will not run into third party code base that happens to use the same name for the include guard, and therefore have to make the include guard unique.

For C++ code base, follow the #pragma once for header files. For C++ code base we deviated from the C include guard because C++ codebase is dominantly compiled in GCC or similar modern compilers and C++ code base is usually not compiled by diverse set of embedded/C compilers. We decided to use this after weighing in on the benefits and the side-effects. The Wikipedia definition is on the harsh side against its use, but there are benefits to avoiding the cryptic #ifndef FOLDER_FOO_HEADER_H__ style.

Reasons in favor:

Reasons against:

#pragma once

void foo(void);

C++ extern

The following block of code is required so that C++ code can use C header files and call the C code. Please note that this is only required in header files and not required in source files.

#ifndef SIBROS__<FILE_NAME>_H
#define SIBROS__<FILE_NAME>_H

#ifdef __cplusplus
extern "C" {
#endif

void foo(void);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* #ifndef SIBROS__<FILE_NAME>_H */

Order of Includes

Follow the examples below, but note that the comments in between include blocks should be used to separate different groups of includes otherwise clang-format will re-order the includes in alphabetical order. The order of include is important because during unit-tests, we hijack the meaning of static keyword and unfortunately the order of includes can lead to trouble during unit-tests. The Unit-Test article further discusses why we hijacked static instead of inventing a new keyword, such as STATIC.

Header File

/* Standard Includes */

/* External Includes */

/* Module Includes */

Private Header File

Not all code modules have to have the private header file. Private function declarations for a code module should go in the *_private.h file. This is because the unit tests may need to access the static functions to perform detailed tests.

The order of includes is just like an ordinary header file, except that we include sl_unit_test_facilitator.h last to hijack the static keyword such that it has no effect during unit-tests. After this file is included, and only during the Unit-Tests, it replaces the meaning of static with <blank> such that the code's private functions are not private and this facilitates Unit-Testing.

/* Standard Includes */

/* External Includes */

/* Module Includes */

#include "sl_unit_test_facilitator.h"

Source File

/* Main Module Header */

// #include "{__name__}.h"

/* Standard Includes */

/* External Includes */

/* Private Module Includes */

// #include "{__name__}_private.h"        // either this
// #include "sl_unit_test_facilitator.h"  // or this

Unit Test file

/* Standard Includes */
#include "unity.h"

/* Mock Includes */

/* External Includes */

/* Module Includes */

// #include "{__name__}.h"
// #include "{__name__}_private.h"        // either this
// #include "sl_unit_test_facilitator.h"  // or this

Naming Convention

General Rules

Variable Names

       int book = 5;
       int books[3] = {4, 2, 5}; // an array of books

Limit Abbreviations

No Redundant Names

Avoid the following because it has the object name repeated too many times:

sl_data_carrier_s data_carrier_tcp;
sl_data_carrier__append(&data_carrier_tcp);

// Whenever 'data_carrier_tcp' is used, we will always use it
// with this API name sl_data_carrier__() therefore adding
// another 'data_carrier_' is redundant

Avoid repeating the module name in member variables of a struct.

typedef struct {
  void *buffer_memory;
  size_t buffer_memory_size_bytes;
} buffer_s;

Types

We should be able to decipher the type looking at the name of the type. Therefore, follow the following naming convention for new types.

Avoid obscuring a type, for example: typedef char hostname[32];. This makes the code unsafe because an aribtrary char array can get past the compiler checks:

void set_default_hostname(hostname name) {
  strncpy(name, "sibros", sizeof(name) - 1);
}

void oops(void) {
  char hostname[2];
  set_default_hostname(hostname);
}

You can make this code safer by using a data structure which will avoid the oops() function above.

typedef struct {
  char string[32];
} hostname_s;

Use strong types

Avoid creating types that can fail basic sanity checks. Here is an example:

typedef char array_type[32];
void set_data(array_type array) {
  // ...
}

void main(void) {
  char data[2];
  set_data(data); // Oops
}

Instead, opt for better types:

typedef struct {
  char data[32];
} data_t;

void set_data(data_t *data_ptr);

Also, avoid macros that can make it through type checks. C may be limited (no C++ templates), but you rather be safe than sorry.

// DO NOT DO THIS
#define MIN_OF(X, Y)

// In C, define mins explicitly, and of course, do not use a macro
uint8_t min_of_uint8(uint8_t x, uint8_t y);
uint16_t min_of_uint16(uint16_t x, uint16_t y);
uint32_t min_of_uint32(uint32_t x, uint32_t y);

Preferred Types

Use <stdint.h>

Use size_t

Functions

Enums

Example

typedef enum {
  APP_BATTERY__STATUS_CODE_INVALID = 0,
  APP_BATTERY__STATUS_CODE_CHARGING,
  APP_BATTERY__STATUS_CODE_DISCHARGING,
  APP_BATTERY__STATUS_CODE_IDLE,
} app_battery__status_code_e;  

Example of a list

typedef enum {
  MCU_PORTPIN__PIN_CAN0_RX,
  MCU_PORTPIN__PIN_CAN0_TX,
  MCU_PORTPIN__PIN_CAN_ID0,
  MCU_PORTPIN__PIN_CAN_STB,
  MCU_PORTPIN__PIN_WATCHDOG,
  MCU_PORTPIN__PIN_COUNT,    
} mcu_portpin__pin_e;

Structs

Unions

Function Pointers

While Loops

Macros

Better alternatives to #defines are discussed below:

Macro guidelines

Macros as compile-time switches

Macros used for compile-time switching should be treated as boolean values. This means that a macro should either be defined as 0 to disable the feature or 1 to enable it.

Reference the following code of an arbitrary file, such as socket_proxy.c. Note that you want to avoid:

Example: socket_proxy.c:

/**
 * Start by defining your 'default'
 * This allows the build system to override the default
 */
#ifndef MODULE_NAME__USE_POLL_API
#define MODULE_NAME__USE_POLL_API (1)
#endif

/**
 * Check that the define is picked up by the compiler before you use the compiler switch
 */
#ifndef MODULE_NAME__USE_POLL_API
#error  "MODULE_NAME__USE_POLL_API must be defined"
#endif

/**
 * Example usage of the macro
 * Note that the #endif indicates what #if we are ending
 */
static int wait_for_read(int socket, uint32_t timeout_ms) {
  int return_code = -1;

#if MODULE_NAME__USE_POLL_API
  struct pollfd poll_socket_read = {.fd = socket, .events = POLLIN};
  return_code = poll(&poll_socket_read, 1, timeout_ms);
#else
  // ...
  return_code = select((socket + 1), &set, NULL, NULL, &timeout);
#endif /* MODULE_NAME__USE_POLL_API */

  return return_code;
}

Other Guidelines

String Literals in Print Statements

When using printf(const char *format, ...) or its variants, string literals should be used for the format parameter as opposed to a char * variable. The reason is because the compile can check the string literal’s % symbols, and match them against the number of arguments passed into printf() variants. The consequence of not matching the parameters with % symbols is stack corruption, hence, the compiler checks are vital for this use-case.

int value = 1;

// Good
printf("Value is %d", value);

// Bad
const char* const format = "Value is %d";
printf(format, value);

Code Templates

The empty lines between includes, and their order is very important. The clang-format will re-order #includes if they are not ordered correctly.

The templates follow the Order of Includes and we do not duplicate the reasons here.

We use these templates with the d3vnu1l.template-generator-vscode plugin for VSCode, hence the macros enclosed within {...} seen below.

Header File

/***********************************************************************************************************************
 * SIBROS TECHNOLOGIES, INC. CONFIDENTIAL
 * Copyright (c) 2018 - 2021 Sibros Technologies, Inc.
 * All Rights Reserved.
 * NOTICE: All information contained herein is, and remains the property of Sibros Technologies, Inc. and its suppliers,
 * if any. The intellectual and technical concepts contained herein are proprietary to Sibros Technologies, Inc. and its
 * suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or
 * copyright law. Dissemination of this information or reproduction of this material is strictly forbidden unless prior
 * written permission is obtained from Sibros Technologies, Inc.
 **********************************************************************************************************************/

/**
 * @file
 * Brief information about the code module
 *
 * Thread Safety Assessment:
 * <Not thread safe because>
 * <Thread safe by using xyz design>
 */

#ifndef SIBROS__{__upperCaseName__}_H
#define SIBROS__{__upperCaseName__}_H

#ifdef __cplusplus
extern "C" {
#endif

/***********************************************************************************************************************
 *
 *                                                  I N C L U D E S
 *
 **********************************************************************************************************************/
/* Standard Includes */

/* External Includes */

/* Module Includes */

/***********************************************************************************************************************
 *
 *                                                   D E F I N E S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                                  T Y P E D E F S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                     F U N C T I O N   D E C L A R A T I O N S
 *
 **********************************************************************************************************************/

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* #ifdef SIBROS__{__upperCaseName__}_H */

Private Header File

/***********************************************************************************************************************
 * SIBROS TECHNOLOGIES, INC. CONFIDENTIAL
 * Copyright (c) 2018 - 2021 Sibros Technologies, Inc.
 * All Rights Reserved.
 * NOTICE: All information contained herein is, and remains the property of Sibros Technologies, Inc. and its suppliers,
 * if any. The intellectual and technical concepts contained herein are proprietary to Sibros Technologies, Inc. and its
 * suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or
 * copyright law. Dissemination of this information or reproduction of this material is strictly forbidden unless prior
 * written permission is obtained from Sibros Technologies, Inc.
 **********************************************************************************************************************/

#ifndef SIBROS__{__upperCaseName__}_PRIVATE_H
#define SIBROS__{__upperCaseName__}_PRIVATE_H

#ifdef __cplusplus
extern "C" {
#endif

/***********************************************************************************************************************
 *
 *                                                  I N C L U D E S
 *
 **********************************************************************************************************************/
/* Standard Includes */

/* External Includes */

/* Module Includes */
#include "sl_unit_test_facilitator.h"

/***********************************************************************************************************************
 *
 *                                                   D E F I N E S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                                  T Y P E D E F S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                 P R I V A T E   D A T A   D E C L A R A T I O N S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                     F U N C T I O N   D E C L A R A T I O N S
 *
 **********************************************************************************************************************/

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* #ifdef SIBROS__{__upperCaseName__}_PRIVATE_H */

Source File

/***********************************************************************************************************************
 * SIBROS TECHNOLOGIES, INC. CONFIDENTIAL
 * Copyright (c) 2018 - 2021 Sibros Technologies, Inc.
 * All Rights Reserved.
 * NOTICE: All information contained herein is, and remains the property of Sibros Technologies, Inc. and its suppliers,
 * if any. The intellectual and technical concepts contained herein are proprietary to Sibros Technologies, Inc. and its
 * suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or
 * copyright law. Dissemination of this information or reproduction of this material is strictly forbidden unless prior
 * written permission is obtained from Sibros Technologies, Inc.
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                                  I N C L U D E S
 *
 **********************************************************************************************************************/
/* Main Module Header */
// #include "{__name__}.h"

/* Standard Includes */

/* External Includes */

/* Private Module Includes */
// #include "{__name__}_private.h"        // either this
// #include "sl_unit_test_facilitator.h"  // or this

/***********************************************************************************************************************
 *
 *                                                   D E F I N E S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                                  T Y P E D E F S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                             P R I V A T E   F U N C T I O N   D E C L A R A T I O N S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                  P R I V A T E   D A T A   D E F I N I T I O N S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                         P R I V A T E   F U N C T I O N S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                          P U B L I C   F U N C T I O N S
 *
 **********************************************************************************************************************/

Test File

/***********************************************************************************************************************
 * SIBROS TECHNOLOGIES, INC. CONFIDENTIAL
 * Copyright (c) 2018 - 2021 Sibros Technologies, Inc.
 * All Rights Reserved.
 * NOTICE: All information contained herein is, and remains the property of Sibros Technologies, Inc. and its suppliers,
 * if any. The intellectual and technical concepts contained herein are proprietary to Sibros Technologies, Inc. and its
 * suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or
 * copyright law. Dissemination of this information or reproduction of this material is strictly forbidden unless prior
 * written permission is obtained from Sibros Technologies, Inc.
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                                  I N C L U D E S
 *
 **********************************************************************************************************************/
/* Standard Includes */
#include "unity.h"

/* Mock Includes */

/* External Includes */

/* Module Includes */
// #include "{__name__}.h"
// #include "{__name__}_private.h"        // either this
// #include "sl_unit_test_facilitator.h"  // or this

/***********************************************************************************************************************
 *
 *                                                   D E F I N E S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                                  T Y P E D E F S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                             P R I V A T E   F U N C T I O N   D E C L A R A T I O N S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                  P R I V A T E   D A T A   D E F I N I T I O N S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                         P R I V A T E   F U N C T I O N S
 *
 **********************************************************************************************************************/

/***********************************************************************************************************************
 *
 *                                     T E S T   S E T U P   &   T E A R D O W N
 *
 **********************************************************************************************************************/

void setUp(void) {}

void tearDown(void) {}

/***********************************************************************************************************************
 *
 *                                                     T E S T S
 *
 **********************************************************************************************************************/

void test_simple(void) {}