Skip to content

Commit

Permalink
Merge pull request #152 from UAVCAN/beta
Browse files Browse the repository at this point in the history
Libcanard v1.0
  • Loading branch information
pavel-kirienko authored Oct 12, 2020
2 parents 253794a + 977e313 commit 54a004b
Show file tree
Hide file tree
Showing 16 changed files with 282 additions and 208 deletions.
1 change: 1 addition & 0 deletions .idea/dictionaries/pavel.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 28 additions & 31 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dist: xenial
dist: focal
env:
- CTEST_OUTPUT_ON_FAILURE=1

Expand All @@ -15,29 +15,30 @@ matrix:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-9
- g++-9-multilib
- gcc-9-multilib
- g++-10
- g++-10-multilib
- gcc-10-multilib
- linux-libc-dev:i386
env:
- CC=gcc-9
- CXX=g++-9
- CC=gcc-10
- CXX=g++-10
script:
# ANALYSIS
# Using the build wrapper from Sonar and collecting the code coverage.
# Define NDEBUG=1 to avoid assertion checks being reported as uncovered statements.
- cmake tests -DCMAKE_BUILD_TYPE=Debug -DNO_STATIC_ANALYSIS=1 -DCMAKE_C_FLAGS='-DNDEBUG=1'
- build-wrapper-linux-x86-64 --out-dir sonar-dump make all
- make test
- gcov-9 --preserve-paths --long-file-names $(find CMakeFiles/test_private_cov.dir -name '*.gcno')
- gcov-9 --preserve-paths --long-file-names $(find CMakeFiles/test_private_le_cov.dir -name '*.gcno')
- gcov-9 --preserve-paths --long-file-names $(find CMakeFiles/test_public_cov.dir -name '*.gcno')
- gcov-10 --preserve-paths --long-file-names $(find CMakeFiles/test_private_cov.dir -name '*.gcno')
- gcov-10 --preserve-paths --long-file-names $(find CMakeFiles/test_private_le_cov.dir -name '*.gcno')
- gcov-10 --preserve-paths --long-file-names $(find CMakeFiles/test_public_cov.dir -name '*.gcno')
- 'sonar-scanner -Dsonar.projectKey=libcanard
-Dsonar.organization=uavcan
-Dsonar.sources=libcanard
-Dsonar.cfamily.gcov.reportsPath=.
-Dsonar.cfamily.build-wrapper-output=sonar-dump
-Dsonar.cfamily.cache.enabled=false'
-Dsonar.cfamily.cache.enabled=false
-Dsonar.cfamily.threads=1'
- make clean

# DEBUG
Expand All @@ -50,46 +51,42 @@ matrix:
- make all VERBOSE=1 && make test
- make clean

# -------------------- Clang 9 (Part 1) --------------------
# -------------------- Clang --------------------
- language: cpp
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages: # Install a newer GCC because https://stackoverflow.com/a/51512150/1007777.
- g++-9
- g++-9-multilib
- gcc-9-multilib
- g++-10
- g++-10-multilib
- gcc-10-multilib
- linux-libc-dev:i386
- libc6-dev-i386
- libstdc++-7-dev:i386
script:
# Set up the toolchain.
- wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 9
- sudo apt install clang-tidy-9 clang-format-9
- clang++-9 -E -x c++ - -v < /dev/null # Print the Clang configuration for troubleshooting purposes.
- wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 10
- sudo apt install clang-tidy-10 clang-format-10
- clang++-10 -E -x c++ - -v < /dev/null # Print the Clang configuration for troubleshooting purposes.

# DEBUG
- cmake -DCMAKE_C_COMPILER=clang-9 -DCMAKE_CXX_COMPILER=clang++-9 tests -DCMAKE_BUILD_TYPE=Debug
# DEBUG + format check
- cmake -DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 tests -DCMAKE_BUILD_TYPE=Debug
- make VERBOSE=1 && make test
- make format VERBOSE=1
- 'modified="$(git status --porcelain --untracked-files=no)"'
- echo "${modified}"
- 'if [ -n "$modified" ]; then echo "Run make format to reformat the code properly."; exit 1; fi'
- make clean

# RELEASE
- cmake -DCMAKE_C_COMPILER=clang-9 -DCMAKE_CXX_COMPILER=clang++-9 tests -DCMAKE_BUILD_TYPE=Release
# RELEASE (skip static analysis because it is done in the DEBUG configuration)
- cmake -DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 tests -DCMAKE_BUILD_TYPE=Release -DNO_STATIC_ANALYSIS=1
- make VERBOSE=1 && make test
- make clean

# MINSIZEREL
- cmake -DCMAKE_C_COMPILER=clang-9 -DCMAKE_CXX_COMPILER=clang++-9 tests -DCMAKE_BUILD_TYPE=MinSizeRel
# MINSIZEREL (skip static analysis because it is done in the DEBUG configuration)
- cmake -DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 tests -DCMAKE_BUILD_TYPE=MinSizeRel -DNO_STATIC_ANALYSIS=1
- make VERBOSE=1 && make test
- make clean

# Format check
- make format VERBOSE=1
- 'modified="$(git status --porcelain --untracked-files=no)"'
- echo "${modified}"
- 'if [ -n "$modified" ]; then echo "Run make format to reformat the code properly."; exit 1; fi'

# -------------------- AVR GCC --------------------
- language: c
addons:
Expand Down
51 changes: 35 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ embedded systems.

