summaryrefslogtreecommitdiff
path: root/app/mac/impl/input-device-serial-controller.cc
diff options
context:
space:
mode:
Diffstat (limited to 'app/mac/impl/input-device-serial-controller.cc')
-rw-r--r--app/mac/impl/input-device-serial-controller.cc96
1 files changed, 96 insertions, 0 deletions
diff --git a/app/mac/impl/input-device-serial-controller.cc b/app/mac/impl/input-device-serial-controller.cc
new file mode 100644
index 0000000..7a493a7
--- /dev/null
+++ b/app/mac/impl/input-device-serial-controller.cc
@@ -0,0 +1,96 @@
+#include "impl/input-device-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::mac
+{
+ input_device_serial_controller::input_device_serial_controller(char const* path)
+ : path_{ path }
+ {
+ fd_ = open(path, O_RDONLY | O_NOCTTY | O_NDELAY | O_NONBLOCK);
+ if (fd_ == -1)
+ {
+ perror("input_device_serial_controller: open");
+ return;
+ }
+
+ if (!set_up()) { close(); }
+ }
+
+ input_device_serial_controller::~input_device_serial_controller()
+ {
+ close();
+ }
+
+ auto input_device_serial_controller::is_reliable() const -> bool
+ {
+ return fd_ != -1;
+ }
+
+ auto input_device_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 input_device_serial_controller::set_up() -> bool
+ {
+ if (ioctl(fd_, TIOCEXCL) == -1)
+ {
+ perror("input_device_serial_controller: ioctl");
+ return false;
+ }
+
+ auto attr = termios{};
+ if (tcgetattr(fd_, &attr) == -1)
+ {
+ perror("input_device_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("input_device_serial_controller: tcsetattr");
+ return false;
+ }
+
+ return true;
+ }
+
+ auto input_device_serial_controller::close() -> void
+ {
+ if (fd_ != -1)
+ {
+ ::close(fd_);
+ fd_ = -1;
+ }
+ }
+} // namespace nes::app::mac \ No newline at end of file