Thank you for your interest in contributing to CRUMBS! This guide covers how to build, test, and contribute to the project.
For all platforms:
- Git
- C compiler (gcc, clang, or MSVC)
- CMake 3.13 or later
For Arduino development:
- Arduino IDE or PlatformIO
- AVR toolchain (included with Arduino)
For Linux development:
- linux-wire library (installation guide)
git clone https://github.com/FEASTorg/CRUMBS.git
cd CRUMBSBasic build:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallelWith Linux HAL enabled:
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCRUMBS_ENABLE_LINUX_HAL=ON \
-DCRUMBS_BUILD_EXAMPLES=ON
cmake --build build --parallelWith tests:
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DCRUMBS_ENABLE_TESTS=ON
cmake --build build --parallel
ctest --test-dir build --output-on-failureInstall system-wide:
sudo cmake --install build --prefix /usr/localCRUMBS is designed to work seamlessly with Arduino IDE and PlatformIO:
Arduino IDE:
- Copy CRUMBS folder to
~/Arduino/libraries/ - Restart Arduino IDE
- Open any example from File → Examples → CRUMBS
PlatformIO:
# platformio.ini
lib_deps =
cameronbrooks11/CRUMBS@^0.11.0Or for local development (see Local Development below).
CRUMBS includes comprehensive unit tests for core functionality:
# Build with tests enabled
cmake -S . -B build -DCRUMBS_ENABLE_TESTS=ON
cmake --build build
# Run all tests
ctest --test-dir build --output-on-failure
# Run specific test
./build/test_encode_decode
./build/test_crc_failureTest coverage:
test_encode_decode— Frame encoding/decodingtest_crc_failure— CRC validation and error handlingtest_handlers— Handler registration and dispatchtest_msg_helpers— Message builder/reader helperstest_version— Version macro validationtest_context— Context initializationtest_peripheral_flow— Peripheral receive/reply flowtest_reply_flow— SET_REPLY patterntest_set_reply— Request opcode handlingtest_scan_fake— Scanner logic (simulated I²C)test_reply_handler— Reply handler registration, dispatch, and fall-through
Integration tests require physical I²C hardware:
Arduino integration:
- Upload
examples/core_usage/arduino/basic_peripheral/to peripheral device - Upload
examples/core_usage/arduino/basic_controller/to controller device - Connect I²C (SDA/SCL) between devices
- Verify LED blinks in response to commands
Linux integration:
- Connect Arduino peripheral to Raspberry Pi I²C bus
- Build and run
examples/core_usage/linux/simple_controller/ - Verify communication via serial monitor and Linux output
When adding new features:
- Write test first (create
tests/test_<feature>.c) - Verify test fails (no implementation yet)
- Implement feature (in
src/core/orsrc/hal/) - Verify test passes
- Add documentation (update relevant docs)
We follow a concise in-source documentation style. See docs/doxygen-style-guide.md for complete guidelines.
Key requirements:
- All public functions must have docblocks
- Use Doxygen-compatible format
- Include
@brief,@param,@returnas needed - Keep descriptions focused and concise
Example:
/**
* @brief Encode a CRUMBS message into wire format
*
* @param msg Message to encode
* @param buffer Output buffer (min 31 bytes)
* @param buffer_len Size of output buffer
* @return Encoded frame length (4–31 bytes), or 0 on error
*/
size_t crumbs_encode_message(const crumbs_message_t *msg,
uint8_t *buffer,
size_t buffer_len);Before submitting a PR, run the documentation checker:
./scripts/doccheck.shThis runs Doxygen and reports warnings for missing/incomplete documentation.
CI behavior:
- Documentation check runs on all PRs (non-blocking)
- Warnings reported but don't fail build
- Goal: Incrementally improve documentation quality
User-facing documentation lives in docs/:
protocol.md— Wire format specificationapi-reference.md— Complete API documentationarchitecture.md— Design and conceptsplatform-setup.md— Installation guidesexamples.md— Learning pathcreate-a-family.md— Guide for custom device families
When changing public APIs:
- Update relevant documentation files
- Add cross-references where appropriate
- Update code examples if needed
- Check for broken links
When developing changes to CRUMBS itself, test locally before publishing:
Development workflow:
-
Edit example's
platformio.ini:# Change from registry version lib_deps = cameronbrooks11/CRUMBS@^0.11.0 # To local symlink lib_deps = symlink://../../../../
-
Make changes to CRUMBS source
-
Build example to test:
cd examples/core_usage/arduino/basic_peripheral pio run -
Revert
platformio.inibefore committing:lib_deps = cameronbrooks11/CRUMBS@^0.11.0
Path explanation:
- From:
examples/core_usage/arduino/basic_peripheral/ - To repo root:
../../../../ - PlatformIO expects
library.jsonat target
Clean build after switching:
pio run --target clean
pio runGeneral principles:
- Follow Linux kernel style (K&R variant)
- 4-space indentation (no tabs)
- 80-column line limit (flexible for readability)
- Consistent naming:
crumbs_snake_casefor public APIs
Function naming:
// Public API: crumbs_ prefix
crumbs_encode_message()
crumbs_controller_send()
// Internal helpers: crumbs_ prefix, descriptive
crumbs_compute_crc8()
crumbs_validate_payload_length()Error handling:
// Return 0 on success, negative on error
int crumbs_do_something(void) {
if (bad_condition) {
return -1; // Generic error
}
if (specific_problem) {
return -2; // Specific error code
}
return 0; // Success
}Public headers (src/*.h):
- Minimal includes (only what's necessary)
- Well-documented with Doxygen comments
- Stable API (avoid breaking changes)
Internal headers (src/core/*.h, src/hal/*.h):
- Platform-specific or implementation details
- May change between versions
- Document key structures and algorithms
Use platform guards for platform-specific code:
// In HAL implementation files
#ifdef ARDUINO
#include <Wire.h>
// Arduino-specific code
#endif
#ifdef __linux__
#include <linux/i2c-dev.h>
// Linux-specific code
#endifBefore starting work:
- Check existing issues for duplicates
- Create new issue describing problem/feature
- Discuss approach with maintainers
# Fork on GitHub, then clone
git clone https://github.com/YOUR_USERNAME/CRUMBS.git
cd CRUMBS
# Create feature branch
git checkout -b feature/your-feature-nameBranch naming:
feature/— New featuresfix/— Bug fixesdocs/— Documentation onlyrefactor/— Code restructuring
Best practices:
- Small, focused commits
- One logical change per commit
- Write descriptive commit messages
- Include tests for new features
- Update documentation
Commit message format:
Short summary (50 chars or less)
More detailed explanation if needed. Wrap at 72 characters.
Explain what and why, not how (code shows how).
Fixes #123
# Run unit tests
cmake -S . -B build -DCRUMBS_BUILD_TESTS=ON
cmake --build build
ctest --test-dir build --output-on-failure
# Check documentation
./scripts/doccheck.sh
# Test on target platform (Arduino/Linux)
# ... build and run examples ...Before submitting:
- All tests pass
- Documentation updated
- No compiler warnings
- Code follows style guide
- Commit history is clean
PR description should include:
- What changed and why
- Link to related issue(s)
- Testing performed
- Breaking changes (if any)
- Respond to comments promptly
- Make requested changes
- Push updates to same branch
- Request re-review when ready
Core principles:
- Keep core strictly C (no C++ in
src/core/) - HALs may use platform idioms (Arduino C++, Linux ioctl)
- No dynamic allocation in core
- Maintain backward compatibility when possible
Adding HAL support:
- Create
src/hal/<platform>/directory - Implement write and read primitives
- Add platform guards to prevent cross-contamination
- Update CMake to conditionally build HAL
- Add examples for new platform
- Document setup in
platform-setup.md
CRC implementation:
The project includes a CRC-8 generator script:
# Generate CRC-8 implementations
python scripts/generate_crc8.py
# Output: dist/crc/c99/ (multiple variants)
# Default: nibble table (16-byte, good balance)Variants:
full— 256-byte table (fastest)nibble— 16-byte table (default, balanced)bitwise— No table (slowest, minimal memory)
Staging to source:
# Script stages selected variant to src/crc/
python scripts/generate_crc8.py # --no-stage to skip-
Update version numbers:
library.json— PlatformIO registrylibrary.properties— Arduino registrysrc/crumbs_version.h— C macros
-
Update CHANGELOG.md:
- List all changes since last release
- Categorize: Added, Changed, Fixed, Removed
- Note breaking changes prominently
-
Tag release:
git tag -a vX.Y.Z -m "Release vX.Y.Z" git push origin vX.Y.Z -
Publish to registries:
- GitHub releases (automatic from tag)
- PlatformIO registry (via library.json)
- Arduino Library Manager (via library.properties)
Automated checks:
- CMake build (Linux, macOS, Windows)
- Unit test execution
- Documentation generation
- Arduino library validation
Future additions:
- Integration tests with hardware simulator
- Code coverage reporting
- Performance benchmarks
Good first issues:
- Documentation improvements
- Example enhancements
- Test additions
- Bug fixes (labeled
good first issue)
Areas to explore:
src/core/crumbs_core.c— Core protocol logicsrc/crumbs.h— Public APIsrc/hal/arduino/— Arduino integrationsrc/hal/linux/— Linux integrationexamples/— Usage patterns
Start here:
src/crumbs.h— Public API overviewsrc/core/crumbs_core.c— Message handlingsrc/hal/arduino/crumbs_i2c_arduino.cpp— Arduino HALexamples/core_usage/arduino/basic_peripheral/— Simple example
Follow the data flow:
- Controller builds message (
crumbs_msg_init,crumbs_msg_add_*) - Encode to wire format (
crumbs_encode_message) - Send via HAL (
crumbs_controller_send→ write_fn) - Peripheral receives (
crumbs_peripheral_handle_receive) - Decode and validate (
crumbs_decode_message) - Dispatch to handlers or callbacks
- Issues: Open an issue on GitHub
- Discussions: Use GitHub Discussions for general questions
- Security: Email maintainers directly (see SECURITY.md if present)
We appreciate your contributions!