libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::LinuxGPIO Class Reference

基于 Linux GPIO character device uAPI 的 Linux GPIO 实现 Linux GPIO implementation based on the Linux GPIO character-device uAPI More...

#include <linux_gpio.hpp>

Inheritance diagram for LibXR::LinuxGPIO:
[legend]
Collaboration diagram for LibXR::LinuxGPIO:
[legend]

Public Member Functions

 LinuxGPIO (const std::string &chip_path, unsigned int line_offset)
 
 LinuxGPIO (const LinuxGPIO &)=delete
 
LinuxGPIOoperator= (const LinuxGPIO &)=delete
 
bool Read () override
 读取 GPIO 引脚状态。Reads the GPIO pin state.
 
void Write (bool value) override
 写入 GPIO 引脚状态。Writes the GPIO pin state.
 
ErrorCode EnableInterrupt () override
 使能 GPIO 引脚中断。Enables the GPIO pin interrupt.
 
ErrorCode DisableInterrupt () override
 禁用 GPIO 引脚中断。Disables the GPIO pin interrupt.
 
ErrorCode SetConfig (Configuration config) override
 配置 GPIO 引脚参数。Configures the GPIO pin settings.
 
- Public Member Functions inherited from LibXR::GPIO
 GPIO ()
 默认构造函数。Default constructor.
 
virtual ~GPIO ()=default
 虚析构函数。Virtual destructor.
 
ErrorCode RegisterCallback (Callback callback)
 注册 GPIO 事件回调函数。Registers a callback function for GPIO events.
 

Private Types

enum class  AbiVersion : uint8_t { UNKNOWN = 0 , V2 = 1 , V1 = 2 }
 
enum class  RequestKind : uint8_t { NONE = 0 , HANDLE = 1 , EVENT = 2 }
 

Private Member Functions

ErrorCode OpenChip ()
 
void CloseChip ()
 
void CloseRequest ()
 
ErrorCode InitInterruptWakePipe ()
 
void CloseInterruptWakePipe ()
 
void NotifyInterruptThread ()
 
void WaitForInterruptLoopIdle ()
 
void WaitForInterruptThreadStopped ()
 
ErrorCode DetectAbiVersion ()
 
ErrorCode ReopenRequest (Configuration config)
 
ErrorCode OpenRequestV2 (Configuration config)
 
ErrorCode ReconfigureRequestV2 (Configuration config)
 
ErrorCode OpenRequestV1 (Configuration config)
 
ErrorCode ReconfigureRequestV1 (Configuration config)
 
ErrorCode PumpEventQueue (int fd, AbiVersion abi_version, size_t &event_count, int timeout_ms) const
 
ErrorCode ReadEventsV2 (int fd, size_t &event_count) const
 
ErrorCode ReadEventsV1 (int fd, size_t &event_count) const
 
void StartInterruptThread ()
 
void InterruptLoop ()
 
ErrorCode EnsureConfigured () const
 
bool NeedsRequestReopen (Configuration config) const
 

Static Private Member Functions

static bool IsInterruptDirection (Direction direction)
 

Private Attributes

std::string chip_path_
 
unsigned int line_offset_ = 0U
 
int chip_fd_ = -1
 
std::atomic< int > request_fd_ {-1}
 
std::atomic< AbiVersion > abi_version_ {AbiVersion::UNKNOWN}
 
std::atomic< RequestKind > request_kind_ {RequestKind::NONE}
 
Configuration current_config_ = {Direction::INPUT, Pull::NONE}
 
bool has_config_ = false
 
std::atomic< bool > interrupt_enabled_ {false}
 
std::atomic< bool > interrupt_thread_started_ {false}
 
std::atomic< bool > interrupt_thread_exit_ {false}
 
std::atomic< bool > interrupt_poll_active_ {false}
 
Thread interrupt_thread_
 
int interrupt_wake_pipe_ [2] = {-1, -1}
 

Static Private Attributes

static constexpr size_t EVENT_BUFFER_CAPACITY = 64
 
static constexpr size_t INTERRUPT_THREAD_STACK_SIZE = 16384
 

Additional Inherited Members

- Public Types inherited from LibXR::GPIO
enum class  Direction : uint8_t {
  INPUT , OUTPUT_PUSH_PULL , OUTPUT_OPEN_DRAIN , FALL_INTERRUPT ,
  RISING_INTERRUPT , FALL_RISING_INTERRUPT
}
 定义 GPIO 引脚的方向类型。Defines the direction types for GPIO pins. More...
 
enum class  Pull : uint8_t { NONE , UP , DOWN }
 定义 GPIO 引脚的上拉/下拉模式。Defines the pull-up/pull-down configurations for GPIO pins. More...
 
using Callback = LibXR::Callback<>
 
- Data Fields inherited from LibXR::GPIO
Callback callback_
 GPIO 事件的回调函数。Callback function for GPIO events.
 

Detailed Description

