chore: testing

This commit is contained in:
anjingyu 2025-07-07 19:47:10 +08:00
parent bb42ea200e
commit 6f08e0973c
18 changed files with 2487 additions and 56 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ lib/
ref/
refs/
.obsidian/
.marscode/
Cargo.lock

View File

@ -9,6 +9,8 @@ Run the installation command, then you can run AD tools(just like `admake`, `adg
``` shell
# Install dependencies
python3 -m pip install -U build setuptools wheel
# On Debina12/Ubuntu 24.04, you should install the following packages for your system python3
# sudo apt install -y python3-build python3-setuptools python3-wheel python3-venv
# Install adtools from source locally
# Install into the user enviroment($HOME/.local/lib)

View File

@ -0,0 +1,8 @@
# CMake Auxiliary Scripts
Auxiliary CMake scripts for AdMake.
## References
- [Ethos U](https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-core-platform)

View File

@ -1,5 +1,6 @@
# CMAKE toolchain for the gcc arm-none-eabi
# CMAKE toolchain for the gcc arm-none-eabi-gcc or armclang
#
# Reference: https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-core-platform
set (CMAKE_SYSTEM_NAME Generic)
set (CMAKE_SYSTEM_PROCESSOR arm)
set (CMAKE_SYSTEM_VERSION 1)
@ -64,7 +65,6 @@ set (CMAKE_EXE_LINKER_FLAGS "${_COMPILER_OPTIONS} -Wl,-Map=linker.map -Wl,-cref
# Linker flags
# set (CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections --specs=nano.specs --specs=nosys.specs -mthumb -g2 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mabi=aapcs -T${LINKER_SCRIPT} -Wl,-Map=${CMAKE_PROJECT_NAME}.map" CACHE INTERNAL "Linker options")
# adjust the default behaviour of the find_xxx() commands:
# search headers and libraries in the target environment,
# search programs in the host environment

1
dbcc/.gitignore vendored
View File

@ -2,6 +2,7 @@
.build/
bin/
lib/
test/dbcc/
# Generated by Cargo
# will have compiled files and executables

View File

@ -3,25 +3,24 @@ cmake_minimum_required (VERSION 3.15)
project (dbcc)
set (ADMAKE_NEED_EXCEPTION ON)
# set (ADMAKE_DISABLE_ADDRESS_SANITIZER ON)
set (ADMAKE_DISABLE_ADDRESS_SANITIZER ON)
include (CMakeListsPub)
set (TARGET_NAME ${CMAKE_PROJECT_NAME})
append_3rd_modules (pybind11)
include_directories (
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/source")
if (DEFINED ADMAKE_BUILD_TEST)
append_modules (dbcc)
file (GLOB_RECURSE TEST_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp")
add_executable (${TARGET_NAME}_test ${TEST_SRC})
add_dependencies (${TARGET_NAME}_test ${TARGET_NAME})
target_link_libraries (${TARGET_NAME}_test ${TARGET_NAME})
add_dependencies (${TARGET_NAME}_test ${DBCC_DEPS})
target_link_libraries (${TARGET_NAME}_test ${DBCC_LIB})
else ()
set (TARGET_NAME ${CMAKE_PROJECT_NAME})
include_directories (
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/source")
file (GLOB_RECURSE SRC
"${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
@ -45,12 +44,38 @@ else ()
#-----------------------#
# Build Python3 binding #
#-----------------------#
find_package (PythonInterp 3)
find_package (PythonLibs 3)
# find_package (Python3)
# Use the system-wide python3 firstly
if (EXISTS "/usr/bin/python3")
execute_process (
COMMAND /usr/bin/python3 --version
OUTPUT_VARIABLE PYTHON_VERSION_OUTPUT
ERROR_VARIABLE PYTHON_VERSION_ERROR
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE PYTHON_VERSION_RESULT)
if (PYTHONLIBS_FOUND)
# if (PYTHON3_FOUND)
if (NOT PYTHON_VERSION_RESULT EQUAL 0)
message (FATAL_ERROR "Failed to execute 'python3 --version': ${PYTHON_VERSION_ERROR}")
endif ()
string (REGEX MATCH "Python ([0-9]+\\.[0-9]+(\\.[0-9]+)*)" _ ${PYTHON_VERSION_OUTPUT})
set (PYTHON_VERSION "${CMAKE_MATCH_1}")
if (NOT PYTHON_VERSION)
message (FATAL_ERROR "Failed to parse Python version from output: ${PYTHON_VERSION_OUTPUT}")
endif ()
message_color ("YELLOW" "-- Detected Python version: ${PYTHON_VERSION}")
set (Python3_EXECUTABLE "/usr/bin/python3")
endif ()
# find_package (PythonInterp 3)
# find_package (PythonLibs 3)
# find_package (Python3)
set (Python3_FIND_STRATEGY LOCATION)
find_package (Python3 ${PYTHON_VERSION} COMPONENTS Interpreter Development)
# if (PYTHONLIBS_FOUND)
if (Python3_FOUND)
# NOTE:
# Because of the stupid design of Python(in pyconfig.h, the author force link python_d for debug version), so when build debug version in AnaConda environment, maybe you can not find the debug version library, so you can only build the release version.
# Build python binding
@ -60,9 +85,10 @@ else ()
file (GLOB_RECURSE PYSRC
"${CMAKE_CURRENT_SOURCE_DIR}/binding/py/*.cpp")
append_3rd_modules (pybind11)
find_package (pybind11 CONFIG REQUIRED)
pybind11_add_module (${PY_TARGET_NAME} ${PYSRC})
pybind11_add_module (${PY_TARGET_NAME} ${PYSRC} $<TARGET_OBJECTS:${TARGET_NAME}_OBJ>)
target_include_directories (${PY_TARGET_NAME} PRIVATE
${pybind11_INCLUDE_DIR}
${PYTHON_INCLUDE_DIRS})
@ -96,27 +122,42 @@ else ()
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${PY_TARGET_NAME}> "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}/dbcc")
# Build python3 package
# Generate setup.py file
# Generate setup.py, pyproject.toml file
# For compatibily
set (PYTHON_VERSION_MAJOR ${Python3_VERSION_MAJOR})
set (PYTHON_VERSION_MINOR ${Python3_VERSION_MINOR})
configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/binding/py/setup.py.in"
"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}/setup.py" @ONLY)
configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/binding/py/pyproject.toml.in"
"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}/pyproject.toml" @ONLY)
set (SETUP_PY "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}/setup.py")
set (PYPROJECT_TOML "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}/pyproject.toml")
if (WIN32)
string (REPLACE "/" "\\" DEST_DIR "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}")
add_custom_command (TARGET ${PY_TARGET_NAME} POST_BUILD
WORKING_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}
COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} bdist_wheel
COMMAND ${Python3_EXECUTABLE} ${SETUP_PY} bdist_wheel
COMMAND xcopy "dist" "${DEST_DIR}" /c /g /d /e /r /h /y
COMMENT "Build wheel package for DBCC Python3, ${PYPKG_SUFFIX}"
DEPENDS ${SETUP_PY} ${INIT_OUTPUT})
else ()
add_custom_command (TARGET ${PY_TARGET_NAME} POST_BUILD
WORKING_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}
COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} -q bdist_wheel
COMMAND ${Python3_EXECUTABLE} -m build --wheel
COMMAND cp "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}/dist/*.whl" ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}
COMMENT "Build wheel package for DBCC Python3, ${PYPKG_SUFFIX}"
DEPENDS ${SETUP_PY} ${INIT_OUTPUT})
DEPENDS ${PYPROJECT_TOML} ${SETUP_PY} ${INIT_OUTPUT})
# add_custom_command (TARGET ${PY_TARGET_NAME} POST_BUILD
# WORKING_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}
# COMMAND ${Python3_EXECUTABLE} ${SETUP_PY} -q bdist_wheel
# COMMAND cp "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${PY3DIR}/dist/*.whl" ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}
# COMMENT "Build wheel package for DBCC Python3, ${PYPKG_SUFFIX}"
# DEPENDS ${SETUP_PY} ${INIT_OUTPUT})
endif ()
add_custom_command (TARGET ${PY_TARGET_NAME} POST_BUILD

View File

@ -4,6 +4,19 @@ A library to help tools parse the DBC file and convert them to other formats.
:note: C++ 11 is required.
## Build
``` bash
# For Python extension, please install the following package for your system python3(/usr/bin/python3)
sudo apt install -y python3-build python3-setuptools python3-wheel python3-venv
admake build
```
## References
- [OVMS.V3](https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/tree/master/vehicle/OVMS.V3/components/dbc/src)
## TODOs
- [ ] Generate optimized code to replace if-else/switch for message parsing, LUT based on binary-search, even based on the PHF/MPHF.

View File

@ -0,0 +1,27 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "dbcc"
version = "@DBCC_VERSION@"
authors = [
{ name = "donkey", email = "anjingyu_ws@foxmal.com" }
]
description = "A package containing a precompiled .so library"
readme = "README.md"
requires-python = "~=@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@"
license = { text = "MIT" }
classifiers = [
"Programming Language :: Python :: 3",
"Operating System :: POSIX :: Linux",
]
dependencies = []
[tool.setuptools]
packages = ["dbcc"]
package-dir = { "" = "." }
[tool.setuptools.package-data]
dbcc = ["_dbcc.so"]

View File

@ -53,6 +53,13 @@ def main():
author="donkey",
author_email="<anjingyu_ws@foxmail.com>",
classifiers=[
'Programming Language :: Python :: 3.13',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.6',
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',

View File

@ -39,6 +39,7 @@ public:
typedef Signals::reference reference;
friend std::istream& operator>>(std::istream& in, Message& msg);
friend std::ostream& operator<<(std::ostream& out, const Message& msg);
/// \brief The name of this \c Message
inline const std::string Name() const

View File

@ -202,10 +202,12 @@ public:
return msg_id_;
}
std::string ToDbcString() const;
friend std::istream& operator>>(std::istream& in, Signal& sig);
friend std::ostream& operator<<(std::ostream& out, CompiledSignalParameter& p);
friend std::ostream& operator<<(std::ostream& out, LayoutInfo& p);
friend std::ostream& operator<<(std::ostream& out, Signal& cs);
friend std::ostream& operator<<(std::ostream& out, const CompiledSignalParameter& p);
friend std::ostream& operator<<(std::ostream& out, const LayoutInfo& p);
friend std::ostream& operator<<(std::ostream& out, const Signal& cs);
private:
bool Compile();

View File

@ -53,5 +53,16 @@ public:
const ParsedValue& pv) = 0;
};
inline std::ostream& operator<<(std::ostream& out, const ParsedValue& pv)
{
if (pv.is_integer) {
out << pv.i;
} else {
out << pv.f;
}
return out;
}
} // namespace dbcc
} // namespace ad

