diff --git a/.ci/clang-tidy.sh b/.ci/clang-tidy.sh new file mode 100755 index 0000000..e5861a2 --- /dev/null +++ b/.ci/clang-tidy.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +echo "Doing clang-tidy..." +bool=false +# explicitly set IFS to contain only a line feed +IFS=' +' +filelist="$(find . -not \( -path './*build*' -prune \) -not \( -path './include' -prune \) -not \( -path './lib' -prune \) -type f ! -name "$(printf "*\n*")")" +for file in $filelist; do + if echo "$file" | grep -q -E ".*(\.cpp|\.h|\.hpp)$" ; then + #Extra check missing dependencies due to clang-tidy doesn't toggle exit code. + clang_tidy_lib_check="$(clang-tidy -warnings-as-errors='*' --color -header-filter='.*,-cpptoml.hpp' "$file" -- -I. -std=c++14 2>&1)" + for tidy_line in $clang_tidy_lib_check; do + echo "$tidy_line" | grep -q -v -E "^Error while processing*" + if [ $? -eq 1 ]; then + bool=true + fi + echo "$tidy_line" | grep -q -v -E ".* error: .*" + if [ $? -eq 1 ]; then + bool=true + fi + echo "$tidy_line" + done + fi +done +if $bool; then + exit 1 +else + echo "No clang-tidy errors found." +fi + +exit 0 diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..de644d1 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,2 @@ +Checks: '*,-llvm-header-guard,-fuchsia*,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-constant-array-index,-bugprone-narrowing-conversions,-cppcoreguidelines-narrowing-conversions,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-hicpp-signed-bitwise,-bugprone-exception-escape,-cppcoreguidelines-pro-type-member-init,-cppcoreguidelines-pro-type-cstyle-cast,-hicpp-member-init,-google-readability-namespace-comments,-llvm-namespace-comment,-cppcoreguidelines-pro-type-vararg,-hicpp-vararg,-modernize-use-trailing-return-type' +WarningsAsErrors: 'true' \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..52e2f38 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,52 @@ +--- + +image: samueldebruyn/debian-git:latest + +stages: + - style + - test + - build + + +clang_tidy: + image: joethei/clang_tidy + stage: style + tags: + - docker-ci + script: + - sh .ci/clang-tidy.sh; + +make_test: + stage: test + tags: + - docker-ci + script: + - apt-get update + - apt-get install -y g++ make cmake clang-tidy + - git clone https://github.com/catchorg/Catch2.git + - cd Catch2 + - cmake -Bbuild -H. -DBUILD_TESTING=OFF + - cmake --build build/ --target install + - cd .. + - mkdir build + - cd build + - cmake .. + - make + - make test + +cmake_build: + stage: build + tags: + - docker-ci + script: + - apt-get update + - apt-get install -y g++ make cmake clang-tidy + - git clone https://github.com/catchorg/Catch2.git + - cd Catch2 + - cmake -Bbuild -H. -DBUILD_TESTING=OFF + - cmake --build build/ --target install + - cd .. + - mkdir build + - cd build + - cmake .. + - make \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 9214fad..c8b82de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.2.0] +### Added +- shared memory access (local) +- signaling - Continuous Integration ## [0.1.0] - 2019-10-24 diff --git a/CMakeLists.txt b/CMakeLists.txt index d9fd70d..7a23c62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,21 +13,21 @@ set(CMAKE_CXX_STANDARD 14) # enable clang_tidy set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=*") -set(CMAKE_CXX_CLANG_TIDY clang-tidy;-header-filter=.;-checks=*;) +set(CMAKE_CXX_CLANG_TIDY clang-tidy;-header-filter=.;) file(GLOB_RECURSE SOURCES src/*.cpp) -file(GLOB_RECURSE HEADERS src/*.h) +file(GLOB_RECURSE HEADERS src/*.hpp) file(GLOB_RECURSE TESTS test/*.cpp) include_directories(src) include_directories(test) -add_library(library ${SOURCES} ${HEADERS}) +add_library(library ${SOURCES} ${HEADERS} src/FontType.cpp) file(COPY "${CMAKE_SOURCE_DIR}/src/" DESTINATION "${CMAKE_SOURCE_DIR}/include" FILES_MATCHING - PATTERN *.h + PATTERN *.hpp ) set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib) diff --git a/src/Color.cpp b/src/Color.cpp index 3daac50..85ac7df 100644 --- a/src/Color.cpp +++ b/src/Color.cpp @@ -1,8 +1,33 @@ +#include "Color.hpp" -#include "Color.h" +namespace vkvm { -Color::Color(unsigned char red, unsigned char green, unsigned char blue) - : red(red), green(green), blue(blue){ + Color::Color(unsigned char red, unsigned char green, unsigned char blue) noexcept + : red(red), green(green), blue(blue) { -} + } + auto Color::getRed() -> unsigned char { + return red; + } + + auto Color::getGreen() -> unsigned char { + return green; + } + + auto Color::getBlue() -> unsigned char { + return blue; + } + + auto Color::setRed(unsigned char value) -> void { + red = value; + } + + auto Color::setGreen(unsigned char value) -> void { + green = value; + } + + auto Color::setBlue(unsigned char value) -> void { + blue = value; + } +} \ No newline at end of file diff --git a/src/Color.h b/src/Color.h deleted file mode 100644 index 3d75e99..0000000 --- a/src/Color.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef LIBRARY_COLOR_H -#define LIBRARY_COLOR_H - - -/** - * color values represented as rgb values. - * @author Johannes Theiner - * @since 0.1.0 - */ -class Color { - -private: - unsigned char red; - unsigned char green; - unsigned char blue; - -public: - Color(unsigned char red, unsigned char green, unsigned char blue); - -}; - -const Color black = Color(0, 0, 0); -const Color white = Color(255, 255, 255); - -#endif diff --git a/src/Color.hpp b/src/Color.hpp new file mode 100644 index 0000000..a8159b1 --- /dev/null +++ b/src/Color.hpp @@ -0,0 +1,40 @@ +#ifndef LIBRARY_COLOR_HPP +#define LIBRARY_COLOR_HPP + +namespace vkvm { + +/** + * color values represented as rgb values. + * @author Johannes Theiner + * @since 0.1.0 + */ + class Color { + + private: + unsigned char red; + unsigned char green; + unsigned char blue; + + public: + Color(unsigned char red, unsigned char green, unsigned char blue) noexcept; + + auto getRed() -> unsigned char; + + auto getGreen() -> unsigned char; + + auto getBlue() -> unsigned char; + + auto setRed(unsigned char value) -> void; + + auto setGreen(unsigned char value) -> void; + + auto setBlue(unsigned char value) -> void; + + }; + + const static Color black = Color(0, 0, 0); + const static Color white = Color(255, 255, 255); + +} + +#endif diff --git a/src/EventType.h b/src/EventType.h deleted file mode 100644 index 6daa1ea..0000000 --- a/src/EventType.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef LIBRARY_EVENTTYPE_H -#define LIBRARY_EVENTTYPE_H - -/** - * types of events. - * @since 0.1.0 - * @uthor Johannes Theiner - */ -enum EventType { - Timer = 1, - MouseMove = 2, - MouseButton = 3, - KeyDown = 4, - KeyUp = 5, - UpdateControlRegisters = 6, - Redraw = 7, - RenderText = 8 -}; - -#endif diff --git a/src/EventType.hpp b/src/EventType.hpp new file mode 100644 index 0000000..79f4d94 --- /dev/null +++ b/src/EventType.hpp @@ -0,0 +1,24 @@ +#ifndef LIBRARY_EVENTTYPE_HPP +#define LIBRARY_EVENTTYPE_HPP + +namespace vkvm { + +/** + * types of events. + * @since 0.1.0 + * @uthor Johannes Theiner + */ + enum EventType { + Timer = 1, + MouseMove = 2, + MouseButton = 3, + KeyDown = 4, + KeyUp = 5, + UpdateControlRegisters = 6, + Redraw = 7, + RenderText = 8 + }; + +} + +#endif diff --git a/src/Font.h b/src/Font.h deleted file mode 100644 index 308dbc8..0000000 --- a/src/Font.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef LIBRARY_FONT_H -#define LIBRARY_FONT_H - - -class Font { -private: - Font(); - -public: - std::string getName(); - int getHeight(); - int getWidth(); - -}; - - -#endif diff --git a/src/FontType.cpp b/src/FontType.cpp new file mode 100644 index 0000000..5e69054 --- /dev/null +++ b/src/FontType.cpp @@ -0,0 +1,24 @@ +#include "FontType.hpp" + +namespace vkvm { + + FontType::FontType(int id, const char * name, int height, int width) noexcept : id(id), name(name), height(height), width(width) { + } + + auto FontType::getId() const -> int { + return id; + } + + auto FontType::getName() const -> std::string { + return std::string(name); + } + + auto FontType::getHeight() const -> int { + return height; + } + + auto FontType::getWidth() const -> int { + return width; + } + +} \ No newline at end of file diff --git a/src/FontType.hpp b/src/FontType.hpp new file mode 100644 index 0000000..349abd1 --- /dev/null +++ b/src/FontType.hpp @@ -0,0 +1,33 @@ +#ifndef LIBRARY_FONT_H + +#define LIBRARY_FONT_H + +#include +#include + +namespace vkvm { + + class FontType { + private: + int id; + const char * name; + int height; + int width; + + public: + FontType(int id, const char * name, int height, int width) noexcept; + + auto getId() const -> int; + + auto getName() const -> std::string; + + auto getHeight() const -> int; + + auto getWidth() const -> int; + + }; + + static const FontType font_1 = FontType(1, "DummyFont", 10, 5); +} + +#endif diff --git a/src/GraphicMode.h b/src/GraphicMode.h deleted file mode 100644 index d447ee8..0000000 --- a/src/GraphicMode.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef LIBRARY_GRAPHICMODE_H -#define LIBRARY_GRAPHICMODE_H - -/** - * all possible graphics modes. - * @author Johannes Theiner - * @since 0.1.0 - */ -enum GraphicMode { - Text = 1, - TwoColors = 2, - Gray_256 = 3, - TrueColor = 4, -}; - -#endif diff --git a/src/GraphicMode.hpp b/src/GraphicMode.hpp new file mode 100644 index 0000000..92d51d7 --- /dev/null +++ b/src/GraphicMode.hpp @@ -0,0 +1,19 @@ +#ifndef LIBRARY_GRAPHICMODE_HPP +#define LIBRARY_GRAPHICMODE_HPP + + +namespace vkvm { +/** + * all possible graphics modes. + * @author Johannes Theiner + * @since 0.1.0 + */ + enum GraphicMode { + Text = 1, + TwoColors = 2, + Gray_256 = 3, + RGB = 4 + }; +} + +#endif diff --git a/src/KeyCode.cpp b/src/KeyCode.cpp index 6e7e2c7..aaa7e7d 100644 --- a/src/KeyCode.cpp +++ b/src/KeyCode.cpp @@ -1,9 +1,11 @@ +#include "KeyCode.hpp" -#include "KeyCode.h" +namespace vkvm { -KeyCode::KeyCode(int value) : value(value) {} + KeyCode::KeyCode(int value) noexcept : value(value) {} + + auto KeyCode::getValue() -> int { + return value; + } -int KeyCode::getValue() { - return value; } - diff --git a/src/KeyCode.h b/src/KeyCode.h deleted file mode 100644 index 65ab74d..0000000 --- a/src/KeyCode.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef LIBRARY_KEYCODE_H -#define LIBRARY_KEYCODE_H - -class KeyCode { -private: - int value; -public: - explicit KeyCode(int value); - int getValue(); -}; - -const KeyCode Backspace = KeyCode(8); -const KeyCode tabulator = KeyCode(9); - -#endif diff --git a/src/KeyCode.hpp b/src/KeyCode.hpp new file mode 100644 index 0000000..34d2890 --- /dev/null +++ b/src/KeyCode.hpp @@ -0,0 +1,22 @@ +#ifndef LIBRARY_KEYCODE_HPP +#define LIBRARY_KEYCODE_HPP + +#include + +namespace vkvm { + + class KeyCode { + private: + int value; + public: + explicit KeyCode(int value) noexcept; + + auto getValue() -> int; + }; + + const static KeyCode Backspace = KeyCode(8); + const static KeyCode tabulator = KeyCode(9); + +} + +#endif \ No newline at end of file diff --git a/src/LayoutVersion.h b/src/LayoutVersion.h deleted file mode 100644 index ce24e93..0000000 --- a/src/LayoutVersion.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LIBRARY_LAYOUTVERSION_H -#define LIBRARY_LAYOUTVERSION_H - -enum LayoutVersion { - V1 = 1 -}; - -#endif diff --git a/src/LayoutVersion.hpp b/src/LayoutVersion.hpp new file mode 100644 index 0000000..7e36985 --- /dev/null +++ b/src/LayoutVersion.hpp @@ -0,0 +1,12 @@ +#ifndef LIBRARY_LAYOUTVERSION_HPP +#define LIBRARY_LAYOUTVERSION_HPP + +namespace vkvm { + + enum LayoutVersion { + V1 = 1 + }; + +} + +#endif diff --git a/src/SharedMemoryAccess.cpp b/src/SharedMemoryAccess.cpp new file mode 100644 index 0000000..697b5b0 --- /dev/null +++ b/src/SharedMemoryAccess.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SharedMemoryAccess.hpp" /* header is important for the shmID. name could be different. maybe not needed cause: (shmget(memory_access_key, NULL, 0)) */ +#include "internal.hpp" + +namespace vkvm { + constexpr int PERM = 0666; /* access rights */ + constexpr int LOCK = -1; + constexpr int UNLOCK = 1; + constexpr int SEM_KEY = 123458L; + +//int memoryAccessKey; /* var type is int. but could be another type. */ //TODO: look after type in sharedmemory group + int semId; + struct sembuf semaphore; + + std::vector localSharedMemory; + + auto initSemaphore() -> int { + /* Testen, ob das Semaphor bereits existiert */ + semId = semget(SEM_KEY, 0, IPC_PRIVATE); + if (semId < 0) { + /* ... existiert noch nicht, also anlegen */ + /* Alle Zugriffsrechte der Dateikreierungsmaske */ + /* erlauben */ + umask(0); + semId = semget(SEM_KEY, 1, IPC_CREAT | IPC_EXCL | PERM); + if (semId < 0) { + return -1; + } + /* Semaphor mit 1 initialisieren */ + if (semctl(semId, 0, SETVAL, 1) == -1) { + return -1; + } + } + return 1; + } + + auto semaphoreOperation(int op) -> int { + semaphore.sem_op = static_cast(op); + semaphore.sem_flg = SEM_UNDO; + if (semop(semId, &semaphore, 1) == -1) { + perror(" semop "); + return -1; + } + return 1; + } + + auto writeSharedMemory(char *data, int size, int offset) -> void { + lockSharedMemory(); + memcpy(getSharedMemory() + offset, data, size); + unlockSharedMemory(); + } + + auto getSharedMemory() -> char * { + int shmId = shmget(impl.sharedMemoryKey, 0, 0); + if (shmId < 0) { + //using a local buffer for shared memory testing + if (localSharedMemory.empty()) { + initSemaphore(); + constexpr int kilo = 1024; + localSharedMemory.resize(impl.sharedMemorySize * kilo); + } + return &localSharedMemory[0]; + } + return static_cast(shmat(shmId, nullptr, 0)); + } + + auto getSharedMemory(char *address, int size, int offset) -> void { + lockSharedMemory(); + memcpy(address, getSharedMemory() + offset, size); + unlockSharedMemory(); + } + + auto getSharedMemorySize() -> int { + return impl.sharedMemorySize; + } + + auto lockSharedMemory() -> void { + semaphoreOperation(LOCK); + } + + auto unlockSharedMemory() -> void { + semaphoreOperation(UNLOCK); + } + +} \ No newline at end of file diff --git a/src/SharedMemoryAccess.hpp b/src/SharedMemoryAccess.hpp new file mode 100644 index 0000000..7068262 --- /dev/null +++ b/src/SharedMemoryAccess.hpp @@ -0,0 +1,41 @@ +#ifndef LIBRARY_SHAREDMEMORYACCESSS_H +#define LIBRARY_SHAREDMEMORYACCESSS_H + +namespace vkvm { + auto initSemaphore() -> int; + +/** + * use lock and unlock when writing + * @return pointer to the shared memory + */ + auto getSharedMemory() -> char *; + +/** + * use lock and unlock when writing, + * set content to the address + * @param *address target address + * @param size of data + * @param offset where the data is written on the shared memory + */ + auto getSharedMemory(char *address, int size, int offset) -> void; + +/** + * + * @return the size of the shared memory + */ + auto getSharedMemorySize() -> int; + + auto lockSharedMemory() -> void; + + auto unlockSharedMemory() -> void; + +/** + * + * @param data pointer to data + * @param size of data + * @param offset where the data is written on the shared memory + */ + auto writeSharedMemory(char *data, int size, int offset) -> void; +} + +#endif diff --git a/src/add.cpp b/src/add.cpp deleted file mode 100644 index c3f4e9f..0000000 --- a/src/add.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "add.h" - -int add(int a, int b){ - return a + b; -} diff --git a/src/add.h b/src/add.h deleted file mode 100644 index c950a3c..0000000 --- a/src/add.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef LIBRARY_ADD_H -#define LIBRARY_ADD_H - -int add(int a, int b); - -#endif diff --git a/src/internal.cpp b/src/internal.cpp index d9575d2..82b515a 100644 --- a/src/internal.cpp +++ b/src/internal.cpp @@ -1,5 +1,81 @@ -#include "internal.h" +#include "internal.hpp" +#include "SharedMemoryAccess.hpp" +#include "vkvm.hpp" -Internal internal; +#include +namespace vkvm { + Impl impl; + + auto sendSignal(pid_t pid, int signalNumber) -> void { + kill(pid, signalNumber); + } + + auto onSignal(int signalNumber, void(*callback)(int)) -> void { + signal(signalNumber, callback); + } + + auto getInterrupTable() -> InterruptEntry * { + return reinterpret_cast(getSharedMemory() + sizeof(Registers) + impl.reservedSize); + } + + auto getRegisters() -> Registers * { + return reinterpret_cast(getSharedMemory()); + } + + auto getTextArea() -> char * { + return ((getSharedMemory() + sizeof(Registers) + impl.reservedSize) + + sizeof(InterruptEntry) * impl.interruptEntyCount); + } + + auto getPixelArea() -> char * { + return (((getSharedMemory() + sizeof(Registers) + impl.reservedSize) + + sizeof(InterruptEntry) * impl.interruptEntyCount) + + getCharactersPerRow() * getCharactersPerColumn()); + } + + auto callEvent(EventType type) -> bool { + auto ivt = getInterrupTable(); + if (ivt[type].pid != 0) { + sendSignal(ivt[type].pid, ivt[type].signum); + } + return true; + } + + auto setLayoutVersion(LayoutVersion newValue) -> void { + lockSharedMemory(); + getRegisters()->layout_version = newValue; + unlockSharedMemory(); + } + + auto setCharactersPerColumn(int newValue) -> void { + lockSharedMemory(); + getRegisters()->characters_per_column = newValue; + unlockSharedMemory(); + } + + auto setCharactersPerRow(int newValue) -> void { + lockSharedMemory(); + getRegisters()->characters_per_row = newValue; + unlockSharedMemory(); + } + + auto setMousePosition(int x, int y) -> void { + lockSharedMemory(); + getRegisters()->mouse_pos_x = x; + getRegisters()->mouse_pos_y = y; + unlockSharedMemory(); + } + + auto buttonPressed(KeyCode keyCode) -> void { + lockSharedMemory(); + auto reg = getRegisters(); + if (reg->keyboardBuffer_index_write == sizeof(reg->keyboardBuffer)) { + reg->keyboardBuffer_index_write = 0; + } + reg->keyboardBuffer[reg->keyboardBuffer_index_write++] = keyCode.getValue(); + unlockSharedMemory(); + } + +} diff --git a/src/internal.h b/src/internal.h deleted file mode 100644 index 65baee5..0000000 --- a/src/internal.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef LIBRARY_INTERNAL_H -#define LIBRARY_INTERNAL_H - -#include "EventType.h" -#include "KeyCode.h" -#include "LayoutVersion.h" -#include "GraphicMode.h" -#include "Color.h" - -/** - * the Control Registers - * @author Julian Hinxlage - * @since 0.1.0 - */ -struct Registers{ - int layout_version; - int trigger_reset; - int width_pixels; - int height_pixels; - GraphicMode graphicMode; - int autoRedrawInterval; - int timerInterruptInterval; - Color background_color; - Color foreground_color; - int characters_per_row; - int characters_per_column; - int textMode_font; - int textMode_font_width; - int textMode_font_height; - int mouse_pos_x; - int mouse_pos_y; - char keyboardBuffer[16]; - int keyboardBuffer_index_w; - int keyboardBuffer_index_r; -}; - -struct InterruptEntry{ - int pid; - int signum; -}; - -/** - * internal values for the library. - */ -struct Internal{ - int sharedMemoryPid; -}; -extern Internal internal; - -/** - * set layout version. - * @param newValue new layout version number. - */ -void setLayoutVersion(LayoutVersion newValue); - -/** - * set characters per line for current font. - * @param newValue characters per line. - */ -void setCharactersPerLine(int newValue); - -/** - * set characters per row for current font. - * @param newValue - */ -void setCharactersPerRow(int newValue); - -/** - * call a specific event. - * @param type - * @return true if there is a handler registered. - */ -bool callEvent(EventType type); - -/** - * set mouse position to x,y value. - * @param x x coordinate - * @param y y coordinate - */ -void setMousePosition(int x, int y); - -/** - * register pressed button. - * @param keyCode pressed key. - */ -void buttonPressed(KeyCode keyCode); - -// Shared Memory Layout -// -------------------------------------------------------------------- -// struct ControlRegisters -// char reserved[1024] -// Interrupt Vector Table [64] -// text area [max_textMode_width * max_textMode_height] -// pixel area [max_height_pixels * max_height_pixels * sizeof(uint_32)] - - -#endif \ No newline at end of file diff --git a/src/internal.hpp b/src/internal.hpp new file mode 100644 index 0000000..d237f92 --- /dev/null +++ b/src/internal.hpp @@ -0,0 +1,135 @@ +#ifndef LIBRARY_INTERNAL_HPP +#define LIBRARY_INTERNAL_HPP + +#include "Color.hpp" +#include "EventType.hpp" +#include "GraphicMode.hpp" +#include "KeyCode.hpp" +#include "LayoutVersion.hpp" +#include +#include +#include + +namespace vkvm { + +/** + * the Control Registers + * @author Julian Hinxlage + * @since 0.1.0 + */ + +constexpr int keyboardBufferSize = 16; + + struct Registers { + int layout_version; + int trigger_reset; + int width_pixels; + int height_pixels; + GraphicMode graphicMode; + int autoRedrawInterval; + int timerInterruptInterval; + Color background_color; + Color foreground_color; + int characters_per_row; + int characters_per_column; + int textMode_font; + int textMode_font_width; + int textMode_font_height; + int mouse_pos_x; + int mouse_pos_y; + std::array keyboardBuffer; + int keyboardBuffer_index_write; + int keyboardBuffer_index_read; + }; + + struct InterruptEntry { + int pid; + int signum; + }; + +/** + * internal values for the library. + */ + struct Impl { + int sharedMemoryPid; + key_t sharedMemoryKey; + int sharedMemorySize; + int interruptEntyCount = 64; //NOLINT + int reservedSize = 1024; //NOLINT + std::vector> eventTable; + }; + + extern Impl impl; + +/** + * send a signal to a process + * @param pid of the process to which the signal is send + * @param signalNumber + */ + auto sendSignal(pid_t pid, int signalNumber) -> void; + +/** + * calls the callback if a signal is received + * @param signalNumber + */ + auto onSignal(int signalNumber, void(*callback)(int)) -> void; + + + auto getInterrupTable() -> InterruptEntry *; + + auto getRegisters() -> Registers *; + + auto getTextArea() -> char *; + + auto getPixelArea() -> char *; + + +/** + * set layout version. + * @param newValue new layout version number. + */ + auto setLayoutVersion(LayoutVersion newValue) -> void; + +/** + * set characters per column for current font. + * @param newValue characters per column. + */ + auto setCharactersPerColumn(int newValue) -> void; + +/** + * set characters per row for current font. + * @param newValue + */ + auto setCharactersPerRow(int newValue) -> void; + +/** + * call a specific event. + * @param type + * @return true if there is a handler registered. + */ + auto callEvent(EventType type) -> bool; + +/** + * set mouse position to x,y value. + * @param x x coordinate + * @param y y coordinate + */ + auto setMousePosition(int x, int y) -> void; + +/** + * register pressed button. + * @param keyCode pressed key. + */ + auto buttonPressed(KeyCode keyCode) -> void; + +// Shared Memory Layout +// -------------------------------------------------------------------- +// struct ControlRegisters +// char reserved[1024] +// Interrupt Vector Table [64] +// text area [max_textMode_width * max_textMode_height] +// pixel area [max_height_pixels * max_height_pixels * sizeof(uint_32)] + +} + +#endif \ No newline at end of file diff --git a/src/log.cpp b/src/log.cpp new file mode 100644 index 0000000..c015f84 --- /dev/null +++ b/src/log.cpp @@ -0,0 +1,114 @@ + +/** + * @author Julian Hinxlage + * @since 0.1.0 + */ + +#include "log.hpp" +#include + +namespace vkvm { + //converts the level to a string of the level + auto getLevelName(LogLevel level) -> std::string { + switch(level){ + case LogLevel::DEBUG: + return "DEBUG"; + case LogLevel::INFO: + return "INFO"; + case LogLevel::WARNING: + return "WARNING"; + case LogLevel::ERROR: + return "ERROR"; + case LogLevel::CRITICAL: + return "CRITICAL"; + default: + return "NON"; + } + } + +//converts the level to a ansi color code + auto getLevelColor(LogLevel level) -> std::string { + switch(level){ + case LogLevel::DEBUG: + return "0;37"; + case LogLevel::INFO: + return "0"; + case LogLevel::WARNING: + return "1;33"; + case LogLevel::ERROR: + return "1;31"; + case LogLevel::CRITICAL: + return "1;35"; + default: + return "0"; + } + } + + LogLevel logLevel = LogLevel::INFO; + +//log the current time + auto logTime() -> void { + time_t rawtime; + time(&rawtime); + struct tm *timeinfo; + timeinfo = localtime(&rawtime); + + constexpr int decimalBase = 10; + + if (timeinfo->tm_hour < decimalBase) { + std::cout << "0"; + } + std::cout << timeinfo->tm_hour; + std::cout << ":"; + if (timeinfo->tm_min < decimalBase) { + std::cout << "0"; + } + std::cout << timeinfo->tm_min; + std::cout << ":"; + if (timeinfo->tm_sec < decimalBase) { + std::cout << "0"; + } + std::cout << timeinfo->tm_sec; + } + +//log the message + auto log(LogLevel level, const std::string &msg) -> void { + if(level >= logLevel) { + std::string levelName = getLevelName(level); + const int maxLevelNameLength = 8; + + //time + std::cout << "["; + logTime(); + std::cout << "] "; + + //color and level name;lo + std::cout << "["; + std::cout << "\033[" << getLevelColor(level) << "m" << levelName << "\033[0m"; + std::cout << "] "; + for (int i = levelName.size(); i < maxLevelNameLength; i++) { + std::cout << " "; + } + + //message + for(char c : msg){ + if(c == '\n'){ + //intend newlines so that they align with the start of the message + std::cout << "\n"; + const int paddingSize = 22; + for(int i = 0; i < paddingSize;i++){ + std::cout << " "; + } + }else{ + std::cout << c; + } + } + std::cout << "\n"; + } + } + + auto setLogLevel(LogLevel level) -> void { + logLevel = level; + } + +} diff --git a/src/log.hpp b/src/log.hpp new file mode 100644 index 0000000..8d80990 --- /dev/null +++ b/src/log.hpp @@ -0,0 +1,52 @@ +#ifndef LIBRARY_LOG_HPP +#define LIBRARY_LOG_HPP + +#include +#include + +namespace vkvm { + enum LogLevel{ + DEBUG = 1, + INFO = 2, + WARNING = 3, + ERROR = 4, + CRITICAL = 5, + OFF = 6 + }; + +/** + * log the messgae with logLevel and timestamp + * @author Julian Hinxlage + * @since 0.1.0 + */ + auto log(LogLevel level, const std::string &msg) -> void; + + + template + static auto buildString(std::stringstream &stream, T t) -> void { + stream << t; + } + + template + static auto buildString(std::stringstream &stream, T t, Ts... ts) -> void { + stream << t; + buildString(stream, ts...); + } + + template + static auto log(LogLevel level, T... t) -> void { + std::stringstream stream; + buildString(stream, t...); + log(level, stream.str()); + } + + +/** + * set the logLevel, the log function will use this to determine if the message is logged + * @author Julian Hinxlage + * @since 0.1.0 + */ + auto setLogLevel(LogLevel level) -> void; +} + +#endif diff --git a/src/vkvm.cpp b/src/vkvm.cpp index 45218e4..3493667 100644 --- a/src/vkvm.cpp +++ b/src/vkvm.cpp @@ -1,6 +1,199 @@ -#include "vkvm.h" -#include "internal.h" +#include "SharedMemoryAccess.hpp" +#include "internal.hpp" +#include "vkvm.hpp" -void initialize(int pid) { - internal.sharedMemoryPid = pid; -} +#include +#include + +namespace vkvm { + // NOLINT + auto initialize(int pid) -> void { + impl.sharedMemoryPid = pid; + impl.sharedMemoryKey = 12345;// NOLINT + impl.sharedMemorySize = 8000;// NOLINT + initSemaphore(); + setDefaultValues(); + } + + auto setDefaultValues() -> void { + if(getSharedMemory() != nullptr) { + //set default values + setCharactersPerRow(60);// NOLINT + setCharactersPerColumn(20);// NOLINT + setHeight(600);// NOLINT + setWidth(800);// NOLINT + setMousePosition(42, 42);// NOLINT + setBackgroundColor(Color(200, 50, 20));// NOLINT + setForegroundColor(Color(20, 200, 50));// NOLINT + setMode(GraphicMode::RGB);// NOLINT + setRedrawInterval(20);// NOLINT + setTimerInterruptInterval(10);// NOLINT + } + } + + auto registerEvent(EventType type, const std::function &handler) -> bool { + int signum = SIGUSR1 + impl.eventTable.size(); + auto ivt = getInterrupTable(); + + lockSharedMemory(); + + ivt[type].pid = getpid(); + ivt[type].signum = signum; + impl.eventTable.push_back(handler); + + onSignal(signum, [](int sig){ + if(sig >= SIGUSR1){ + if((sig - SIGUSR1) < impl.eventTable.size()){ + impl.eventTable[sig - SIGUSR1](); + } + } + }); + + unlockSharedMemory(); + + return true; + } + + auto setPixel(int x, int y, Color color) -> bool { + char *ptr = getPixelArea() + (y * getWidth() + x) * 3; + ptr[0] = color.getRed(); + ptr[1] = color.getGreen(); + ptr[2] = color.getBlue(); + return false; + } + + auto getPixel(int x, int y) -> Color { + //TODO(julian): other than RGB colores + //only RGB colores for now + unsigned char *ptr = reinterpret_cast(getPixelArea()) + (y * getWidth() + x) * 3; + return {ptr[0], ptr[1], ptr[2]}; + } + + auto setText(std::string text) -> bool { + lockSharedMemory(); + char *ptr = getTextArea(); + for(int i = 0; i < static_cast(text.size());i++){ + if(i >= getCharactersPerColumn() * getCharactersPerRow()){ + break; + } + ptr[i] = text[i]; + } + if(text.size() < getCharactersPerColumn() * getCharactersPerRow()){ + ptr[text.size()] = '\0'; + } + unlockSharedMemory(); + return true; + } + + auto getText() -> std::string { + return std::string (getTextArea()); + } + + auto getLayoutVersion() -> LayoutVersion { + return static_cast(getRegisters()->layout_version); + } + + auto reset() -> void { + //TODO(julian): reset + } + + auto getWidth() -> int { + return getRegisters()->width_pixels; + } + + auto setWidth(int newValue) -> void { + lockSharedMemory(); + getRegisters()->width_pixels = newValue; + unlockSharedMemory(); + } + + auto getHeight() -> int { + return getRegisters()->height_pixels; + } + + auto setHeight(int newValue) -> void { + lockSharedMemory(); + getRegisters()->height_pixels = newValue; + unlockSharedMemory(); + } + + auto getMode() -> GraphicMode { + return getRegisters()->graphicMode; + } + + auto setMode(GraphicMode newValue) -> void { + lockSharedMemory(); + getRegisters()->graphicMode = newValue; + unlockSharedMemory(); + } + + auto getRedrawInterval() -> int { + return getRegisters()->autoRedrawInterval; + } + + auto setRedrawInterval(int newValue) -> void { + lockSharedMemory(); + getRegisters()->autoRedrawInterval = newValue; + unlockSharedMemory(); + } + + auto getTimerInterruptInterval() -> int { + return getRegisters()->timerInterruptInterval; + } + + auto setTimerInterruptInterval(int newValue) -> void { + lockSharedMemory(); + getRegisters()->timerInterruptInterval = newValue; + unlockSharedMemory(); + } + + auto getBackgroundColor() -> Color { + return getRegisters()->background_color; + } + + auto setBackgroundColor(Color newValue) -> void { + lockSharedMemory(); + getRegisters()->background_color = newValue; + unlockSharedMemory(); + } + + auto getForegroundColor() -> Color { + return getRegisters()->foreground_color; + } + + auto setForegroundColor(Color newValue) -> void { + lockSharedMemory(); + getRegisters()->foreground_color = newValue; + unlockSharedMemory(); + } + + auto getCharactersPerRow() -> int { + return getRegisters()->characters_per_row; + } + + auto getCharactersPerColumn() -> int { + return getRegisters()->characters_per_column; + } + + auto getFont() -> FontType { + //TODO(julian): get font properly + return font_1; + } + + auto setFont(const FontType &newValue) -> void { + //TODO(julian): setFont properly + lockSharedMemory(); + getRegisters()->textMode_font = newValue.getId(); + unlockSharedMemory(); + } + + auto getMousePosition() -> Coordinates { + return {getRegisters()->mouse_pos_x, getRegisters()->mouse_pos_y}; + } + + auto getLastPressedKey() -> KeyCode { + //TODO(julian): get key properly + return KeyCode(0); + } + +} \ No newline at end of file diff --git a/src/vkvm.h b/src/vkvm.hpp similarity index 63% rename from src/vkvm.h rename to src/vkvm.hpp index a95731f..8f86e7f 100644 --- a/src/vkvm.h +++ b/src/vkvm.hpp @@ -1,27 +1,34 @@ -#ifndef LIBRARY_VKVM_H -#define LIBRARY_VKVM_H +#ifndef LIBRARY_VKVM_HPP +#define LIBRARY_VKVM_HPP -#include +#include "Color.hpp" +#include "EventType.hpp" +#include "FontType.hpp" +#include "GraphicMode.hpp" +#include "KeyCode.hpp" +#include "LayoutVersion.hpp" +#include "log.hpp" #include -#include "Color.h" -#include "EventType.h" -#include "GraphicMode.h" -#include "Font.h" -#include "KeyCode.h" -#include "LayoutVersion.h" +#include -/** +namespace vkvm { + /** * @since 0.1.0 * @author Johannes Theiner */ -//TODO: better documentation + struct Coordinates { + int x; + int y; + }; /** * initialize the connection with the shared-memory application * @param pid pip of shared-memory application */ -void initialize(int pid); + auto initialize(int pid) -> void; + + auto setDefaultValues() -> void; /** * set pixel at a x,y position to a certain color. @@ -30,7 +37,7 @@ void initialize(int pid); * @param color color of pixel * @return true if operation succeeded, false if it failed. */ -bool setPixel(int x, int y, Color color); + auto setPixel(int x, int y, Color color) -> bool; /** * get color of pixel at x,y position @@ -38,7 +45,7 @@ bool setPixel(int x, int y, Color color); * @param y y coordinate of pixel * @return color of pixel */ -Color getPixel(int x, int y); + auto getPixel(int x, int y) -> Color; /** * register handler for event. @@ -46,19 +53,19 @@ Color getPixel(int x, int y); * @param handler function to call. * @return true if handler could be registered, false if it failed. */ -bool registerEvent(EventType type, std::function handler); + auto registerEvent(EventType type, const std::function &handler) -> bool; /** * set displayed text in Text mode * @param text text to display * @return if text could be set, false if it could not be set. */ -bool setText(std::string text); + auto setText(std::string text) -> bool; /** * get currently saved/displayed text. */ -std::string getText(); + auto getText() -> std::string; //Control registers start here @@ -68,71 +75,71 @@ std::string getText(); * get version of the used layout * @return layout version */ -LayoutVersion getLayoutVersion(); + auto getLayoutVersion() -> LayoutVersion; /** * reset all values to default. */ -void reset(); + auto reset() -> void; /** * get width of window. * @return width of window. */ -int getWidth(); + auto getWidth() -> int; /** * set width of window. * @param newValue new width for window. */ -void setWidth(int newValue); + auto setWidth(int newValue) -> void; /** * get height for window. * @return height of window. */ -int getHeight(); + auto getHeight() -> int; /** * set height of window. * @param newValue new height for window. */ -void setHeight(int newValue); + auto setHeight(int newValue) -> void; /** * get graphics display mode. * @return GraphicMode. */ -GraphicMode getMode(); + auto getMode() -> GraphicMode; /** * set new graphics display mode. * @param newValue new graphics display mode. */ -void setMode(GraphicMode newValue); + auto setMode(GraphicMode newValue) -> void; /** * get interval between redraws in milliseconds. */ -int getRedrawInterval(); + auto getRedrawInterval() -> int; /** * set interval between redraws. * @param newValue new interval in milliseconds. */ -void setRedrawInterval(int newValue); + auto setRedrawInterval(int newValue) -> void; /** * get time between timer interrupts. * @return time between interrupts in milliseconds. */ -int getTimerInterruptInterval(); + auto getTimerInterruptInterval() -> int; /** * set time between timer interrupts. * @param newValue new time between interrupts in milliseconds. */ -void setTimerInterruptInterval(int newValue); + auto setTimerInterruptInterval(int newValue) -> void; //black/white mode @@ -140,25 +147,25 @@ void setTimerInterruptInterval(int newValue); * get background color in two color mode. * @return background color. */ -Color getBackgroundColor(); + auto getBackgroundColor() -> Color; /** * set background color in two color mode. * @param newValue new background color. */ -void setBackgroundColor(Color newValue); + auto setBackgroundColor(Color newValue) -> void; /** * get foreground color in two color mode. * @return foreground color. */ -Color getForegroundColor(); + auto getForegroundColor() -> Color; /** * set foreground color in two color mode. * @param newValue new foreground color. */ -void setForegroundColor(Color newValue); + auto setForegroundColor(Color newValue) -> void; //text mode @@ -166,36 +173,37 @@ void setForegroundColor(Color newValue); * get characters per row in text mode. * @return characters per row. */ -int getCharactersPerRow(); + auto getCharactersPerRow() -> int; /** * get characters per column in text mode. * @return characters per column. */ -int getCharactersPerColumn(); + auto getCharactersPerColumn() -> int; /** * get currently used font in text mode. * @return currently used font. */ -Font getFont(); + auto getFont() -> FontType; /** * set text mode font. * @param newValue new text mode font. */ -void setFont(Font newValue); + auto setFont(const FontType &newValue) -> void; /** * get current mouse position * @return mouse position as x,y pair */ -std::pair getMousePosition(); + auto getMousePosition() -> Coordinates; /** * get key code of last key press. * @return KeyCode of last key press. */ -KeyCode getLastPressedKey(); + auto getLastPressedKey() -> KeyCode; +} #endif \ No newline at end of file diff --git a/test/add_test.cpp b/test/add_test.cpp deleted file mode 100644 index 0b30d42..0000000 --- a/test/add_test.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include "../src/add.h" - -TEST_CASE("add works") { - SECTION("equals") { - REQUIRE(add(2, 2) == 4); - } - SECTION("not equals") { - REQUIRE(add(2, 2) != 5); - } -} \ No newline at end of file diff --git a/test/public_test.cpp b/test/public_test.cpp new file mode 100644 index 0000000..05f9467 --- /dev/null +++ b/test/public_test.cpp @@ -0,0 +1,10 @@ +#include "catch2/catch.hpp" +#include "../src/vkvm.hpp" + +TEST_CASE("add works") { + vkvm::initialize(0); + vkvm::setText("Hello World"); + SECTION("equals") { + REQUIRE(vkvm::getText() == "Hello World"); + } +} \ No newline at end of file diff --git a/test/test_main.cpp b/test/test_main.cpp index 1a32dbe..ef0a1b7 100644 --- a/test/test_main.cpp +++ b/test/test_main.cpp @@ -1,6 +1,6 @@ #define CATCH_CONFIG_MAIN -#include +#include "catch2/catch.hpp" //Dont touch this file. // add your own tests in this directory according to https://github.com/catchorg/Catch2/blob/master/docs/tutorial.md \ No newline at end of file