基于 Linux GPIO character device uAPI 的 Linux GPIO 实现 Linux GPIO implementation based on the Linux GPIO character-device uAPI

Note
优先使用 GPIO chardev v2;旧内核仅在需要时回退到 v1。
Prefer GPIO chardev v2; fall back to v1 only on older kernels.
当前运行级验证聚焦在 chardev v2;v1 fallback 目前仅作为兼容路径保留。
Runtime validation currently focuses on chardev v2; the v1 fallback is kept as a compatibility path.

Definition at line 25 of file linux_gpio.hpp.

Member Enumeration Documentation

◆ AbiVersion

enum class LibXR::LinuxGPIO::AbiVersion : uint8_t
strongprivate

Definition at line 44 of file linux_gpio.hpp.

45 {
46 UNKNOWN = 0,
47 V2 = 1,
48 V1 = 2,
49 };

◆ RequestKind

enum class LibXR::LinuxGPIO::RequestKind : uint8_t
strongprivate

Definition at line 51 of file linux_gpio.hpp.

52 {
53 NONE = 0,
54 HANDLE = 1,
55 EVENT = 2,
56 };

Constructor & Destructor Documentation

◆ LinuxGPIO()

LibXR::LinuxGPIO::LinuxGPIO ( const std::string & chip_path,
unsigned int line_offset )

Definition at line 295 of file linux_gpio.cpp.

296 : chip_path_(chip_path), line_offset_(line_offset)
297{
298 UNUSED(InitInterruptWakePipe());
299 UNUSED(OpenChip());
300}

◆ ~LinuxGPIO()

LibXR::LinuxGPIO::~LinuxGPIO ( )
override

Definition at line 302 of file linux_gpio.cpp.

303{
304 interrupt_thread_exit_.store(true);
305 request_kind_.store(RequestKind::NONE);
306 interrupt_enabled_.store(false);
307 NotifyInterruptThread();
308 WaitForInterruptThreadStopped();
309 CloseRequest();
310 CloseChip();
311 CloseInterruptWakePipe();
312}

Member Function Documentation

◆ CloseChip()

void LibXR::LinuxGPIO::CloseChip ( )
private

Definition at line 587 of file linux_gpio.cpp.

588{
589 if (chip_fd_ >= 0)
590 {
591 close(chip_fd_);
592 chip_fd_ = -1;
593 }
594 abi_version_.store(AbiVersion::UNKNOWN);
595}

◆ CloseInterruptWakePipe()

void LibXR::LinuxGPIO::CloseInterruptWakePipe ( )
private

Definition at line 640 of file linux_gpio.cpp.

641{
642 for (int& fd : interrupt_wake_pipe_)
643 {
644 if (fd >= 0)
645 {
646 close(fd);
647 fd = -1;
648 }
649 }
650}

◆ CloseRequest()

void LibXR::LinuxGPIO::CloseRequest ( )
private

Definition at line 597 of file linux_gpio.cpp.

598{
599 request_kind_.store(RequestKind::NONE);
600 interrupt_enabled_.store(false);
601 NotifyInterruptThread();
602 WaitForInterruptLoopIdle();
603
604 const int request_fd = request_fd_.exchange(-1);
605 if (request_fd >= 0)
606 {
607 close(request_fd);
608 }
609
610 request_kind_.store(RequestKind::NONE);
611 interrupt_enabled_.store(false);
612 has_config_ = false;
613}

◆ DetectAbiVersion()

ErrorCode LibXR::LinuxGPIO::DetectAbiVersion ( )
private

Definition at line 724 of file linux_gpio.cpp.

725{
726 if (abi_version_.load() != AbiVersion::UNKNOWN)
727 {
728 return ErrorCode::OK;
729 }
730
731 gpiochip_info chip_info = {};
732 if (ioctl(chip_fd_, GPIO_GET_CHIPINFO_IOCTL, &chip_info) < 0)
733 {
734 XR_LOG_ERROR("Failed to read GPIO chip info: %s", std::strerror(errno));
735 return ErrorCode::FAILED;
736 }
737
738 if (chip_info.lines == 0U)
739 {
740 XR_LOG_ERROR("GPIO chip exposes zero lines");
741 return ErrorCode::FAILED;
742 }
743
744#if XR_LINUX_GPIO_HAS_V2
745 gpio_v2_line_info info = {};
746 info.offset = (line_offset_ < chip_info.lines) ? line_offset_ : 0U;
747 if (ioctl(chip_fd_, GPIO_V2_GET_LINEINFO_IOCTL, &info) == 0)
748 {
749 abi_version_.store(AbiVersion::V2);
750 return ErrorCode::OK;
751 }
752
753 if ((errno == ENOTTY) || (errno == EINVAL)
754#ifdef EOPNOTSUPP
755 || (errno == EOPNOTSUPP)
756#endif
757 )
758 {
759 abi_version_.store(AbiVersion::V1);
760 return ErrorCode::OK;
761 }
762
763 XR_LOG_ERROR("Failed to probe GPIO chardev ABI: %s", std::strerror(errno));
764 return ErrorCode::FAILED;
765#else
766 abi_version_.store(AbiVersion::V1);
767 return ErrorCode::OK;
768#endif
769}
@ FAILED
操作失败 | Operation failed
@ OK
操作成功 | Operation successful