View File

@ -97,21 +97,34 @@ void DbcIterator::Parse(std::istream& stream)
if (stream.fail()) {
stream.clear();
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} else {
}
if (msg.SignalCount() > 0) {
messages_.emplace_back(msg);
message_index_[msg.Id()] = static_cast<uint32_t>(messages_.size() - 1);
std::cout << msg << std::endl;
}
} else if (preamble == kPreambleComment) {
// TODO(anjingyu): Parse the comment
std::cout << "[W] CM_ is unsupported now, ignore!" << std::endl;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} else if (preamble == kPreambleValueTable) {
std::cout << "[W] VAL_TABLE_ is unsupported now, ignore!" << std::endl;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} else if (preamble == kPreambleAttribute) {
std::cout << "[W] BA_ is unsupported now, ignore!" << std::endl;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} else if (preamble == kPreambleAttributeDefinition) {
std::cout << "[W] BA_DEF_ is unsupported now, ignore!" << std::endl;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} else if (preamble == kPreambleEnvironmentVariable) {
std::cout << "[W] EV_ is unsupported now, ignore!" << std::endl;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} else if (preamble == kPreambleNode) {
std::cout << "[W] BU_ is unsupported now, ignore!";
std::cout << "[W] BU_ is unsupported now, ignore!" << std::endl;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} else {
std::cout << "[W] " << preamble << "is unsupported now, ignore!";
std::cout << "[W] " << preamble << " is unsupported now, ignore!" << std::endl;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
} while (!stream.eof());

