Skip to content

Full refactor, to many changes, to lazy to write commit messages #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 140
TabWidth: 4
UseTab: Never
BreakBeforeBraces: Allman
AllowShortFunctionsOnASingleLine: Empty
PointerAlignment: Left
DerivePointerAlignment: false
SpaceBeforeParens: ControlStatements
SortIncludes: true
IncludeBlocks: Regroup
ReflowComments: true
ContinuationIndentWidth: 4
BinPackParameters: false
BinPackArguments: false

30 changes: 30 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Checks: >
-*,
readability-* ,
modernize-* ,
-modernize-use-trailing-return-type,
-readability-magic-numbers,

WarningsAsErrors: >
bugprone-* ,
performance-* ,
clang-analyzer-*

HeaderFilterRegex: 'src/.*'
FormatStyle: file

CheckOptions:
- key: modernize-use-auto.MinTypeNameLength
value: '5'
- key: modernize-use-auto.RemoveStars
value: 'false'
- key: readability-identifier-naming.VariableCase
value: lower_case
- key: readability-identifier-naming.MemberCase
value: lower_case
- key: readability-identifier-naming.PrivateMemberPrefix
value: '_'
- key: readability-function-size.ParameterThreshold
value: '8'
- key: readability-braces-around-statements.ShortStatementLines
value: '0'
13 changes: 13 additions & 0 deletions .devcontainer/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM fedora:42

RUN dnf install -y \
clang \
clang-tools-extra \
clangd \
clang-format \
clang-tidy \
clang-analyzer \
cmake \
git \
ninja-build \
&& dnf clean all
28 changes: 28 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"build": {
"dockerfile": "./Dockerfile.dev"
},
"customizations": {
"vscode": {
"extensions": [
"mhutchie.git-graph",
"ms-azuretools.vscode-docker",
"vivaxy.vscode-conventional-commits",
"github.vscode-github-actions",
"llvm-vs-code-extensions.vscode-clangd",
"ms-vscode.cmake-tools"
]
}
},
"runArgs": [
"--network",
"host",
"--privileged",
"--device",
"/dev/bus/usb:/dev/bus/usb",
"--device-cgroup-rule=c 188:* rwm",
"--device-cgroup-rule=c 166:* rwm",
"--group-add=dialout",
"--volume=/dev/serial/by-id:/dev/serial/by-id:ro"
]
}
45 changes: 45 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Build & Release CPP-Unix-Bindings

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "**" ]
release:
types: [ created ]

jobs:
build:
name: Build shared library
runs-on: ubuntu-latest
env:
CC: clang
CXX: clang++

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake clang make

- name: Configure CMake
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release

- name: Compile
run: cmake --build build -j $(nproc)

- name: Upload library artifact
uses: actions/upload-artifact@v4
with:
name: libCPP-Unix-Bindings
path: build/libCPP-Unix-Bindings.so
retention-days: 14

- name: Attach library to release
if: github.event_name == 'release'
uses: softprops/action-gh-release@v1
with:
files: build/libCPP-Unix-Bindings.so
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.vscode/
build/
src/version_config.cpp
.cache/
.cache/
compile_commands.json
57 changes: 54 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.30)

set(VERSION_MAJOR 0)
set(VERSION_MINOR 2)
Expand All @@ -7,7 +7,32 @@ set(VERSION_PATCH 0)
set(PROJECT_N CPP-Unix-Bindings)
project(${PROJECT_N} VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})

set(CMAKE_CXX_STANDARD 20)
# Generate compile_commands.json for clang-based tooling (clangd / clang-tidy)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

include(cmake/CPM.cmake)

CPMAddPackage(
NAME "googletest"
GITHUB_REPOSITORY "google/googletest"
GIT_TAG "v1.17.0"
GIT_SHALLOW TRUE
OPTIONS "GTEST_BUILD_TESTS OFF"
OPTIONS "GTEST_BUILD_EXAMPLES OFF"
OPTIONS "GTEST_BUILD_DOCS OFF"
)

# Ensure clang tooling can pick up compile_commands.json from project root
if(CMAKE_EXPORT_COMPILE_COMMANDS)
add_custom_target(copy-compile-commands ALL
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_BINARY_DIR}/compile_commands.json
${PROJECT_SOURCE_DIR}/compile_commands.json
COMMENT "Copy compile_commands.json to project root"
VERBATIM)
endif()

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED True)