◆ DisableInterrupt()

ErrorCode LibXR::LinuxGPIO::DisableInterrupt ( )
overridevirtual

禁用 GPIO 引脚中断。Disables the GPIO pin interrupt.

Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::GPIO.

Definition at line 423 of file linux_gpio.cpp.

424{
425 if (EnsureConfigured() != ErrorCode::OK)
426 {
428 }
429
430 if (!IsInterruptDirection(current_config_.direction))
431 {
432 return ErrorCode::ARG_ERR;
433 }
434
435 if (!interrupt_enabled_.load())
436 {
437 return ErrorCode::OK;
438 }
439
440 const Configuration inactive_config = ResolveRequestConfig(current_config_, false);
442 if (NeedsRequestReopen(inactive_config))
443 {
444 ec = ReopenRequest(inactive_config);
445 }
446 else if (abi_version_.load() == AbiVersion::V2)
447 {
448 ec = ReconfigureRequestV2(inactive_config);
449 }
450 else
451 {
452 ec = ReconfigureRequestV1(inactive_config);
453 }
454 if (ec != ErrorCode::OK)
455 {
456 return ec;
457 }
458
459 has_config_ = true;
460 interrupt_enabled_.store(false);
461 return ErrorCode::OK;
462}
ErrorCode
定义错误码枚举
@ STATE_ERR
状态错误 | State error
@ ARG_ERR
参数错误 | Argument error
Direction direction
GPIO 引脚方向。GPIO pin direction.
Definition gpio.hpp:47

◆ EnableInterrupt()

ErrorCode LibXR::LinuxGPIO::EnableInterrupt ( )
overridevirtual

使能 GPIO 引脚中断。Enables the GPIO pin interrupt.

Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::GPIO.

Definition at line 382 of file linux_gpio.cpp.

383{
384 if (EnsureConfigured() != ErrorCode::OK)
385 {
387 }
388
389 if (!IsInterruptDirection(current_config_.direction))
390 {
391 return ErrorCode::ARG_ERR;
392 }
393
394 if (interrupt_enabled_.load())
395 {
396 return ErrorCode::OK;
397 }
398
400 if (NeedsRequestReopen(current_config_))
401 {
402 ec = ReopenRequest(current_config_);
403 }
404 else if (abi_version_.load() == AbiVersion::V2)
405 {
406 ec = ReconfigureRequestV2(current_config_);
407 }
408 else
409 {
410 ec = ReconfigureRequestV1(current_config_);
411 }
412 if (ec != ErrorCode::OK)
413 {
414 return ec;
415 }
416
417 has_config_ = true;
418 interrupt_enabled_.store(true);
419 StartInterruptThread();
420 return ErrorCode::OK;
421}

◆ EnsureConfigured()

ErrorCode LibXR::LinuxGPIO::EnsureConfigured ( ) const
private

Definition at line 1058 of file linux_gpio.cpp.

1059{
1060 if (!has_config_ || (request_fd_.load() < 0))
1061 {
1062 XR_LOG_ERROR("GPIO is not configured");
1063 ASSERT(false);
1064 return ErrorCode::STATE_ERR;
1065 }
1066
1067 return ErrorCode::OK;
1068}

◆ InitInterruptWakePipe()

ErrorCode LibXR::LinuxGPIO::InitInterruptWakePipe ( )
private

Definition at line 615 of file linux_gpio.cpp.

616{
617 if (interrupt_wake_pipe_[0] >= 0)
618 {
619 return ErrorCode::OK;
620 }
621
622 if (pipe(interrupt_wake_pipe_) < 0)
623 {
624 XR_LOG_ERROR("Failed to create GPIO interrupt wake pipe: %s", std::strerror(errno));
625 return ErrorCode::INIT_ERR;
626 }
627
628 if ((SetNonBlocking(interrupt_wake_pipe_[0]) < 0) ||
629 (SetNonBlocking(interrupt_wake_pipe_[1]) < 0))
630 {
631 XR_LOG_ERROR("Failed to configure GPIO interrupt wake pipe: %s",
632 std::strerror(errno));
633 CloseInterruptWakePipe();
634 return ErrorCode::INIT_ERR;
635 }
636
637 return ErrorCode::OK;
638}
@ INIT_ERR
初始化错误 | Initialization error

◆ InterruptLoop()

void LibXR::LinuxGPIO::InterruptLoop ( )
private

Definition at line 522 of file linux_gpio.cpp.

