Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9ec420f
setup of lvbms system
ManushPatell Oct 24, 2025
843fed6
Merge branch 'main' into manush/BMS-Driver
HarshPatel08 Oct 28, 2025
6ed41a8
compile error
ManushPatell Oct 30, 2025
afa5242
Merge main into manush/BMS-Driver
ManushPatell Nov 8, 2025
7bb0b75
Improve static code analysis time for PRs (#542)
SpeakBoy Nov 9, 2025
fc14370
pec15 & sendcmd function
ManushPatell Nov 9, 2025
556ee51
added enum codes and read/write command
ManushPatell Nov 16, 2025
13b7a4b
Transmit Git Hash over CAN (#540)
luaibash Nov 20, 2025
97696f8
CCNT for data integrity and helper functions
ManushPatell Nov 23, 2025
29ffb03
cobs library (#547)
BlakeFreer Dec 5, 2025
d996284
rename cobs library (#548)
BlakeFreer Dec 5, 2025
0181eaa
Disable pre-commit static analysis (#549)
BlakeFreer Dec 5, 2025
6953bc0
more read functions
ManushPatell Dec 19, 2025
a2b4b60
fix CCNT misunderstanding
ManushPatell Dec 21, 2025
e4bee93
idk gang more commands
ManushPatell Dec 21, 2025
0eba844
removed unneccessary functions, simplified implementation
ManushPatell Dec 26, 2025
5384a47
failure cases for PEC and CCNT
ManushPatell Jan 9, 2026
e3c453c
Remove samparent97 from CODEOWNERS (#554)
samparent97 Jan 10, 2026
5058c52
Remove the CODEOWNERs file (#556)
BlakeFreer Jan 14, 2026
177690b
setup of lvbms system
ManushPatell Oct 24, 2025
640a64f
compile error
ManushPatell Oct 30, 2025
52f7957
pec15 & sendcmd function
ManushPatell Nov 9, 2025
76de297
added enum codes and read/write command
ManushPatell Nov 16, 2025
0a0a0e9
CCNT for data integrity and helper functions
ManushPatell Nov 23, 2025
016511c
more read functions
ManushPatell Dec 19, 2025
05e7c9b
fix CCNT misunderstanding
ManushPatell Dec 21, 2025
423da01
idk gang more commands
ManushPatell Dec 21, 2025
c9ee8d2
Added Read All Commands
HarshPatel08 Dec 22, 2025
eb58c02
Resolve merge conflicts
ManushPatell Jan 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/CODEOWNERS

This file was deleted.

16 changes: 14 additions & 2 deletions .github/workflows/build-test-projects.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/cache@v4
with:
Expand Down Expand Up @@ -52,10 +54,20 @@ jobs:
- name: Perform Static Code Analysis on PlatformIO Projects
shell: bash
run: |
git ls-files -z 'projects/**/platformio.ini' | while IFS= read -r -d '' ini; do
git ls-files -z 'projects/**/platformio.ini' | grep -zv 'projects/demo/' | while IFS= read -r -d '' ini; do
dir=$(dirname "$ini")
echo "============================================================"
echo "==== Performing Static Code Analysis on $dir"
echo "============================================================"
pio check --project-dir "$dir" --fail-on-defect=high || exit 1

SUBDIRS=("$dir/src" "$dir/include")
EXCLUDE_PREFIX="stm*"

# Check for changes in $dir/src and $dir/include, excluding files within $dir/src/platforms/stm*
if git diff --name-only origin/main...HEAD -- "${SUBDIRS[@]}" ":!$dir/src/platforms/$EXCLUDE_PREFIX" | grep -q .; then
echo "Changes detected in $dir → running pio check"
pio check --project-dir "$dir" --flags "--checks=bugprone-*,clang-analyzer-*,google-*,performance-*" --fail-on-defect=high || exit 1
else
echo "No changes in $dir → skipping"
fi
done
8 changes: 0 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,3 @@ repos:
- id: clang-format
require_serial: true
stages: [pre-commit]

- repo: local
hooks:
- id: pio-check
name: Platform IO Static Analysis
entry: bash scripts/static_analysis/static_analysis.sh
language: system
stages: [pre-commit]
5 changes: 5 additions & 0 deletions lib/cobs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
69 changes: 69 additions & 0 deletions lib/cobs/cobs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "cobs.hpp"

#include <cstdint>
#include <cstdlib>

namespace macfe::cobs {

Decoder::Decoder(uint8_t* buffer)
: buffer(buffer), length(0), block_remaining_(0), code_(0xff) {}

bool Decoder::Decode(const uint8_t* encoded, size_t encoded_length) {
// adapted from
// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
// differences: supports procedural decoding / does not require `encoded` to
// contain the entire message

const uint8_t* input_cursor = encoded;

for (; input_cursor < encoded + encoded_length; --block_remaining_) {
if (block_remaining_ > 0) {
buffer[length++] = *input_cursor++;
} else {
block_remaining_ = *input_cursor++;
if (block_remaining_ == 0) {
return true;
}
if (code_ != 0xff) {
buffer[length++] = 0;
}
code_ = block_remaining_;
}
}
return false;
}

constexpr size_t MaxEncodedLength(size_t raw_length) {
constexpr size_t LEADING_ZERO = 1;
constexpr size_t TERMINATING_ZERO = 1;
size_t MAX_STUFF_BYTES = (raw_length + 253) / 254;
return LEADING_ZERO + raw_length + MAX_STUFF_BYTES + TERMINATING_ZERO;
}

size_t Encode(const uint8_t* raw, size_t length, uint8_t* output) {
uint8_t* encode_cursor = output;

uint8_t zero_offset = 1;
uint8_t* zero_offset_p = encode_cursor++;

for (const uint8_t* byte = raw; length--; ++byte) {
if (*byte != 0) {
*encode_cursor++ = *byte;
++zero_offset;
}
if ((*byte == 0) || (zero_offset == 0xff)) {
*zero_offset_p = zero_offset;
zero_offset = 1;
zero_offset_p = encode_cursor;
if ((*byte == 0) || (length > 0)) {
++encode_cursor;
}
}
}
*zero_offset_p = zero_offset; // write the final zero_offset value
*encode_cursor++ = 0; // write delimiter

return size_t(encode_cursor - output);
}

} // namespace macfe::cobs
25 changes: 25 additions & 0 deletions lib/cobs/cobs.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <stdint.h>
#include <stdlib.h>

namespace macfe::cobs {

class Decoder {
public:
Decoder(uint8_t* buffer);
bool Decode(const uint8_t* encoded, size_t encoded_length);

uint8_t* buffer;
size_t length;

private:
uint8_t block_remaining_;
uint8_t code_;
};

constexpr size_t MaxEncodedLength(size_t raw_length);

size_t Encode(const uint8_t* raw, size_t length, uint8_t* output);

} // namespace macfe::cobs
9 changes: 9 additions & 0 deletions lib/cobs/platformio.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[platformio]
include_dir = .
src_dir = .

[env:native]
test_framework = googletest
platform = native
test_build_src = true
build_src_filter = +<cobs.cpp>
157 changes: 157 additions & 0 deletions lib/cobs/test/cobs_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include "cobs.hpp"

#include "gtest/gtest.h"

using namespace macfe::cobs;

void EXPECT_ARRAY_EQUAL(uint8_t* expected, size_t expected_len, uint8_t* actual,
size_t actual_len) {
ASSERT_EQ(expected_len, actual_len);
for (size_t i = 0; i < expected_len; i++) {
EXPECT_EQ(expected[i], actual[i]) << "Differ at index " << i;
}
}

TEST(COBS, ZeroString) {
uint8_t decoded[] = {0x00};
size_t dec_length = sizeof(decoded) / sizeof(decoded[0]);

uint8_t encoded[] = {0x01, 0x01, 0x00};
size_t enc_length = sizeof(encoded) / sizeof(encoded[0]);

uint8_t enc_output[256];
size_t enc_length_actual = Encode(decoded, dec_length, enc_output);
EXPECT_ARRAY_EQUAL(encoded, enc_length, enc_output, enc_length_actual);

uint8_t dec_output[256];
Decoder decoder(dec_output);
EXPECT_TRUE(decoder.Decode(encoded, enc_length));
EXPECT_ARRAY_EQUAL(decoded, dec_length, decoder.buffer, decoder.length);
}

TEST(COBS, EmptyString) {
uint8_t decoded[] = {};
size_t dec_length = sizeof(decoded) / sizeof(decoded[0]);

uint8_t encoded[] = {0x01, 0x00};
size_t enc_length = sizeof(encoded) / sizeof(encoded[0]);

uint8_t enc_output[256];
size_t enc_length_actual = Encode(decoded, dec_length, enc_output);
EXPECT_ARRAY_EQUAL(encoded, enc_length, enc_output, enc_length_actual);

uint8_t dec_output[256];
Decoder decoder(dec_output);
EXPECT_TRUE(decoder.Decode(encoded, enc_length));
EXPECT_ARRAY_EQUAL(decoded, dec_length, decoder.buffer, decoder.length);
}

TEST(COBS, Short) {
uint8_t decoded[] = {0x11, 0x22, 0x00, 0x33};
size_t dec_length = sizeof(decoded) / sizeof(decoded[0]);

uint8_t encoded[] = {0x03, 0x11, 0x22, 0x02, 0x33, 0x00};
size_t enc_length = sizeof(encoded) / sizeof(encoded[0]);

uint8_t enc_output[256];
size_t enc_length_actual = Encode(decoded, dec_length, enc_output);
EXPECT_ARRAY_EQUAL(encoded, enc_length, enc_output, enc_length_actual);

uint8_t dec_output[256];
Decoder decoder(dec_output);
EXPECT_TRUE(decoder.Decode(encoded, enc_length));
EXPECT_ARRAY_EQUAL(decoded, dec_length, decoder.buffer, decoder.length);
}

TEST(COBS, ManyZeros) {
uint8_t decoded[] = {0x11, 0x00, 0x00, 0x00};
size_t dec_length = sizeof(decoded) / sizeof(decoded[0]);

uint8_t encoded[] = {0x02, 0x11, 0x01, 0x01, 0x01, 0x00};
size_t enc_length = sizeof(encoded) / sizeof(encoded[0]);

uint8_t enc_output[256];
size_t enc_length_actual = Encode(decoded, dec_length, enc_output);
EXPECT_ARRAY_EQUAL(encoded, enc_length, enc_output, enc_length_actual);

uint8_t dec_output[256];
Decoder decoder(dec_output);
EXPECT_TRUE(decoder.Decode(encoded, enc_length));
EXPECT_ARRAY_EQUAL(decoded, dec_length, decoder.buffer, decoder.length);
}

TEST(COBS, FFBlock) {
uint8_t decoded[] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54,
0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c,
0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4,
0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc,
0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4,
0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0,
0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
0xfd, 0xfe, 0xff};
size_t dec_length = sizeof(decoded) / sizeof(decoded[0]);

uint8_t encoded[] = {
0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
0xfc, 0xfd, 0xfe, 0x02, 0xff, 0x00};
size_t enc_length = sizeof(encoded) / sizeof(encoded[0]);

uint8_t enc_output[512];
size_t enc_length_actual = Encode(decoded, dec_length, enc_output);
EXPECT_ARRAY_EQUAL(encoded, enc_length, enc_output, enc_length_actual);

uint8_t dec_output[512] = {0};
Decoder decoder(dec_output);
EXPECT_TRUE(decoder.Decode(encoded, enc_length));
EXPECT_ARRAY_EQUAL(decoded, dec_length, decoder.buffer, decoder.length);

// Test partial decoding
uint8_t dec_output2[512] = {0};
decoder = Decoder(dec_output2);
size_t i;
for (i = 0; i < enc_length - 50; i += 10) {
EXPECT_FALSE(decoder.Decode(encoded + i, 10));
}
EXPECT_TRUE(decoder.Decode(encoded + i, enc_length - i));
EXPECT_ARRAY_EQUAL(decoded, dec_length, decoder.buffer, decoder.length);
}

int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
7 changes: 4 additions & 3 deletions lib/periph/periph/spi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ namespace macfe::periph {

class SpiMaster {
public:
virtual ~SpiMaster() = default;
/// Transmit `length` bytes from `tx_data`
virtual void Transmit(uint8_t* tx_data, size_t length);
virtual void Transmit(uint8_t* tx_data, size_t length) {}

/// Receive `length` bytes and place them into `rx_data`
virtual void Receive(uint8_t* rx_data, size_t length);
virtual void Receive(uint8_t* rx_data, size_t length) {}

/// Transmit `length` bytes from `tx_data` and receive `length` bytes,
/// placing them into `rx_data`
virtual void TransmitReceive(uint8_t* tx_data, uint8_t* rx_data,
size_t length);
size_t length) {}
};

} // namespace macfe::periph
6 changes: 6 additions & 0 deletions projects/dashboard/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ flags =
-Wall
-Wno-unused-function ; having problems with unused MPU_Config()
-D LV_BUILD_TEST=0
extra_scripts =
pre:../../scripts/build/generate_git_hash.py

[env:vehicle]
platform = ststm32
Expand All @@ -47,6 +49,7 @@ lib_deps =
${common.lib_deps}

extra_scripts =
${common.extra_scripts}
pre:../../scripts/build/add_hardfloat.py

build_src_filter =
Expand Down Expand Up @@ -79,3 +82,6 @@ build_flags =
-l SDL2
lib_deps =
${common.lib_deps}

extra_scripts =
${common.extra_scripts}
3 changes: 3 additions & 0 deletions projects/front_controller/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ flags =
-Werror
-Wall
-Wno-unused-function ; having problems with unused MPU_Config()
extra_scripts =
pre:../../scripts/build/generate_git_hash.py

[env:vehicle]
platform = ststm32
Expand All @@ -45,6 +47,7 @@ custom_freertos_heap_impl = ""
custom_freertos_config_location = src/platforms/stm32-ev6/Inc/FreeRTOSConfig.h

extra_scripts =
${common.extra_scripts}
pre:../../scripts/build/add_hardfloat.py

build_src_filter =
Expand Down
Loading