diff --git a/.ci/clang-tidy.sh b/.ci/clang-tidy.sh index e5861a2..f567cec 100755 --- a/.ci/clang-tidy.sh +++ b/.ci/clang-tidy.sh @@ -9,7 +9,7 @@ filelist="$(find . -not \( -path './*build*' -prune \) -not \( -path './include' 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)" + clang_tidy_lib_check="$(clang-tidy -warnings-as-errors='*' --color "$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 diff --git a/.clang-tidy b/.clang-tidy index de644d1..f404c2e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,2 +1,3 @@ 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 +WarningsAsErrors: 'true' +HeaderFilterRegex: '.*,-catch.hpp' \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a23c62..1554107 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,8 +12,7 @@ project(library) 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=.;) +set(CMAKE_CXX_CLANG_TIDY clang-tidy;) file(GLOB_RECURSE SOURCES src/*.cpp) @@ -22,7 +21,8 @@ file(GLOB_RECURSE TESTS test/*.cpp) include_directories(src) include_directories(test) -add_library(library ${SOURCES} ${HEADERS} src/FontType.cpp) +add_library(library ${SOURCES} ${HEADERS}) + file(COPY "${CMAKE_SOURCE_DIR}/src/" DESTINATION "${CMAKE_SOURCE_DIR}/include" diff --git a/src/Color.cpp b/src/Color.cpp index 85ac7df..8f03829 100644 --- a/src/Color.cpp +++ b/src/Color.cpp @@ -2,9 +2,16 @@ namespace vkvm { - Color::Color(unsigned char red, unsigned char green, unsigned char blue) noexcept - : red(red), green(green), blue(blue) { + Color::Color() noexcept + : red(0), green(0), blue(0) {} + Color::Color(unsigned char red, unsigned char green, unsigned char blue) noexcept + : red(red), green(green), blue(blue) {} + + Color::Color(unsigned int hex) noexcept { + red = (unsigned char) ((hex >> 16 & 0xFF));//NOLINT + green = (unsigned char) ((hex >> 8u & 0xFF));//NOLINT + blue = (unsigned char) ((hex & 0xFF));//NOLINT } auto Color::getRed() -> unsigned char { @@ -30,4 +37,12 @@ namespace vkvm { auto Color::setBlue(unsigned char value) -> void { blue = value; } + + bool Color::operator==(const Color &other) const { + return this->blue == other.blue && this->green == other.green && this->red == other.red; + } + + bool Color::operator!=(const Color &other) const { + return this->blue != other.blue || this->green != other.green || this->red != other.red; + } } \ No newline at end of file diff --git a/src/Color.hpp b/src/Color.hpp index a8159b1..8b3cc99 100644 --- a/src/Color.hpp +++ b/src/Color.hpp @@ -16,8 +16,12 @@ namespace vkvm { unsigned char blue; public: + Color() noexcept; + Color(unsigned char red, unsigned char green, unsigned char blue) noexcept; + explicit Color(unsigned int hex) noexcept; + auto getRed() -> unsigned char; auto getGreen() -> unsigned char; @@ -30,10 +34,17 @@ namespace vkvm { auto setBlue(unsigned char value) -> void; + bool operator==(const Color &other) const ; + + bool operator!=(const Color &other) const ; + }; const static Color black = Color(0, 0, 0); const static Color white = Color(255, 255, 255); + const static Color green = Color(0, 255, 0); + const static Color red = Color(255, 0, 0); + const static Color blue = Color(0, 0, 255); } diff --git a/src/EventType.hpp b/src/EventType.hpp index 79f4d94..49ca834 100644 --- a/src/EventType.hpp +++ b/src/EventType.hpp @@ -11,12 +11,17 @@ namespace vkvm { enum EventType { Timer = 1, MouseMove = 2, - MouseButton = 3, - KeyDown = 4, - KeyUp = 5, - UpdateControlRegisters = 6, - Redraw = 7, - RenderText = 8 + MouseLeftUp = 3, + MouseLeftDown = 4, + MouseRightUp = 5, + MouseRightDown = 6, + MouseMiddleDown = 7, + MouseMiddleUp = 8, + KeyDown = 9, + KeyUp = 10, + UpdateControlRegisters = 11, + Redraw = 12, + RenderText = 13 }; } diff --git a/src/KeyCode.cpp b/src/KeyCode.cpp deleted file mode 100644 index aaa7e7d..0000000 --- a/src/KeyCode.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "KeyCode.hpp" - -namespace vkvm { - - KeyCode::KeyCode(int value) noexcept : value(value) {} - - auto KeyCode::getValue() -> int { - return value; - } - -} diff --git a/src/KeyCode.hpp b/src/KeyCode.hpp index 34d2890..d09dfdb 100644 --- a/src/KeyCode.hpp +++ b/src/KeyCode.hpp @@ -5,18 +5,53 @@ namespace vkvm { - class KeyCode { - private: - int value; - public: - explicit KeyCode(int value) noexcept; - - auto getValue() -> int; + enum KeyCode { + Backspcce = 32, + Tab = 33, + Enter = 37, + ShiftLeft = 249, + ShiftRight = 249, + Ctrl = 251, + Alt = 257, + Delete = 279, + Space = -65224, + Zero = -65208, + One = -65207, + Two = -65206, + Three = -65205, + Four = -65204, + Five = -65203, + Six = -65202, + Seven = -65201, + Eight = -65200, + Nine = -65199, + A = -65159, + B = -65158, + C = -65157, + D = -65156, + E = -65155, + F = -65154, + G = -65153, + H = -65152, + I = -65151, + J = -65150, + K = -65149, + L = -65148, + M = -65147, + N = -65146, + O = -65145, + P = -65144, + Q = -65143, + R = -65142, + S = -65141, + T = -65140, + U = -65139, + V = -65138, + W = -65137, + X = -65136, + Y = -65135, + Z = -65134, }; - - const static KeyCode Backspace = KeyCode(8); - const static KeyCode tabulator = KeyCode(9); - } #endif \ No newline at end of file diff --git a/src/SharedMemoryAccess.cpp b/src/SharedMemoryAccess.cpp index 697b5b0..57392e3 100644 --- a/src/SharedMemoryAccess.cpp +++ b/src/SharedMemoryAccess.cpp @@ -11,6 +11,7 @@ #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" +#include "log.hpp" namespace vkvm { constexpr int PERM = 0666; /* access rights */ @@ -60,18 +61,36 @@ namespace vkvm { unlockSharedMemory(); } + char *getLocalMemory(){ + static bool givenWarning {false}; + if(!givenWarning && impl.localMemoryWarn){ + givenWarning = true; + log(LogLevel::WARNING, "no shared memory found, using local memory instead!"); + } + if (localSharedMemory.empty()) { + constexpr int kilo = 1024; + localSharedMemory.resize(impl.sharedMemorySize * kilo); + } + return &localSharedMemory[0]; + } + auto getSharedMemory() -> char * { + if(impl.sharedMemory != nullptr){ + return impl.sharedMemory; + } 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 getLocalMemory(); } - return static_cast(shmat(shmId, nullptr, 0)); + char *ptr = static_cast(shmat(shmId, nullptr, 0)); + if(reinterpret_cast(ptr) == static_cast(-1)){ + log(LogLevel::WARNING, strerror(errno)); + }else{ + impl.sharedMemory = ptr; + return ptr; + } + return getLocalMemory(); } auto getSharedMemory(char *address, int size, int offset) -> void { diff --git a/src/internal.cpp b/src/internal.cpp index 82b515a..436c76e 100644 --- a/src/internal.cpp +++ b/src/internal.cpp @@ -16,7 +16,7 @@ namespace vkvm { signal(signalNumber, callback); } - auto getInterrupTable() -> InterruptEntry * { + auto getInterruptTable() -> InterruptEntry * { return reinterpret_cast(getSharedMemory() + sizeof(Registers) + impl.reservedSize); } @@ -36,9 +36,12 @@ namespace vkvm { } auto callEvent(EventType type) -> bool { - auto ivt = getInterrupTable(); - if (ivt[type].pid != 0) { - sendSignal(ivt[type].pid, ivt[type].signum); + auto ivt = getInterruptTable(); + for(int i = 0; i < impl.interruptEntrysPerEventType;i++){ + auto &entry= ivt[type * impl.interruptEntrysPerEventType + i]; + if (entry.pid != 0) { + sendSignal(entry.pid, entry.signum); + } } return true; } @@ -71,10 +74,10 @@ namespace vkvm { auto buttonPressed(KeyCode keyCode) -> void { lockSharedMemory(); auto reg = getRegisters(); - if (reg->keyboardBuffer_index_write == sizeof(reg->keyboardBuffer)) { + if (reg->keyboardBuffer_index_write >= sizeof(reg->keyboardBuffer)) { reg->keyboardBuffer_index_write = 0; } - reg->keyboardBuffer[reg->keyboardBuffer_index_write++] = keyCode.getValue(); + reg->keyboardBuffer[reg->keyboardBuffer_index_write++] = keyCode; unlockSharedMemory(); } diff --git a/src/internal.hpp b/src/internal.hpp index d237f92..e1b5ea2 100644 --- a/src/internal.hpp +++ b/src/internal.hpp @@ -6,6 +6,7 @@ #include "GraphicMode.hpp" #include "KeyCode.hpp" #include "LayoutVersion.hpp" +#include #include #include #include @@ -54,9 +55,12 @@ constexpr int keyboardBufferSize = 16; int sharedMemoryPid; key_t sharedMemoryKey; int sharedMemorySize; - int interruptEntyCount = 64; //NOLINT + int interruptEntyCount = 256; //NOLINT + int interruptEntrysPerEventType = 8; //NOLINT int reservedSize = 1024; //NOLINT std::vector> eventTable; + bool localMemoryWarn = true; + char *sharedMemory = nullptr; }; extern Impl impl; @@ -75,7 +79,7 @@ constexpr int keyboardBufferSize = 16; auto onSignal(int signalNumber, void(*callback)(int)) -> void; - auto getInterrupTable() -> InterruptEntry *; + auto getInterruptTable() -> InterruptEntry *; auto getRegisters() -> Registers *; diff --git a/src/vkvm.cpp b/src/vkvm.cpp index 3493667..df48721 100644 --- a/src/vkvm.cpp +++ b/src/vkvm.cpp @@ -16,57 +16,144 @@ namespace vkvm { } auto setDefaultValues() -> void { + impl.localMemoryWarn = false; if(getSharedMemory() != nullptr) { //set default values + setMode(GraphicMode::RGB); 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 + setBackgroundColor(black); + setForegroundColor(white); setRedrawInterval(20);// NOLINT setTimerInterruptInterval(10);// NOLINT + setFont(FontType(3,"",0,0)); } + impl.localMemoryWarn = true; } auto registerEvent(EventType type, const std::function &handler) -> bool { int signum = SIGUSR1 + impl.eventTable.size(); - auto ivt = getInterrupTable(); + auto ivt = getInterruptTable(); lockSharedMemory(); - ivt[type].pid = getpid(); - ivt[type].signum = signum; - impl.eventTable.push_back(handler); + for(int i = 0; i < impl.interruptEntrysPerEventType;i++){ + auto &entry= ivt[type * impl.interruptEntrysPerEventType + i]; + if (entry.pid == 0) { - onSignal(signum, [](int sig){ - if(sig >= SIGUSR1){ - if((sig - SIGUSR1) < impl.eventTable.size()){ - impl.eventTable[sig - SIGUSR1](); - } + entry.pid = getpid(); + entry.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; } - }); - + } unlockSharedMemory(); - - return true; + return false; } 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(); + lockSharedMemory(); + auto reg = getRegisters(); + const int bitsPerPixel = 8; + + switch(reg->graphicMode) { + case Text: { + int pixelIndex = (y * getWidth() + x); + unsigned char *ptr = reinterpret_cast(getPixelArea()) + (pixelIndex / bitsPerPixel); + if(color == reg->foreground_color){ + //set bit to 1 + ptr[0] |= (1 << (pixelIndex % bitsPerPixel)); + } + else{ + //set bit to 0 + ptr[0] &= ~(1 << (pixelIndex % bitsPerPixel)); + } + break; + } + case TwoColors: { + int pixelIndex = (y * getWidth() + x); + unsigned char *ptr = reinterpret_cast(getPixelArea()) + (pixelIndex / bitsPerPixel); + if(color == reg->foreground_color){ + //set bit to 1 + ptr[0] |= (1 << (pixelIndex % bitsPerPixel)); + } + else{ + //set bit to 0 + ptr[0] &= ~(1 << (pixelIndex % bitsPerPixel)); + } + break; + } + case Gray_256: { + unsigned char *ptr = reinterpret_cast(getPixelArea()) + (y * getWidth() + x); + int avg = color.getRed() + color.getGreen() + color.getBlue(); + avg /= 3; + ptr[0] = avg; + break; + } + case RGB: { + unsigned char *ptr = reinterpret_cast(getPixelArea()) + (y * getWidth() + x) * 3; + ptr[0] = color.getRed(); + ptr[1] = color.getGreen(); + ptr[2] = color.getBlue(); + break; + } + } + unlockSharedMemory(); 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]}; + Color color = Color(0,0,0); + auto reg = getRegisters(); + const int bitsPerPixel = 8; + + switch(reg->graphicMode) { + case Text: { + int pixelIndex = (y * getWidth() + x); + unsigned char *ptr = reinterpret_cast(getPixelArea()) + pixelIndex / bitsPerPixel; + bool bit = static_cast(ptr[0] & (1 << (pixelIndex % bitsPerPixel))); + if(bit){ + color = reg->foreground_color; + }else{ + color =reg->background_color; + } + break; + } + case TwoColors: { + int pixelIndex = (y * getWidth() + x); + unsigned char *ptr = reinterpret_cast(getPixelArea()) + (pixelIndex / bitsPerPixel); + bool bit = static_cast(ptr[0] & (1 << (pixelIndex % bitsPerPixel))); + if(bit){ + color = reg->foreground_color; + }else{ + color =reg->background_color; + } + break; + } + case Gray_256: { + unsigned char *ptr = reinterpret_cast(getPixelArea()) + (y * getWidth() + x) * 1; + color = {ptr[0], ptr[0], ptr[0]}; + break; + } + case RGB: { + unsigned char *ptr = reinterpret_cast(getPixelArea()) + (y * getWidth() + x) * 3; + color = {ptr[0], ptr[1], ptr[2]}; + break; + } + } + return color; } auto setText(std::string text) -> bool { @@ -123,7 +210,32 @@ namespace vkvm { auto setMode(GraphicMode newValue) -> void { lockSharedMemory(); - getRegisters()->graphicMode = newValue; + auto reg = getRegisters(); + if(reg->graphicMode != newValue){ + + std::vector pixels; + int height = reg->height_pixels; + int width = reg->width_pixels; + pixels.resize(height * width); + + for(int y = 0; y < height;y++){ + for(int x = 0;x < width;x++){ + pixels[y * width + x] = getPixel(x,y); + } + } + + getRegisters()->graphicMode = newValue; + + unlockSharedMemory(); + for(int y = 0; y < height;y++){ + for(int x = 0;x < width;x++){ + setPixel(x,y, pixels[y * width + x]); + } + } + lockSharedMemory(); + }else{ + reg->graphicMode = newValue; + } unlockSharedMemory(); } @@ -151,7 +263,7 @@ namespace vkvm { return getRegisters()->background_color; } - auto setBackgroundColor(Color newValue) -> void { + auto setBackgroundColor(const Color &newValue) -> void { lockSharedMemory(); getRegisters()->background_color = newValue; unlockSharedMemory(); @@ -161,7 +273,7 @@ namespace vkvm { return getRegisters()->foreground_color; } - auto setForegroundColor(Color newValue) -> void { + auto setForegroundColor(const Color &newValue) -> void { lockSharedMemory(); getRegisters()->foreground_color = newValue; unlockSharedMemory(); @@ -177,7 +289,7 @@ namespace vkvm { auto getFont() -> FontType { //TODO(julian): get font properly - return font_1; + return {getRegisters()->textMode_font, "", 0, 0}; } auto setFont(const FontType &newValue) -> void { @@ -192,8 +304,17 @@ namespace vkvm { } auto getLastPressedKey() -> KeyCode { - //TODO(julian): get key properly - return KeyCode(0); + lockSharedMemory(); + auto keyCode = KeyCode(0); + auto reg = getRegisters(); + if(reg->keyboardBuffer_index_read != reg->keyboardBuffer_index_write) { + keyCode = static_cast(reg->keyboardBuffer[reg->keyboardBuffer_index_read++]); + if (reg->keyboardBuffer_index_read >= sizeof(reg->keyboardBuffer)) { + reg->keyboardBuffer_index_read = 0; + } + } + unlockSharedMemory(); + return keyCode; } } \ No newline at end of file diff --git a/src/vkvm.hpp b/src/vkvm.hpp index 8f86e7f..ed70601 100644 --- a/src/vkvm.hpp +++ b/src/vkvm.hpp @@ -153,7 +153,7 @@ namespace vkvm { * set background color in two color mode. * @param newValue new background color. */ - auto setBackgroundColor(Color newValue) -> void; + auto setBackgroundColor(const Color &newValue) -> void; /** * get foreground color in two color mode. @@ -165,7 +165,7 @@ namespace vkvm { * set foreground color in two color mode. * @param newValue new foreground color. */ - auto setForegroundColor(Color newValue) -> void; + auto setForegroundColor(const Color &newValue) -> void; //text mode diff --git a/test/color_test.cpp b/test/color_test.cpp new file mode 100644 index 0000000..32154ff --- /dev/null +++ b/test/color_test.cpp @@ -0,0 +1,49 @@ +#include "../src/vkvm.hpp" +#include +#include + +TEST_CASE("Colors") { + vkvm::initialize(0); + vkvm::setPixel(10, 10, vkvm::black);//NOLINT + vkvm::setPixel(11, 11, vkvm::white);//NOLINT + vkvm::setPixel(12, 12, vkvm::green);//NOLINT + vkvm::setPixel(13, 13, vkvm::red);//NOLINT + vkvm::setPixel(14, 14, vkvm::blue);//NOLINT + vkvm::setPixel(15, 15, vkvm::Color(66, 77, 88)); //NOLINT + vkvm::setPixel(16, 16, vkvm::Color(0xFFFFFF));//NOLINT + + SECTION("RGB") { + REQUIRE(vkvm::getPixel(10, 10) == vkvm::black);//NOLINT + REQUIRE(vkvm::getPixel(11, 11) == vkvm::white);//NOLINT + REQUIRE(vkvm::getPixel(12, 12) == vkvm::green);//NOLINT + REQUIRE(vkvm::getPixel(13, 13) == vkvm::red);//NOLINT + REQUIRE(vkvm::getPixel(14, 14) == vkvm::blue);//NOLINT + REQUIRE(vkvm::getPixel(15, 15) == vkvm::Color(66, 77, 88));//NOLINT + REQUIRE(vkvm::getPixel(16, 16) == vkvm::white);//NOLINT + } + + SECTION("TwoColors") { + vkvm::setMode(vkvm::TwoColors); + REQUIRE(vkvm::getPixel(10, 10) == vkvm::black);//NOLINT + REQUIRE(vkvm::getPixel(11, 11) == vkvm::white);//NOLINT + REQUIRE(vkvm::getPixel(12, 12) == vkvm::black);//NOLINT + REQUIRE(vkvm::getPixel(13, 13) == vkvm::black);//NOLINT + REQUIRE(vkvm::getPixel(14, 14) == vkvm::black);//NOLINT + REQUIRE(vkvm::getPixel(15, 15) == vkvm::black);//NOLINT + REQUIRE(vkvm::getPixel(16, 16) == vkvm::white);//NOLINT + + } + + SECTION("Gray256") { + vkvm::setMode(vkvm::Gray_256); + REQUIRE(vkvm::getPixel(10, 10) == vkvm::black);//NOLINT + REQUIRE(vkvm::getPixel(11, 11) == vkvm::white);//NOLINT + REQUIRE(vkvm::getPixel(12, 12) == vkvm::Color(85, 85, 85));//NOLINT + REQUIRE(vkvm::getPixel(13, 13) == vkvm::Color(85, 85, 85));//NOLINT + REQUIRE(vkvm::getPixel(14, 14) == vkvm::Color(85, 85, 85));//NOLINT + REQUIRE(vkvm::getPixel(15, 15) == vkvm::Color(77, 77, 77));//NOLINT + REQUIRE(vkvm::getPixel(16, 16) == vkvm::white);//NOLINT + } + +} +