523{
524 while (!interrupt_thread_exit_.load())
525 {
526 if (!interrupt_enabled_.load())
527 {
528 Thread::Sleep(1);
529 continue;
530 }
531
532 if (request_kind_.load() != RequestKind::EVENT)
533 {
534 Thread::Sleep(1);
535 continue;
536 }
537
538 const int fd = request_fd_.load();
539 if (fd < 0)
540 {
541 Thread::Sleep(1);
542 continue;
543 }
544
545 size_t event_count = 0;
546 interrupt_poll_active_.store(true);
547 const ErrorCode pump = PumpEventQueue(fd, abi_version_.load(), event_count, 100);
548 interrupt_poll_active_.store(false);
549 if (pump == ErrorCode::OK)
550 {
551 for (size_t i = 0; i < event_count; ++i)
552 {
553 callback_.Run(false);
554 }
555 continue;
556 }
557
558 if (pump != ErrorCode::EMPTY)
559 {
560 Thread::Sleep(1);
561 }
562 }
563
564 interrupt_poll_active_.store(false);
565 interrupt_thread_started_.store(false);
566}
Callback callback_
GPIO 事件的回调函数。Callback function for GPIO events.
Definition gpio.hpp:56
static void Sleep(uint32_t milliseconds)
让线程进入休眠状态 Puts the thread to sleep
Definition thread.cpp:15
@ EMPTY
为空 | Empty

◆ IsInterruptDirection()

bool LibXR::LinuxGPIO::IsInterruptDirection ( Direction direction)
staticprivate

Definition at line 1069 of file linux_gpio.cpp.

1070{
1071 return direction == Direction::RISING_INTERRUPT ||
1072 direction == Direction::FALL_INTERRUPT ||
1074}
@ RISING_INTERRUPT
上升沿中断模式。Rising edge interrupt mode.
@ FALL_RISING_INTERRUPT
双沿触发中断模式。Both edge interrupt mode.
@ FALL_INTERRUPT
下降沿中断模式。Falling edge interrupt mode.

◆ NeedsRequestReopen()

bool LibXR::LinuxGPIO::NeedsRequestReopen ( Configuration config) const
private

Definition at line 1076 of file linux_gpio.cpp.

1077{
1078 if (request_fd_.load() < 0)
1079 {
1080 return true;
1081 }
1082
1083 const bool old_interrupt =
1084 interrupt_enabled_.load() && IsInterruptDirection(current_config_.direction);
1085 const bool new_interrupt = IsInterruptDirection(config.direction);
1086
1087 if (abi_version_.load() == AbiVersion::V2)
1088 {
1089 return old_interrupt != new_interrupt;
1090 }
1091
1092 if (new_interrupt)
1093 {
1094 return true;
1095 }
1096
1097 if (old_interrupt)
1098 {
1099 return true;
1100 }
1101
1102 return request_kind_.load() != RequestKind::HANDLE;
1103}

◆ NotifyInterruptThread()

void LibXR::LinuxGPIO::NotifyInterruptThread ( )
private

Definition at line 652 of file linux_gpio.cpp.

653{
654 if (interrupt_wake_pipe_[1] < 0)
655 {
656 return;
657 }
658
659 const uint8_t signal = 1U;
660 while (true)
661 {
662 const ssize_t ret = write(interrupt_wake_pipe_[1], &signal, sizeof(signal));
663 if (ret >= 0)
664 {
665 return;
666 }
667
668 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
669 {
670 DrainInterruptWakeFd(interrupt_wake_pipe_[0]);
671 continue;
672 }
673
674 if (errno == EINTR)
675 {
676 continue;
677 }
678
679 return;
680 }
681}

◆ OpenChip()

ErrorCode LibXR::LinuxGPIO::OpenChip ( )
private

Definition at line 568 of file linux_gpio.cpp.

569{
570 if (chip_fd_ >= 0)
571 {
572 return ErrorCode::OK;
573 }
574
575 chip_fd_ = open(chip_path_.c_str(), O_RDONLY | O_CLOEXEC);
576 if (chip_fd_ < 0)
577 {
578 XR_LOG_ERROR("Failed to open GPIO chip: %s (%s)", chip_path_.c_str(),
579 std::strerror(errno));
580 ASSERT(false);
581 return ErrorCode::INIT_ERR;
582 }
583
584 return DetectAbiVersion();
585}

◆ OpenRequestV1()

ErrorCode LibXR::LinuxGPIO::OpenRequestV1 ( Configuration config)
private

Definition at line 855 of file linux_gpio.cpp.

