summaryrefslogtreecommitdiff
path: root/app/controller/serial-controller.cc
diff options
context:
space:
mode:
authorHannes Schulze <hannes.hs.schulze@fau.de>2025-05-02 12:50:57 +0200
committerHannes Schulze <hannes.hs.schulze@fau.de>2025-05-02 12:50:57 +0200
commit24c521f5a4b9f2e1a98668e9d9f7b19b4c9a9bd7 (patch)
treea48ca9a718c719b30dae19a78b709874ca9b2bc5 /app/controller/serial-controller.cc
parentdef315971fccfe6a1a1743b3de62addd5f0527dc (diff)
add controller test program
Diffstat (limited to 'app/controller/serial-controller.cc')
-rw-r--r--app/controller/serial-controller.cc96
1 files changed, 96 insertions, 0 deletions
diff --git a/app/controller/serial-controller.cc b/app/controller/serial-controller.cc
new file mode 100644
index 0000000..8485ec4
--- /dev/null
+++ b/app/controller/serial-controller.cc
@@ -0,0 +1,96 @@
+#include "serial-controller.hh"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+namespace nes::app::test
+{
+ serial_controller::serial_controller(char const* path)
+ : path_{ path }
+ {
+ fd_ = open(path, O_RDONLY | O_NOCTTY | O_NDELAY | O_NONBLOCK);
+ if (fd_ == -1)
+ {
+ perror("serial_controller: open");
+ return;
+ }
+
+ if (!set_up()) { close(); }
+ }
+
+ serial_controller::~serial_controller()
+ {
+ close();
+ }
+
+ auto serial_controller::is_reliable() const -> bool
+ {
+ return fd_ != -1;
+ }
+
+ auto serial_controller::read_buttons() -> sys::button_mask
+ {
+ if (fd_ == -1) { return sys::button_mask{}; }
+
+ // Poll for any updates until we can't read anymore.
+ while (true)
+ {
+ auto buf = u8{};
+ auto const res = read(fd_, &buf, 1);
+ if (res == -1)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) { break; }
+
+ perror("read from controller");
+ close();
+ break;
+ }
+
+ current_ = sys::button_mask::from_raw_value(buf);
+ }
+
+ return current_;
+ }
+
+
+ auto serial_controller::set_up() -> bool
+ {
+ if (ioctl(fd_, TIOCEXCL) == -1)
+ {
+ perror("serial_controller: ioctl");
+ return false;
+ }
+
+ auto attr = termios{};
+ if (tcgetattr(fd_, &attr) == -1)
+ {
+ perror("serial_controller: tcgetattr");
+ return false;
+ }
+
+ cfsetispeed(&attr, B57600);
+ cfsetospeed(&attr, B57600);
+ attr.c_cflag = attr.c_cflag | CLOCAL | CREAD;
+ attr.c_cflag = (attr.c_cflag & static_cast<tcflag_t>(~CSIZE)) | CS8;
+
+ if (tcsetattr(fd_, TCSANOW, &attr) == -1)
+ {
+ perror("serial_controller: tcsetattr");
+ return false;
+ }
+
+ return true;
+ }
+
+ auto serial_controller::close() -> void
+ {
+ if (fd_ != -1)
+ {
+ ::close(fd_);
+ fd_ = -1;
+ }
+ }
+} // namespace nes::app::mac