file(GLOB_RECURSE SRCS ${PROJECT_SOURCE_DIR}/src/**.cpp)
Expand Down Expand Up @@ -51,4 +76,30 @@ set_target_properties(${PROJECT_N} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR})

target_include_directories(${PROJECT_N} PUBLIC include)
target_include_directories(${PROJECT_N} PUBLIC ${PROJECT_SOURCE_DIR}/src)

add_executable(serial_integration_tests tests/serial_test.cpp)
target_link_libraries(serial_integration_tests PRIVATE ${PROJECT_N} gtest_main)

target_include_directories(serial_integration_tests PRIVATE ${PROJECT_SOURCE_DIR}/src)

add_custom_command(TARGET serial_integration_tests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${PROJECT_N}>
$<TARGET_FILE_DIR:serial_integration_tests>
COMMENT "Copy shared library next to test binary")

# Unit test target covering additional API aspects
add_executable(serial_unit_tests tests/serial_unit_tests.cpp)
target_link_libraries(serial_unit_tests PRIVATE ${PROJECT_N} gtest_main)
target_include_directories(serial_unit_tests PRIVATE ${PROJECT_SOURCE_DIR}/src)

add_custom_command(TARGET serial_unit_tests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${PROJECT_N}>
$<TARGET_FILE_DIR:serial_unit_tests>
COMMENT "Copy shared library next to unit test binary")

enable_testing()
add_test(NAME SerialEchoTest COMMAND serial_integration_tests /dev/ttyUSB0)
add_test(NAME SerialUnitTests COMMAND serial_unit_tests)
80 changes: 79 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,79 @@
# Serial
# CPP-Unix-Bindings

A compact C++23 library for talking to serial devices on Linux (e.g. Arduino).
The project builds a **shared library `libCPP-Unix-Bindings.so`** that can be used via
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer the following name:

Suggested change
The project builds a **shared library `libCPP-Unix-Bindings.so`** that can be used via
The project builds a **shared library `lib_cpp_bindings_unix.so`** that can be used via

Maybe we should rename all repositories to be snake_case...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renaming is done in #2, and will be linux conform

Deno's native FFI.

---

## 1 Building the library

```bash
# Clone
git clone https://github.com/Serial-IO/cpp-bindings-unix.git cpp-bindings-unix
cd cpp-bindings-unix

# Dependencies (Debian/Ubuntu)
sudo apt-get install build-essential cmake clang make

# Compile
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j

# The resulting library will be located at
# build/libCPP-Unix-Bindings.so
```

> Because `CMAKE_EXPORT_COMPILE_COMMANDS` is enabled, the build also generates a
> `compile_commands.json` that is automatically copied to the project root —
> handy for clang-tools (clangd, clang-tidy, …).

---

## 2 Using the library from **Deno** (v1.42 or newer)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## 2 Using the library from **Deno** (v1.42 or newer)
## 2 Using the library from **Deno** (v2 or newer)


Deno ships with a first-class FFI API.

```ts
// serial_deno.ts
const lib = Deno.dlopen('./build/libCPP-Unix-Bindings.so', {
serialOpen: { parameters: [ 'buffer', 'i32', 'i32', 'i32', 'i32' ], result: 'pointer' },
serialClose: { parameters: [ 'pointer' ], result: 'void' },
serialRead: { parameters: [ 'pointer', 'buffer', 'i32', 'i32', 'i32' ], result: 'i32' },
serialWrite: { parameters: [ 'pointer', 'buffer', 'i32', 'i32', 'i32' ], result: 'i32' },
});

const enc = new TextEncoder();
const dec = new TextDecoder();

// Note: device path must be null-terminated
const handle = lib.symbols.serialOpen(enc.encode('/dev/ttyUSB0\0'), 115200, 8, 0, 0);

const writeBuf = enc.encode('Hello\n');
lib.symbols.serialWrite(handle, writeBuf, writeBuf.length, 100, 1);

const readBuf = new Uint8Array(128);
const n = lib.symbols.serialRead(handle, readBuf, readBuf.length, 500, 1);
console.log(dec.decode(readBuf.subarray(0, n)));

lib.symbols.serialClose(handle);
lib.close();
```

---

## 3 C API reference

| Function | Description |
|----------|-------------|
| `intptr_t serialOpen(const char* dev, int baud, int bits, int parity, int stop)` | Open a device and return a handle. |
| `void serialClose(intptr_t handle)` | Close the port. |
| `int serialRead(...)` | Read bytes with timeout. |
| `int serialWrite(...)` | Write bytes with timeout. |
| `int serialGetPortsInfo(char* buffer, int len, const char* sep)` | List ports under `/dev/serial/by-id`. |
| `void serialOnError(void (*)(int))` | Register an error callback. |
| *(others in `serial.h`)* |

Return values ≤ 0 indicate error codes defined in `status_codes.h`.

---
Loading