856{
857 if (IsInterruptDirection(config.direction))
858 {
859 gpioevent_request request = {};
860 request.lineoffset = line_offset_;
861 request.handleflags = BuildHandleFlagsV1(config);
862 request.eventflags = BuildEventFlagsV1(config.direction);
863 CopyConsumer(request.consumer_label, LINUX_GPIO_CONSUMER);
864
865 if (ioctl(chip_fd_, GPIO_GET_LINEEVENT_IOCTL, &request) < 0)
866 {
867 XR_LOG_ERROR("Failed to request GPIO event line (v1): %s", std::strerror(errno));
868 return ErrorCode::FAILED;
869 }
870
871 request_fd_.store(request.fd);
872 request_kind_.store(RequestKind::EVENT);
873 }
874 else
875 {
876 gpiohandle_request request = {};
877 request.lineoffsets[0] = line_offset_;
878 request.lines = 1U;
879 request.flags = BuildHandleFlagsV1(config);
880 CopyConsumer(request.consumer_label, LINUX_GPIO_CONSUMER);
881
882 if (ioctl(chip_fd_, GPIO_GET_LINEHANDLE_IOCTL, &request) < 0)
883 {
884 XR_LOG_ERROR("Failed to request GPIO handle line (v1): %s", std::strerror(errno));
885 return ErrorCode::FAILED;
886 }
887
888 request_fd_.store(request.fd);
889 request_kind_.store(RequestKind::HANDLE);
890 }
891
892 if (SetNonBlocking(request_fd_.load()) < 0)
893 {
894 XR_LOG_ERROR("Failed to enable non-blocking GPIO request fd: %s",
895 std::strerror(errno));
896 CloseRequest();
897 return ErrorCode::FAILED;
898 }
899
900 return ErrorCode::OK;
901}

◆ OpenRequestV2()

ErrorCode LibXR::LinuxGPIO::OpenRequestV2 ( Configuration config)
private

Definition at line 783 of file linux_gpio.cpp.

784{
785#if XR_LINUX_GPIO_HAS_V2
786 gpio_v2_line_request request = {};
787 request.offsets[0] = line_offset_;
788 request.num_lines = 1U;
789 request.event_buffer_size =
790 IsInterruptDirection(config.direction) ? EVENT_BUFFER_CAPACITY : 0U;
791 CopyConsumer(request.consumer, LINUX_GPIO_CONSUMER);
792 request.config.flags = BuildLineFlagsV2(config);
793
794 if (ioctl(chip_fd_, GPIO_V2_GET_LINE_IOCTL, &request) < 0)
795 {
796 XR_LOG_ERROR("Failed to request GPIO line (v2): %s", std::strerror(errno));
797 return ErrorCode::FAILED;
798 }
799
800 request_fd_.store(request.fd);
801 request_kind_.store(IsInterruptDirection(config.direction) ? RequestKind::EVENT
802 : RequestKind::HANDLE);
803 if (SetNonBlocking(request.fd) < 0)
804 {
805 XR_LOG_ERROR("Failed to enable non-blocking GPIO request fd: %s",
806 std::strerror(errno));
807 CloseRequest();
808 return ErrorCode::FAILED;
809 }
810
811 return ErrorCode::OK;
812#else
813 (void)config;
814 ASSERT(false);
815 return ErrorCode::FAILED;
816#endif
817}

◆ PumpEventQueue()

ErrorCode LibXR::LinuxGPIO::PumpEventQueue ( int fd,
AbiVersion abi_version,
size_t & event_count,
int timeout_ms ) const
private

Definition at line 925 of file linux_gpio.cpp.

927{
928 if (fd < 0)
929 {
931 }
932
933 const PollReadableResult ready = PollReadable(fd, interrupt_wake_pipe_[0], timeout_ms);
934 if (ready == PollReadableResult::ERROR)
935 {
936 if (errno == EBADF)
937 {
938 return ErrorCode::EMPTY;
939 }
940 XR_LOG_ERROR("Failed to poll GPIO fd: %s", std::strerror(errno));
941 return ErrorCode::FAILED;
942 }
943
944 if ((ready == PollReadableResult::TIMEOUT) || (ready == PollReadableResult::WAKE))
945 {
946 return ErrorCode::EMPTY;
947 }
948
949 if (abi_version == AbiVersion::V2)
950 {
951 return ReadEventsV2(fd, event_count);
952 }
953
954 return ReadEventsV1(fd, event_count);
955}

◆ Read()

bool LibXR::LinuxGPIO::Read ( )
overridevirtual

读取 GPIO 引脚状态。Reads the GPIO pin state.

Returns
返回引脚状态,true 表示高电平,false 表示低电平。Returns the pin state, true for high, false for low.

Implements LibXR::GPIO.

Definition at line 314 of file linux_gpio.cpp.

315{
316 if (EnsureConfigured() != ErrorCode::OK)
317 {
318 return false;
319 }
320
321 const int request_fd = request_fd_.load();
322 if (abi_version_.load() == AbiVersion::V2)
323 {
324#if XR_LINUX_GPIO_HAS_V2
325 gpio_v2_line_values values = {};
326 values.mask = 1ULL;
327 if (ioctl(request_fd, GPIO_V2_LINE_GET_VALUES_IOCTL, &values) < 0)
328 {
329 XR_LOG_ERROR("Failed to read GPIO value: %s", std::strerror(errno));
330 return false;
331 }
332 return (values.bits & 1ULL) != 0U;
333#else
334 ASSERT(false);
335 return false;
336#endif
337 }
338
339 gpiohandle_data values = {};
340 if (ioctl(request_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &values) < 0)
341 {
342 XR_LOG_ERROR("Failed to read GPIO value: %s", std::strerror(errno));
343 return false;
344 }
345
346 return values.values[0] != 0U;
347}