View File

@ -26,7 +26,20 @@ std::istream& operator>>(std::istream& in, Message& msg)
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// As long as there is a signal, parse the signal
while (in) {
while (true) {
std::string preamble;
auto pos = in.tellg();
in >> preamble;
// Check if we are actually reading a signal
if (preamble != "SG_") {
if (in.eof()) {
return in;
}
// Revert the stream to the preamble position
in.seekg(pos, std::ios_base::beg);
break;
}
Signal sig;
in >> sig;
if (in) {
@ -49,5 +62,21 @@ std::set<std::string> Message::To() const
return collection;
}
std::ostream& operator<<(std::ostream& out, const Message& msg)
{
out << "BU_ " << msg.Id() << " " << msg.Name()
<< ": " << msg.Dlc() << " ";
if (!msg.From().empty()) {
out << msg.From();
}
out << "\n";
for (auto& sig : msg.signals_) {
out << " " << sig.ToDbcString() << "\n";
}
return out;
}
} // namespace dbcc
} // namespace ad

View File

@ -12,7 +12,7 @@
namespace ad {
namespace dbcc {
static inline std::string& trim(std::string& str, const std::string& toTrim = " ")
static inline std::string& Trim(std::string& str, const std::string& toTrim = " ")
{
std::string::size_type pos = str.find_last_not_of(toTrim);
@ -33,7 +33,7 @@ static inline std::vector<std::string>& Split(const std::string& s, char delim,
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
elems.push_back(Trim(item));
}
return elems;
@ -69,16 +69,6 @@ static inline bool ConsumeNumber(std::istream& in, double& num)
std::istream& operator>>(std::istream& in, Signal& sig)
{
std::string preamble;
in >> preamble;
// Check if we are actually reading a signal otherwise fail the stream
if (preamble != "SG_") {
in.setstate(std::ios_base::failbit);
return in;
}
sig.is_float_ = false;
// Parse the signal name
in >> sig.name_;
@ -148,7 +138,7 @@ std::istream& operator>>(std::istream& in, Signal& sig)
// Unit string
std::stringstream unit;
in.ignore(std::numeric_limits<std::streamsize>::max(), '\"');
while (in.peek() == '\"') {
while (in.peek() != '\"') {
unit.put(in.get());
}
@ -158,7 +148,7 @@ std::istream& operator>>(std::istream& in, Signal& sig)
}
std::string unitstr = unit.str();
sig.unit_ = trim(unitstr, "\"");
sig.unit_ = Trim(unitstr, "\"");
std::string to;
getline(in, to);
@ -452,7 +442,7 @@ bool Signal::BitsLayout(LayoutInfo& info)
return true;
}
std::ostream& operator<<(std::ostream& out, Signal::CompiledSignalParameter& p)
std::ostream& operator<<(std::ostream& out, const Signal::CompiledSignalParameter& p)
{
out << "CompiledSignalParameter: { index: " << p.index << ", "
<< "shift: " << p.shift << ", "
@ -462,7 +452,7 @@ std::ostream& operator<<(std::ostream& out, Signal::CompiledSignalParameter& p)
return out;
}
std::ostream& operator<<(std::ostream& out, Signal::LayoutInfo& p)
std::ostream& operator<<(std::ostream& out, const Signal::LayoutInfo& p)
{
out << "Bits: { ";
for (auto bit : p.bits) {
@ -478,7 +468,7 @@ std::ostream& operator<<(std::ostream& out, Signal::LayoutInfo& p)
return out;
}
std::ostream& operator<<(std::ostream& out, Signal& cs)
std::ostream& operator<<(std::ostream& out, const Signal& cs)
{
int i = 0;
out << "Message: " << cs.GetMessageId() << ", Signal: " << cs.Name()
@ -498,5 +488,36 @@ std::ostream& operator<<(std::ostream& out, Signal& cs)
return out;
}
std::string Signal::ToDbcString() const
{
std::ostringstream oss;
oss << "SG_ " << Name();
if (GetMultiplexor() == Multiplexor::kMultiplexor) {
oss << " M" << MultiplexedNumber() << ": ";
} else if (GetMultiplexor() == Multiplexor::kNone) {
oss << " : ";
} else {
oss << " M: ";
}
oss << StartBit() << "|" << Length() << "@"
<< (GetByteOrder() == ByteOrder::kMotorola ? 0 : 1) << " "
<< (GetSign() == Sign::kUnsigned ? "+" : "-") << " ("
<< Factor() << "," << Offset() << ") ["
<< Minimum() << "|" << Maximum() << "] \""
<< Unit() << "\"";
if (!to_.empty()) {
char delimiter = ' ';
for (auto t : to_) {
oss << delimiter << t;
delimiter = ',';
}
}
return oss.str();
}
} // namespace dbcc
} // namespace ad

2189
dbcc/test-data/j1939.dbc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,9 +11,9 @@ const std::string usage = "This parser is meant to be used via CLi at the moment
class MyDelegate : public ad::dbcc::SignalDecodeDelegate
{
virtual void onDecoded(uint32_t msgId, const std::string &signalName, double pv, void */* userData */)
virtual void OnDecoded(uint32_t msg_id, const std::string &signal_name, const ad::dbcc::ParsedValue &pv)
{
std::cout << "msg: #0x" << std::hex << msgId << std::dec << ", " << signalName << " -> pv: " << pv << std::endl;
std::cout << "msg: #0x" << std::hex << msg_id << std::dec << ", " << signal_name << " -> pv: " << pv << std::endl;
}
};
@ -29,7 +29,7 @@ int main(int argc, char *argv[])
for (auto msg : iter)
{
std::cout << "msg: " << msg.name() << std::endl;
std::cout << "msg: " << msg.Name() << std::endl;
}
std::shared_ptr<ad::dbcc::SignalDecodeDelegate> delegate = std::make_shared<MyDelegate>();
@ -37,23 +37,23 @@ int main(int argc, char *argv[])
uint8_t data[8] = { 0 };
data[0] = 0x01;
data[1] = 0xA8;
uint8_t data1[2] = { 0x40, 0x0 };
ad::dbcc::SignalProcessor sp(iter);
sp.registerDelegate(578, "ACCAccReqValHSC2", delegate);
sp.registerDelegate(498, "SysBPMHSC2", delegate);
sp.registerDelegate(498, "SysBPMEnbdHSC2", delegate);
sp.RegisterDelegate(578, "ACCAccReqValHSC2", delegate);
sp.RegisterDelegate(498, "SysBPMHSC2", delegate);
sp.RegisterDelegate(498, "SysBPMEnbdHSC2", delegate);
sp.decodeMessage(578, data, 8);
sp.decodeMessage(498, data1, 2);
sp.DecodeMessage(578, data, 8);
sp.DecodeMessage(498, data1, 2);
std::cout << "Keep the order stable" << std::endl;
for (auto msg : iter)
{
std::cout << "msg: " << msg.name() << std::endl;
std::cout << "msg: " << msg.Name() << std::endl;
}
// Unpacked value: -5.1

65
dbcc/test/test_py.sh Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env bash
#
# Prepare the dbcc Python package for test.py,
# and run it with arguments
#
# Author: donkey <anjingyu_ws@foxmail.com>
readonly CUR_DIR=$(cd $(dirname $0); pwd)
readonly PROJ_DIR=$(dirname $CUR_DIR)
readonly VERSIONS=(
"linux/x64"
"linux/arm64"
"windows/x64"
"android/arm64"
)
function main()
{
local _PKG=""
pushd "$PROJ_DIR/test" >/dev/null 2>&1 || exit
if [ ! -d "dbcc" ]; then
# Check the Release version first
for V in ${VERSIONS[@]}; do
for E in "Release" "Debug"; do
if [ -d "$PROJ_DIR/.build/$V/lib/$E/" ]; then
pushd "$PROJ_DIR/.build/$V/lib/$E/" >/dev/null 2>&1 || exit
_PKG=$(find ./ -name "dbcc-*.whl")
if [ -n "$_PKG" ]; then
_PKG="${PWD}/$(basename $_PKG)"
fi
popd >/dev/null 2>&1 || exit
if [ -n "$_PKG" ]; then
break
fi
fi
done
if [ -n "$_PKG" ]; then
break
fi
done
if [ -z "$_PKG" ]; then
echo "Failed to find the dbcc python package, please it build first!"
exit 2
fi
cp $_PKG ./
_PKG=$(basename $_PKG)
unzip $_PKG
# Remove package info and the package itself
rm -rf $_PKG
_INFO_DIR=$(find ./ -type d -name "dbcc-*-info")
if [ -n "$_INFO_DIR" ]; then
rm -rf $_INFO_DIR
fi
fi
/usr/bin/python3 "./test.py" "$@"
popd >/dev/null 2>&1 || exit
}
main "$@"