2019-11-13 13:37:49 +01:00
|
|
|
#include "SharedMemoryAccess.hpp"
|
|
|
|
#include "internal.hpp"
|
|
|
|
#include "vkvm.hpp"
|
2019-11-07 16:34:15 +01:00
|
|
|
|
2019-11-06 13:41:24 +01:00
|
|
|
#include <csignal>
|
2019-11-12 14:07:02 +01:00
|
|
|
#include <unistd.h>
|
2019-10-29 15:24:57 +01:00
|
|
|
|
2019-11-13 13:37:49 +01:00
|
|
|
namespace vkvm {
|
2019-11-29 11:39:40 +01:00
|
|
|
|
2019-11-13 13:37:49 +01:00
|
|
|
auto initialize(int pid) -> void {
|
|
|
|
impl.sharedMemoryPid = pid;
|
2019-11-29 11:39:40 +01:00
|
|
|
impl.sharedMemoryKey = 12345;
|
|
|
|
impl.sharedMemorySize = 8000;
|
2019-11-13 13:37:49 +01:00
|
|
|
initSemaphore();
|
|
|
|
setDefaultValues();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto registerEvent(EventType type, const std::function<void()> &handler) -> bool {
|
|
|
|
int signum = SIGUSR1 + impl.eventTable.size();
|
2019-11-28 12:19:46 +01:00
|
|
|
auto ivt = getInterruptTable();
|
2019-11-13 13:37:49 +01:00
|
|
|
|
|
|
|
lockSharedMemory();
|
|
|
|
|
2019-12-01 19:56:35 +01:00
|
|
|
for (int i = 0; i < impl.interruptEntrysPerEventType; i++) {
|
|
|
|
auto &entry = ivt[type * impl.interruptEntrysPerEventType + i];
|
2019-11-19 11:56:18 +01:00
|
|
|
if (entry.pid == 0) {
|
2019-11-13 13:37:49 +01:00
|
|
|
|
2019-11-19 11:56:18 +01:00
|
|
|
entry.pid = getpid();
|
|
|
|
entry.signum = signum;
|
|
|
|
impl.eventTable.push_back(handler);
|
2019-11-13 13:37:49 +01:00
|
|
|
|
2019-12-01 19:56:35 +01:00
|
|
|
onSignal(signum, [](int sig) {
|
|
|
|
if (sig >= SIGUSR1) {
|
|
|
|
if ((sig - SIGUSR1) < impl.eventTable.size()) {
|
2019-11-19 11:56:18 +01:00
|
|
|
impl.eventTable[sig - SIGUSR1]();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
unlockSharedMemory();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2019-11-13 13:37:49 +01:00
|
|
|
unlockSharedMemory();
|
2019-11-19 11:56:18 +01:00
|
|
|
return false;
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto setPixel(int x, int y, Color color) -> bool {
|
2019-12-04 13:33:04 +01:00
|
|
|
if(x < 0 || y < 0){
|
|
|
|
return false;
|
|
|
|
}
|
2019-12-01 19:56:35 +01:00
|
|
|
if (x > getWidth() || y > getHeight()) {
|
2019-11-29 11:39:40 +01:00
|
|
|
return false;
|
|
|
|
}
|
2019-12-04 13:08:21 +01:00
|
|
|
//lockSharedMemory();
|
2019-11-26 12:33:34 +01:00
|
|
|
auto reg = getRegisters();
|
2019-11-27 13:39:16 +01:00
|
|
|
const int bitsPerPixel = 8;
|
2019-11-26 12:33:34 +01:00
|
|
|
|
2019-12-01 19:56:35 +01:00
|
|
|
switch (reg->graphicMode) {
|
2019-11-26 12:33:34 +01:00
|
|
|
case Text: {
|
|
|
|
int pixelIndex = (y * getWidth() + x);
|
2019-11-27 13:39:16 +01:00
|
|
|
unsigned char *ptr = reinterpret_cast<unsigned char *>(getPixelArea()) + (pixelIndex / bitsPerPixel);
|
2019-12-01 19:56:35 +01:00
|
|
|
if (color == reg->foreground_color) {
|
2019-11-26 12:33:34 +01:00
|
|
|
//set bit to 1
|
2019-11-27 13:39:16 +01:00
|
|
|
ptr[0] |= (1 << (pixelIndex % bitsPerPixel));
|
2019-12-01 19:56:35 +01:00
|
|
|
} else {
|
2019-11-26 12:33:34 +01:00
|
|
|
//set bit to 0
|
2019-11-27 13:39:16 +01:00
|
|
|
ptr[0] &= ~(1 << (pixelIndex % bitsPerPixel));
|
2019-11-26 12:33:34 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TwoColors: {
|
|
|
|
int pixelIndex = (y * getWidth() + x);
|
2019-11-27 13:39:16 +01:00
|
|
|
unsigned char *ptr = reinterpret_cast<unsigned char *>(getPixelArea()) + (pixelIndex / bitsPerPixel);
|
2020-01-07 15:22:54 +01:00
|
|
|
if (color.getRed() > 127 || color.getGreen() > 127 || color.getBlue() > 127) {
|
2019-11-26 12:33:34 +01:00
|
|
|
//set bit to 1
|
2019-11-27 13:39:16 +01:00
|
|
|
ptr[0] |= (1 << (pixelIndex % bitsPerPixel));
|
2019-12-01 19:56:35 +01:00
|
|
|
} else {
|
2019-11-26 12:33:34 +01:00
|
|
|
//set bit to 0
|
2019-11-27 13:39:16 +01:00
|
|
|
ptr[0] &= ~(1 << (pixelIndex % bitsPerPixel));
|
2019-11-26 12:33:34 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Gray_256: {
|
2019-11-27 13:39:16 +01:00
|
|
|
unsigned char *ptr = reinterpret_cast<unsigned char *>(getPixelArea()) + (y * getWidth() + x);
|
2019-11-26 12:33:34 +01:00
|
|
|
int avg = color.getRed() + color.getGreen() + color.getBlue();
|
|
|
|
avg /= 3;
|
2019-11-27 13:39:16 +01:00
|
|
|
ptr[0] = avg;
|
2019-11-26 12:33:34 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case RGB: {
|
|
|
|
unsigned char *ptr = reinterpret_cast<unsigned char *>(getPixelArea()) + (y * getWidth() + x) * 3;
|
2019-11-27 13:39:16 +01:00
|
|
|
ptr[0] = color.getRed();
|
|
|
|
ptr[1] = color.getGreen();
|
|
|
|
ptr[2] = color.getBlue();
|
2019-11-26 12:33:34 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-12-04 13:08:21 +01:00
|
|
|
//unlockSharedMemory();
|
2019-11-29 11:39:40 +01:00
|
|
|
return true;
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getPixel(int x, int y) -> Color {
|
2019-12-05 09:49:54 +01:00
|
|
|
if(x < 0 || y < 0) {
|
|
|
|
return getBackgroundColor();
|
|
|
|
}
|
2019-12-01 19:56:35 +01:00
|
|
|
if (x > getWidth() || y > getHeight()) {
|
2019-11-29 11:39:40 +01:00
|
|
|
return getBackgroundColor();
|
|
|
|
}
|
|
|
|
|
2019-12-01 19:56:35 +01:00
|
|
|
Color color = Color(0, 0, 0);
|
2019-11-26 12:33:34 +01:00
|
|
|
auto reg = getRegisters();
|
2019-11-27 13:39:16 +01:00
|
|
|
const int bitsPerPixel = 8;
|
2019-11-21 11:35:54 +01:00
|
|
|
|
2019-12-01 19:56:35 +01:00
|
|
|
switch (reg->graphicMode) {
|
2019-11-26 12:33:34 +01:00
|
|
|
case Text: {
|
|
|
|
int pixelIndex = (y * getWidth() + x);
|
2019-11-27 13:39:16 +01:00
|
|
|
unsigned char *ptr = reinterpret_cast<unsigned char *>(getPixelArea()) + pixelIndex / bitsPerPixel;
|
|
|
|
bool bit = static_cast<bool>(ptr[0] & (1 << (pixelIndex % bitsPerPixel)));
|
2019-12-01 19:56:35 +01:00
|
|
|
if (bit) {
|
2019-11-26 12:33:34 +01:00
|
|
|
color = reg->foreground_color;
|
2019-12-01 19:56:35 +01:00
|
|
|
} else {
|
|
|
|
color = reg->background_color;
|
2019-11-26 12:33:34 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TwoColors: {
|
|
|
|
int pixelIndex = (y * getWidth() + x);
|
2019-11-27 13:39:16 +01:00
|
|
|
unsigned char *ptr = reinterpret_cast<unsigned char *>(getPixelArea()) + (pixelIndex / bitsPerPixel);
|
|
|
|
bool bit = static_cast<bool>(ptr[0] & (1 << (pixelIndex % bitsPerPixel)));
|
2019-12-01 19:56:35 +01:00
|
|
|
if (bit) {
|
2019-11-26 12:33:34 +01:00
|
|
|
color = reg->foreground_color;
|
2019-12-01 19:56:35 +01:00
|
|
|
} else {
|
|
|
|
color = reg->background_color;
|
2019-11-26 12:33:34 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Gray_256: {
|
|
|
|
unsigned char *ptr = reinterpret_cast<unsigned char *>(getPixelArea()) + (y * getWidth() + x) * 1;
|
|
|
|
color = {ptr[0], ptr[0], ptr[0]};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case RGB: {
|
|
|
|
unsigned char *ptr = reinterpret_cast<unsigned char *>(getPixelArea()) + (y * getWidth() + x) * 3;
|
|
|
|
color = {ptr[0], ptr[1], ptr[2]};
|
|
|
|
break;
|
2019-11-21 11:35:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return color;
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto setText(std::string text) -> bool {
|
|
|
|
lockSharedMemory();
|
|
|
|
char *ptr = getTextArea();
|
2019-12-04 13:08:21 +01:00
|
|
|
for (int i = 0; i < static_cast<int>(text.size()); i++) {
|
2019-12-04 10:14:31 +01:00
|
|
|
if (i < getCharactersPerColumn() * getCharactersPerRow()) {
|
2019-12-01 19:56:35 +01:00
|
|
|
ptr[i] = text[i];
|
2019-11-06 13:41:24 +01:00
|
|
|
}
|
|
|
|
}
|
2019-12-01 19:56:35 +01:00
|
|
|
if (text.size() < getCharactersPerColumn() * getCharactersPerRow()) {
|
2019-11-13 13:37:49 +01:00
|
|
|
ptr[text.size()] = '\0';
|
2019-11-07 16:34:15 +01:00
|
|
|
}
|
2019-11-13 13:37:49 +01:00
|
|
|
unlockSharedMemory();
|
2019-12-04 10:14:31 +01:00
|
|
|
callEvent(EventType::RenderText);
|
2019-11-13 13:37:49 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto getText() -> std::string {
|
2019-12-05 09:49:54 +01:00
|
|
|
std::string text = getTextArea();
|
|
|
|
|
|
|
|
return text.substr(0, getCharactersPerColumn() * getCharactersPerRow());
|
2019-12-01 19:56:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto clearText() -> bool {
|
|
|
|
lockSharedMemory();
|
|
|
|
char *ptr = getTextArea();
|
2019-12-04 10:14:31 +01:00
|
|
|
for (int i = 0; i < getCharactersPerColumn() * getCharactersPerRow(); ++i) {
|
2019-12-01 19:56:35 +01:00
|
|
|
ptr[i] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
unlockSharedMemory();
|
2019-12-04 10:14:31 +01:00
|
|
|
callEvent(EventType::RenderText);
|
2019-12-01 19:56:35 +01:00
|
|
|
return true;
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getLayoutVersion() -> LayoutVersion {
|
|
|
|
return static_cast<LayoutVersion>(getRegisters()->layout_version);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto reset() -> void {
|
2019-12-08 19:06:16 +01:00
|
|
|
setDefaultValues();
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getWidth() -> int {
|
|
|
|
return getRegisters()->width_pixels;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto setWidth(int newValue) -> void {
|
|
|
|
lockSharedMemory();
|
|
|
|
getRegisters()->width_pixels = newValue;
|
|
|
|
unlockSharedMemory();
|
2019-12-04 13:08:21 +01:00
|
|
|
callEvent(EventType::UpdateControlRegisters);
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getHeight() -> int {
|
|
|
|
return getRegisters()->height_pixels;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto setHeight(int newValue) -> void {
|
|
|
|
lockSharedMemory();
|
|
|
|
getRegisters()->height_pixels = newValue;
|
|
|
|
unlockSharedMemory();
|
2019-12-04 13:08:21 +01:00
|
|
|
callEvent(EventType::UpdateControlRegisters);
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getMode() -> GraphicMode {
|
|
|
|
return getRegisters()->graphicMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto setMode(GraphicMode newValue) -> void {
|
|
|
|
lockSharedMemory();
|
2019-11-26 13:22:53 +01:00
|
|
|
auto reg = getRegisters();
|
2019-12-01 19:56:35 +01:00
|
|
|
if (reg->graphicMode != newValue) {
|
2019-11-26 13:22:53 +01:00
|
|
|
|
|
|
|
std::vector<Color> pixels;
|
|
|
|
int height = reg->height_pixels;
|
|
|
|
int width = reg->width_pixels;
|
|
|
|
pixels.resize(height * width);
|
|
|
|
|
2019-12-01 19:56:35 +01:00
|
|
|
for (int y = 0; y < height; y++) {
|
|
|
|
for (int x = 0; x < width; x++) {
|
|
|
|
pixels[y * width + x] = getPixel(x, y);
|
2019-11-26 13:22:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getRegisters()->graphicMode = newValue;
|
|
|
|
|
|
|
|
unlockSharedMemory();
|
2019-12-01 19:56:35 +01:00
|
|
|
for (int y = 0; y < height; y++) {
|
|
|
|
for (int x = 0; x < width; x++) {
|
|
|
|
setPixel(x, y, pixels[y * width + x]);
|
2019-11-26 13:22:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
lockSharedMemory();
|
2019-12-01 19:56:35 +01:00
|
|
|
} else {
|
2019-11-26 13:22:53 +01:00
|
|
|
reg->graphicMode = newValue;
|
|
|
|
}
|
2019-11-13 13:37:49 +01:00
|
|
|
unlockSharedMemory();
|
2019-12-04 13:08:21 +01:00
|
|
|
callEvent(EventType::UpdateControlRegisters);
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getRedrawInterval() -> int {
|
|
|
|
return getRegisters()->autoRedrawInterval;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto setRedrawInterval(int newValue) -> void {
|
|
|
|
lockSharedMemory();
|
|
|
|
getRegisters()->autoRedrawInterval = newValue;
|
|
|
|
unlockSharedMemory();
|
2019-12-04 13:08:21 +01:00
|
|
|
callEvent(EventType::UpdateControlRegisters);
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getTimerInterruptInterval() -> int {
|
|
|
|
return getRegisters()->timerInterruptInterval;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto setTimerInterruptInterval(int newValue) -> void {
|
|
|
|
lockSharedMemory();
|
|
|
|
getRegisters()->timerInterruptInterval = newValue;
|
|
|
|
unlockSharedMemory();
|
2019-12-04 13:08:21 +01:00
|
|
|
callEvent(EventType::UpdateControlRegisters);
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getBackgroundColor() -> Color {
|
|
|
|
return getRegisters()->background_color;
|
|
|
|
}
|
|
|
|
|
2019-11-27 13:39:16 +01:00
|
|
|
auto setBackgroundColor(const Color &newValue) -> void {
|
2019-11-13 13:37:49 +01:00
|
|
|
lockSharedMemory();
|
|
|
|
getRegisters()->background_color = newValue;
|
|
|
|
unlockSharedMemory();
|
2019-12-04 13:08:21 +01:00
|
|
|
callEvent(EventType::UpdateControlRegisters);
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getForegroundColor() -> Color {
|
|
|
|
return getRegisters()->foreground_color;
|
|
|
|
}
|
|
|
|
|
2019-11-27 13:39:16 +01:00
|
|
|
auto setForegroundColor(const Color &newValue) -> void {
|
2019-11-13 13:37:49 +01:00
|
|
|
lockSharedMemory();
|
|
|
|
getRegisters()->foreground_color = newValue;
|
|
|
|
unlockSharedMemory();
|
2019-12-04 13:08:21 +01:00
|
|
|
callEvent(EventType::UpdateControlRegisters);
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getCharactersPerRow() -> int {
|
|
|
|
return getRegisters()->characters_per_row;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto getCharactersPerColumn() -> int {
|
|
|
|
return getRegisters()->characters_per_column;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto getFont() -> FontType {
|
2019-12-11 13:03:50 +01:00
|
|
|
return FontType(getRegisters()->textMode_font);
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto setFont(const FontType &newValue) -> void {
|
|
|
|
lockSharedMemory();
|
2019-12-11 13:03:50 +01:00
|
|
|
getRegisters()->textMode_font = newValue;
|
2019-11-13 13:37:49 +01:00
|
|
|
unlockSharedMemory();
|
2019-12-04 13:08:21 +01:00
|
|
|
callEvent(EventType::UpdateControlRegisters);
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto getMousePosition() -> Coordinates {
|
|
|
|
return {getRegisters()->mouse_pos_x, getRegisters()->mouse_pos_y};
|
|
|
|
}
|
|
|
|
|
|
|
|
auto getLastPressedKey() -> KeyCode {
|
2019-11-26 11:49:19 +01:00
|
|
|
lockSharedMemory();
|
2019-11-27 13:39:16 +01:00
|
|
|
auto keyCode = KeyCode(0);
|
2019-11-26 11:49:19 +01:00
|
|
|
auto reg = getRegisters();
|
2020-01-07 11:40:47 +01:00
|
|
|
|
|
|
|
if(reg->keyboardBuffer_index_read >= reg->keyboardBuffer_index_write) {
|
|
|
|
auto code = reg->keyboardBuffer[(reg->keyboardBuffer_index_read) % keyboardBufferSize];
|
2019-12-11 13:03:50 +01:00
|
|
|
keyCode = KeyCode(code);
|
2020-01-07 10:54:25 +01:00
|
|
|
}else{
|
2020-01-07 11:40:47 +01:00
|
|
|
auto code = reg->keyboardBuffer[(reg->keyboardBuffer_index_read) % keyboardBufferSize];
|
|
|
|
keyCode = KeyCode(code);
|
2019-11-26 11:49:19 +01:00
|
|
|
}
|
2020-01-07 11:40:47 +01:00
|
|
|
|
2019-11-26 11:49:19 +01:00
|
|
|
unlockSharedMemory();
|
|
|
|
return keyCode;
|
2019-11-13 13:37:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|