◆ ReadEventsV1()

ErrorCode LibXR::LinuxGPIO::ReadEventsV1 ( int fd,
size_t & event_count ) const
private

Definition at line 1013 of file linux_gpio.cpp.

1014{
1015 bool received = false;
1016 while (true)
1017 {
1018 gpioevent_data event = {};
1019 const ssize_t bytes = read(fd, &event, sizeof(event));
1020 if (bytes < 0)
1021 {
1022 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
1023 {
1024 break;
1025 }
1026 if (errno == EBADF)
1027 {
1028 return received ? ErrorCode::OK : ErrorCode::EMPTY;
1029 }
1030
1031 XR_LOG_ERROR("Failed to read GPIO v1 events: %s", std::strerror(errno));
1032 return ErrorCode::FAILED;
1033 }
1034
1035 if (bytes == 0)
1036 {
1037 break;
1038 }
1039
1040 if (bytes != static_cast<ssize_t>(sizeof(event)))
1041 {
1042 XR_LOG_ERROR("Corrupted GPIO v1 event payload length");
1043 return ErrorCode::FAILED;
1044 }
1045
1046 if (!IsKnownGPIOEvent(event.id))
1047 {
1048 continue;
1049 }
1050
1051 ++event_count;
1052 received = true;
1053 }
1054
1055 return received ? ErrorCode::OK : ErrorCode::EMPTY;
1056}

◆ ReadEventsV2()

ErrorCode LibXR::LinuxGPIO::ReadEventsV2 ( int fd,
size_t & event_count ) const
private

Definition at line 957 of file linux_gpio.cpp.

958{
959#if XR_LINUX_GPIO_HAS_V2
960 bool received = false;
961 while (true)
962 {
963 std::array<gpio_v2_line_event, EVENT_BUFFER_CAPACITY> events = {};
964 const ssize_t bytes = read(fd, events.data(), sizeof(events));
965 if (bytes < 0)
966 {
967 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
968 {
969 break;
970 }
971 if (errno == EBADF)
972 {
973 return received ? ErrorCode::OK : ErrorCode::EMPTY;
974 }
975
976 XR_LOG_ERROR("Failed to read GPIO v2 events: %s", std::strerror(errno));
977 return ErrorCode::FAILED;
978 }
979
980 if (bytes == 0)
981 {
982 break;
983 }
984
985 if ((bytes % static_cast<ssize_t>(sizeof(gpio_v2_line_event))) != 0)
986 {
987 XR_LOG_ERROR("Corrupted GPIO v2 event payload length");
988 return ErrorCode::FAILED;
989 }
990
991 const size_t count = static_cast<size_t>(bytes / sizeof(gpio_v2_line_event));
992 for (size_t i = 0; i < count; ++i)
993 {
994 if (!IsKnownGPIOEvent(events[i].id))
995 {
996 continue;
997 }
998
999 ++event_count;
1000 received = true;
1001 }
1002 }
1003
1004 return received ? ErrorCode::OK : ErrorCode::EMPTY;
1005#else
1006 (void)fd;
1007 event_count = 0U;
1008 ASSERT(false);
1009 return ErrorCode::FAILED;
1010#endif
1011}

◆ ReconfigureRequestV1()

ErrorCode LibXR::LinuxGPIO::ReconfigureRequestV1 ( Configuration config)
private

Definition at line 903 of file linux_gpio.cpp.

904{
905 if (request_kind_.load() != RequestKind::HANDLE)
906 {
907 return ReopenRequest(config);
908 }
909
910#if XR_LINUX_GPIO_V1_HAS_SET_CONFIG
911 gpiohandle_config handle_config = {};
912 handle_config.flags = BuildHandleFlagsV1(config);
913 if (ioctl(request_fd_.load(), GPIOHANDLE_SET_CONFIG_IOCTL, &handle_config) < 0)
914 {
915 XR_LOG_ERROR("Failed to reconfigure GPIO line (v1): %s", std::strerror(errno));
916 return ErrorCode::FAILED;
917 }
918
919 return ErrorCode::OK;
920#else
921 return ReopenRequest(config);
922#endif
923}

◆ ReconfigureRequestV2()

ErrorCode LibXR::LinuxGPIO::ReconfigureRequestV2 ( Configuration config)
private

Definition at line 819 of file linux_gpio.cpp.

