Skip to content

Commit

Permalink
Merge pull request #19 from joshua-jerred/gfs-merge
Browse files Browse the repository at this point in the history
GFS Updates
  • Loading branch information
joshua-jerred authored Oct 19, 2024
2 parents c8a4417 + c990a09 commit 2f612d9
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 34 deletions.
33 changes: 18 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
cmake_minimum_required(VERSION 3.25)
project(SignalEasel VERSION 1.0 DESCRIPTION "A WAV file utility library for modulating audio")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
project(SignalEasel
VERSION 0.1
DESCRIPTION "SignalEasel is a C++ library for audio modulation and demodulation through a variety of analog and digital modes."
HOMEPAGE_URL "https://signaleasel.joshuajer.red"
)

# --- Configuration ---------------
# The following options can be set to enable/disable features.
Expand All @@ -13,13 +16,12 @@ option(SIGNALEASEL_COVERAGE "Enable code coverage" OFF)
# ---------------------------------

# # Check if SignalEasel is being used directly or via add_subdirectory
set(MAIN_PROJECT OFF)

set(SIG_EAS_MAIN_PROJECT OFF)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(MAIN_PROJECT ON)
set(SIG_EAS_MAIN_PROJECT ON)
endif()

message(STATUS "=== SignalEasel Main project: ${MAIN_PROJECT}")
message(STATUS "=== SignalEasel Main project: ${SIG_EAS_MAIN_PROJECT}")

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \
Expand All @@ -39,13 +41,14 @@ if(SSTV_ENABLED)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/SSTV-Image-Tools EXCLUDE_FROM_ALL SYSTEM)
endif()

if(MAIN_PROJECT)
if(SIG_EAS_MAIN_PROJECT)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/Boost_erSeat EXCLUDE_FROM_ALL SYSTEM)
endif()

if(SIGNALEASEL_COVERAGE)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/project/cmake)
include(CodeCoverage)
if(SIGNALEASEL_COVERAGE)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/project/cmake)
include(CodeCoverage)
endif()
endif()

# --------------------------------
Expand Down Expand Up @@ -109,7 +112,7 @@ target_include_directories(SignalEasel
set_target_properties(SignalEasel PROPERTIES FOLDER include/signal_easel.hpp)

if(SSTV_ENABLED)
message(STATUS "=== - SSTV : Enabled")
message(STATUS "=== - SSTV : ON")
target_link_libraries(SignalEasel sstv-image-tools)
add_definitions(-DMAGICKCORE_QUANTUM_DEPTH=8)
add_definitions(-DMAGICKCORE_HDRI_ENABLE=1) # Required or there are linking errors with Magick::Color::Color
Expand All @@ -125,7 +128,7 @@ endif()
unset(SSTV_ENABLED CACHE)

if(USE_PULSEAUDIO)
message(STATUS "=== - PulseAudio : Enabled")
message(STATUS "=== - PulseAudio : ON")
find_path(PULSEAUDIO_INCLUDE_DIR
NAMES pulse/pulseaudio.h
)
Expand All @@ -142,14 +145,14 @@ endif()
# --------------------------------
# Code Coverage & Unit Tests
if(SIGNALEASEL_COVERAGE)
message(STATUS "=== - Code Coverage : Enabled")
message(STATUS "=== - Code Coverage : ON")
append_coverage_compiler_flags_to_target(SignalEasel)
else()
message(STATUS "=== - Code Coverage : Disabled")
endif()

if(SIGNALEASEL_UNIT_TESTS)
message(STATUS "=== - Unit Tests : Enabled")
message(STATUS "=== - Unit Tests : ON")
enable_testing()
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests)
Expand Down
1 change: 1 addition & 0 deletions include/SignalEasel/modulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef SIGNAL_EASEL_MODULATOR_HPP_
#define SIGNAL_EASEL_MODULATOR_HPP_

#include <cstdint>
#include <vector>