[UAVCAN](https://uavcan.org) is an open lightweight data bus standard designed for reliable intravehicular
communication in aerospace and robotic applications via CAN bus, Ethernet, and other robust transports.
The acronym UAVCAN stands for *Uncomplicated Application-level Vehicular Communication And Networking*.
The acronym UAVCAN stands for *Uncomplicated Application-level Vehicular Computing And Networking*.

**READ THE DOCS: [`libcanard/canard.h`](/libcanard/canard.h)**
**Read the docs in [`libcanard/canard.h`](/libcanard/canard.h).**

Contribute: [`CONTRIBUTING.md`](/CONTRIBUTING.md)
Find examples, starters, tutorials on the
[UAVCAN forum](https://forum.uavcan.org/t/libcanard-examples-starters-tutorials/935).

Ask questions: [forum.uavcan.org](https://forum.uavcan.org)
If you want to contribute, please read [`CONTRIBUTING.md`](/CONTRIBUTING.md).

## Features

Expand Down Expand Up @@ -138,20 +139,32 @@ But first, we need to subscribe:
CanardRxSubscription heartbeat_subscription;
(void) canardRxSubscribe(&ins, // Subscribe to messages uavcan.node.Heartbeat.
CanardTransferKindMessage,
32085, // The fixed Subject-ID of the Heartbeat message type (see DSDL definition).
7, // The maximum payload size (max DSDL object size) from the DSDL definition.
7509, // The fixed Subject-ID of the Heartbeat message type (see DSDL definition).
16, // The extent (the maximum possible payload size); pick a huge value if not sure.
CANARD_DEFAULT_TRANSFER_ID_TIMEOUT_USEC,
&heartbeat_subscription);

CanardRxSubscription my_service_subscription;
(void) canardRxSubscribe(&ins, // Subscribe to an arbitrary service response.
CanardTransferKindResponse,
123, // The Service-ID to subscribe to.
1024, // The maximum payload size (max DSDL object size).
(void) canardRxSubscribe(&ins, // Subscribe to an arbitrary service response.
CanardTransferKindResponse, // Specify that we want service responses, not requests.
123, // The Service-ID whose responses we will receive.
1024, // The extent (the maximum payload size); pick a huge value if not sure.
CANARD_DEFAULT_TRANSFER_ID_TIMEOUT_USEC,
&my_service_subscription);
```

The "extent" refers to the minimum amount of memory required to hold any serialized representation of any compatible
version of the data type; or, on other words, it is the the maximum possible size of received objects.
This parameter is determined by the data type author at the data type definition time.
It is typically larger than the maximum object size in order to allow the data type author to introduce more
fields in the future versions of the type;
for example, `MyMessage.1.0` may have the maximum size of 100 bytes and the extent 200 bytes;
a revised version `MyMessage.1.1` may have the maximum size anywhere between 0 and 200 bytes.
It is always safe to pick a larger value if not sure.
You will find a more rigorous description in the UAVCAN Specification.

In Libcanard we use the term "subscription" not only for subjects (messages), but also for services, for simplicity.

We can subscribe and unsubscribe at runtime as many times as we want.
Normally, however, an embedded application would subscribe once and roll with it.
Okay, this is how we receive transfers:
Expand Down Expand Up @@ -187,21 +200,21 @@ The DSDL serialization helper library can be used to (de-)serialize DSDL objects
Here's a simple deserialization example for a `uavcan.node.Heartbeat.1.0` message:

```c
uint8_t mode = canardDSDLGetU8(heartbeat_transfer->payload, heartbeat_transfer->payload_size, 34, 3);
uint8_t mode = canardDSDLGetU8(heartbeat_transfer->payload, heartbeat_transfer->payload_size, 40, 8);
uint32_t uptime = canardDSDLGetU32(heartbeat_transfer->payload, heartbeat_transfer->payload_size, 0, 32);
uint32_t vssc = canardDSDLGetU32(heartbeat_transfer->payload, heartbeat_transfer->payload_size, 37, 19);
uint8_t health = canardDSDLGetU8(heartbeat_transfer->payload, heartbeat_transfer->payload_size, 32, 2);
uint8_t vssc = canardDSDLGetU32(heartbeat_transfer->payload, heartbeat_transfer->payload_size, 48, 8);
uint8_t health = canardDSDLGetU8(heartbeat_transfer->payload, heartbeat_transfer->payload_size, 32, 8);
```

And the opposite:

```c
uint8_t buffer[7];
// destination offset value bit-length
canardDSDLSetUxx(&buffer[0], 34, 2, 3); // mode
canardDSDLSetUxx(&buffer[0], 40, 2, 8); // mode
canardDSDLSetUxx(&buffer[0], 0, 0xDEADBEEF, 32); // uptime
canardDSDLSetUxx(&buffer[0], 37, 0x7FFFF, 19); // vssc
canardDSDLSetUxx(&buffer[0], 32, 2, 2); // health
canardDSDLSetUxx(&buffer[0], 48, 0x7F, 8); // vssc
canardDSDLSetUxx(&buffer[0], 32, 2, 8); // health
// Now it can be transmitted:
my_transfer->payload = &buffer[0];
my_transfer->payload_size = sizeof(buffer);
Expand All @@ -210,3 +223,9 @@ result = canardTxPush(&ins, &my_transfer);
Full API specification is available in the documentation.
If you find the examples to be unclear or incorrect, please, open a ticket.
## Revisions
### v1.0
The initial release.
Loading

0 comments on commit 54a004b

Please sign in to comment.