820{
821#if XR_LINUX_GPIO_HAS_V2
822 const bool was_interrupt_request =
823 (request_kind_.load() == RequestKind::EVENT) && interrupt_enabled_.load();
824 if (was_interrupt_request)
825 {
826 request_kind_.store(RequestKind::NONE);
827 interrupt_enabled_.store(false);
828 NotifyInterruptThread();
829 WaitForInterruptLoopIdle();
830 }
831
832 gpio_v2_line_config line_config = {};
833 line_config.flags = BuildLineFlagsV2(config);
834
835 if (ioctl(request_fd_.load(), GPIO_V2_LINE_SET_CONFIG_IOCTL, &line_config) < 0)
836 {
837 XR_LOG_ERROR("Failed to reconfigure GPIO line (v2): %s", std::strerror(errno));
838 return ErrorCode::FAILED;
839 }
840
841 request_kind_.store(IsInterruptDirection(config.direction) ? RequestKind::EVENT
842 : RequestKind::HANDLE);
843 if (was_interrupt_request && IsInterruptDirection(config.direction))
844 {
845 interrupt_enabled_.store(true);
846 }
847 return ErrorCode::OK;
848#else
849 (void)config;
850 ASSERT(false);
851 return ErrorCode::FAILED;
852#endif
853}

◆ ReopenRequest()

ErrorCode LibXR::LinuxGPIO::ReopenRequest ( Configuration config)
private

Definition at line 771 of file linux_gpio.cpp.

772{
773 CloseRequest();
774
775 if (abi_version_.load() == AbiVersion::V2)
776 {
777 return OpenRequestV2(config);
778 }
779
780 return OpenRequestV1(config);
781}

◆ SetConfig()

ErrorCode LibXR::LinuxGPIO::SetConfig ( Configuration config)
overridevirtual

配置 GPIO 引脚参数。Configures the GPIO pin settings.

Parameters
config需要应用的 GPIO 配置。The GPIO configuration to apply.
Returns
操作结果的错误码。Error code indicating the result of the operation.

Implements LibXR::GPIO.

Definition at line 464 of file linux_gpio.cpp.

465{
466 const ErrorCode chip_ready = OpenChip();
467 if (chip_ready != ErrorCode::OK)
468 {
469 return chip_ready;
470 }
471
472 const bool keep_interrupt_enabled =
473 interrupt_enabled_.load() && IsInterruptDirection(config.direction);
474 const Configuration request_config =
475 ResolveRequestConfig(config, keep_interrupt_enabled);
476
478 if (request_fd_.load() < 0)
479 {
480 ec = ReopenRequest(request_config);
481 }
482 else if (NeedsRequestReopen(request_config))
483 {
484 ec = ReopenRequest(request_config);
485 }
486 else if (abi_version_.load() == AbiVersion::V2)
487 {
488 ec = ReconfigureRequestV2(request_config);
489 }
490 else
491 {
492 ec = ReconfigureRequestV1(request_config);
493 }
494
495 if (ec != ErrorCode::OK)
496 {
497 return ec;
498 }
499
500 current_config_ = config;
501 has_config_ = true;
502 interrupt_enabled_.store(keep_interrupt_enabled);
503 if (keep_interrupt_enabled)
504 {
505 StartInterruptThread();
506 }
507 return ErrorCode::OK;
508}

◆ StartInterruptThread()

void LibXR::LinuxGPIO::StartInterruptThread ( )
private

Definition at line 510 of file linux_gpio.cpp.

511{
512 if (interrupt_thread_started_.exchange(true))
513 {
514 return;
515 }
516
517 interrupt_thread_.Create<LinuxGPIO*>(
518 this, [](LinuxGPIO* self) { self->InterruptLoop(); }, "irq_gpio",
519 INTERRUPT_THREAD_STACK_SIZE, Thread::Priority::MEDIUM);
520}
@ MEDIUM
中等优先级 Medium priority
void Create(ArgType arg, void(*function)(ArgType arg), const char *name, size_t stack_depth, Thread::Priority priority)
创建新线程 Creates a new thread
Definition thread.hpp:68

◆ WaitForInterruptLoopIdle()

void LibXR::LinuxGPIO::WaitForInterruptLoopIdle ( )
private

Definition at line 683 of file linux_gpio.cpp.

684{
685 if (!interrupt_thread_started_.load())
686 {
687 return;
688 }
689
690 for (uint32_t i = 0; i < 200; ++i)
691 {
692 if (!interrupt_poll_active_.load())
693 {
694 return;
695 }
696
697 Thread::Sleep(1);
698 }
699
700 XR_LOG_WARN("Timed out waiting for GPIO interrupt loop to go idle");
701}

◆ WaitForInterruptThreadStopped()

void LibXR::LinuxGPIO::WaitForInterruptThreadStopped ( )
private

Definition at line 703 of file linux_gpio.cpp.