#include <SignalEasel/settings.hpp>
Expand Down
3 changes: 2 additions & 1 deletion include/SignalEasel/psk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ class Modulator : public signal_easel::Modulator {
* @brief Constructor for the PSK Modulator
* @param settings The settings for the modulator
*/
Modulator(psk::Settings settings = psk::Settings()) : settings_(settings) {}
Modulator(psk::Settings settings = psk::Settings())
: signal_easel::Modulator(settings), settings_(settings) {}
~Modulator() = default;

void encodeString(const std::string &input);
Expand Down
2 changes: 1 addition & 1 deletion lib/WavGen
2 changes: 1 addition & 1 deletion project/test_coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ cd build
rm -f coverage_data.*

# Configure
cmake .. -DCMAKE_BUILD_TYPE=Debug -DSIGNALEASEL_COVERAGE=ON
cmake .. -DCMAKE_BUILD_TYPE=Debug -DSIGNALEASEL_COVERAGE=ON -DSIGNALEASEL_UNIT_TESTS=ON

# Build
cmake --build . --target signal_easel_unit_tests
Expand Down
14 changes: 7 additions & 7 deletions src/modulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,20 @@ void Modulator::writeToFile(const std::string &filename) {
throw Exception(Exception::Id::INVALID_CALL_SIGN);
}

if (settings_.call_sign_mode == Settings::CallSignMode::AFTER ||
settings_.call_sign_mode == Settings::CallSignMode::BEFORE_AND_AFTER) {
addSilence(static_cast<uint32_t>(settings_.call_sign_pause_seconds *
AUDIO_SAMPLE_RATE));
addMorseCode(settings_.call_sign);
}

try {
wavgen::Writer wav_file(filename);

for (const auto &sample : audio_buffer_) {
wav_file.addSample(sample);
}

if (settings_.call_sign_mode == Settings::CallSignMode::AFTER ||
settings_.call_sign_mode == Settings::CallSignMode::BEFORE_AND_AFTER) {
addSilence(static_cast<uint32_t>(settings_.call_sign_pause_seconds *
AUDIO_SAMPLE_RATE));
addMorseCode(settings_.call_sign);
}

wav_file.done();
} catch (const std::exception &e) {
throw Exception(Exception::Id::FILE_OPEN_ERROR);
Expand Down
18 changes: 13 additions & 5 deletions src/utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,34 @@
*/

#include <algorithm>
#include <cctype>

#include "utilities.hpp"

namespace signal_easel {

bool isCallSignValid(const std::string &call_sign) {
constexpr size_t k_min_call_sign_length = 3;
constexpr size_t k_max_call_sign_length = 6;
constexpr size_t k_max_call_sign_length = 7;

if (call_sign.length() < k_min_call_sign_length ||
call_sign.length() > k_max_call_sign_length) {
return false;
}

if (std::all_of(call_sign.begin(), call_sign.end(),
[](char symbol) { return std::isdigit(symbol); })) {
return false;
bool contains_digit = false;
bool contains_letter = false;
for (const auto &symbol : call_sign) {
if (std::isdigit(symbol)) { // Check if there is at least one digit
contains_digit = true;
} else if (std::isalpha(symbol)) { // Check if there is at least one letter
contains_letter = true;
} else {
return false; // non-alphanumeric character
}
}

return true;
return contains_digit && contains_letter;
}

} // namespace signal_easel
3 changes: 2 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(signal_easel_unit_tests_sources
${CMAKE_CURRENT_SOURCE_DIR}/ax25_crc_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ax25_frame_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/psk_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utilities_test.cpp
)

if(SSTV_TEST_ENABLED)
Expand All @@ -25,7 +26,7 @@ add_executable(signal_easel_unit_tests
)
target_link_libraries(signal_easel_unit_tests GTest::GTest GTest::Main SignalEasel BoosterSeat)
# target_link_libraries(signal_easel_unit_tests SignalEasel)
target_include_directories(signal_easel_unit_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src)
target_include_directories(signal_easel_unit_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..)
gtest_discover_tests(signal_easel_unit_tests)

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/afsk_timing_skew.wav ${CMAKE_CURRENT_BINARY_DIR}/afsk_timing_skew.wav COPYONLY)
Expand Down
29 changes: 27 additions & 2 deletions tests/psk_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,38 @@

using namespace signal_easel;

TEST(PSK_test, bpsk) {
TEST(PSK_test, bpsk125) {
psk::Settings settings;
settings.mode = psk::Settings::Mode::BPSK;
settings.symbol_rate = psk::Settings::SymbolRate::SR_500;
settings.symbol_rate = psk::Settings::SymbolRate::SR_125;

psk::Modulator modulator(settings);
modulator.encodeString("Hello World!");
modulator.encodeString("Hello World!");
modulator.writeToFile("test_bpsk_125.wav");
}

TEST(PSK_test, qpsk500) {
psk::Settings settings;
settings.mode = psk::Settings::Mode::QPSK;
settings.symbol_rate = psk::Settings::SymbolRate::SR_500;

psk::Modulator modulator(settings);
modulator.encodeString("Hello World!");
modulator.encodeString("Hello World!");
modulator.writeToFile("test_qpsk_500.wav");
}

TEST(PSK_test, addCallSign) {
psk::Settings settings;
settings.mode = psk::Settings::Mode::BPSK;
settings.symbol_rate = psk::Settings::SymbolRate::SR_125;
settings.call_sign = "T3ST";
settings.call_sign_mode =
signal_easel::Settings::CallSignMode::BEFORE_AND_AFTER;

psk::Modulator modulator(settings);
modulator.encodeString("Hello World!");
modulator.encodeString("Hello World!");
modulator.writeToFile("test_psk_add_call_sign.wav");
}
38 changes: 38 additions & 0 deletions tests/utilities_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// =*============================= SignalEasel ==============================*=
/// A C++ library for audio modulation/demodulation into analog & digital modes.
/// Detailed documentation can be found here: https://signaleasel.joshuajer.red
///
/// @author Joshua Jerred
/// @date 2024-10-18
///
/// @copyright Copyright 2024 Joshua Jerred. All rights reserved.
/// @license This project is licensed under the GNU GPL v3.0 license.
/// =*========================================================================*=

#include <string>
#include <vector>

#include "gtest/gtest.h"

#include "src/utilities.hpp"

TEST(utilities_test, isCallSignValid) {
// -- Test Valid Call Signs --
// From https://en.wikipedia.org/wiki/Amateur_radio_call_signs
std::vector<std::string> valid_call_signs = {
"K4X", "B2AA", "N2ASD", "A22A", "I20000X", "4X4AAA", "3DA0RS", "HL1AA"};

for (const auto &call_sign : valid_call_signs) {
EXPECT_TRUE(signal_easel::isCallSignValid(call_sign))
<< call_sign << " should be considered valid";
}

// -- Test Invalid Call Signs --
std::vector<std::string> invalid_call_signs = {"K4", "BAA", "TOOLONGOFCALL",
"NON-ALPHANUMERIC", "1234"};

for (const auto &call_sign : invalid_call_signs) {
EXPECT_FALSE(signal_easel::isCallSignValid(call_sign))
<< call_sign << " should be considered invalid";
}
}

0 comments on commit 2f612d9

Please sign in to comment.