Skip to content

Commit

Permalink
Pilkki utility cicd, win&macos implementations, code cleanup, deps vi…
Browse files Browse the repository at this point in the history
…a FetchContent (#1)

* Create pilkki-software-multiplatform.yml

* Windows and MacOS implementations

* Code cleanup

* Use FetchContent instead of submodules
  • Loading branch information
SmallSharky authored Nov 5, 2023
1 parent 19707dd commit 22dadad
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform.
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
name: CMake on multiple platforms
name: Pilkki software (console utility) on multiple platforms

on:
push:
branches: [ "main" ]
branches: [ "main", "**-cicd" ]
pull_request:
branches: [ "main" ]
branches: [ "main" ]

jobs:

build:
runs-on: ${{ matrix.os }}

Expand All @@ -23,43 +24,51 @@ jobs:
#
# To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list.
matrix:
os: [ubuntu-latest, windows-latest]
os: [ubuntu-latest, windows-latest, macos-latest]
build_type: [Release]
c_compiler: [gcc, clang, cl]
include:
- os: ubuntu-latest
c_compiler: gcc
cpp_compiler: g++
- os: ubuntu-latest
c_compiler: clang
cpp_compiler: clang++
- os: windows-latest
c_compiler: cl
cpp_compiler: cl
- os: ubuntu-latest
- os: windows-latest
c_compiler: gcc
cpp_compiler: g++
- os: ubuntu-latest
- os: windows-latest
c_compiler: clang
cpp_compiler: clang++
- os: macos-latest
c_compiler: gcc
cpp_compiler: g++
- os: macos-latest
c_compiler: clang
cpp_compiler: clang++
exclude:
- os: windows-latest
c_compiler: gcc
- os: windows-latest
c_compiler: clang
- os: macos-latest
c_compiler: cl
- os: ubuntu-latest
c_compiler: cl

steps:
- name: Install libudev
run: sudo apt-get install -y libudev-dev
if: matrix.os == 'ubuntu-latest'

- uses: actions/checkout@v3

- name: Checkout submodules
run: git submodule update --init --recursive

- name: Set reusable strings
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
id: strings
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/software/build" >> "$GITHUB_OUTPUT"
echo "build-source-dir=${{ github.workspace }}/software/build" >> "$GITHUB_OUTPUT"
echo "build-source-dir=${{ github.workspace }}/software" >> "$GITHUB_OUTPUT"
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
Expand Down
6 changes: 0 additions & 6 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
[submodule "deps/argparse"]
path = software/deps/argparse
url = https://github.com/morrisfranken/argparse
[submodule "deps/magic_enum"]
path = software/deps/magic_enum
url = https://github.com/Neargye/magic_enum
[submodule "firmware/3dparty/embedded-cmake-snippets"]
path = firmware/3dparty/embedded-cmake-snippets
url = https://github.com/SmallSharky/embedded-cmake-snippets.git
Expand Down
58 changes: 45 additions & 13 deletions software/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,28 +1,60 @@
cmake_minimum_required(VERSION 3.24)

cmake_minimum_required(VERSION 3.20)

project(pilkki LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/deps/argparse/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/deps/magic_enum/include)

include(FetchContent)

FetchContent_Declare(
magic_enum
GIT_REPOSITORY https://github.com/Neargye/magic_enum.git
GIT_TAG v0.9.3
)
FetchContent_Declare(
argparse
GIT_REPOSITORY https://github.com/morrisfranken/argparse.git
GIT_TAG 5d3710809364e694f33243810bbd1345975ae1c3
)

FetchContent_GetProperties(argparse)
FetchContent_GetProperties(magic_enum)
if(NOT argparse_POPULATED)
FetchContent_Populate(argparse)
add_subdirectory(${argparse_SOURCE_DIR} ${argparse_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()

if(NOT magic_enum_POPULATED)
FetchContent_Populate(magic_enum)
add_subdirectory(${magic_enum_SOURCE_DIR} ${magic_enum_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()

if (WIN32)
set(SERIAL_IMPL src/serial_win.cpp)
add_library(serial_impl OBJECT src/serial_win.cpp)
elseif(APPLE)
add_library(serial_impl OBJECT src/serial_mac.cpp)
elseif(UNIX)
set(SERIAL_IMPL src/serial_linux.cpp)
add_library(serial_impl OBJECT src/serial_linux.cpp)
target_link_libraries(serial_impl PRIVATE udev)
else()
message(FATAL "There is no implementation of serial for that platform")
message(FATAL "There is no implementation of serial for that platform")
endif()

if (
CMAKE_CXX_COMPILER_ID MATCHES "(Clang|GNU)"
)
add_compile_options(-Wall -Wextra -pedantic)
elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
# using Visual Studio C++
endif()

add_executable(
pilkki
src/pilkki.cpp
${SERIAL_IMPL}
pilkki
src/pilkki.cpp
)

target_link_libraries(pilkki PRIVATE udev)
target_link_libraries(pilkki PRIVATE serial_impl argparse magic_enum::magic_enum)

install(TARGETS pilkki DESTINATION bin)
install(TARGETS pilkki DESTINATION bin)
1 change: 0 additions & 1 deletion software/deps/argparse
Submodule argparse deleted from 977062
1 change: 0 additions & 1 deletion software/deps/magic_enum
Submodule magic_enum deleted from 490482
4 changes: 2 additions & 2 deletions software/src/pilkki.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class Flasher {
}
};

Payload read(uint32_t addr, std::optional<uint32_t> len, bool hex) {
Payload read(uint32_t addr, std::optional<uint32_t> len, [[maybe_unused]] bool hex) {
auto info = connect();

uint32_t payloadLen = 0;
Expand Down Expand Up @@ -174,7 +174,7 @@ class Flasher {
throw std::runtime_error("Missing \"Done\" record");
}
data.resize(realFirmwareLen);
Payload res{.data{std::move(data)}, .crc = crcPayload};
Payload res{std::move(data), crcPayload};
if (!res.checkCRC()) {
throw std::runtime_error("CRC mismatch");
}
Expand Down
4 changes: 2 additions & 2 deletions software/src/serial_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct Serial::Impl_ {
if (fd>0) {
::close(fd);
}

fd = 0;
}
};

Expand Down Expand Up @@ -78,6 +78,7 @@ Serial::Serial(const std::string& name):
Serial::Serial(Serial&& s): impl_(std::move(s.impl_)) {
s.impl_ = nullptr;
}

Serial::~Serial() {}

void Serial::write(const void * data, size_t len) {
Expand All @@ -99,7 +100,6 @@ size_t Serial::read(void * data, size_t maxLen) {
if ( res<0 ) {
throw std::runtime_error("Failed to read: " + std::string(strerror(errno)));
}
// std::cout << "read: " << std::string_view(static_cast<char *>(data), res) << std::endl;
return res;
}

Expand Down
106 changes: 106 additions & 0 deletions software/src/serial_mac.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@

#include "serial.hpp"

#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>

#include <iostream>
#include <string_view>

#include <stdexcept>

struct Serial::Impl_ {
int fd;

Impl_(int descriptor): fd(descriptor) {
if (fd<=0) {
throw std::runtime_error("Failed to open Serial");
}
}

Impl_(const Impl_&) = delete;

Impl_(Impl_&& impl): fd(impl.fd) {
impl.fd = 0;
}

~Impl_() {
if (fd>0) {
::close(fd);
}

}
};

Serial::Serial(const std::string& name):
impl_(new Impl_(::open(name.c_str(), O_RDWR | O_NOCTTY)))
{
auto fd = impl_->fd;

struct termios tty;
memset (&tty, 0, sizeof(tty));

/* Error Handling */
if ( tcgetattr ( fd, &tty ) != 0 ) {
throw std::runtime_error("Failed to tcgetattr: " + std::string(strerror(errno)));
}

// /* Set Baud Rate */
// cfsetospeed (&tty, (speed_t)B9600);
// cfsetispeed (&tty, (speed_t)B9600);

/* Setting other Port Stuff */
tty.c_cflag &= ~PARENB; // Make 8n1
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;

tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_cc[VMIN] = 1; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines

// /* Make raw */
cfmakeraw(&tty);

// /* Flush Port, then applies attributes */
tcflush( fd, TCIFLUSH );
if ( tcsetattr ( fd, TCSANOW, &tty ) != 0) {
throw std::runtime_error("Failed to tcsetattr: " + std::string(strerror(errno)));
}
}

Serial::Serial(Serial&& s): impl_(std::move(s.impl_)) {
s.impl_ = nullptr;
}
Serial::~Serial() {}

void Serial::write(const void * data, size_t len) {
size_t n = len;
while(n > 0) {
int res = ::write(impl_->fd, data, n);
if ( res<0 ) {
throw std::runtime_error("Failed to write: " + std::string(strerror(errno)));
}
if (!res) {
throw std::runtime_error("Failed to write: wrote nothing this time");
}
n -= res;
}
}

size_t Serial::read(void * data, size_t maxLen) {
int res = ::read(impl_->fd, data, maxLen);
if ( res<0 ) {
throw std::runtime_error("Failed to read: " + std::string(strerror(errno)));
}
return res;
}

std::optional<std::string> Serial::autodetect() {
// TODO: implement autodetect
return std::nullopt;
}
Loading

0 comments on commit 22dadad

Please sign in to comment.