704{
705 if (!interrupt_thread_started_.load())
706 {
707 return;
708 }
709
710 for (uint32_t i = 0; i < 500; ++i)
711 {
712 if (!interrupt_thread_started_.load())
713 {
714 return;
715 }
716
717 NotifyInterruptThread();
718 Thread::Sleep(1);
719 }
720
721 XR_LOG_WARN("Timed out waiting for GPIO interrupt thread to stop");
722}

◆ Write()

void LibXR::LinuxGPIO::Write ( bool value)
overridevirtual

写入 GPIO 引脚状态。Writes the GPIO pin state.

Parameters
value要写入的状态,true 表示高电平,false 表示低电平。The value to write, true for high, false for low.

Implements LibXR::GPIO.

Definition at line 349 of file linux_gpio.cpp.

350{
351 if (EnsureConfigured() != ErrorCode::OK)
352 {
353 return;
354 }
355
356 const int request_fd = request_fd_.load();
357 if (abi_version_.load() == AbiVersion::V2)
358 {
359#if XR_LINUX_GPIO_HAS_V2
360 gpio_v2_line_values values = {};
361 values.mask = 1ULL;
362 values.bits = value ? 1ULL : 0ULL;
363 if (ioctl(request_fd, GPIO_V2_LINE_SET_VALUES_IOCTL, &values) < 0)
364 {
365 XR_LOG_WARN("Failed to write GPIO value: %s", std::strerror(errno));
366 }
367 return;
368#else
369 ASSERT(false);
370 return;
371#endif
372 }
373
374 gpiohandle_data values = {};
375 values.values[0] = value ? 1U : 0U;
376 if (ioctl(request_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &values) < 0)
377 {
378 XR_LOG_WARN("Failed to write GPIO value: %s", std::strerror(errno));
379 }
380}

Field Documentation

◆ abi_version_

std::atomic<AbiVersion> LibXR::LinuxGPIO::abi_version_ {AbiVersion::UNKNOWN}
private

Definition at line 62 of file linux_gpio.hpp.

62{AbiVersion::UNKNOWN};

◆ chip_fd_

int LibXR::LinuxGPIO::chip_fd_ = -1
private

Definition at line 60 of file linux_gpio.hpp.

◆ chip_path_

std::string LibXR::LinuxGPIO::chip_path_
private

Definition at line 58 of file linux_gpio.hpp.

◆ current_config_

Configuration LibXR::LinuxGPIO::current_config_ = {Direction::INPUT, Pull::NONE}
private

Definition at line 64 of file linux_gpio.hpp.

@ INPUT
输入模式。Input mode.
@ NONE
无上拉或下拉。No pull-up or pull-down.

◆ EVENT_BUFFER_CAPACITY

size_t LibXR::LinuxGPIO::EVENT_BUFFER_CAPACITY = 64
staticconstexprprivate

Definition at line 41 of file linux_gpio.hpp.

◆ has_config_

bool LibXR::LinuxGPIO::has_config_ = false
private

Definition at line 65 of file linux_gpio.hpp.

◆ interrupt_enabled_

std::atomic<bool> LibXR::LinuxGPIO::interrupt_enabled_ {false}
private

Definition at line 66 of file linux_gpio.hpp.

66{false};

◆ interrupt_poll_active_

std::atomic<bool> LibXR::LinuxGPIO::interrupt_poll_active_ {false}
private

Definition at line 69 of file linux_gpio.hpp.

69{false};

◆ interrupt_thread_

Thread LibXR::LinuxGPIO::interrupt_thread_
private

Definition at line 70 of file linux_gpio.hpp.

◆ interrupt_thread_exit_

std::atomic<bool> LibXR::LinuxGPIO::interrupt_thread_exit_ {false}
private

Definition at line 68 of file linux_gpio.hpp.

68{false};

◆ INTERRUPT_THREAD_STACK_SIZE

size_t LibXR::LinuxGPIO::INTERRUPT_THREAD_STACK_SIZE = 16384
staticconstexprprivate

Definition at line 42 of file linux_gpio.hpp.

◆ interrupt_thread_started_

std::atomic<bool> LibXR::LinuxGPIO::interrupt_thread_started_ {false}
private

Definition at line 67 of file linux_gpio.hpp.

67{false};

◆ interrupt_wake_pipe_

int LibXR::LinuxGPIO::interrupt_wake_pipe_[2] = {-1, -1}
private

Definition at line 71 of file linux_gpio.hpp.

71{-1, -1};

◆ line_offset_

unsigned int LibXR::LinuxGPIO::line_offset_ = 0U
private

Definition at line 59 of file linux_gpio.hpp.

◆ request_fd_

std::atomic<int> LibXR::LinuxGPIO::request_fd_ {-1}
private

Definition at line 61 of file linux_gpio.hpp.

61{-1};

◆ request_kind_

std::atomic<RequestKind> LibXR::LinuxGPIO::request_kind_ {RequestKind::NONE}
private

Definition at line 63 of file linux_gpio.hpp.

63{RequestKind::NONE};

The documentation for this class was generated from the following files: