Skip to content

Commit 865109c

Browse files
committed
1.0.0
Initial commit 1.0.0
0 parents  commit 865109c

File tree

5 files changed

+360
-0
lines changed

5 files changed

+360
-0
lines changed

.gitignore

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Prerequisites
2+
*.d
3+
4+
# Object files
5+
*.o
6+
*.ko
7+
*.obj
8+
*.elf
9+
10+
# Linker output
11+
*.ilk
12+
*.map
13+
*.exp
14+
15+
# Precompiled Headers
16+
*.gch
17+
*.pch
18+
19+
# Libraries
20+
*.lib
21+
*.a
22+
*.la
23+
*.lo
24+
25+
# Shared objects (inc. Windows DLLs)
26+
*.dll
27+
*.so
28+
*.so.*
29+
*.dylib
30+
31+
# Executables
32+
*.exe
33+
*.out
34+
*.app
35+
*.i*86
36+
*.x86_64
37+
*.hex
38+
39+
# Debug files
40+
*.dSYM/
41+
*.su
42+
*.idb
43+
*.pdb
44+
45+
# Kernel Module Compile Results
46+
*.mod*
47+
*.cmd
48+
.tmp_versions/
49+
modules.order
50+
Module.symvers
51+
Mkfile.old
52+
dkms.conf

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Quantum Leaps
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
## Brought to you by:
2+
[![Quantum Leaps](https://www.state-machine.com/attachments/logo_ql_400.png)](https://www.state-machine.com)
3+
<hr>
4+
5+
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/QuantumLeaps/DBC-for-embedded-C)](https://github.com/QuantumLeaps/DBC-for-embedded-C/releases/latest)
6+
[![GitHub](https://img.shields.io/github/license/QuantumLeaps/DBC-for-embedded-C)](https://github.com/QuantumLeaps/DBC-for-embedded-C/blob/master/LICENSE)
7+
8+
# Design By Contract (DBC)
9+
Design By Contract (DBC), pioneered by Bertrand Meyer, views a software system
10+
as a set of components whose collaboration is based on precisely defined
11+
specifications of mutual obligations—the contracts.1 The central idea of this
12+
method is to inherently embed the contracts in the code and validate them
13+
automatically at run time. Doing so consistently has two major benefits:
14+
15+
1. It automatically helps detect bugs (as opposed to "handling" them), and
16+
2. It is one of the best ways to document code.
17+
18+
# DBC for Embedded C and C++
19+
You can implement the most important aspects of DBC (the contracts) in C or
20+
C++ with **assertions**. The Standard C Library macro `assert()` is rarely
21+
applicable to embedded systems, however, because its default behavior (when
22+
the integer expression passed to the macro evaluates to `false`) is to print
23+
an error message and exit. Neither of these actions makes much sense for most
24+
embedded systems, which rarely have a screen to print to and cannot really
25+
exit either (at least not in the same sense that a desktop application can).
26+
Therefore, in an embedded environment, you usually have to define your own
27+
assertions that suit your tools and allow you to customize the error response.
28+
However, you should think twice before you go about "enhancing" assertions
29+
because a large part of their power derives from their relative *simplicity*.
30+
31+
# This DBC implementation
32+
The DBC implementation in this repository consists of just one header file
33+
[dbc_assert.h](./dbc_assert.h), which has been specifically tailored
34+
for embedded systems and has the following properties:
35+
36+
- allows customizing the error response (by implementing the DBC
37+
fault handler `DBC_fault_handler()`);
38+
39+
- conserves memory by avoiding proliferation of multiple copies
40+
of the filename string (macro `DBC_MODULE_NAME()`);
41+
42+
- provides additional macros for checking and documenting preconditions
43+
(`DBC_REQUIRE()`), postconditions (`DBC_ENSURE()`), and invariants
44+
(`DBC_INVARIANT()`).
45+
46+
> **NOTE**<br>
47+
The names of the three last macros are a direct loan from Eiffel,
48+
the programming language that natively supports DBC.
49+
50+
51+
# Example of Use
52+
```
53+
#include "dbc_assert.h" /* Design By Contract (DBC) assertions */
54+
55+
DBC_MODULE_NAME("sst") /* for DBC assertions in this module */
56+
57+
/*..........................................................................*/
58+
void SST_Task_post(SST_Task * const me, SST_Evt const * const e) {
59+
/*! @pre the queue must be sized adequately and cannot overflow */
60+
DBC_REQUIRE(300, me->nUsed <= me->end);
61+
...
62+
}
63+
```
64+
65+
## More DBC Resources
66+
To learn more about DBC for embedded systems, please check out the following
67+
resources:
68+
69+
[1] [Key Concept: Design by Contract](https://www.state-machine.com/dbc)<br>
70+
[2] ["Design by Contract for Embedded C"](https://barrgroup.com/embedded-systems/how-to/design-by-contract-for-embedded-software)<br>
71+
[3] ["A Nail for a Fuse"](https://www.state-machine.com/a-nail-for-a-fuse)<br>
72+
[4] ["An Exception or a Bug"](https://www.state-machine.com/doc/Samek0308.pdf)
73+
74+
75+
# How to Help this Project?
76+
Please feel free to clone, fork, and make pull requests to improve DBC
77+
for Embedded C. If you like this project, please give it a star (in the
78+
upper-right corner of your browser window):
79+
80+
<p align="center"><img src="img/github-star.jpg"/></p>

dbc_assert.h

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*============================================================================
2+
* Design By Contract (DBC) for embedded C and C++
3+
* GitHub: https://github.com/QuantumLeaps/DBC-for-embedded-C
4+
*
5+
* Q u a n t u m L e a P s
6+
* ------------------------
7+
* Modern Embedded Software
8+
*
9+
* Copyright (C) 2005 Quantum Leaps, <state-machine.com>.
10+
*
11+
* SPDX-License-Identifier: MIT
12+
*
13+
* Permission is hereby granted, free of charge, to any person obtaining a
14+
* copy of this software and associated documentation files (the "Software"),
15+
* to deal in the Software without restriction, including without limitation
16+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
17+
* and/or sell copies of the Software, and to permit persons to whom the
18+
* Software is furnished to do so, subject to the following conditions:
19+
*
20+
* The above copyright notice and this permission notice shall be included in
21+
* all copies or substantial portions of the Software.
22+
*
23+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29+
* DEALINGS IN THE SOFTWARE.
30+
============================================================================*/
31+
#ifndef DBC_ASSERT_H_
32+
#define DBC_ASSERT_H_
33+
34+
/*! @file
35+
* @brief Memory-efficient Design by Contract (DBC) for embedded C and C++.
36+
*
37+
* @note
38+
* The runtime checking of the DBC assertions can be disabled by defining
39+
* the macro #DBC_DISABLE. However, it is generally **not** advisable to
40+
* disable assertions, *especially* in the production code. Instead, the
41+
* assertion fault handler DBC_fault_handler() should be very carefully
42+
* designed and tested under all fault conditions.
43+
*/
44+
45+
/* Active DbC macros -------------------------------------------------------*/
46+
#ifndef DBC_DISABLE
47+
48+
/*! Define the user-specified module name for assertions in this file.
49+
*
50+
* @details
51+
* Macro to be placed at the top of each C/C++ module to define the
52+
* single instance of the module name string to be used in reporting
53+
* assertions in this module. This macro takes the user-supplied parameter
54+
* `name_`.
55+
*
56+
* @param[in] name_ string constant representing the module name
57+
*
58+
* @note
59+
* This macro should **not** be terminated by a semicolon.
60+
*/
61+
#define DBC_MODULE_NAME(name_) \
62+
static char const DBC_module_name_[] = name_;
63+
64+
/*! General purpose assertion with user-specified ID number.
65+
*
66+
* @details
67+
* Makes sure the `expr_` parameter is TRUE. Calls the DBC_fault_handler()
68+
* callback if the `expr_` evaluates to FALSE. This assertion takes the
69+
* user-supplied parameter `label_` to identify the location of this
70+
* assertion within the module. This avoids the volatility of using line
71+
* numbers, which change whenever a line of code is added or removed
72+
* upstream from the assertion.
73+
*
74+
* @param[in] label_ numeric label of the assertion (unique within the module)
75+
* @param[in] expr_ Boolean expression to check
76+
*
77+
* @note
78+
* The `expr_` expression is **not** evaluated if assertions are
79+
* disabled with the ::DBC_DISABLE switch.
80+
*/
81+
#define DBC_ASSERT(label_, expr_) ((expr_) \
82+
? ((void)0) : DBC_fault_handler(&DBC_module_name_[0], (label_)))
83+
84+
/*! General purpose assertion with user-specified ID number that
85+
* evaluates the `expr_` expression even when assertions are disabled.
86+
*
87+
* @details
88+
* Like the DBC_ASSERT() macro, except it **always** evaluates the
89+
* `expr_` expression even when DBC assertions are disabled with the
90+
* #DBC_DISABLE macro.
91+
*
92+
* @param[in] label_ numeric label of the assertion (unique within the module)
93+
* @param[in] expr_ Boolean expression to check
94+
*/
95+
#define DBC_ALLEGE(label_, expr_) DBC_ASSERT(label_, expr_)
96+
97+
/*! Assertion for a wrong path through the code
98+
*
99+
* @details
100+
* Calls the DBC_fault_handler() callback if ever executed. This assertion
101+
* takes the user-supplied parameter `id_` to identify the location of
102+
* this assertion within the file. This avoids the volatility of using
103+
* line numbers, which change whenever a line of code is added or removed
104+
* upstream from the assertion.
105+
*
106+
* @param[in] label_ numeric label of the assertion (unique within the module)
107+
*/
108+
#define DBC_ERROR(label_) DBC_fault_handler(&DBC_module_name_[0], (label_))
109+
110+
/*! Assertion for checking preconditions.
111+
*
112+
* @details
113+
* Equivalent to DBC_ASSERT(), except the name provides a better
114+
* documentation of the intention of this assertion.
115+
*
116+
* @param[in] label_ numeric label of the assertion (unique within the module)
117+
* @param[in] expr_ Boolean expression to check
118+
*
119+
* @note
120+
* The `expr_` expression is **not** evaluated if assertions are
121+
* disabled with the ::DBC_DISABLE switch.
122+
*/
123+
#define DBC_REQUIRE(label_, expr_) DBC_ASSERT((label_), (expr_))
124+
125+
/*! Assertion for checking postconditions.
126+
*
127+
* @details
128+
* Equivalent to DBC_ASSERT(), except the name provides a better
129+
* documentation of the intention of this assertion.
130+
*
131+
* @param[in] label_ numeric label of the assertion (unique within the module)
132+
* @param[in] expr_ Boolean expression to check
133+
*
134+
* @note
135+
* The `expr_` expression is **not** evaluated if assertions are
136+
* disabled with the ::DBC_DISABLE switch.
137+
*/
138+
#define DBC_ENSURE(label_, expr_) DBC_ASSERT((label_), (expr_))
139+
140+
/*! Assertion for checking invariants.
141+
*
142+
* @details
143+
* Equivalent to DBC_ASSERT(), except the name provides a better
144+
* documentation of the intention of this assertion.
145+
*
146+
* @param[in] label_ numeric label of the assertion (unique within the module)
147+
* @param[in] expr_ Boolean expression to check
148+
*
149+
* @note
150+
* The `expr_` expression is **not** evaluated if assertions are
151+
* disabled with the ::DBC_DISABLE switch.
152+
*/
153+
#define DBC_INVARIANT(label_, expr_) DBC_ASSERT((label_), (expr_))
154+
155+
#ifndef DBC_NORETURN
156+
#define DBC_NORETURN
157+
#endif
158+
159+
#ifdef __cplusplus
160+
extern "C" {
161+
#endif
162+
163+
/*! DBC assertion fault handler.
164+
*
165+
* @details
166+
* This is an application-specific callback function needs to be defined in
167+
* the application to perform the clean system shutdown and perhaps a reset.
168+
* The DBC_fault_handler() function is the last line of defense after the
169+
* system failure and its implementation should be very **carefully**
170+
* designed and **tested** under various fault conditions, including but
171+
* not limited to: stack overflow, stack corruption, or calling
172+
* DBC_fault_handler() from ISRs.
173+
174+
* @param[in] module name of the file/module in which the assertion failed
175+
* (constant, zero-terminated C string)
176+
* @param[in] label unique label of the assertion within the module.
177+
* This could be a line number or a user-defined label.
178+
*
179+
* @returns
180+
* This callback function should **not return** (see #NORETURN),
181+
* as continuation after an assertion failure does not make sense.
182+
*
183+
* @note
184+
* It is typically a **bad idea** to implement DBC_fault_handler() as an
185+
* endless loop that ties up the CPU. During debugging, DBC_fault_handler()
186+
* is an ideal place to put a breakpoint.
187+
*/
188+
DBC_NORETURN void DBC_fault_handler(char const * module, int label);
189+
190+
#ifdef __cplusplus
191+
}
192+
#endif
193+
194+
/* Inactive DbC macros -----------------------------------------------------*/
195+
#else
196+
197+
#define DBC_MODULE_NAME(dummy_)
198+
#define DBC_ASSERT(label_, expr_) ((void)0)
199+
#define DBC_ERROR(label_) ((void)0)
200+
#define DBC_REQUIRE(label_, expr_) ((void)0)
201+
#define DBC_ENSURE(label_, expr_) ((void)0)
202+
#define DBC_INVARIANT(label_, expr_) ((void)0)
203+
#define DBC_ALLEGE(label_, expr_) ((void)(expr_))
204+
205+
#endif /* Inactive DBC macros */
206+
207+
#endif /* DBC_ASSERT_ */

img/github-star.jpg

25 KB
Loading

0 commit comments

Comments
 (0)