1 // Copyright 2021 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include "pw_assert/check.h" 17 #include "pw_digital_io/internal/conversions.h" 18 #include "pw_function/function.h" 19 #include "pw_result/result.h" 20 #include "pw_status/status.h" 21 #include "pw_status/try.h" 22 23 namespace pw::digital_io { 24 25 // The logical state of a digital line. 26 enum class State : bool { 27 kActive = true, 28 kInactive = false, 29 }; 30 31 // The triggering configuration for an interrupt handler. 32 enum class InterruptTrigger : int { 33 // Trigger on transition from kInactive to kActive. 34 kActivatingEdge, 35 // Trigger on transition from kActive to kInactive. 36 kDeactivatingEdge, 37 // Trigger on any state transition between kActive and kInactive. 38 kBothEdges, 39 }; 40 41 // Interrupt handling function. The argument contains the latest known state of 42 // the line. It is backend-specific if, when, and how this state is updated. 43 using InterruptHandler = ::pw::Function<void(State sampled_state)>; 44 45 /// A digital I/O line that may support input, output, and interrupts, but makes 46 /// no guarantees about whether any operations are supported. You must check the 47 /// various `provides_*` flags before calling optional methods. Unsupported 48 /// methods invoke `PW_CRASH`. 49 /// 50 /// All methods are potentially blocking. Unless otherwise specified, access 51 /// from multiple threads to a single line must be externally synchronized - for 52 /// example using `pw::Borrowable`. Unless otherwise specified, none of the 53 /// methods are safe to call from an interrupt handler. Therefore, this 54 /// abstraction may not be suitable for bitbanging and other low-level uses of 55 /// GPIO. 56 /// 57 /// Note that the initial state of a line is not guaranteed to be consistent 58 /// with either the "enabled" or "disabled" state. Users of the API who need to 59 /// ensure the line is disabled (ex. output not driving the line) should call 60 /// `Disable()`. 61 /// 62 /// This class should almost never be used in APIs directly. Instead, use one of 63 /// the derived classes that explicitly supports the functionality that your 64 /// API needs. 65 /// 66 /// This class cannot be extended directly. Instead, extend one of the 67 /// derived classes that explicitly support the functionality that you want to 68 /// implement. 69 class DigitalIoOptional { 70 public: 71 virtual ~DigitalIoOptional() = default; 72 73 /// @returns `true` if input (getting state) is supported. provides_input()74 constexpr bool provides_input() const { return config_.input; } 75 /// @returns `true` if output (setting state) is supported. provides_output()76 constexpr bool provides_output() const { return config_.output; } 77 /// @returns `true` if interrupt handlers can be registered. provides_interrupt()78 constexpr bool provides_interrupt() const { return config_.interrupt; } 79 80 /// Gets the state of the line. 81 /// 82 /// @warning This method is not thread-safe and cannot be used in interrupt 83 /// handlers. 84 /// 85 /// @returns @rst 86 /// 87 /// .. pw-status-codes:: 88 /// 89 /// OK: Returns an active or inactive state. 90 /// 91 /// FAILED_PRECONDITION: The line has not been enabled. 92 /// 93 /// Returns Other status codes as defined by the backend. 94 /// 95 /// @endrst GetState()96 Result<State> GetState() { return DoGetState(); } 97 98 /// Sets the state of the line. 99 /// 100 /// Callers are responsible to wait for the voltage level to settle after this 101 /// call returns. 102 /// 103 /// @warning This method is not thread-safe and cannot be used in interrupt 104 /// handlers. 105 /// 106 /// @returns @rst 107 /// 108 /// .. pw-status-codes:: 109 /// 110 /// OK: The state has been set. 111 /// 112 /// FAILED_PRECONDITION: The line has not been enabled. 113 /// 114 /// Returns other status codes as defined by the backend. 115 /// 116 /// @endrst SetState(State state)117 Status SetState(State state) { return DoSetState(state); } 118 119 /// Checks if the line is in the active state. 120 /// 121 /// The line is in the active state when `GetState()` returns 122 /// `State::kActive`. 123 /// 124 /// @warning This method is not thread-safe and cannot be used in interrupt 125 /// handlers. 126 /// 127 /// @returns @rst 128 /// 129 /// .. pw-status-codes:: 130 /// 131 /// OK: ``true`` if the line is in the active state, otherwise ``false``. 132 /// 133 /// FAILED_PRECONDITION: The line has not been enabled. 134 /// 135 /// Returns other status codes as defined by the backend. 136 /// 137 /// @endrst IsStateActive()138 Result<bool> IsStateActive() { 139 PW_TRY_ASSIGN(const State state, GetState()); 140 return state == State::kActive; 141 } 142 143 /// Sets the line to the active state. Equivalent to 144 /// `SetState(State::kActive)`. 145 /// 146 /// Callers are responsible to wait for the voltage level to settle after this 147 /// call returns. 148 /// 149 /// @warning This method is not thread-safe and cannot be used in interrupt 150 /// handlers. 151 /// 152 /// @returns @rst 153 /// 154 /// .. pw-status-codes:: 155 /// 156 /// OK: The state has been set. 157 /// 158 /// FAILED_PRECONDITION: The line has not been enabled. 159 /// 160 /// Returns other status codes as defined by the backend. 161 /// 162 /// @endrst SetStateActive()163 Status SetStateActive() { return SetState(State::kActive); } 164 165 /// Sets the line to the inactive state. Equivalent to 166 /// `SetState(State::kInactive)`. 167 /// 168 /// Callers are responsible to wait for the voltage level to settle after 169 /// this call returns. 170 /// 171 /// @warning This method is not thread-safe and cannot be used in interrupt 172 /// handlers. 173 /// 174 /// @returns @rst 175 /// 176 /// .. pw-status-codes:: 177 /// 178 /// OK: The state has been set. 179 /// 180 /// FAILED_PRECONDITION: The line has not been enabled. 181 /// 182 /// Returns other status codes as defined by the backend. 183 /// 184 /// @endrst SetStateInactive()185 Status SetStateInactive() { return SetState(State::kInactive); } 186 187 /// Sets an interrupt handler to execute when an interrupt is triggered, and 188 /// configures the condition for triggering the interrupt. 189 /// 190 /// The handler is executed in a backend-specific context—this may be a 191 /// system interrupt handler or a shared notification thread. Do not do any 192 /// blocking or expensive work in the handler. The only universally safe 193 /// operations are the IRQ-safe functions on `pw_sync` primitives. 194 /// 195 /// In particular, it is NOT safe to get the state of a `DigitalIo` 196 /// line—either from this line or any other `DigitalIoOptional` 197 /// instance—inside the handler. 198 /// 199 /// @warning This method is not thread-safe and cannot be used in interrupt 200 /// handlers. 201 /// 202 /// @pre No handler is currently set. 203 /// 204 /// @returns @rst 205 /// 206 /// .. pw-status-codes:: 207 /// 208 /// OK: The interrupt handler was configured. 209 /// 210 /// INVALID_ARGUMENT: The handler is empty. 211 /// 212 /// Returns other status codes as defined by the backend. 213 /// 214 /// @endrst SetInterruptHandler(InterruptTrigger trigger,InterruptHandler && handler)215 Status SetInterruptHandler(InterruptTrigger trigger, 216 InterruptHandler&& handler) { 217 if (handler == nullptr) { 218 return Status::InvalidArgument(); 219 } 220 return DoSetInterruptHandler(trigger, std::move(handler)); 221 } 222 223 /// Clears the interrupt handler and disables any existing interrupts that 224 /// are enabled. 225 /// 226 /// @warning This method is not thread-safe and cannot be used in interrupt 227 /// handlers. 228 /// 229 /// @returns @rst 230 /// 231 /// .. pw-status-codes:: 232 /// 233 /// OK: The interrupt handler was cleared. 234 /// 235 /// Returns other status codes as defined by the backend. 236 /// 237 /// @endrst ClearInterruptHandler()238 Status ClearInterruptHandler() { 239 PW_TRY(DisableInterruptHandler()); 240 return DoSetInterruptHandler(InterruptTrigger::kActivatingEdge, nullptr); 241 } 242 243 /// Enables interrupts which will trigger the interrupt handler. 244 /// 245 /// @warning This method is not thread-safe and cannot be used in interrupt 246 /// handlers. 247 /// 248 /// @pre A handler has been set using `SetInterruptHandler()`. 249 /// 250 /// @returns @rst 251 /// 252 /// .. pw-status-codes:: 253 /// 254 /// OK: The interrupt handler was configured. 255 /// 256 /// FAILED_PRECONDITION: The line has not been enabled. 257 /// 258 /// Returns other status codes as defined by the backend. 259 /// 260 /// @endrst EnableInterruptHandler()261 Status EnableInterruptHandler() { return DoEnableInterruptHandler(true); } 262 263 /// Disables the interrupt handler. This is a no-op if interrupts are 264 /// disabled. 265 /// 266 /// This method can be called inside the interrupt handler for this line 267 /// without any external synchronization. However, the exact behavior is 268 /// backend-specific. There may be queued events that will trigger the handler 269 /// again after this call returns. 270 /// 271 /// @returns @rst 272 /// 273 /// .. pw-status-codes:: 274 /// 275 /// OK: The interrupt handler was disabled. 276 /// 277 /// Returns other status codes as defined by the backend. 278 /// 279 /// @endrst DisableInterruptHandler()280 Status DisableInterruptHandler() { return DoEnableInterruptHandler(false); } 281 282 /// Enables the line to initialize it into the default state as determined by 283 /// the backend. 284 /// 285 /// This may enable pull-up/down resistors, drive the line high/low, etc. 286 /// The line must be enabled before getting/setting the state or enabling 287 /// interrupts. Callers are responsible for waiting for the voltage level to 288 /// settle after this call returns. 289 /// 290 /// @warning This method is not thread-safe and cannot be used in interrupt 291 /// handlers. 292 /// 293 /// @returns @rst 294 /// 295 /// .. pw-status-codes:: 296 /// 297 /// OK: The line is enabled and ready for use. 298 /// 299 /// Returns other status codes as defined by the backend. 300 /// 301 /// @endrst Enable()302 Status Enable() { return DoEnable(true); } 303 304 /// Disables the line to power down any pull-up/down resistors and disconnect 305 /// from any voltage sources. 306 /// 307 /// This is usually done to save power. Interrupt handlers are automatically 308 /// disabled. 309 /// 310 /// @warning This method is not thread-safe and cannot be used in interrupt 311 /// handlers. 312 /// 313 /// @returns @rst 314 /// 315 /// .. pw-status-codes:: 316 /// 317 /// OK: The line is disabled. 318 /// 319 /// Returns other status codes as defined by the backend. 320 /// 321 /// @endrst Disable()322 Status Disable() { 323 if (provides_interrupt()) { 324 PW_TRY(DisableInterruptHandler()); 325 } 326 return DoEnable(false); 327 } 328 329 private: 330 friend class DigitalInterrupt; 331 friend class DigitalIn; 332 friend class DigitalInInterrupt; 333 friend class DigitalOut; 334 friend class DigitalOutInterrupt; 335 friend class DigitalInOut; 336 friend class DigitalInOutInterrupt; 337 338 // Private constructor so that only friends can extend us. DigitalIoOptional(internal::Provides config)339 constexpr DigitalIoOptional(internal::Provides config) : config_(config) {} 340 341 /// Enables the line to initialize it into the default state as determined by 342 /// the backend or disables the line to power down any pull-up/down resistors 343 /// and disconnect from any voltage sources. 344 /// 345 /// This may enable pull-up/down resistors, drive the line high/low, etc. 346 /// The line must be enabled before getting/setting the state or enabling 347 /// interrupts. Callers are responsible for waiting for the voltage level to 348 /// settle after this call returns. 349 /// 350 /// Calling DoEnable(true) on an already-enabled line should be a no-op, it 351 /// shouldn't reset the line back to the "default state". 352 /// 353 /// Calling DoEnable(false) should force the line into the disabled state, 354 /// If the line was not initialized at object construction time. 355 /// 356 /// @pre This method cannot be used in interrupt contexts. 357 /// @pre When disabling, the interrupt handler must already be disabled. 358 /// 359 /// @returns @rst 360 /// 361 /// .. pw-status-codes:: 362 /// 363 /// OK: The line is enabled and ready for use. 364 /// 365 /// Returns other status codes as defined by the backend. 366 /// 367 /// @endrst 368 virtual Status DoEnable(bool enable) = 0; 369 370 /// Gets the state of the line. 371 /// 372 /// @pre This method cannot be used in interrupt contexts. 373 /// 374 /// @returns @rst 375 /// 376 /// .. pw-status-codes:: 377 /// 378 /// OK: An active or inactive state. 379 /// 380 /// FAILED_PRECONDITION: The line has not been enabled. 381 /// 382 /// Returns other status codes as defined by the backend. 383 /// 384 /// @endrst 385 virtual Result<State> DoGetState() = 0; 386 387 /// Sets the state of the line. 388 /// 389 /// Callers are responsible to wait for the voltage level to settle after this 390 /// call returns. 391 /// 392 /// @pre This method cannot be used in interrupt contexts. 393 /// 394 /// @returns @rst 395 /// 396 /// .. pw-status-codes:: 397 /// 398 /// OK: The state has been set. 399 /// 400 /// FAILED_PRECONDITION: The line has not been enabled. 401 /// 402 /// Returns other status codes as defined by the backend. 403 /// 404 /// @endrst 405 virtual Status DoSetState(State level) = 0; 406 407 /// Sets or clears an interrupt handler to execute when an interrupt is 408 /// triggered, and configures the condition for triggering the interrupt. 409 /// 410 /// The handler is executed in a backend-specific context—this may be a 411 /// system interrupt handler or a shared notification thread. 412 /// 413 /// The implementation is expected to provide the handler the last known state 414 /// of the input. The intention is to either sample the current state and 415 /// provide that or if not possible provide the state which triggerred the 416 /// interrupt (e.g. active for activating edge, and inactive for deactivating 417 /// edge). 418 /// 419 /// The handler is cleared by passing an empty handler, this can be checked by 420 /// comparing the handler to a nullptr. The implementation must guarantee that 421 /// the handler is not currently executing and (and will never execute again) 422 /// after returning from DoSetInterruptHandler(_, nullptr). 423 /// 424 /// @pre This method cannot be used in interrupt contexts. 425 /// @pre If setting a handler, no handler is permitted to be currently set. 426 /// @pre When cleaing a handler, the interrupt handler must be disabled. 427 /// 428 /// @returns @rst 429 /// 430 /// .. pw-status-codes:: 431 /// 432 /// OK: The interrupt handler was configured. 433 /// 434 /// Returns other status codes as defined by the backend. 435 /// 436 /// @endrst 437 virtual Status DoSetInterruptHandler(InterruptTrigger trigger, 438 InterruptHandler&& handler) = 0; 439 440 /// Enables or disables interrupts which will trigger the interrupt handler. 441 /// 442 /// @warning This interrupt handler disabling must be both thread-safe and, 443 /// interrupt-safe, however enabling is not interrupt-safe and not 444 /// thread-safe. 445 /// 446 /// @pre When enabling, a handler must have been set using 447 /// `DoSetInterruptHandler()`. 448 /// @pre Interrupt handler enabling cannot be used in interrupt contexts. 449 /// 450 /// @returns @rst 451 /// 452 /// .. pw-status-codes:: 453 /// 454 /// OK: The interrupt handler was configured. 455 /// 456 /// FAILED_PRECONDITION: The line has not been enabled. 457 /// 458 /// Returns other status codes as defined by the backend. 459 /// 460 /// @endrst 461 virtual Status DoEnableInterruptHandler(bool enable) = 0; 462 463 // The configuration of this line. 464 const internal::Provides config_; 465 }; 466 467 // A digital I/O line that supports only interrupts. 468 // 469 // The input and output methods are hidden and must not be called. 470 // 471 // Use this class in APIs when only interrupt functionality is required. 472 // Extend this class to implement a line that only supports interrupts. 473 // 474 class DigitalInterrupt 475 : public DigitalIoOptional, 476 public internal::Conversions<DigitalInterrupt, DigitalIoOptional> { 477 public: 478 // Available functionality 479 using DigitalIoOptional::ClearInterruptHandler; 480 using DigitalIoOptional::DisableInterruptHandler; 481 using DigitalIoOptional::EnableInterruptHandler; 482 using DigitalIoOptional::SetInterruptHandler; 483 484 protected: DigitalInterrupt()485 constexpr DigitalInterrupt() 486 : DigitalIoOptional(internal::AlwaysProvidedBy<DigitalInterrupt>()) {} 487 488 private: 489 // Unavailable functionality 490 using DigitalIoOptional::provides_input; 491 using DigitalIoOptional::provides_interrupt; 492 using DigitalIoOptional::provides_output; 493 494 using DigitalIoOptional::GetState; 495 using DigitalIoOptional::IsStateActive; 496 using DigitalIoOptional::SetState; 497 using DigitalIoOptional::SetStateActive; 498 using DigitalIoOptional::SetStateInactive; 499 500 // These overrides invoke PW_CRASH. 501 Status DoSetState(State) final; 502 Result<State> DoGetState() final; 503 }; 504 505 // A digital I/O line that supports only input (getting state). 506 // 507 // The output and interrupt methods are hidden and must not be called. 508 // 509 // Use this class in APIs when only input functionality is required. 510 // Extend this class to implement a line that only supports getting state. 511 // 512 class DigitalIn : public DigitalIoOptional, 513 public internal::Conversions<DigitalIn, DigitalIoOptional> { 514 public: 515 // Available functionality 516 using DigitalIoOptional::GetState; 517 using DigitalIoOptional::IsStateActive; 518 519 protected: DigitalIn()520 constexpr DigitalIn() 521 : DigitalIoOptional(internal::AlwaysProvidedBy<DigitalIn>()) {} 522 523 private: 524 // Unavailable functionality 525 using DigitalIoOptional::provides_input; 526 using DigitalIoOptional::provides_interrupt; 527 using DigitalIoOptional::provides_output; 528 529 using DigitalIoOptional::ClearInterruptHandler; 530 using DigitalIoOptional::DisableInterruptHandler; 531 using DigitalIoOptional::EnableInterruptHandler; 532 using DigitalIoOptional::SetInterruptHandler; 533 using DigitalIoOptional::SetState; 534 using DigitalIoOptional::SetStateActive; 535 using DigitalIoOptional::SetStateInactive; 536 537 // These overrides invoke PW_CRASH. 538 Status DoSetState(State) final; 539 Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) final; 540 Status DoEnableInterruptHandler(bool) final; 541 }; 542 543 // An input line that supports interrupts. 544 // 545 // The output methods are hidden and must not be called. 546 // 547 // Use in APIs when input and interrupt functionality is required. 548 // 549 // Extend this class to implement a line that supports input (getting state) and 550 // listening for interrupts at the same time. 551 // 552 class DigitalInInterrupt 553 : public DigitalIoOptional, 554 public internal::Conversions<DigitalInInterrupt, DigitalIoOptional> { 555 public: 556 // Available functionality 557 using DigitalIoOptional::ClearInterruptHandler; 558 using DigitalIoOptional::DisableInterruptHandler; 559 using DigitalIoOptional::EnableInterruptHandler; 560 using DigitalIoOptional::GetState; 561 using DigitalIoOptional::IsStateActive; 562 using DigitalIoOptional::SetInterruptHandler; 563 564 protected: DigitalInInterrupt()565 constexpr DigitalInInterrupt() 566 : DigitalIoOptional(internal::AlwaysProvidedBy<DigitalInInterrupt>()) {} 567 568 private: 569 // Unavailable functionality 570 using DigitalIoOptional::provides_input; 571 using DigitalIoOptional::provides_interrupt; 572 using DigitalIoOptional::provides_output; 573 574 using DigitalIoOptional::SetState; 575 using DigitalIoOptional::SetStateActive; 576 using DigitalIoOptional::SetStateInactive; 577 578 // These overrides invoke PW_CRASH. 579 Status DoSetState(State) final; 580 }; 581 582 // A digital I/O line that supports only output (setting state). 583 // 584 // Input and interrupt functions are hidden and must not be called. 585 // 586 // Use in APIs when only output functionality is required. 587 // Extend this class to implement a line that supports output only. 588 // 589 class DigitalOut : public DigitalIoOptional, 590 public internal::Conversions<DigitalOut, DigitalIoOptional> { 591 public: 592 // Available functionality 593 using DigitalIoOptional::SetState; 594 using DigitalIoOptional::SetStateActive; 595 using DigitalIoOptional::SetStateInactive; 596 597 protected: DigitalOut()598 constexpr DigitalOut() 599 : DigitalIoOptional(internal::AlwaysProvidedBy<DigitalOut>()) {} 600 601 private: 602 // Unavailable functionality 603 using DigitalIoOptional::provides_input; 604 using DigitalIoOptional::provides_interrupt; 605 using DigitalIoOptional::provides_output; 606 607 using DigitalIoOptional::ClearInterruptHandler; 608 using DigitalIoOptional::DisableInterruptHandler; 609 using DigitalIoOptional::EnableInterruptHandler; 610 using DigitalIoOptional::GetState; 611 using DigitalIoOptional::IsStateActive; 612 using DigitalIoOptional::SetInterruptHandler; 613 614 // These overrides invoke PW_CRASH. 615 Result<State> DoGetState() final; 616 Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) final; 617 Status DoEnableInterruptHandler(bool) final; 618 }; 619 620 // A digital I/O line that supports output and interrupts. 621 // 622 // Input methods are hidden and must not be called. 623 // 624 // Use in APIs when output and interrupt functionality is required. For 625 // example, to represent a two-way signalling line. 626 // 627 // Extend this class to implement a line that supports both output and 628 // listening for interrupts at the same time. 629 // 630 class DigitalOutInterrupt 631 : public DigitalIoOptional, 632 public internal::Conversions<DigitalOutInterrupt, DigitalIoOptional> { 633 public: 634 // Available functionality 635 using DigitalIoOptional::ClearInterruptHandler; 636 using DigitalIoOptional::DisableInterruptHandler; 637 using DigitalIoOptional::EnableInterruptHandler; 638 using DigitalIoOptional::SetInterruptHandler; 639 using DigitalIoOptional::SetState; 640 using DigitalIoOptional::SetStateActive; 641 using DigitalIoOptional::SetStateInactive; 642 643 protected: DigitalOutInterrupt()644 constexpr DigitalOutInterrupt() 645 : DigitalIoOptional(internal::AlwaysProvidedBy<DigitalOutInterrupt>()) {} 646 647 private: 648 // Unavailable functionality 649 using DigitalIoOptional::provides_input; 650 using DigitalIoOptional::provides_interrupt; 651 using DigitalIoOptional::provides_output; 652 653 using DigitalIoOptional::GetState; 654 using DigitalIoOptional::IsStateActive; 655 656 // These overrides invoke PW_CRASH. 657 Result<State> DoGetState() final; 658 }; 659 660 // A digital I/O line that supports both input and output. 661 // 662 // Use in APIs when both input and output functionality is required. For 663 // example, to represent a line which is shared by multiple controllers. 664 // 665 // Extend this class to implement a line that supports both input and output at 666 // the same time. 667 // 668 class DigitalInOut 669 : public DigitalIoOptional, 670 public internal::Conversions<DigitalInOut, DigitalIoOptional> { 671 public: 672 // Available functionality 673 using DigitalIoOptional::GetState; 674 using DigitalIoOptional::IsStateActive; 675 using DigitalIoOptional::SetState; 676 using DigitalIoOptional::SetStateActive; 677 using DigitalIoOptional::SetStateInactive; 678 679 protected: DigitalInOut()680 constexpr DigitalInOut() 681 : DigitalIoOptional(internal::AlwaysProvidedBy<DigitalInOut>()) {} 682 683 private: 684 // Unavailable functionality 685 using DigitalIoOptional::provides_input; 686 using DigitalIoOptional::provides_interrupt; 687 using DigitalIoOptional::provides_output; 688 689 using DigitalIoOptional::ClearInterruptHandler; 690 using DigitalIoOptional::DisableInterruptHandler; 691 using DigitalIoOptional::EnableInterruptHandler; 692 using DigitalIoOptional::SetInterruptHandler; 693 694 // These overrides invoke PW_CRASH. 695 Status DoSetInterruptHandler(InterruptTrigger, InterruptHandler&&) final; 696 Status DoEnableInterruptHandler(bool) final; 697 }; 698 699 // A line that supports input, output, and interrupts. 700 // 701 // Use in APIs when input, output, and interrupts are required. For example to 702 // represent a two-way shared line with state transition notifications. 703 // 704 // Extend this class to implement a line that supports all the functionality at 705 // the same time. 706 // 707 class DigitalInOutInterrupt 708 : public DigitalIoOptional, 709 public internal::Conversions<DigitalInOutInterrupt, DigitalIoOptional> { 710 public: 711 // Available functionality 712 using DigitalIoOptional::ClearInterruptHandler; 713 using DigitalIoOptional::DisableInterruptHandler; 714 using DigitalIoOptional::EnableInterruptHandler; 715 using DigitalIoOptional::GetState; 716 using DigitalIoOptional::IsStateActive; 717 using DigitalIoOptional::SetInterruptHandler; 718 using DigitalIoOptional::SetState; 719 using DigitalIoOptional::SetStateActive; 720 using DigitalIoOptional::SetStateInactive; 721 722 protected: DigitalInOutInterrupt()723 constexpr DigitalInOutInterrupt() 724 : DigitalIoOptional(internal::AlwaysProvidedBy<DigitalInOutInterrupt>()) { 725 } 726 727 private: 728 // Unavailable functionality 729 using DigitalIoOptional::provides_input; 730 using DigitalIoOptional::provides_interrupt; 731 using DigitalIoOptional::provides_output; 732 }; 733 734 } // namespace pw::digital_io 735