diff --git a/components/peripheral/include/maix_key.hpp b/components/peripheral/include/maix_key.hpp index 62e2a2d2..b0b7fd7c 100755 --- a/components/peripheral/include/maix_key.hpp +++ b/components/peripheral/include/maix_key.hpp @@ -52,9 +52,9 @@ namespace maix::peripheral::key * callback will be called with args key(key.Keys) and value(key.State). * If set to null, you can get key value by read() function. * This callback called in a standalone thread, so you can block a while in callback, and you should be carefully when operate shared data. - * @param open auto open device in constructor, if false, you need call open() to open device - * @param device The key device to use. Default is "/dev/input/event0". - * Set it to "/dev/input/powerkey" to use the power key on the MaixCam-Pro. + * @param open auto open device in constructor, if false, you need call open() to open device. + * @param device Specifies the input device to use. The default initializes all keys, + * for a specific device, provide the path (e.g., "/dev/input/device"). * @param long_press_time The duration (in milliseconds) from pressing the key to triggering the long press event. Default is 2000ms. * @maixpy maix.peripheral.key.Key.__init__ * @maixcdk maix.peripheral.key.Key.Key @@ -113,7 +113,7 @@ namespace maix::peripheral::key int long_press_time(int press_time = -1); private: - int _fd; + std::vector _fds; std::string _device; std::function _callback; void *_data; diff --git a/components/peripheral/port/linux/maix_key.cpp b/components/peripheral/port/linux/maix_key.cpp index 50861431..967d268f 100755 --- a/components/peripheral/port/linux/maix_key.cpp +++ b/components/peripheral/port/linux/maix_key.cpp @@ -60,6 +60,7 @@ namespace maix::peripheral::key int long_press_time; bool read_thread_exit; bool read_thread_need_exit; + std::vector fds; Key *key; std::function callback; }; @@ -81,12 +82,16 @@ namespace maix::peripheral::key return; } ev.events = EPOLLIN; - ev.data.fd = data->fd; - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev) < 0) - { - data->read_thread_exit = true; - log::error("epoll_ctl add failed: %s", strerror(errno)); - return; + for (int fd : data->fds) { + if (fd > 0) { + ev.data.fd = fd; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { + log::error("epoll_ctl add failed for fd %d: %s", fd, strerror(errno)); + data->read_thread_exit = true; + close(epoll_fd); + return; + } + } } int fail_count = 0; while (!data->read_thread_need_exit && !app::need_exit()) @@ -94,6 +99,7 @@ namespace maix::peripheral::key int nfds = epoll_wait(epoll_fd, &ev, 1, 200); if (nfds > 0) { + data->fd = ev.data.fd; err::Err e = data->key->read(key, value); if (e == err::Err::ERR_NONE) { @@ -134,7 +140,6 @@ namespace maix::peripheral::key if(_key_defult_listener) rm_default_listener(); this->_callback = callback; - this->_fd = -1; this->_data = nullptr; this->_device = ""; Port_Data *data = new Port_Data(); @@ -185,37 +190,49 @@ namespace maix::peripheral::key err::Err Key::open() { - if (this->_fd > 0) + if (this->_fds.size()) { this->close(); } bool is_open = false; if(!this->_device.empty()) { - this->_fd = ::open(_device.c_str(), O_RDONLY); - if (this->_fd > 0) + int fd = ::open(_device.c_str(), O_RDONLY); + if (fd > 0) { + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + this->_fds.push_back(fd); is_open = true; + } } if(!is_open) { - this->_fd = ::open(KEY_DEVICE, O_RDONLY); - if (this->_fd < 0) + int fd = ::open(KEY_DEVICE, O_RDONLY); + if (fd < 0) { - this->_fd = ::open(KEY_DEVICE2, O_RDONLY); - if (this->_fd < 0) - { - return err::Err::ERR_NOT_FOUND; + std::vector key_devices = {{KEY_DEVICE2}}; + for (const auto& device : key_devices) { + int fd = ::open(device.c_str(), O_RDONLY); + if (fd == -1) { + log::error(("Failed to open device: " + device).c_str()); + this->_device = device; + return err::Err::ERR_NOT_FOUND; + } + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + this->_fds.push_back(fd); } + } else { + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + this->_fds.push_back(fd); } } - // set non-blocking - int flags = fcntl(this->_fd, F_GETFL, 0); - fcntl(this->_fd, F_SETFL, flags | O_NONBLOCK); if (this->_callback) { // new thread to read key Port_Data *data = (Port_Data *)this->_data; - data->fd = this->_fd; + data->fds = this->_fds; data->read_thread_exit = false; data->read_thread_need_exit = false; data->thread = new thread::Thread(_read_process, this->_data); @@ -226,14 +243,25 @@ namespace maix::peripheral::key err::Err Key::read(int &key, int &value) { - if (this->_fd < 0) + Port_Data *data = (Port_Data *)this->_data; + if (this->_fds.size() == 0) { return err::Err::ERR_NOT_OPEN; } struct input_event ev; + int ret; while (1) { - int ret = ::read(this->_fd, &ev, sizeof(struct input_event)); + if (this->_callback == nullptr) { + for (int fd : this->_fds) + { + ret = ::read(fd, &ev, sizeof(struct input_event)); + if (ret > 0 && ev.code != 0) + break; + } + } else { + ret = ::read(data->fd, &ev, sizeof(struct input_event)); + } if (ret < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK) @@ -277,22 +305,29 @@ namespace maix::peripheral::key { Port_Data *data = (Port_Data *)this->_data; data->read_thread_need_exit = true; - if (this->_fd > 0) + + bool err = false; + for (int &fd : this->_fds) { - int ret = ::close(this->_fd); - this->_fd = -1; - if (ret < 0) + if (fd > 0) { - return err::Err::ERR_IO; + int ret = ::close(fd); + if (ret < 0) + { + log::error("Failed to close fd %d: %s", fd, strerror(errno)); + err = true; + } + fd = -1; } } - this->_fd = -1; - return err::Err::ERR_NONE; + + this->_fds.clear(); + return err ? err::Err::ERR_IO : err::Err::ERR_NONE; } bool Key::is_opened() { - return this->_fd > 0; + return this->_fds.size() > 0; } int Key::long_press_time(int press_time) diff --git a/components/peripheral/port/maixcam/maix_key.cpp b/components/peripheral/port/maixcam/maix_key.cpp index dd1ed380..f997737b 100755 --- a/components/peripheral/port/maixcam/maix_key.cpp +++ b/components/peripheral/port/maixcam/maix_key.cpp @@ -70,6 +70,7 @@ namespace maix::peripheral::key bool read_thread_need_exit; bool powerkey_thread_exit; bool powerkey_thread_need_exit; + std::vector fds; Key *key; std::function callback; }; @@ -91,12 +92,16 @@ namespace maix::peripheral::key return; } ev.events = EPOLLIN; - ev.data.fd = data->fd; - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev) < 0) - { - data->read_thread_exit = true; - log::error("epoll_ctl add failed: %s", strerror(errno)); - return; + for (int fd : data->fds) { + if (fd > 0) { + ev.data.fd = fd; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { + log::error("epoll_ctl add failed for fd %d: %s", fd, strerror(errno)); + data->read_thread_exit = true; + close(epoll_fd); + return; + } + } } int fail_count = 0; while (!data->read_thread_need_exit && !app::need_exit()) @@ -104,6 +109,7 @@ namespace maix::peripheral::key int nfds = epoll_wait(epoll_fd, &ev, 1, 200); if (nfds > 0) { + data->fd = ev.data.fd; err::Err e = data->key->read(key, value); if (e == err::Err::ERR_NONE) { @@ -303,7 +309,6 @@ namespace maix::peripheral::key if(_key_defult_listener) rm_default_listener(); this->_callback = callback; - this->_fd = -1; this->_data = nullptr; this->_device = device; Port_Data *data = new Port_Data(); @@ -325,7 +330,9 @@ namespace maix::peripheral::key data->key = this; data->callback = callback; - if (sys::device_id() == "maixcam_pro" && !fs::exists(KEY_DEVICE1)) { + if (sys::device_id() == "maixcam_pro" && + !fs::exists(KEY_DEVICE1) && + (device == "" || device == KEY_DEVICE1)) { log::info("%s: Init pmu power key.", sys::device_name().c_str()); _init_power_key((void*)data); } @@ -382,38 +389,54 @@ namespace maix::peripheral::key err::Err Key::open() { - if (this->_fd > 0) + if (this->_fds.size()) { this->close(); } bool is_open = false; if(!this->_device.empty()) { - this->_fd = ::open(_device.c_str(), O_RDONLY); - if (this->_fd > 0) + int fd = ::open(_device.c_str(), O_RDONLY); + if (fd > 0) { + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + this->_fds.push_back(fd); is_open = true; + } } if(!is_open) { - this->_fd = ::open(KEY_DEVICE, O_RDONLY); - if (this->_fd < 0) + int fd = ::open(KEY_DEVICE, O_RDONLY); + if (fd < 0) { - this->_fd = ::open(KEY_DEVICE0, O_RDONLY); - if (this->_fd < 0) - { - this->_device = KEY_DEVICE0; - return err::Err::ERR_NOT_FOUND; + std::vector key_devices; + if (sys::device_id() == "maixcam_pro") { + key_devices = {KEY_DEVICE0, KEY_DEVICE1}; + } else { + key_devices = {KEY_DEVICE0}; + } + for (const auto& device : key_devices) { + int fd = ::open(device.c_str(), O_RDONLY); + if (fd == -1) { + log::error(("Failed to open device: " + device).c_str()); + this->_device = device; + return err::Err::ERR_NOT_FOUND; + } + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + this->_fds.push_back(fd); } + } else { + int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + this->_fds.push_back(fd); } } - // set non-blocking - int flags = fcntl(this->_fd, F_GETFL, 0); - fcntl(this->_fd, F_SETFL, flags | O_NONBLOCK); if (this->_callback) { // new thread to read key Port_Data *data = (Port_Data *)this->_data; - data->fd = this->_fd; + data->fds = this->_fds; data->read_thread_exit = false; data->read_thread_need_exit = false; data->thread = new thread::Thread(_read_process, this->_data); @@ -424,14 +447,25 @@ namespace maix::peripheral::key err::Err Key::read(int &key, int &value) { - if (this->_fd < 0) + Port_Data *data = (Port_Data *)this->_data; + if (this->_fds.size() == 0) { return err::Err::ERR_NOT_OPEN; } struct input_event ev; + int ret; while (1) { - int ret = ::read(this->_fd, &ev, sizeof(struct input_event)); + if (this->_callback == nullptr) { + for (int fd : this->_fds) + { + ret = ::read(fd, &ev, sizeof(struct input_event)); + if (ret > 0 && ev.code != 0) + break; + } + } else { + ret = ::read(data->fd, &ev, sizeof(struct input_event)); + } if (ret < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK) @@ -478,22 +512,29 @@ namespace maix::peripheral::key { Port_Data *data = (Port_Data *)this->_data; data->read_thread_need_exit = true; - if (this->_fd > 0) + + bool err = false; + for (int &fd : this->_fds) { - int ret = ::close(this->_fd); - this->_fd = -1; - if (ret < 0) + if (fd > 0) { - return err::Err::ERR_IO; + int ret = ::close(fd); + if (ret < 0) + { + log::error("Failed to close fd %d: %s", fd, strerror(errno)); + err = true; + } + fd = -1; } } - this->_fd = -1; - return err::Err::ERR_NONE; + + this->_fds.clear(); + return err ? err::Err::ERR_IO : err::Err::ERR_NONE; } bool Key::is_opened() { - return this->_fd > 0; + return this->_fds.size() > 0; } int Key::long_press_time(int press_time)