packages feed

fuyu-gpio-direct (empty) → 0.1.0.0

raw patch · 6 files changed

+2192/−0 lines, 6 filesdep +basedep +bytestringdep +unix

Dependencies added: base, bytestring, unix, vector

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for fuyu-gpio-direct++## 0.1.0.0 -- 2026-07-29++* Initial release. Low-level FFI bindings for libgpiod v2 in Haskell.
+ LICENSE view
@@ -0,0 +1,459 @@+                  GNU LESSER GENERAL PUBLIC LICENSE+                       Version 2.1, February 1999++ Copyright (C) 1991, 1999 Free Software Foundation, Inc.+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++[This is the first released version of the Lesser GPL.  It also counts+ as the successor of the GNU Library Public License, version 2, hence+ the version number 2.1.]++                            Preamble++  The licenses for most software are designed to take away your+freedom to share and change it.  By contrast, the GNU General Public+Licenses are intended to guarantee your freedom to share and change+free software--to make sure the software is free for all its users.++  This license, the Lesser General Public License, applies to some+specially designated software packages--typically libraries--of the+Free Software Foundation and other authors who decide to use it.  You+can use it too, but we suggest you first think carefully about whether+this license or the ordinary General Public License is the better+strategy to use in any particular case, based on the explanations below.++  When we speak of free software, we are referring to freedom of use,+not price.  Our General Public Licenses are designed to make sure that+you have the freedom to distribute copies of free software (and charge+for this service if you wish); that you receive source code or can get+it if you want it; that you can change the software and use pieces of+it in new free programs; and that you are informed that you can do+these things.++  To protect your rights, we need to make restrictions that forbid+distributors to deny you these rights or to ask you to surrender these+rights.  These restrictions translate to certain responsibilities for+you if you distribute copies of the library or if you modify it.++  For example, if you distribute copies of the library, whether gratis+or for a fee, you must give the recipients all the rights that we gave+you.  You must make sure that they, too, receive or can get the source+code.  If you link other code with the library, you must provide+complete object files to the recipients, so that they can relink them+with the library after making changes to the library and recompiling+it.  And you must show them these terms so they know their rights.++  We protect your rights with a two-step method: (1) we copyright the+library, and (2) we offer you this license which gives you legal+permission to copy, distribute and/or modify the library.++  To protect each distributor, we want to make it very clear that+there is no warranty for the free library.  Also, if the library is+modified by someone else and passed on, the recipients should know+that what they have is not the original version, so that the original+author's reputation will not be affected by problems that might be+introduced by others.++  Finally, software patents pose a constant threat to the existence of+any free program.  We wish to make sure that a company cannot+individually obtain patent licenses, in effect transforming the+program into proprietary software.  To prevent this, we have made it+clear that any patent must be licensed for everyone's free use or not+licensed at all.++  Most GNU software, including some libraries, is covered by the+ordinary GNU General Public License.  This license, the GNU Lesser+General Public License, applies to certain designated libraries, and+is quite different from the ordinary General Public License.  We use+this license for certain libraries in order to permit linking those+libraries into non-free programs.++  When a program is linked with a library, whether statically or using+a shared library, the combination of the two is legally speaking a+combined work, a derivative of the original library.  The ordinary+General Public License therefore permits such linking only if the+entire combination fits its criteria of freedom.  The Lesser General+Public License permits more lax criteria for linking other code with+the library.++  We call this license the "Lesser" General Public License because it+does Less to protect the user's freedom than the ordinary General+Public License.  It also provides other free software developers Less+of an advantage over competing non-free programs.  These disadvantages+are the reason we use the ordinary General Public License for many+libraries.  However, the Lesser license provides advantages in certain+special circumstances.++  For example, on rare occasions, there may be a special need to+encourage the widest possible use of a certain library, so that it becomes+a de-facto standard.  To achieve this, non-free programs must be+allowed to use the library.  A more frequent case is that a free+library does the same job as widely used non-free libraries.  In this+case, there is little to gain by limiting the free library to free+software only, so we use the Lesser General Public License.++  In other cases, permission to use a particular library in non-free+programs enables a greater number of people to use a large body of+free software.  For example, permission to use the GNU C Library in+non-free programs enables many more people to use the whole GNU+operating system, as well as its variant, the GNU/Linux operating+system.++  Although the Lesser General Public License is Less protective of the+users' freedom, it does ensure that the user of a program that is+linked with the Library has the freedom and the wherewithal to run+that program using a modified version of the Library.++  The precise terms and conditions for copying, distribution and+modification follow.  Pay close attention to the difference between a+"work based on the library" and a "work that uses the library".  The+former contains code derived from the library, whereas the latter must+be combined with the library in order to run.++                  GNU LESSER GENERAL PUBLIC LICENSE+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++  0. This License Agreement applies to any software library or other+program which contains a notice placed by the copyright holder or+other authorized party saying it may be distributed under the terms of+this Lesser General Public License (also called "this License").+Each licensee is addressed as "you".++  A "library" means a collection of software functions and/or data+prepared so as to be conveniently combined with application programs+(which use some of those functions and data) to form executables.++  The "Library", below, refers to any such software library or work+which has been distributed under these terms.  A "work based on the+Library" means either the Library or any derivative work under+copyright law: that is to say, a work containing the Library or a+portion of it, either verbatim or with modifications and/or translated+into another language.  (Hereinafter, translation is included without+limitation in the term "modification".)++  "Source code" for a work means the preferred form of the work for+making modifications to it.  For a fully made executable work, complete+source code means all the source code for all modules it contains, plus+any associated interface definition files, plus the scripts used to+control compilation and installation of the executable.++  Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope.  The act of+running a program using the Library is not restricted, and output from+such a program is covered only if its contents constitute a work based+on the Library (independent of the use of the Library in a tool for+writing it).  Whether that is true depends on what the Library does+and what the program that uses the Library does.++  1. You may copy and distribute verbatim copies of the Library's+complete source code as you receive it, in any medium, provided that+you conspicuously and appropriately publish on each copy an+appropriate copyright notice and disclaimer of warranty; keep intact+all the notices that refer to this License and to the absence of any+warranty; and distribute a copy of this License along with the+Library.++  You may charge a fee for the physical act of transferring a copy,+and you may at your option offer warranty protection in exchange for a+fee.++  2. You may modify your copy or copies of the Library or any portion+of it, thus forming a work based on the Library, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++    a) The modified work must itself be a software library.++    b) You must cause the files modified to carry prominent notices+    stating that you changed the files and the date of any change.++    c) You must cause the whole of the work to be licensed at no+    charge to all third parties under the terms of this License.++    d) If a facility in the modified Library refers to a function or a+    table of data to be supplied by an application program that uses+    the facility, other than as an argument passed when the facility+    is invoked, then you must make a good faith effort to ensure that,+    in the event an application does not supply such function or+    table, the facility still operates, and performs whatever part of+    its purpose remains meaningful.++    (For example, a function in a library to compute square roots has+    a purpose that is entirely well-defined independent of the+    application.  Therefore, Subsection 2d requires that any+    application-supplied function or table used by this function must+    be optional: if the application does not supply it, the square+    root function must still compute square roots.)++These requirements apply to the modified work as a whole.  If+identifiable sections of that work are not derived from the Library,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works.  But when you+distribute the same sections as part of a whole which is a work based+on the Library, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote+it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Library.++In addition, mere aggregation of another work not based on the Library+with the Library (or with a work based on the Library) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++  3. You may opt to apply the terms of the ordinary GNU General Public+License instead of this License to a given copy of the Library.  To do+this, you must alter all the notices that refer to this License, so+that they refer to the ordinary GNU General Public License, version 2,+instead of to this License.  (If a newer version than version 2 of the+ordinary GNU General Public License has appeared, then you can specify+that version instead if you wish.)  Do not make any other change in+these notices.++  Once this change is made in a given copy, it is irreversible for+that copy, so the ordinary GNU General Public License applies to all+subsequent copies and derivative works made from that copy.++  This option is useful when you wish to copy part of the code of+the Library into a program that is not a library.++  4. You may copy and distribute the Library (or a portion or+derivative of it, under Section 2) in object code or executable form+under the terms of Sections 1 and 2 above provided that you accompany+it with the complete corresponding machine-readable source code, which+must be distributed under the terms of Sections 1 and 2 above on a+medium customarily used for software interchange.++  If distribution of object code is made by offering access to copy+from a designated place, then offering equivalent access to copy the+source code from the same place satisfies the requirement to+distribute the source code, even though third parties are not+compelled to copy the source along with the object code.++  5. A program that contains no derivative of any portion of the+Library, but is designed to work with the Library by being compiled or+linked with it, is called a "work that uses the Library".  Such a+work, in isolation, is not a derivative work of the Library, and+therefore falls outside the scope of this License.++  However, linking a "work that uses the Library" with the Library+creates an executable that is a derivative of the Library (because it+contains portions of the Library), rather than a "work that uses the+library".  The executable is therefore covered by this License.+Section 6 states terms for distribution of such executables.++  When a "work that uses the Library" uses material from a header file+that is part of the Library, the object code for the work may be a+derivative work of the Library even though the source code is not.+Whether this is true is especially significant if the work can be+linked without the Library, or if the work is itself a library.  The+threshold for this to be true is not precisely defined by law.++  If such an object file uses only numerical parameters, data+structure layouts and accessors, and small macros and small inline+functions (ten lines or less in length), then the use of the object+file is unrestricted, regardless of whether it is legally a derivative+work.  (Executables containing this object code plus portions of the+Library will still fall under Section 6.)++  Otherwise, if the work is a derivative of the Library, you may+distribute the object code for the work under the terms of Section 6.+Any executables containing that work also fall under Section 6,+whether or not they are linked directly with the Library itself.++  6. As an exception to the Sections above, you may also combine or+link a "work that uses the Library" with the Library to produce a+work containing portions of the Library, and distribute that work+under terms of your choice, provided that the terms permit+modification of the work for the customer's own use and reverse+engineering for debugging such modifications.++  You must give prominent notice with each copy of the work that the+Library is used in it and that the Library and its use are covered by+this License.  You must supply a copy of this License.  If the work+during execution displays copyright notices, you must include the+copyright notice for the Library among them, as well as a reference+directing the user to the copy of this License.  Also, you must do one+of these things:++    a) Accompany the work with the complete corresponding+    machine-readable source code for the Library including whatever+    changes were used in the work (which must be distributed under+    Sections 1 and 2 above); and, if the work is an executable linked+    with the Library, with the complete machine-readable "work that+    uses the Library", as object code and/or source code, so that the+    user can modify the Library and then relink to produce a modified+    executable containing the modified Library.  (It is understood+    that the user who changes the contents of definitions files in the+    Library will not necessarily be able to recompile the application+    to use the modified definitions.)++    b) Use a suitable shared library mechanism for linking with the+    Library.  A suitable mechanism is one that (1) uses at run time a+    copy of the library already present on the user's computer system,+    rather than copying library functions into the executable, and (2)+    will operate properly with a modified version of the library, if+    the user installs one, as long as the modified version is+    interface-compatible with the version that the work was made with.++    c) Accompany the work with a written offer, valid for at+    least three years, to give the same user the materials+    specified in Subsection 6a, above, for a charge no more+    than the cost of performing this distribution.++    d) If distribution of work is made by offering access to copy from+    a designated place, offer equivalent access to copy the above+    specified materials from the same place.++    e) Verify that the user has already received a copy of these+    materials or that you have already sent this user a copy.++  For an executable, the required form of the "work that uses the+Library" must include any data and utility programs needed for+reproducing the executable from it.  However, as a special exception,+the materials to be distributed need not include anything that is+normally distributed (in either source or binary form) with the major+components (compiler, kernel, and so on) of the operating system on+which the executable runs, unless that component itself accompanies+the executable.++  It may happen that this requirement contradicts the license+restrictions of other proprietary libraries that do not normally+accompany the operating system.  Such a contradiction means you cannot+use both them and the Library together in an executable that you+distribute.++  7. You may place library facilities that are a work based on the+Library side-by-side in a single library together with other library+facilities not covered by this License, and distribute such a combined+library, provided that the separate distribution of the work based on+the Library and of the other library facilities is otherwise+permitted, and provided that you do these two things:++    a) Accompany the combined library with a copy of the same work+    based on the Library, uncombined with any other library+    facilities.  This must be distributed under the terms of the+    Sections above.++    b) Give prominent notice with the combined library of the fact+    that part of it is a work based on the Library, and explaining+    where to find the accompanying uncombined form of the same work.++  8. You may not copy, modify, sublicense, link with, or distribute+the Library except as expressly provided under this License.  Any+attempt otherwise to copy, modify, sublicense, link with, or+distribute the Library is void, and will automatically terminate your+rights under this License.  However, parties who have received copies,+or rights, from you under this License will not have their licenses+terminated so long as such parties remain in full compliance.++  9. You are not required to accept this License, since you have not+signed it.  However, nothing else grants you permission to modify or+distribute the Library or its derivative works.  These actions are+prohibited by law if you do not accept this License.  Therefore, by+modifying or distributing the Library (or any work based on the+Library), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Library or works based on it.++  10. Each time you redistribute the Library (or any work based on the+Library), the recipient automatically receives a license from the+original licensor to copy, distribute, link with or modify the Library+subject to these terms and conditions.  You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties with+this License.++  11. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License.  If you cannot+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Library at all.  For example, if a patent+license would not permit royalty-free redistribution of the Library by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Library.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply, and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system which is+implemented by public license practices.  Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++  12. If the distribution and/or use of the Library is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Library under this License may+add an explicit geographical distribution limitation excluding those+countries, so that distribution is permitted only in or among countries+not thus excluded.  In such case, this License incorporates the+limitation as if written in the body of this License.++  13. The Free Software Foundation may publish revised and/or new+versions of the Lesser General Public License from time to time.+Such new versions will be similar in spirit to the present version,+but may differ in detail to address new problems or concerns.++Each version is given a distinguishing version number.  If the Library+specifies a version number of this License which applies to it and+"any later version", you have the option of following the terms and+conditions either of that version or of any later version published by+the Free Software Foundation.  If the Library does not specify a+license version number, you may choose any version ever published by+the Free Software Foundation.++  14. If you wish to incorporate parts of the Library into other free+programs whose distribution conditions are incompatible with these,+write to the author to ask for permission.  For software which is+copyrighted by the Free Software Foundation, write to the Free+Software Foundation; we sometimes make exceptions for this.  Our+decision will be guided by the two goals of preserving the free status+of all derivatives of our free software and of promoting the sharing+and reuse of software generally.++                            NO WARRANTY++  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.++  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH+DAMAGES.++                     END OF TERMS AND CONDITIONS
+ fuyu-gpio-direct.cabal view
@@ -0,0 +1,35 @@+cabal-version:      3.0+name:               fuyu-gpio-direct +version:            0.1.0.0+synopsis:           Direct Haskell bindings for Linux libgpiod v2+description:+    Mid-level and low-level Haskell bindings for interacting with Linux GPIO+    character devices using libgpiod v2. Provides type-safe abstractions for+    line requests, chip management, edge event monitoring, and settings.+license:            LGPL-2.1-or-later+license-file:       LICENSE+author:             BassGT+maintainer:         sebastian11medrano@gmail.com+category:           System, Hardware+build-type:         Simple+extra-doc-files:    CHANGELOG.md++source-repository head+    type:     git+    location: https://github.com/BassGT/fuyu-gpio-direct.git++common warnings+    ghc-options: -Wall++library+    import:           warnings+    exposed-modules:  Fuyu.GPIO.Direct,+                      Fuyu.GPIO.Direct.Types,+                      Fuyu.GPIO.Direct.Bindings+    build-depends:    base >= 4.18 && < 5,+                      bytestring >= 0.10 && < 0.13,+                      unix >= 2.7 && < 2.9,+                      vector >= 0.12 && < 0.14+    extra-libraries:  gpiod+    hs-source-dirs:   src+    default-language: Haskell2010
+ src/Fuyu/GPIO/Direct.hs view
@@ -0,0 +1,873 @@+{-# LANGUAGE PatternSynonyms #-}+-- |+-- Module      : Fuyu.GPIO.Direct+-- Description : Mid-level Haskell bindings for Linux GPIO character device interface (libgpiod v2).+-- Maintainer  : BassGT+-- Portability : POSIX (Linux GPIO character device interface)+--+-- High-level direct Haskell interface for interacting with Linux GPIO character devices+-- using @libgpiod v2@.+module Fuyu.GPIO.Direct+  ( -- * Module Overview+    -- $overview++    -- * High-Level Opaque Handles (Abstract Types)+    Chip+  , ChipInfo+  , InfoEvent+  , LineInfo+  , LineSettings+  , LineConfig+  , LineRequest+  , RequestConfig+  , EventBuffer+  , RawEdgeEvent++    -- * Safety & Index Wrappers+  , LineOffset(..)++    -- * Line Definitions & Patterns+  , LineValue(..)+  , pattern LineActive+  , pattern LineInactive+  , pattern LineError++  , LineDirection(..)+  , pattern DirAsIs+  , pattern DirInput+  , pattern DirOutput++  , LineEdge(..)+  , pattern EdgeNone+  , pattern EdgeRising+  , pattern EdgeFalling+  , pattern EdgeBoth++  , LineBias(..)+  , pattern BiasAsIs+  , pattern BiasUnknown+  , pattern BiasDisabled+  , pattern BiasPullUp+  , pattern BiasPullDown++  , LineDrive(..)+  , pattern PushPull+  , pattern OpenDrain+  , pattern OpenSource++  , LineClock(..)+  , pattern Monotonic+  , pattern Realtime+  , pattern Hardware++  , InfoEventType(..)+  , pattern LineRequested+  , pattern LineReleased+  , pattern LineConfigChanged++  , EdgeEventType(..)+  , pattern Rising+  , pattern Falling++  , WaitResult(..)+  , TimeoutNs(..)+  , TimestampNs+  , EdgeEvent(..)++    -- * Chip Management+  , chipOpen+  , chipClose+  , chipInfo+  , chipPath+  , chipLineInfo+  , chipWatchLineInfo+  , chipUnwatchLineInfo+  , chipFd+  , chipWaitInfoEvent+  , chipReadInfoEvent+  , chipLineOffsetFromName+  , chipRequestLines++    -- * Chip Info+  , chipInfoFree+  , chipInfoName+  , chipInfoLabel+  , chipInfoNumLines++    -- * Line Information+  , lineInfoFree+  , lineInfoCopy+  , lineInfoOffset+  , lineInfoName+  , lineInfoIsUsed+  , lineInfoConsumer+  , lineInfoDirection+  , lineInfoEdgeDetection+  , lineInfoBias+  , lineInfoDrive+  , lineInfoIsActiveLow+  , lineInfoIsDebounced+  , lineInfoDebouncePeriod+  , lineInfoEventClock++    -- * Line Watch (Info Event)+  , infoEventFree+  , infoEventType+  , infoEventTimestamp+  , infoEventLineInfo++    -- * Line Settings+  , lineSettingsNew+  , lineSettingsFree+  , lineSettingsReset+  , lineSettingsCopy+  , lineSettingsSetDirection+  , lineSettingsDirection+  , lineSettingsSetEdgeDetection+  , lineSettingsEdgeDetection+  , lineSettingsSetBias+  , lineSettingsBias+  , lineSettingsSetDrive+  , lineSettingsDrive+  , lineSettingsSetEventClock+  , lineSettingsEventClock+  , lineSettingsSetActiveLow+  , lineSettingsActiveLow+  , lineSettingsSetDebouncePeriodUs+  , lineSettingsDebouncePeriodUs+  , lineSettingsSetOutputValue+  , lineSettingsOutputValue++    -- * Line Configuration+  , lineConfigNew+  , lineConfigFree+  , lineConfigReset+  , lineConfigAddLineSettings+  , lineConfigLineSettings+  , lineConfigSetOutputValues+  , lineConfigNumOffsets+  , lineConfigConfiguredOffsets++    -- * Request Configuration+  , requestConfigNew+  , requestConfigFree+  , requestConfigSetConsumer+  , requestConfigConsumer+  , requestConfigSetEventBufferSize+  , requestConfigEventBufferSize++    -- * Line Request+  , lineRequestRelease+  , lineRequestChipName+  , lineRequestNumLines+  , lineRequestRequestedOffsets+  , lineRequestValue+  , lineRequestSubsetValues+  , lineRequestValues+  , lineRequestSetValue+  , lineRequestSetValuesSubset+  , lineRequestSetValues+  , lineRequestReconfigure+  , lineRequestFd+  , lineRequestWaitEdgeEvents+  , lineRequestReadEdgeEvents++    -- * Edge Events & Event Buffer+  , rawEdgeEventFree+  , rawEdgeEventCopy+  , rawEdgeEventType+  , rawEdgeEventTimestampNs+  , rawEdgeEventLineOffset+  , rawEdgeEventGlobalSeqNo+  , rawEdgeEventLineSeqNo+  , eventBufferNew+  , eventBufferCapacity+  , eventBufferFree+  , eventBufferGetEvent+  , eventBufferNumEvents++    -- * Utilities+  , isGPIOChip+  , gpiodAPIVersion+  ) where++import System.Posix.Types (Fd)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import Foreign.C.Error (Errno, getErrno, eINVAL)+import Foreign.C.Types (CInt, CLong)+import Foreign.Marshal.Utils (toBool)+import Foreign.Ptr (Ptr, nullPtr)+import Data.Vector.Storable (Vector)+import qualified Data.Vector.Storable as V+import qualified Data.Vector.Storable.Mutable as MV+import Data.Word (Word64)++import Fuyu.GPIO.Direct.Bindings+import Fuyu.GPIO.Direct.Types++-- $overview+-- High-level direct Haskell interface for interacting with Linux GPIO character devices+-- using @libgpiod v2@.+--+-- This module wraps lower-level FFI calls into type-safe Haskell operations using 'ByteString',+-- 'Vector', and 'Either' 'Foreign.C.Error.Errno' error handling.+--+-- All resources wrapping C pointers (such as t'Chip, t'LineInfo, t'LineSettings, t'LineConfig,+-- t'LineRequest, etc.) must be explicitly freed or released when no longer needed.++--------------------------------------------------------------------------------+-- INTERNAL ERROR HELPERS+--------------------------------------------------------------------------------++checkNull :: IO (Ptr a) -> IO (Either Errno (Ptr a))+checkNull action = do+  ptr <- action+  if ptr == nullPtr+    then Left <$> getErrno+    else return $ Right ptr++checkMinusOne :: IO CInt -> IO (Either Errno ())+checkMinusOne action = do+  res <- action+  if res == -1+    then Left <$> getErrno+    else return $ Right ()++--------------------------------------------------------------------------------+-- INTERNAL HELPERS+--------------------------------------------------------------------------------+ +timeoutNsToC :: TimeoutNs -> CLong+timeoutNsToC Immediate        = 0+timeoutNsToC Infinite         = -1+timeoutNsToC (Nanoseconds ns) = fromIntegral ns++--------------------------------------------------------------------------------+-- 1. CHIP MANAGEMENT+--------------------------------------------------------------------------------++-- | Open a GPIO chip device node at the given filesystem path (e.g. @"\/dev\/gpiochip0"@).+--+-- Returns 'Right' t'Chip on success, or 'Left' 'Errno' on failure (such as 'Foreign.C.Error.eACCES'+-- if permissions are missing or 'Foreign.C.Error.eNOENT' if the path does not exist).+-- The returned handle must be closed with 'chipClose' when finished to free file descriptors and memory.+chipOpen :: ByteString -> IO (Either Errno Chip)+chipOpen bs = BS.useAsCString bs $ \cStr -> do+  res <- checkNull (c_gpiod_chip_open cStr)+  return $ Chip <$> res++-- | Close an open GPIO chip device handle and release associated kernel and C resources.+chipClose :: Chip -> IO ()+chipClose (Chip ptr) = c_gpiod_chip_close ptr++-- | Query static information (device name, label, line count) about an open GPIO chip.+--+-- Returns 'Right' t'ChipInfo on success. The caller must explicitly free the returned+-- object using 'chipInfoFree'.+chipInfo :: Chip -> IO (Either Errno ChipInfo)+chipInfo (Chip ptr) = do+  res <- checkNull (c_gpiod_chip_get_info ptr)+  return $ ChipInfo <$> res++-- | Retrieve the filesystem device path used when opening the chip.+--+-- Returns 'Right' 'ByteString' containing the path (e.g. @"\/dev\/gpiochip0"@).+chipPath :: Chip -> IO (Either Errno ByteString)+chipPath (Chip ptr) = do+  res <- checkNull (c_gpiod_chip_get_path ptr)+  case res of+    Left err -> return (Left err)+    Right cStr -> Right <$> BS.packCString cStr++-- | Query a snapshot of status and configuration information for a specific line offset.+--+-- Returns 'Right' t'LineInfo on success. The caller must explicitly free the returned+-- object using 'lineInfoFree'.+chipLineInfo :: Chip -> LineOffset -> IO (Either Errno LineInfo)+chipLineInfo (Chip ptr) offset = do+  res <- checkNull $ c_gpiod_chip_get_line_info ptr offset+  return $ LineInfo <$> res++-- | Query line status snapshot and subscribe to status change events for the specified line offset.+--+-- Future status change events (such as line requested, released, or reconfigured) can be waited for+-- via 'chipWaitInfoEvent' and read via 'chipReadInfoEvent'.+-- The caller must explicitly free the returned t'LineInfo object using 'lineInfoFree'.+chipWatchLineInfo :: Chip -> LineOffset -> IO (Either Errno LineInfo)+chipWatchLineInfo (Chip ptr) offset = do+  res <- checkNull $ c_gpiod_chip_watch_line_info ptr offset+  return $ LineInfo <$> res   ++-- | Stop watching a line offset for status change events.+--+-- Disables notifications previously initiated via 'chipWatchLineInfo'.+chipUnwatchLineInfo :: Chip -> LineOffset -> IO (Either Errno ())+chipUnwatchLineInfo (Chip ptr) offset = do+  checkMinusOne $ c_gpiod_chip_unwatch_line_info ptr offset++-- | Retrieve the underlying Linux file descriptor ('Fd') associated with an open t'Chip.+--+-- Can be passed to event loops ('GHC.Event', @epoll@, @select@, etc.) to monitor line watch events.+chipFd :: Chip -> IO Fd+chipFd (Chip ptr) = c_gpiod_chip_get_fd ptr++-- | Wait for status change events on any of the watched lines on the chip.+--+-- Accepts a t'TimeoutNs parameter ('Immediate', 'Infinite', or 'Nanoseconds').+-- Returns 'Right' 'EventReady' if an event is available to read, or 'Right' 'Timeout' if timed out.+chipWaitInfoEvent :: Chip -> TimeoutNs -> IO (Either Errno WaitResult)+chipWaitInfoEvent (Chip ptr) ns = do+  res <- c_gpiod_chip_wait_info_event ptr (fromIntegral $ timeoutNsToC ns)+  if res == -1+    then Left <$> getErrno+    else case res of+      1 -> return $ Right EventReady+      0 -> return $ Right Timeout+      _ -> return $ Right Timeout+  +-- | Read a single line status change event (t'InfoEvent) from the chip.+--+-- Should be called when 'chipWaitInfoEvent' indicates 'EventReady'.+-- The caller must free the returned t'InfoEvent with 'infoEventFree'.+chipReadInfoEvent :: Chip -> IO (Either Errno InfoEvent)+chipReadInfoEvent (Chip ptr) = do+  res <- checkNull $ c_gpiod_chip_read_info_event ptr +  return $ InfoEvent <$> res   ++-- | Look up the zero-based line offset index on the chip given a pin name string.+--+-- Returns 'Right' t'LineOffset if the pin name exists, or 'Left' 'Errno' (e.g. 'Foreign.C.Error.eENOENT') if not found.+chipLineOffsetFromName :: Chip -> ByteString -> IO (Either Errno LineOffset)+chipLineOffsetFromName (Chip ptr) name = do+  res <- BS.useAsCString name $ \cStr -> c_gpiod_chip_get_line_offset_from_name ptr cStr+  if res == -1 +    then Left <$> getErrno +    else return $ Right $ LineOffset (fromIntegral res)++-- | Request exclusive kernel control over a collection of lines on the chip.+--+-- Takes optional t'RequestConfig (consumer label, event buffer size) and mandatory t'LineConfig (settings mapped to offsets).+-- Returns 'Right' t'LineRequest on success. The handle must be released with 'lineRequestRelease'.+chipRequestLines :: Chip -> Maybe RequestConfig -> LineConfig -> IO (Either Errno LineRequest)+chipRequestLines (Chip chipPtr) maybeReqConf (LineConfig lineConfPtr) = do+  let reqConfPtr = case maybeReqConf of+                     Just (RequestConfig ptr) -> ptr+                     Nothing                  -> nullPtr+  res <- checkNull (c_gpiod_chip_request_lines chipPtr reqConfPtr lineConfPtr)+  return $ LineRequest <$> res++--------------------------------------------------------------------------------+-- 2. CHIP INFO+--------------------------------------------------------------------------------++-- | Free a t'ChipInfo structure allocated by 'chipInfo'.+chipInfoFree :: ChipInfo -> IO ()+chipInfoFree (ChipInfo info) = c_gpiod_chip_info_free info ++-- | Retrieve the kernel device name string of the chip (e.g. @"gpiochip4"@).+chipInfoName :: ChipInfo -> IO ByteString+chipInfoName (ChipInfo info) = do+  res <- c_gpiod_chip_info_get_name info+  if res == nullPtr+    then return BS.empty+    else BS.packCString res++-- | Retrieve the hardware controller label string of the chip (e.g. @"pinctrl-bcm2835"@).+chipInfoLabel :: ChipInfo -> IO ByteString+chipInfoLabel (ChipInfo info) = do+  res <- c_gpiod_chip_info_get_label info+  if res == nullPtr+    then return BS.empty+    else BS.packCString res++-- | Retrieve the total number of GPIO lines exposed by the chip.+chipInfoNumLines :: ChipInfo -> IO Word +chipInfoNumLines (ChipInfo info) = do+  res <- c_gpiod_chip_info_get_num_lines info+  return $ fromIntegral res++--------------------------------------------------------------------------------+-- 4. LINE INFORMATION+--------------------------------------------------------------------------------++-- | Free a t'LineInfo snapshot structure allocated by 'chipLineInfo', 'chipWatchLineInfo', or 'infoEventLineInfo'.+lineInfoFree :: LineInfo -> IO ()+lineInfoFree (LineInfo info) = c_gpiod_line_info_free info++-- | Duplicate a t'LineInfo object. The copy must be freed separately with 'lineInfoFree'.+lineInfoCopy :: LineInfo -> IO (Either Errno LineInfo)+lineInfoCopy (LineInfo info) = do+  res <- checkNull (c_gpiod_line_info_copy info)+  return $ LineInfo <$> res++-- | Retrieve the zero-based line offset index from a t'LineInfo snapshot.+lineInfoOffset :: LineInfo -> IO LineOffset+lineInfoOffset (LineInfo info) = c_gpiod_line_info_get_offset info++-- | Retrieve the name of the GPIO line, or 'Nothing' if unnamed in device tree / specs.+lineInfoName :: LineInfo -> IO (Maybe ByteString)+lineInfoName (LineInfo info) = do+  res <- c_gpiod_line_info_get_name info+  if res == nullPtr+    then return Nothing+    else Just <$> BS.packCString res ++-- | Check whether the line is currently in use / claimed by a driver or consumer.+lineInfoIsUsed :: LineInfo -> IO Bool+lineInfoIsUsed (LineInfo info) = do+  res <- c_gpiod_line_info_is_used info+  return $ toBool res++-- | Retrieve the consumer identification string of the entity using the line, or 'Nothing' if unclaimed.+lineInfoConsumer :: LineInfo -> IO (Maybe ByteString)+lineInfoConsumer (LineInfo info) = do+  name <- c_gpiod_line_info_get_consumer info+  if name == nullPtr+    then return Nothing+    else Just <$> BS.packCString name++-- | Query the line direction setting ('DirInput' or 'DirOutput').+lineInfoDirection :: LineInfo -> IO LineDirection+lineInfoDirection (LineInfo info) = c_gpiod_line_info_get_direction info++-- | Query the line edge detection mode ('EdgeNone', 'EdgeRising', 'EdgeFalling', 'EdgeBoth').+lineInfoEdgeDetection :: LineInfo -> IO LineEdge+lineInfoEdgeDetection (LineInfo info) = c_gpiod_line_info_get_edge_detection info++-- | Query internal pull resistor bias ('BiasDisabled', 'BiasPullUp', 'BiasPullDown', etc.).+lineInfoBias :: LineInfo -> IO LineBias+lineInfoBias (LineInfo info) = c_gpiod_line_info_get_bias info++-- | Query output driver mode ('PushPull', 'OpenDrain', 'OpenSource').+lineInfoDrive :: LineInfo -> IO LineDrive+lineInfoDrive (LineInfo info) = c_gpiod_line_info_get_drive info++-- | Check if active-low signal inversion is enabled on this line.+lineInfoIsActiveLow :: LineInfo -> IO Bool+lineInfoIsActiveLow (LineInfo info) = do+  res <- c_gpiod_line_info_is_active_low info+  return $ toBool res++-- | Check if hardware/kernel input debounce filtering is enabled for this line.+lineInfoIsDebounced :: LineInfo -> IO Bool+lineInfoIsDebounced (LineInfo info) = do+  res <- c_gpiod_line_info_is_debounced info+  return $ toBool res++-- | Query the input debounce period in microseconds (0 if debouncing is disabled).+lineInfoDebouncePeriod :: LineInfo -> IO Word  +lineInfoDebouncePeriod (LineInfo info) = do+  res <- c_gpiod_line_info_get_debounce_period_us info+  return $ fromIntegral res++-- | Query the timestamp clock source used for line edge events ('Monotonic', 'Realtime', 'Hardware').+lineInfoEventClock :: LineInfo -> IO LineClock+lineInfoEventClock (LineInfo info) = c_gpiod_line_info_get_event_clock info++--------------------------------------------------------------------------------+-- 5. LINE WATCH (INFO EVENT) +--------------------------------------------------------------------------------++-- | Free an t'InfoEvent structure allocated by 'chipReadInfoEvent'.+infoEventFree :: InfoEvent -> IO ()+infoEventFree (InfoEvent event) = c_gpiod_info_event_free event ++-- | Query event classification ('LineRequested', 'LineReleased', or 'LineConfigChanged').+infoEventType :: InfoEvent -> IO InfoEventType+infoEventType (InfoEvent event) = c_gpiod_info_event_get_event_type event ++-- | Query timestamp (in nanoseconds) when the line status event occurred.+infoEventTimestamp :: InfoEvent -> IO TimestampNs +infoEventTimestamp (InfoEvent event) = c_gpiod_info_event_get_timestamp_ns event++-- | Extract a line info snapshot (t'LineInfo) representing updated state at event time.+infoEventLineInfo :: InfoEvent -> IO LineInfo+infoEventLineInfo (InfoEvent event) = LineInfo <$> c_gpiod_info_event_get_line_info event+  +--------------------------------------------------------------------------------+-- 6. LINE SETTINGS+--------------------------------------------------------------------------------++-- | Allocate a new t'LineSettings object with default attributes.+--+-- Must be freed with 'lineSettingsFree' when finished.+lineSettingsNew :: IO (Either Errno LineSettings)+lineSettingsNew = do +  res <- checkNull c_gpiod_line_settings_new+  return $ LineSettings <$> res ++-- | Free a t'LineSettings object and release associated resources.+lineSettingsFree :: LineSettings -> IO ()+lineSettingsFree (LineSettings settings) = c_gpiod_line_settings_free settings ++-- | Reset a t'LineSettings object back to default values.+lineSettingsReset :: LineSettings -> IO ()+lineSettingsReset (LineSettings settings) = c_gpiod_line_settings_reset settings ++-- | Duplicate a t'LineSettings object. The copy must be freed with 'lineSettingsFree'.+lineSettingsCopy :: LineSettings -> IO (Either Errno LineSettings)+lineSettingsCopy (LineSettings settings) = do+  res <- checkNull (c_gpiod_line_settings_copy settings)+  return $ LineSettings <$> res++-- | Set the line pin direction ('DirInput', 'DirOutput', 'DirAsIs') in settings.+lineSettingsSetDirection :: LineSettings -> LineDirection -> IO (Either Errno ())+lineSettingsSetDirection (LineSettings settings) dir =+  checkMinusOne $ c_gpiod_line_settings_set_direction settings dir+  +-- | Get the line pin direction in settings.+lineSettingsDirection :: LineSettings -> IO LineDirection+lineSettingsDirection (LineSettings settings) = c_gpiod_line_settings_get_direction settings++-- | Set edge detection mode ('EdgeNone', 'EdgeRising', 'EdgeFalling', 'EdgeBoth') in settings.+lineSettingsSetEdgeDetection :: LineSettings -> LineEdge -> IO (Either Errno ())+lineSettingsSetEdgeDetection (LineSettings settings) edge =+  checkMinusOne $ c_gpiod_line_settings_set_edge_detection settings edge++-- | Get edge detection mode from settings.+lineSettingsEdgeDetection :: LineSettings -> IO LineEdge+lineSettingsEdgeDetection (LineSettings settings) = c_gpiod_line_settings_get_edge_detection settings++-- | Set internal pull bias ('BiasDisabled', 'BiasPullUp', 'BiasPullDown', 'BiasAsIs') in settings.+lineSettingsSetBias :: LineSettings -> LineBias -> IO (Either Errno ())+lineSettingsSetBias (LineSettings settings) bias =+  checkMinusOne $ c_gpiod_line_settings_set_bias settings bias++-- | Get internal pull bias from settings.+lineSettingsBias :: LineSettings -> IO LineBias+lineSettingsBias (LineSettings settings) = c_gpiod_line_settings_get_bias settings++-- | Set output driver mode ('PushPull', 'OpenDrain', 'OpenSource') in settings.+lineSettingsSetDrive :: LineSettings -> LineDrive -> IO (Either Errno ())+lineSettingsSetDrive (LineSettings settings) drive =+  checkMinusOne $ c_gpiod_line_settings_set_drive settings drive++-- | Get output driver mode from settings.+lineSettingsDrive :: LineSettings -> IO LineDrive+lineSettingsDrive (LineSettings settings) = c_gpiod_line_settings_get_drive settings++-- | Set event timestamp clock source ('Monotonic', 'Realtime', 'Hardware') in settings.+lineSettingsSetEventClock :: LineSettings -> LineClock -> IO (Either Errno ())+lineSettingsSetEventClock (LineSettings settings) clock =+  checkMinusOne $ c_gpiod_line_settings_set_event_clock settings clock++-- | Get event timestamp clock source from settings.+lineSettingsEventClock :: LineSettings -> IO LineClock+lineSettingsEventClock (LineSettings settings) = c_gpiod_line_settings_get_event_clock settings++-- | Set active-low signal inversion flag in settings.+lineSettingsSetActiveLow :: LineSettings -> Bool -> IO ()+lineSettingsSetActiveLow (LineSettings settings) activeLow =+  c_gpiod_line_settings_set_active_low settings (if activeLow then 1 else 0)++-- | Get active-low signal inversion flag from settings.+lineSettingsActiveLow :: LineSettings -> IO Bool+lineSettingsActiveLow (LineSettings settings) = do+  res <- c_gpiod_line_settings_get_active_low settings+  return $ toBool res++-- | Set input debounce period in microseconds in settings.+lineSettingsSetDebouncePeriodUs :: LineSettings -> Word -> IO ()+lineSettingsSetDebouncePeriodUs (LineSettings settings) us =+  c_gpiod_line_settings_set_debounce_period_us settings (fromIntegral us)++-- | Get input debounce period in microseconds from settings.+lineSettingsDebouncePeriodUs :: LineSettings -> IO Word+lineSettingsDebouncePeriodUs (LineSettings settings) = do+  res <- c_gpiod_line_settings_get_debounce_period_us settings+  return $ fromIntegral res++-- | Set initial output value ('LineActive' or 'LineInactive') in settings.+lineSettingsSetOutputValue :: LineSettings -> LineValue -> IO (Either Errno ())+lineSettingsSetOutputValue (LineSettings settings) val =+  checkMinusOne $ c_gpiod_line_settings_set_output_value settings val++-- | Get output value from settings.+lineSettingsOutputValue :: LineSettings -> IO LineValue+lineSettingsOutputValue (LineSettings settings) = c_gpiod_line_settings_get_output_value settings++--------------------------------------------------------------------------------+-- 7. LINE CONFIGURATION+--------------------------------------------------------------------------------++-- | Allocate a new t'LineConfig accumulator object.+--+-- Must be freed with 'lineConfigFree' when finished.+lineConfigNew :: IO (Either Errno LineConfig)+lineConfigNew = do  +  res <- checkNull c_gpiod_line_config_new +  return $ LineConfig <$> res++-- | Free a t'LineConfig object.+lineConfigFree :: LineConfig -> IO ()+lineConfigFree (LineConfig config) = c_gpiod_line_config_free config++-- | Reset a t'LineConfig object, clearing all associated line settings.+lineConfigReset :: LineConfig -> IO ()+lineConfigReset (LineConfig config) = c_gpiod_line_config_reset config++-- | Associate a set of t'LineOffset's (as a Storable 'Vector') with a t'LineSettings configuration.+lineConfigAddLineSettings :: LineConfig -> Vector LineOffset -> LineSettings -> IO (Either Errno ())+lineConfigAddLineSettings (LineConfig config) offsets (LineSettings settings) = do+  let size = fromIntegral (V.length offsets)+  checkMinusOne $ V.unsafeWith offsets $ \ptr -> +    c_gpiod_line_config_add_line_settings config ptr size settings++-- | Fetch a copy of the t'LineSettings configured for a specific line offset.+lineConfigLineSettings :: LineConfig -> LineOffset -> IO (Either Errno LineSettings)+lineConfigLineSettings (LineConfig config) offset = do+  res <- checkNull $ c_gpiod_line_config_get_line_settings config offset+  return $ LineSettings <$> res ++-- | Override output values for lines configured in t'LineConfig using a Storable 'Vector' of t'LineValue's.+lineConfigSetOutputValues :: LineConfig -> Vector LineValue -> IO (Either Errno ())+lineConfigSetOutputValues (LineConfig config) values = do+  let size = fromIntegral (V.length values)+  checkMinusOne $ V.unsafeWith values $ \ptr ->+    c_gpiod_line_config_set_output_values config ptr size++-- | Query total count of distinct line offsets configured within a t'LineConfig object.+lineConfigNumOffsets :: LineConfig -> IO Word  +lineConfigNumOffsets (LineConfig config) =+  fromIntegral <$> c_gpiod_line_config_get_num_configured_offsets config ++-- | Retrieve all configured line offsets stored in t'LineConfig as a Storable 'Vector'.+lineConfigConfiguredOffsets :: LineConfig -> IO (Vector LineOffset)+lineConfigConfiguredOffsets (LineConfig config) = do+  num <- c_gpiod_line_config_get_num_configured_offsets config+  vec <- MV.new (fromIntegral num)+  _ <- MV.unsafeWith vec $ \ptr ->+    c_gpiod_line_config_get_configured_offsets config ptr num+  V.unsafeFreeze vec++--------------------------------------------------------------------------------+-- 8. REQUESTS CONFIG+--------------------------------------------------------------------------------++-- | Allocate a new t'RequestConfig object.+--+-- Must be freed with 'requestConfigFree' when finished.+requestConfigNew :: IO (Either Errno RequestConfig)+requestConfigNew = do  +  res <- checkNull c_gpiod_request_config_new  +  return $ RequestConfig <$> res ++-- | Free a t'RequestConfig object.+requestConfigFree :: RequestConfig -> IO()+requestConfigFree (RequestConfig config) = c_gpiod_request_config_free config++-- | Set the consumer identification string (e.g. @"my-app"@) in a t'RequestConfig.+requestConfigSetConsumer :: RequestConfig -> ByteString -> IO()+requestConfigSetConsumer (RequestConfig config) name =+  BS.useAsCString name $ \cStr -> do +    c_gpiod_request_config_set_consumer config cStr+  +-- | Get the consumer identification string from a t'RequestConfig.+requestConfigConsumer :: RequestConfig -> IO ByteString+requestConfigConsumer (RequestConfig config) = do+  res <- c_gpiod_request_config_get_consumer config+  BS.packCString res +    +-- | Set the size of kernel event buffer (in number of events) in a t'RequestConfig.+requestConfigSetEventBufferSize :: RequestConfig -> Word -> IO ()+requestConfigSetEventBufferSize (RequestConfig config) size =+  c_gpiod_request_config_set_event_buffer_size config (fromIntegral size)++-- | Get the size of kernel event buffer (in number of events) from a t'RequestConfig.+requestConfigEventBufferSize :: RequestConfig -> IO Word+requestConfigEventBufferSize (RequestConfig config) =+  fromIntegral <$> c_gpiod_request_config_get_event_buffer_size config++--------------------------------------------------------------------------------+-- 9. LINE REQUEST+--------------------------------------------------------------------------------++-- | Release claimed GPIO lines and close the line request object.+lineRequestRelease :: LineRequest -> IO ()+lineRequestRelease (LineRequest request) = c_gpiod_line_request_release request++-- | Retrieve the name of the GPIO chip on which this request was created.+lineRequestChipName :: LineRequest -> IO ByteString+lineRequestChipName (LineRequest request) = do+  res <- c_gpiod_line_request_get_chip_name request+  BS.packCString res  +  +-- | Query total count of lines claimed in this request.+lineRequestNumLines :: LineRequest -> IO Word +lineRequestNumLines (LineRequest request) = +  fromIntegral <$> c_gpiod_line_request_get_num_requested_lines request ++-- | Retrieve all line offsets claimed by this request as a Storable 'Vector'.+lineRequestRequestedOffsets :: LineRequest -> IO (Vector LineOffset)+lineRequestRequestedOffsets (LineRequest request) = do+  num <- c_gpiod_line_request_get_num_requested_lines request+  vec <- MV.new (fromIntegral num)+  _ <- MV.unsafeWith vec $ \ptr ->+    c_gpiod_line_request_get_requested_offsets request ptr num+  V.unsafeFreeze vec++-- | Read the logical value ('LineActive' or 'LineInactive') of a single requested line offset.+lineRequestValue :: LineRequest -> LineOffset -> IO (Either Errno LineValue)+lineRequestValue (LineRequest request) offset = do+  lineValue <- c_gpiod_line_request_get_value request offset+  if lineValue == LineError+    then Left <$> getErrno+    else return $ Right lineValue++-- | Read logical values for a subset of requested lines into a Storable 'Vector'.+lineRequestSubsetValues :: LineRequest -> Vector LineOffset -> IO (Either Errno (Vector LineValue))+lineRequestSubsetValues (LineRequest request) offsets = do+  let numValues = V.length offsets+  mutValues <- MV.new numValues+  res <- V.unsafeWith offsets $ \offsetsPtr ->+    MV.unsafeWith mutValues $ \valuesPtr ->+      c_gpiod_line_request_get_values_subset request (fromIntegral numValues) offsetsPtr valuesPtr+  if res == -1+    then Left <$> getErrno+    else Right <$> V.unsafeFreeze mutValues++-- | Read logical values for all requested lines into a Storable 'Vector'.+lineRequestValues :: LineRequest -> IO (Either Errno (Vector LineValue))+lineRequestValues (LineRequest request) = do+  numLines <- c_gpiod_line_request_get_num_requested_lines request+  mutValues <- MV.new (fromIntegral numLines)+  res <- MV.unsafeWith mutValues $ \valuesPtr ->+    c_gpiod_line_request_get_values request valuesPtr+  if res == -1+    then Left <$> getErrno+    else Right <$> V.unsafeFreeze mutValues++-- | Set the logical value ('LineActive' or 'LineInactive') of a single requested line offset.+lineRequestSetValue :: LineRequest -> LineOffset -> LineValue -> IO (Either Errno ())+lineRequestSetValue _ _ LineError = return (Left eINVAL)+lineRequestSetValue (LineRequest request) offset value =+  checkMinusOne $ c_gpiod_line_request_set_value request offset value++-- | Set logical values for a subset of requested lines from Storable 'Vector's of offsets and values.+lineRequestSetValuesSubset :: LineRequest -> Vector LineOffset -> Vector LineValue -> IO (Either Errno ())+lineRequestSetValuesSubset (LineRequest request) offsets values+  | V.length offsets /= V.length values = return (Left eINVAL)+  | otherwise =+      let numValues = V.length offsets+      in V.unsafeWith offsets $ \offsetsPtr ->+           V.unsafeWith values $ \valuesPtr ->+             checkMinusOne $ c_gpiod_line_request_set_values_subset request (fromIntegral numValues) offsetsPtr valuesPtr++-- | Set logical values for all requested lines from a Storable 'Vector'.+lineRequestSetValues :: LineRequest -> Vector LineValue -> IO (Either Errno ())+lineRequestSetValues (LineRequest request) values =+  V.unsafeWith values $ \valuesPtr ->+    checkMinusOne $ c_gpiod_line_request_set_values request valuesPtr++-- | Update line configurations (direction, edge detection, output values) of existing requested lines.+lineRequestReconfigure :: LineRequest -> LineConfig -> IO (Either Errno ())+lineRequestReconfigure (LineRequest request) (LineConfig config) =+  checkMinusOne $ c_gpiod_line_request_reconfigure_lines request config  ++-- | Retrieve file descriptor ('Fd') associated with the active line request for event looping.+lineRequestFd :: LineRequest -> IO Fd+lineRequestFd (LineRequest request) = c_gpiod_line_request_get_fd request++-- | Wait for hardware edge events to occur on requested input lines.+--+-- Takes a t'TimeoutNs parameter. Returns 'Right' 'EventReady' if events are ready to read.+lineRequestWaitEdgeEvents :: LineRequest -> TimeoutNs -> IO (Either Errno WaitResult)+lineRequestWaitEdgeEvents (LineRequest request) timeoutNs = do+  res <- c_gpiod_line_request_wait_edge_events request (timeoutNsToC timeoutNs)+  if res == -1+    then Left <$> getErrno+    else case res of+      1 -> return $ Right EventReady+      0 -> return $ Right Timeout+      _ -> return $ Right Timeout++-- | Read up to @maxEvents@ edge events from a line request into an t'EventBuffer.+--+-- Returns 'Right' 'Int' containing the number of events read into the buffer.+lineRequestReadEdgeEvents :: LineRequest -> EventBuffer -> Word -> IO (Either Errno Int)+lineRequestReadEdgeEvents (LineRequest reqPtr) (EventBuffer bufPtr) maxEvents = do+  count <- c_gpiod_line_request_read_edge_events reqPtr bufPtr (fromIntegral maxEvents)+  if count == -1+    then Left <$> getErrno+    else return $ Right (fromIntegral count)++--------------------------------------------------------------------------------+-- 10. EDGE EVENTS & EVENT BUFFER+--------------------------------------------------------------------------------++-- | Free a t'RawEdgeEvent object.+rawEdgeEventFree :: RawEdgeEvent -> IO ()+rawEdgeEventFree (RawEdgeEvent event) = c_gpiod_edge_event_free event++-- | Duplicate a t'RawEdgeEvent. The copy must be freed with 'rawEdgeEventFree'.+rawEdgeEventCopy :: RawEdgeEvent -> IO (Either Errno RawEdgeEvent)+rawEdgeEventCopy (RawEdgeEvent event) = do+  res <- checkNull (c_gpiod_edge_event_copy event)+  return $ RawEdgeEvent <$> res++-- | Extract event edge type ('Rising' or 'Falling') from a raw edge event pointer.+rawEdgeEventType :: RawEdgeEvent -> IO EdgeEventType+rawEdgeEventType (RawEdgeEvent event) = c_gpiod_edge_event_get_event_type event++-- | Extract event timestamp (in nanoseconds) from a raw edge event pointer.+rawEdgeEventTimestampNs :: RawEdgeEvent -> IO TimestampNs+rawEdgeEventTimestampNs (RawEdgeEvent event) = c_gpiod_edge_event_get_timestamp_ns event++-- | Retrieve the zero-based line offset index that triggered the edge event.+rawEdgeEventLineOffset :: RawEdgeEvent -> IO LineOffset+rawEdgeEventLineOffset (RawEdgeEvent event) = c_gpiod_edge_event_get_line_offset event ++-- | Retrieve the global event sequence number across all lines on the GPIO chip.+rawEdgeEventGlobalSeqNo :: RawEdgeEvent -> IO Word64 +rawEdgeEventGlobalSeqNo (RawEdgeEvent event) =+  fromIntegral <$> c_gpiod_edge_event_get_global_seqno event  ++-- | Retrieve the line-specific event sequence number.+rawEdgeEventLineSeqNo :: RawEdgeEvent -> IO LineOffset+rawEdgeEventLineSeqNo (RawEdgeEvent event) = c_gpiod_edge_event_get_line_seqno event  ++-- | Allocate a new t'EventBuffer with the specified capacity.+--+-- Must be freed with 'eventBufferFree'.+eventBufferNew :: Word -> IO (Either Errno EventBuffer)+eventBufferNew cap = do+  res <- checkNull $ c_gpiod_edge_event_buffer_new (fromIntegral cap)+  return $ EventBuffer <$> res++-- | Query the maximum capacity of an t'EventBuffer.+eventBufferCapacity :: EventBuffer -> IO Word+eventBufferCapacity (EventBuffer buffer) =+  fromIntegral <$> c_gpiod_edge_event_buffer_get_capacity buffer ++-- | Free an t'EventBuffer and release associated memory.+eventBufferFree :: EventBuffer -> IO ()+eventBufferFree (EventBuffer buffer) = c_gpiod_edge_event_buffer_free buffer ++-- | Retrieve a raw edge event pointer from the buffer by zero-based index.+eventBufferGetEvent :: EventBuffer -> Word -> IO (Either Errno RawEdgeEvent)+eventBufferGetEvent (EventBuffer buffer) idx = do+  res <- checkNull (c_gpiod_edge_event_buffer_get_event buffer (fromIntegral idx))+  return $ RawEdgeEvent <$> res++-- | Query the number of edge events currently populated in the buffer.+eventBufferNumEvents :: EventBuffer -> IO Word+eventBufferNumEvents (EventBuffer buffer) =+  fromIntegral <$> c_gpiod_edge_event_buffer_get_num_events buffer  ++--------------------------------------------------------------------------------+-- 11. UTILITIES+--------------------------------------------------------------------------------++-- | Check whether the filesystem path (e.g. @"\/dev\/gpiochip0"@) refers to a valid GPIO chip character device node.+isGPIOChip :: ByteString -> IO Bool+isGPIOChip path = do+  BS.useAsCString path (fmap toBool . c_gpiod_is_gpiochip_device)++-- | Retrieve the version string of the underlying C @libgpiod@ library (e.g. @"2.1"@).+gpiodAPIVersion :: IO ByteString+gpiodAPIVersion = do+  ver <- c_gpiod_api_version+  if ver == nullPtr+    then return BS.empty+    else BS.packCString ver
+ src/Fuyu/GPIO/Direct/Bindings.hs view
@@ -0,0 +1,457 @@+{-# LANGUAGE ForeignFunctionInterface #-}+-- |+-- Module      : Fuyu.GPIO.Direct.Bindings+-- Description : Low-level FFI bindings to C libgpiod v2 symbols.+-- Maintainer  : BassGT+-- Portability : POSIX (Linux GPIO character device interface)+--+-- Raw Foreign Function Interface (FFI) bindings for @libgpiod v2@ C API functions.+-- Pure in-memory setters, getters, allocators, and deallocators use @unsafe@ imports+-- for zero-overhead performance, while kernel ioctl and I/O calls use default safe imports.+module Fuyu.GPIO.Direct.Bindings where++import Foreign.C.String (CString)+import Foreign.C.Types (CInt(..), CLong(..), CSize(..), CUInt(..), CULong(..), CBool(..))+import Foreign.Ptr (Ptr)+import Fuyu.GPIO.Direct.Types+import Data.Int (Int64)+import System.Posix.Types (Fd(..))++--------------------------------------------------------------------------------+-- 1. CHIP MANAGEMENT+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_chip_open@. Opens a GPIO chip at the given filesystem path.+foreign import ccall "gpiod_chip_open"+  c_gpiod_chip_open :: CString -> IO (Ptr CGpiodChip)++-- | Raw C call to @gpiod_chip_close@. Closes the chip and frees associated C resources.+foreign import ccall "gpiod_chip_close"+  c_gpiod_chip_close :: Ptr CGpiodChip -> IO ()++-- | Raw C call to @gpiod_chip_get_info@. Retrieves static chip information via kernel ioctl.+foreign import ccall "gpiod_chip_get_info"+  c_gpiod_chip_get_info :: Ptr CGpiodChip -> IO (Ptr CGpiodChipInfo) ++-- | Raw C call to @gpiod_chip_get_path@. Returns cached filesystem path string from RAM.+foreign import ccall unsafe "gpiod_chip_get_path"+  c_gpiod_chip_get_path :: Ptr CGpiodChip -> IO CString  ++-- | Raw C call to @gpiod_chip_get_line_info@. Fetches line info snapshot via kernel ioctl.+foreign import ccall "gpiod_chip_get_line_info"+  c_gpiod_chip_get_line_info :: Ptr CGpiodChip -> LineOffset -> IO (Ptr CGpiodLineInfo) ++-- | Raw C call to @gpiod_chip_watch_line_info@. Enables line status watching via kernel ioctl.+foreign import ccall "gpiod_chip_watch_line_info"+  c_gpiod_chip_watch_line_info :: Ptr CGpiodChip -> LineOffset -> IO (Ptr CGpiodLineInfo) ++-- | Raw C call to @gpiod_chip_unwatch_line_info@. Disables status watching via kernel ioctl.+foreign import ccall "gpiod_chip_unwatch_line_info"+  c_gpiod_chip_unwatch_line_info :: Ptr CGpiodChip -> LineOffset -> IO CInt++-- | Raw C call to @gpiod_chip_get_fd@. Returns cached file descriptor from RAM.+foreign import ccall unsafe "gpiod_chip_get_fd"+  c_gpiod_chip_get_fd :: Ptr CGpiodChip -> IO Fd++-- | Raw C call to @gpiod_chip_wait_info_event@. Waits for status events via poll/epoll syscall.+foreign import ccall "gpiod_chip_wait_info_event"+  c_gpiod_chip_wait_info_event :: Ptr CGpiodChip -> Int64 -> IO CInt ++-- | Raw C call to @gpiod_chip_read_info_event@. Reads info event via read syscall.+foreign import ccall "gpiod_chip_read_info_event"+  c_gpiod_chip_read_info_event :: Ptr CGpiodChip -> IO (Ptr CGpiodInfoEvent)++-- | Raw C call to @gpiod_chip_request_lines@. Requests lines via kernel ioctl.+foreign import ccall "gpiod_chip_request_lines"+  c_gpiod_chip_request_lines :: Ptr CGpiodChip +                             -> Ptr CGpiodRequestConfig+                             -> Ptr CGpiodLineConfig+                             -> IO (Ptr CGpiodLineRequest)++-- | Raw C call to @gpiod_chip_get_line_offset_from_name@. Looks up line offset by pin name.+foreign import ccall "gpiod_chip_get_line_offset_from_name"+  c_gpiod_chip_get_line_offset_from_name :: Ptr CGpiodChip -> CString -> IO CInt++--------------------------------------------------------------------------------+-- 2. CHIP INFO+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_chip_info_free@. Frees a chip info object in C heap.+foreign import ccall unsafe "gpiod_chip_info_free"+  c_gpiod_chip_info_free :: Ptr CGpiodChipInfo -> IO ()++-- | Raw C call to @gpiod_chip_info_get_name@. Gets chip device name from RAM.+foreign import ccall unsafe "gpiod_chip_info_get_name"+  c_gpiod_chip_info_get_name :: Ptr CGpiodChipInfo -> IO CString++-- | Raw C call to @gpiod_chip_info_get_label@. Gets hardware controller label from RAM.+foreign import ccall unsafe "gpiod_chip_info_get_label"+  c_gpiod_chip_info_get_label :: Ptr CGpiodChipInfo -> IO CString  ++-- | Raw C call to @gpiod_chip_info_get_num_lines@. Gets total count of lines from RAM.+foreign import ccall unsafe "gpiod_chip_info_get_num_lines"+  c_gpiod_chip_info_get_num_lines :: Ptr CGpiodChipInfo -> IO CSize ++--------------------------------------------------------------------------------+-- 4. LINE INFORMATION+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_line_info_free@. Frees a line info object in C heap.+foreign import ccall unsafe "gpiod_line_info_free"+  c_gpiod_line_info_free :: Ptr CGpiodLineInfo -> IO ()++-- | Raw C call to @gpiod_line_info_copy@. Duplicates line info object in RAM.+foreign import ccall unsafe "gpiod_line_info_copy"+  c_gpiod_line_info_copy :: Ptr CGpiodLineInfo -> IO (Ptr CGpiodLineInfo)++-- | Raw C call to @gpiod_line_info_get_offset@. Returns line offset index from RAM.+foreign import ccall unsafe "gpiod_line_info_get_offset"+  c_gpiod_line_info_get_offset :: Ptr CGpiodLineInfo -> IO LineOffset++-- | Raw C call to @gpiod_line_info_get_name@. Returns pin name string from RAM.+foreign import ccall unsafe "gpiod_line_info_get_name"+  c_gpiod_line_info_get_name :: Ptr CGpiodLineInfo -> IO CString++-- | Raw C call to @gpiod_line_info_is_used@. Checks if line is used from RAM.+foreign import ccall unsafe "gpiod_line_info_is_used"+  c_gpiod_line_info_is_used :: Ptr CGpiodLineInfo -> IO CBool++-- | Raw C call to @gpiod_line_info_get_consumer@. Gets consumer label from RAM.+foreign import ccall unsafe "gpiod_line_info_get_consumer"+  c_gpiod_line_info_get_consumer :: Ptr CGpiodLineInfo -> IO CString++-- | Raw C call to @gpiod_line_info_get_direction@. Gets direction setting from RAM.+foreign import ccall unsafe "gpiod_line_info_get_direction"+  c_gpiod_line_info_get_direction :: Ptr CGpiodLineInfo -> IO LineDirection++-- | Raw C call to @gpiod_line_info_get_edge_detection@. Gets edge mode from RAM.+foreign import ccall unsafe "gpiod_line_info_get_edge_detection"+  c_gpiod_line_info_get_edge_detection :: Ptr CGpiodLineInfo -> IO LineEdge++-- | Raw C call to @gpiod_line_info_get_bias@. Gets internal pull bias setting from RAM.+foreign import ccall unsafe "gpiod_line_info_get_bias"+  c_gpiod_line_info_get_bias :: Ptr CGpiodLineInfo -> IO LineBias++-- | Raw C call to @gpiod_line_info_get_drive@. Gets output drive configuration from RAM.+foreign import ccall unsafe "gpiod_line_info_get_drive"+  c_gpiod_line_info_get_drive :: Ptr CGpiodLineInfo -> IO LineDrive++-- | Raw C call to @gpiod_line_info_is_active_low@. Checks active-low flag from RAM.+foreign import ccall unsafe "gpiod_line_info_is_active_low"+  c_gpiod_line_info_is_active_low :: Ptr CGpiodLineInfo -> IO CBool  ++-- | Raw C call to @gpiod_line_info_is_debounced@. Checks debounce filter flag from RAM.+foreign import ccall unsafe "gpiod_line_info_is_debounced"+  c_gpiod_line_info_is_debounced :: Ptr CGpiodLineInfo -> IO CBool  ++-- | Raw C call to @gpiod_line_info_get_debounce_period_us@. Gets debounce period from RAM.+foreign import ccall unsafe "gpiod_line_info_get_debounce_period_us"+  c_gpiod_line_info_get_debounce_period_us :: Ptr CGpiodLineInfo -> IO CULong++-- | Raw C call to @gpiod_line_info_get_event_clock@. Gets event timestamp clock source from RAM.+foreign import ccall unsafe "gpiod_line_info_get_event_clock"+  c_gpiod_line_info_get_event_clock :: Ptr CGpiodLineInfo -> IO LineClock++--------------------------------------------------------------------------------+-- 5. LINE WATCH (INFO EVENT)+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_info_event_free@. Frees an info event structure in C heap.+foreign import ccall unsafe "gpiod_info_event_free"+  c_gpiod_info_event_free :: Ptr CGpiodInfoEvent -> IO ()++-- | Raw C call to @gpiod_info_event_get_event_type@. Gets event type from RAM.+foreign import ccall unsafe "gpiod_info_event_get_event_type"+  c_gpiod_info_event_get_event_type :: Ptr CGpiodInfoEvent -> IO InfoEventType++-- | Raw C call to @gpiod_info_event_get_timestamp_ns@. Gets event timestamp from RAM.+foreign import ccall unsafe "gpiod_info_event_get_timestamp_ns"+  c_gpiod_info_event_get_timestamp_ns :: Ptr CGpiodInfoEvent -> IO TimestampNs++-- | Raw C call to @gpiod_info_event_get_line_info@. Reads line info pointer from RAM.+foreign import ccall unsafe "gpiod_info_event_get_line_info"+  c_gpiod_info_event_get_line_info :: Ptr CGpiodInfoEvent -> IO (Ptr CGpiodLineInfo)++--------------------------------------------------------------------------------+-- 6. LINE SETTINGS+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_line_settings_new@. Allocates line settings object in RAM.+foreign import ccall unsafe "gpiod_line_settings_new"+  c_gpiod_line_settings_new :: IO (Ptr CGpiodLineSettings)++-- | Raw C call to @gpiod_line_settings_free@. Frees line settings object in RAM.+foreign import ccall unsafe "gpiod_line_settings_free"+  c_gpiod_line_settings_free :: Ptr CGpiodLineSettings -> IO ()++-- | Raw C call to @gpiod_line_settings_reset@. Resets settings object in RAM.+foreign import ccall unsafe "gpiod_line_settings_reset"+  c_gpiod_line_settings_reset :: Ptr CGpiodLineSettings -> IO ()++-- | Raw C call to @gpiod_line_settings_copy@. Duplicates line settings object in RAM.+foreign import ccall unsafe "gpiod_line_settings_copy"+  c_gpiod_line_settings_copy :: Ptr CGpiodLineSettings -> IO (Ptr CGpiodLineSettings)++-- | Raw C call to @gpiod_line_settings_set_direction@. Sets line direction setting in RAM.+foreign import ccall unsafe "gpiod_line_settings_set_direction"+  c_gpiod_line_settings_set_direction :: Ptr CGpiodLineSettings -> LineDirection -> IO CInt      ++-- | Raw C call to @gpiod_line_settings_get_direction@. Gets line direction setting from RAM.+foreign import ccall unsafe "gpiod_line_settings_get_direction"+  c_gpiod_line_settings_get_direction :: Ptr CGpiodLineSettings -> IO LineDirection++-- | Raw C call to @gpiod_line_settings_set_edge_detection@. Sets edge detection setting in RAM.+foreign import ccall unsafe "gpiod_line_settings_set_edge_detection"+  c_gpiod_line_settings_set_edge_detection :: Ptr CGpiodLineSettings -> LineEdge -> IO CInt ++-- | Raw C call to @gpiod_line_settings_get_edge_detection@. Gets edge detection setting from RAM.+foreign import ccall unsafe "gpiod_line_settings_get_edge_detection"+  c_gpiod_line_settings_get_edge_detection :: Ptr CGpiodLineSettings -> IO LineEdge ++-- | Raw C call to @gpiod_line_settings_set_bias@. Sets internal pull bias setting in RAM.+foreign import ccall unsafe "gpiod_line_settings_set_bias"+  c_gpiod_line_settings_set_bias :: Ptr CGpiodLineSettings -> LineBias -> IO CInt++-- | Raw C call to @gpiod_line_settings_get_bias@. Gets internal pull bias setting from RAM.+foreign import ccall unsafe "gpiod_line_settings_get_bias"+  c_gpiod_line_settings_get_bias :: Ptr CGpiodLineSettings -> IO LineBias++-- | Raw C call to @gpiod_line_settings_set_drive@. Sets driver output mode in RAM.+foreign import ccall unsafe "gpiod_line_settings_set_drive"+  c_gpiod_line_settings_set_drive :: Ptr CGpiodLineSettings -> LineDrive -> IO CInt++-- | Raw C call to @gpiod_line_settings_get_drive@. Gets driver output mode from RAM.+foreign import ccall unsafe "gpiod_line_settings_get_drive"+  c_gpiod_line_settings_get_drive :: Ptr CGpiodLineSettings -> IO LineDrive++-- | Raw C call to @gpiod_line_settings_set_active_low@. Sets active-low property flag in RAM.+foreign import ccall unsafe "gpiod_line_settings_set_active_low"+  c_gpiod_line_settings_set_active_low :: Ptr CGpiodLineSettings -> CBool -> IO ()  ++-- | Raw C call to @gpiod_line_settings_get_active_low@. Gets active-low property flag from RAM.+foreign import ccall unsafe "gpiod_line_settings_get_active_low"+  c_gpiod_line_settings_get_active_low :: Ptr CGpiodLineSettings -> IO CBool++-- | Raw C call to @gpiod_line_settings_set_debounce_period_us@. Sets input debounce period in RAM.+foreign import ccall unsafe "gpiod_line_settings_set_debounce_period_us"+  c_gpiod_line_settings_set_debounce_period_us :: Ptr CGpiodLineSettings -> CLong -> IO ()  ++-- | Raw C call to @gpiod_line_settings_get_debounce_period_us@. Gets input debounce period from RAM.+foreign import ccall unsafe "gpiod_line_settings_get_debounce_period_us"+  c_gpiod_line_settings_get_debounce_period_us :: Ptr CGpiodLineSettings -> IO CLong++-- | Raw C call to @gpiod_line_settings_set_event_clock@. Sets event clock source in RAM.+foreign import ccall unsafe "gpiod_line_settings_set_event_clock"+  c_gpiod_line_settings_set_event_clock :: Ptr CGpiodLineSettings -> LineClock -> IO CInt ++-- | Raw C call to @gpiod_line_settings_get_event_clock@. Gets event clock source from RAM.+foreign import ccall unsafe "gpiod_line_settings_get_event_clock"+  c_gpiod_line_settings_get_event_clock :: Ptr CGpiodLineSettings -> IO LineClock++-- | Raw C call to @gpiod_line_settings_set_output_value@. Sets output value setting in RAM.+foreign import ccall unsafe "gpiod_line_settings_set_output_value"+  c_gpiod_line_settings_set_output_value :: Ptr CGpiodLineSettings -> LineValue -> IO CInt ++-- | Raw C call to @gpiod_line_settings_get_output_value@. Gets output value setting from RAM.+foreign import ccall unsafe "gpiod_line_settings_get_output_value"+  c_gpiod_line_settings_get_output_value :: Ptr CGpiodLineSettings -> IO LineValue++--------------------------------------------------------------------------------+-- 7. LINE CONFIGURATION+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_line_config_new@. Allocates line config accumulator in RAM.+foreign import ccall unsafe "gpiod_line_config_new"+  c_gpiod_line_config_new :: IO (Ptr CGpiodLineConfig)++-- | Raw C call to @gpiod_line_config_free@. Frees line config object in RAM.+foreign import ccall unsafe "gpiod_line_config_free"+  c_gpiod_line_config_free :: Ptr CGpiodLineConfig -> IO ()++-- | Raw C call to @gpiod_line_config_reset@. Clears line settings mapping in RAM.+foreign import ccall unsafe "gpiod_line_config_reset"+  c_gpiod_line_config_reset :: Ptr CGpiodLineConfig -> IO ()++-- | Raw C call to @gpiod_line_config_add_line_settings@. Maps array of offsets to settings in RAM.+foreign import ccall unsafe "gpiod_line_config_add_line_settings"+  c_gpiod_line_config_add_line_settings :: Ptr CGpiodLineConfig+                                        -> Ptr LineOffset+                                        -> CSize+                                        -> Ptr CGpiodLineSettings +                                        -> IO CInt++-- | Raw C call to @gpiod_line_config_get_line_settings@. Gets line settings associated with offset in RAM.+foreign import ccall unsafe "gpiod_line_config_get_line_settings"+  c_gpiod_line_config_get_line_settings :: Ptr CGpiodLineConfig -> LineOffset -> IO (Ptr CGpiodLineSettings)++-- | Raw C call to @gpiod_line_config_set_output_values@. Overrides output values in RAM.+foreign import ccall unsafe "gpiod_line_config_set_output_values"+  c_gpiod_line_config_set_output_values :: Ptr CGpiodLineConfig -> Ptr LineValue -> CSize -> IO CInt++-- | Raw C call to @gpiod_line_config_get_num_configured_offsets@. Gets count of offsets from RAM.+foreign import ccall unsafe "gpiod_line_config_get_num_configured_offsets"+  c_gpiod_line_config_get_num_configured_offsets :: Ptr CGpiodLineConfig -> IO CSize++-- | Raw C call to @gpiod_line_config_get_configured_offsets@. Copies configured offsets array in RAM.+foreign import ccall unsafe "gpiod_line_config_get_configured_offsets"+  c_gpiod_line_config_get_configured_offsets :: Ptr CGpiodLineConfig -> Ptr LineOffset -> CSize -> IO CSize++--------------------------------------------------------------------------------+-- 8. REQUESTS CONFIG+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_request_config_new@. Allocates request configuration in RAM.+foreign import ccall unsafe "gpiod_request_config_new"+  c_gpiod_request_config_new :: IO (Ptr CGpiodRequestConfig)++-- | Raw C call to @gpiod_request_config_free@. Frees request config object in RAM.+foreign import ccall unsafe "gpiod_request_config_free"+  c_gpiod_request_config_free :: Ptr CGpiodRequestConfig -> IO()++-- | Raw C call to @gpiod_request_config_set_consumer@. Sets consumer string in RAM.+foreign import ccall unsafe "gpiod_request_config_set_consumer"+  c_gpiod_request_config_set_consumer :: Ptr CGpiodRequestConfig -> CString -> IO()++-- | Raw C call to @gpiod_request_config_get_consumer@. Reads consumer string from RAM.+foreign import ccall unsafe "gpiod_request_config_get_consumer"+  c_gpiod_request_config_get_consumer :: Ptr CGpiodRequestConfig -> IO CString++-- | Raw C call to @gpiod_request_config_set_event_buffer_size@. Sets kernel event buffer size in RAM.+foreign import ccall unsafe "gpiod_request_config_set_event_buffer_size"+  c_gpiod_request_config_set_event_buffer_size :: Ptr CGpiodRequestConfig -> CSize -> IO()   ++-- | Raw C call to @gpiod_request_config_get_event_buffer_size@. Gets kernel event buffer size from RAM.+foreign import ccall unsafe "gpiod_request_config_get_event_buffer_size"+  c_gpiod_request_config_get_event_buffer_size :: Ptr CGpiodRequestConfig -> IO CSize  ++--------------------------------------------------------------------------------+-- 9. LINE REQUEST+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_line_request_release@. Releases lines and closes line request file descriptor.+foreign import ccall "gpiod_line_request_release"+  c_gpiod_line_request_release :: Ptr CGpiodLineRequest -> IO()++-- | Raw C call to @gpiod_line_request_get_chip_name@. Gets chip device name from RAM.+foreign import ccall unsafe "gpiod_line_request_get_chip_name"+  c_gpiod_line_request_get_chip_name :: Ptr CGpiodLineRequest -> IO CString++-- | Raw C call to @gpiod_line_request_get_num_requested_lines@. Gets line count from RAM.+foreign import ccall unsafe "gpiod_line_request_get_num_requested_lines"+  c_gpiod_line_request_get_num_requested_lines :: Ptr CGpiodLineRequest -> IO CSize++-- | Raw C call to @gpiod_line_request_get_requested_offsets@. Copies requested line offsets from RAM.+foreign import ccall unsafe "gpiod_line_request_get_requested_offsets"+  c_gpiod_line_request_get_requested_offsets :: Ptr CGpiodLineRequest -> Ptr LineOffset -> CSize -> IO CSize++-- | Raw C call to @gpiod_line_request_get_value@. Reads logical value via kernel ioctl.+foreign import ccall "gpiod_line_request_get_value"+  c_gpiod_line_request_get_value :: Ptr CGpiodLineRequest -> LineOffset -> IO LineValue ++-- | Raw C call to @gpiod_line_request_get_values_subset@. Reads logical values subset via kernel ioctl.+foreign import ccall "gpiod_line_request_get_values_subset"+  c_gpiod_line_request_get_values_subset :: Ptr CGpiodLineRequest+                                         -> CSize+                                         -> Ptr LineOffset+                                         -> Ptr LineValue+                                         -> IO CInt++-- | Raw C call to @gpiod_line_request_get_values@. Reads logical values via kernel ioctl.+foreign import ccall "gpiod_line_request_get_values"+  c_gpiod_line_request_get_values :: Ptr CGpiodLineRequest -> Ptr LineValue -> IO CInt ++-- | Raw C call to @gpiod_line_request_set_value@. Sets logical value via kernel ioctl.+foreign import ccall "gpiod_line_request_set_value"+  c_gpiod_line_request_set_value :: Ptr CGpiodLineRequest -> LineOffset -> LineValue -> IO CInt ++-- | Raw C call to @gpiod_line_request_set_values_subset@. Sets logical values subset via kernel ioctl.+foreign import ccall "gpiod_line_request_set_values_subset"+  c_gpiod_line_request_set_values_subset :: Ptr CGpiodLineRequest+                                          -> CSize+                                          -> Ptr LineOffset+                                          -> Ptr LineValue+                                          -> IO CInt++-- | Raw C call to @gpiod_line_request_set_values@. Sets logical values via kernel ioctl.+foreign import ccall "gpiod_line_request_set_values"+  c_gpiod_line_request_set_values :: Ptr CGpiodLineRequest -> Ptr LineValue -> IO CInt ++-- | Raw C call to @gpiod_line_request_reconfigure_lines@. Applies new configuration via kernel ioctl.+foreign import ccall "gpiod_line_request_reconfigure_lines"+  c_gpiod_line_request_reconfigure_lines :: Ptr CGpiodLineRequest -> Ptr CGpiodLineConfig -> IO CInt  ++-- | Raw C call to @gpiod_line_request_get_fd@. Returns cached file descriptor from RAM.+foreign import ccall unsafe "gpiod_line_request_get_fd"+  c_gpiod_line_request_get_fd :: Ptr CGpiodLineRequest -> IO Fd ++-- | Raw C call to @gpiod_line_request_wait_edge_events@. Waits for edge events via poll/epoll syscall.+foreign import ccall "gpiod_line_request_wait_edge_events"+  c_gpiod_line_request_wait_edge_events :: Ptr CGpiodLineRequest -> CLong -> IO CInt++-- | Raw C call to @gpiod_line_request_read_edge_events@. Reads edge events via read syscall.+foreign import ccall "gpiod_line_request_read_edge_events" +  c_gpiod_line_request_read_edge_events :: Ptr CGpiodLineRequest -> Ptr CGpiodEdgeEventBuffer -> CSize -> IO CInt++--------------------------------------------------------------------------------+-- 10. EDGE EVENTS & EVENT BUFFER+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_edge_event_free@. Frees an edge event structure in RAM.+foreign import ccall unsafe "gpiod_edge_event_free"+  c_gpiod_edge_event_free :: Ptr CGpiodEdgeEvent -> IO ()++-- | Raw C call to @gpiod_edge_event_copy@. Duplicates an edge event in RAM.+foreign import ccall unsafe "gpiod_edge_event_copy"+  c_gpiod_edge_event_copy :: Ptr CGpiodEdgeEvent -> IO (Ptr CGpiodEdgeEvent)++-- | Raw C call to @gpiod_edge_event_get_event_type@. Gets edge type from RAM.+foreign import ccall unsafe "gpiod_edge_event_get_event_type"+  c_gpiod_edge_event_get_event_type :: Ptr CGpiodEdgeEvent -> IO EdgeEventType++-- | Raw C call to @gpiod_edge_event_get_timestamp_ns@. Gets edge event timestamp from RAM.+foreign import ccall unsafe "gpiod_edge_event_get_timestamp_ns" +  c_gpiod_edge_event_get_timestamp_ns :: Ptr CGpiodEdgeEvent -> IO TimestampNs ++-- | Raw C call to @gpiod_edge_event_get_line_offset@. Gets triggering line offset from RAM.+foreign import ccall unsafe "gpiod_edge_event_get_line_offset"+  c_gpiod_edge_event_get_line_offset :: Ptr CGpiodEdgeEvent -> IO LineOffset++-- | Raw C call to @gpiod_edge_event_get_global_seqno@. Gets global sequence number from RAM.+foreign import ccall unsafe "gpiod_edge_event_get_global_seqno"+  c_gpiod_edge_event_get_global_seqno :: Ptr CGpiodEdgeEvent -> IO CULong ++-- | Raw C call to @gpiod_edge_event_get_line_seqno@. Gets line sequence number from RAM.+foreign import ccall unsafe "gpiod_edge_event_get_line_seqno"+  c_gpiod_edge_event_get_line_seqno :: Ptr CGpiodEdgeEvent -> IO LineOffset ++-- | Raw C call to @gpiod_edge_event_buffer_new@. Allocates edge event buffer in RAM.+foreign import ccall unsafe "gpiod_edge_event_buffer_new"+  c_gpiod_edge_event_buffer_new :: CSize -> IO (Ptr CGpiodEdgeEventBuffer)++-- | Raw C call to @gpiod_edge_event_buffer_get_capacity@. Gets buffer capacity from RAM.+foreign import ccall unsafe "gpiod_edge_event_buffer_get_capacity"+  c_gpiod_edge_event_buffer_get_capacity :: Ptr CGpiodEdgeEventBuffer -> IO CSize++-- | Raw C call to @gpiod_edge_event_buffer_free@. Frees edge event buffer in RAM.+foreign import ccall unsafe "gpiod_edge_event_buffer_free"+  c_gpiod_edge_event_buffer_free :: Ptr CGpiodEdgeEventBuffer -> IO ()++-- | Raw C call to @gpiod_edge_event_buffer_get_event@. Fetches event pointer by index from RAM array.+foreign import ccall unsafe "gpiod_edge_event_buffer_get_event"+  c_gpiod_edge_event_buffer_get_event :: Ptr CGpiodEdgeEventBuffer -> CULong -> IO (Ptr CGpiodEdgeEvent)++-- | Raw C call to @gpiod_edge_event_buffer_get_num_events@. Gets count of events from RAM.+foreign import ccall unsafe "gpiod_edge_event_buffer_get_num_events"+  c_gpiod_edge_event_buffer_get_num_events :: Ptr CGpiodEdgeEventBuffer -> IO CSize ++--------------------------------------------------------------------------------+-- 11. MISCELLANEOUS UTILITIES+--------------------------------------------------------------------------------++-- | Raw C call to @gpiod_is_gpiochip_device@. Performs stat/open filesystem syscall on dev path.+foreign import ccall "gpiod_is_gpiochip_device"+  c_gpiod_is_gpiochip_device :: CString -> IO CBool++-- | Raw C call to @gpiod_api_version@. Returns static version string from RAM.+foreign import ccall unsafe "gpiod_api_version"+  c_gpiod_api_version :: IO CString
+ src/Fuyu/GPIO/Direct/Types.hs view
@@ -0,0 +1,363 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE PatternSynonyms #-}+-- |+-- Module      : Fuyu.GPIO.Direct.Types+-- Description : Core data types, newtype wrappers, and C enum pattern synonyms for libgpiod v2 bindings.+-- Maintainer  : BassGT+-- Portability : POSIX (Linux GPIO character device interface)+--+-- This module defines all data types, opaque handles, safety wrappers, pattern+-- synonyms for C enums, and native helper structures used throughout the+-- @fuyu-gpio-direct@ library.+--+-- Resource handles wrap raw foreign pointers to C structures managed by @libgpiod v2@.+-- Callers are responsible for explicitly freeing handles created via allocations or getters+-- using their corresponding cleanup operations (e.g., 'Fuyu.GPIO.Direct.chipClose',+-- 'Fuyu.GPIO.Direct.lineSettingsFree', etc.).+module Fuyu.GPIO.Direct.Types where++import Foreign.Ptr (Ptr)+import Foreign.Storable (Storable)+import Data.Word (Word64)+import Foreign.C.Types (CInt(..), CUInt(..), CULong(..))++--------------------------------------------------------------------------------+-- CORE TYPES & WRAPPERS+--------------------------------------------------------------------------------++-- | Opaque ghost type representing the C structure @struct gpiod_chip@.+data CGpiodChip ++-- | Opaque ghost type representing the C structure @struct gpiod_chip_info@.+data CGpiodChipInfo++-- | Opaque ghost type representing the C structure @struct gpiod_info_event@.+data CGpiodInfoEvent++-- | Opaque ghost type representing the C structure @struct gpiod_line_info@.+data CGpiodLineInfo ++-- | Opaque ghost type representing the C structure @struct gpiod_line_settings@.+data CGpiodLineSettings  ++-- | Opaque ghost type representing the C structure @struct gpiod_line_config@.+data CGpiodLineConfig  ++-- | Opaque ghost type representing the C structure @struct gpiod_line_request@.+data CGpiodLineRequest    ++-- | Opaque ghost type representing the C structure @struct gpiod_request_config@.+data CGpiodRequestConfig++-- | Opaque ghost type representing the C structure @struct gpiod_edge_event_buffer@.+data CGpiodEdgeEventBuffer++-- | Opaque ghost type representing the C structure @struct gpiod_edge_event@.+data CGpiodEdgeEvent++-- | Opaque handle representing an open GPIO chip device controller.+--+-- Must be explicitly closed with 'Fuyu.GPIO.Direct.chipClose' when no longer needed.+newtype Chip = Chip (Ptr CGpiodChip)+  deriving (Eq, Ord, Show)++-- | Opaque snapshot of static GPIO chip information (name, label, line count).+--+-- Must be explicitly freed with 'Fuyu.GPIO.Direct.chipInfoFree'.+newtype ChipInfo = ChipInfo (Ptr CGpiodChipInfo)+  deriving (Eq, Ord, Show)++-- | Opaque event object emitted when a line watched on a chip changes status.+--+-- Must be explicitly freed with 'Fuyu.GPIO.Direct.infoEventFree'.+newtype InfoEvent = InfoEvent (Ptr CGpiodInfoEvent)+  deriving (Eq, Ord, Show)++-- | Opaque snapshot of a single GPIO line\'s status and configuration attributes.+--+-- Must be explicitly freed with 'Fuyu.GPIO.Direct.lineInfoFree'.+newtype LineInfo = LineInfo (Ptr CGpiodLineInfo)+  deriving (Eq, Ord, Show)++-- | Opaque accumulator for GPIO line configuration settings (direction, drive, bias, etc.).+--+-- Must be explicitly freed with 'Fuyu.GPIO.Direct.lineSettingsFree'.+newtype LineSettings = LineSettings (Ptr CGpiodLineSettings)+  deriving (Eq, Ord, Show)++-- | Opaque map associating line offsets with their respective t'LineSettings.+--+-- Must be explicitly freed with 'Fuyu.GPIO.Direct.lineConfigFree'.+newtype LineConfig = LineConfig (Ptr CGpiodLineConfig)+  deriving (Eq, Ord, Show)++-- | Opaque handle representing requested (claimed) GPIO lines under active kernel control.+--+-- Must be explicitly released with 'Fuyu.GPIO.Direct.lineRequestRelease'.+newtype LineRequest = LineRequest (Ptr CGpiodLineRequest)+  deriving (Eq, Ord, Show)++-- | Opaque request configuration object (consumer name, kernel event buffer size).+--+-- Must be explicitly freed with 'Fuyu.GPIO.Direct.requestConfigFree'.+newtype RequestConfig = RequestConfig (Ptr CGpiodRequestConfig)+  deriving (Eq, Ord, Show)++-- | Opaque fixed-capacity buffer storing edge detection events read from the kernel.+--+-- Must be explicitly freed with 'Fuyu.GPIO.Direct.eventBufferFree'.+newtype EventBuffer = EventBuffer (Ptr CGpiodEdgeEventBuffer) +  deriving (Eq, Ord, Show)++-- | Opaque reference to an individual edge detection event stored within an t'EventBuffer.+--+-- Can be copied using 'Fuyu.GPIO.Direct.rawEdgeEventCopy', which returned copy must be freed+-- via 'Fuyu.GPIO.Direct.rawEdgeEventFree'.+newtype RawEdgeEvent = RawEdgeEvent (Ptr CGpiodEdgeEvent)+  deriving (Eq, Ord, Show)++-- | Type-safe wrapper for zero-based GPIO line offset indices on a chip.+newtype LineOffset = LineOffset CUInt+  deriving (Eq, Ord, Show, Read, Storable)++++--------------------------------------------------------------------------------+-- LINE DEFINITIONS TYPES+--------------------------------------------------------------------------------++-- | Logical line state representation.+--+-- Note that logical values account for active-low inversion: an active-low line set to+-- 'LineActive' corresponds to a physical logic low voltage level on hardware.+newtype LineValue = LineValue CInt+  deriving (Eq, Ord, Read, Storable)++instance Show LineValue where+  show LineActive   = "Active"+  show LineInactive = "Inactive"+  show LineError    = "Error"+  show (LineValue n) = "LineValue " ++ show n++-- | Logical active state (1).+pattern LineActive :: LineValue+pattern LineActive = LineValue 1++-- | Logical inactive state (0).+pattern LineInactive :: LineValue+pattern LineInactive = LineValue 0++-- | Error sentinel returned by low-level functions on failure (-1).+pattern LineError :: LineValue+pattern LineError = LineValue (-1)++{-# COMPLETE LineActive, LineInactive, LineError, LineValue #-}++-- | GPIO line pin direction configuration.+newtype LineDirection = LineDirection CInt+  deriving (Eq, Ord, Read, Storable)++instance Show LineDirection where+  show DirAsIs   = "DirAsIs"+  show DirInput  = "DirInput"+  show DirOutput = "DirOutput"+  show (LineDirection n) = "LineDirection " ++ show n++-- | Leave line direction unchanged during configuration re-application.+pattern DirAsIs :: LineDirection+pattern DirAsIs = LineDirection 1++-- | Configure line as input.+pattern DirInput :: LineDirection+pattern DirInput = LineDirection 2++-- | Configure line as output.+pattern DirOutput :: LineDirection+pattern DirOutput = LineDirection 3++{-# COMPLETE DirAsIs, DirInput, DirOutput, LineDirection #-}++-- | Edge detection mode for monitoring input signal transitions.+newtype LineEdge = LineEdge CInt+  deriving (Eq, Ord, Read, Storable)++instance Show LineEdge where+  show EdgeNone    = "EdgeNone"+  show EdgeRising  = "EdgeRising"+  show EdgeFalling = "EdgeFalling"+  show EdgeBoth    = "EdgeBoth"+  show (LineEdge n) = "LineEdge " ++ show n++-- | Disable edge detection events on this line.+pattern EdgeNone :: LineEdge+pattern EdgeNone = LineEdge 1++-- | Trigger edge events on low-to-high (rising) signal transitions.+pattern EdgeRising :: LineEdge+pattern EdgeRising = LineEdge 2++-- | Trigger edge events on high-to-low (falling) signal transitions.+pattern EdgeFalling :: LineEdge+pattern EdgeFalling = LineEdge 3++-- | Trigger edge events on both rising and falling signal transitions.+pattern EdgeBoth :: LineEdge+pattern EdgeBoth = LineEdge 4++{-# COMPLETE EdgeNone, EdgeRising, EdgeFalling, EdgeBoth, LineEdge #-}++-- | Internal pull resistor bias configuration for a line.+newtype LineBias = LineBias CInt+  deriving (Eq, Ord, Read, Storable)++instance Show LineBias where+  show BiasAsIs     = "BiasAsIs"+  show BiasUnknown  = "BiasUnknown"+  show BiasDisabled = "BiasDisabled"+  show BiasPullUp   = "BiasPullUp"+  show BiasPullDown = "BiasPullDown"+  show (LineBias n) = "LineBias " ++ show n++-- | Keep current line bias settings unchanged.+pattern BiasAsIs :: LineBias+pattern BiasAsIs = LineBias 1++-- | Line bias is unknown or non-standard.+pattern BiasUnknown :: LineBias+pattern BiasUnknown = LineBias 2++-- | Disable internal pull-up and pull-down resistors (floating input / tri-stated).+pattern BiasDisabled :: LineBias+pattern BiasDisabled = LineBias 3++-- | Enable internal pull-up resistor.+pattern BiasPullUp :: LineBias+pattern BiasPullUp = LineBias 4++-- | Enable internal pull-down resistor.+pattern BiasPullDown :: LineBias+pattern BiasPullDown = LineBias 5++{-# COMPLETE BiasAsIs, BiasUnknown, BiasDisabled, BiasPullUp, BiasPullDown, LineBias #-}++-- | Output pin driver mode configuration.+newtype LineDrive = LineDrive CInt+  deriving (Eq, Ord, Read, Storable)++instance Show LineDrive where+  show PushPull   = "PushPull"+  show OpenDrain  = "OpenDrain"+  show OpenSource = "OpenSource"+  show (LineDrive n) = "LineDrive " ++ show n++-- | Standard push-pull driver actively driving high and low output logic levels.+pattern PushPull :: LineDrive+pattern PushPull = LineDrive 1++-- | Open-drain driver mode (sinks current when active, open/high-impedance when inactive).+pattern OpenDrain :: LineDrive+pattern OpenDrain = LineDrive 2++-- | Open-source driver mode (sources current when active, open/high-impedance when inactive).+pattern OpenSource :: LineDrive+pattern OpenSource = LineDrive 3++{-# COMPLETE PushPull, OpenDrain, OpenSource, LineDrive #-}++-- | Timestamp clock source used when recording line edge events in the kernel.+newtype LineClock = LineClock CInt+  deriving (Eq, Ord, Read, Storable)++instance Show LineClock where+  show Monotonic = "Monotonic"+  show Realtime  = "Realtime"+  show Hardware  = "Hardware"+  show (LineClock n) = "LineClock " ++ show n++-- | Kernel @CLOCK_MONOTONIC@ clock source (default).+pattern Monotonic :: LineClock+pattern Monotonic = LineClock 1++-- | Kernel @CLOCK_REALTIME@ wall-clock source.+pattern Realtime :: LineClock+pattern Realtime = LineClock 2++-- | Hardware SoC timestamp clock source (if supported by hardware/kernel).+pattern Hardware :: LineClock+pattern Hardware = LineClock 3++{-# COMPLETE Monotonic, Realtime, Hardware, LineClock #-}++--------------------------------------------------------------------------------+-- OTHER LIBGPIOD DEFINITIONS TYPES+--------------------------------------------------------------------------------++-- | Type of status change event emitted when watching line status on a GPIO chip.+newtype InfoEventType = InfoEventType CInt+  deriving (Eq, Ord, Read, Storable)++instance Show InfoEventType where+  show LineRequested     = "LineRequested"+  show LineReleased      = "LineReleased"+  show LineConfigChanged = "LineConfigChanged"+  show (InfoEventType n) = "InfoEventType " ++ show n++-- | Line was claimed / requested by a process consumer.+pattern LineRequested :: InfoEventType+pattern LineRequested = InfoEventType 1++-- | Line was released by its consumer process.+pattern LineReleased :: InfoEventType+pattern LineReleased = InfoEventType 2++-- | Line configuration attributes were modified.+pattern LineConfigChanged :: InfoEventType+pattern LineConfigChanged = InfoEventType 3++{-# COMPLETE LineRequested, LineReleased, LineConfigChanged, InfoEventType #-}++-- | Direction of transition detected on an input edge event.+newtype EdgeEventType = EdgeEventType CInt+  deriving (Eq, Ord, Read, Storable)++instance Show EdgeEventType where+  show Rising  = "Rising"+  show Falling = "Falling"+  show (EdgeEventType n) = "EdgeEventType " ++ show n++-- | Low-to-high transition detected.+pattern Rising :: EdgeEventType+pattern Rising = EdgeEventType 1++-- | High-to-low transition detected.+pattern Falling :: EdgeEventType+pattern Falling = EdgeEventType 2++{-# COMPLETE Rising, Falling, EdgeEventType #-}++--------------------------------------------------------------------------------+-- NATIVE HELPER TYPES +--------------------------------------------------------------------------------++-- | Result status of waiting on GPIO chip or line request events.+data WaitResult +  = Timeout    -- ^ The specified timeout expired before any event arrived.+  | EventReady -- ^ One or more events are ready to be read.+  deriving (Eq, Ord, Show, Read)++-- | Timeout duration configuration for event waiting calls.+data TimeoutNs+  = Nanoseconds CULong -- ^ Wait for up to the specified duration in nanoseconds.+  | Immediate          -- ^ Non-blocking poll; return status immediately.+  | Infinite           -- ^ Block indefinitely until an event arrives (-1 in C API).+  deriving (Eq, Ord, Show, Read)++-- | Absolute timestamp represented in nanoseconds.+type TimestampNs = Word64++-- | Pure Haskell structure containing parsed edge event information.+data EdgeEvent = EdgeEvent +  { eventLineOffset :: LineOffset   -- ^ Offset index of the line that generated the edge event.+  , edgeType        :: EdgeEventType -- ^ Type of edge transition ('Rising' or 'Falling').+  , timestamp       :: TimestampNs   -- ^ Event timestamp in nanoseconds.+  } deriving (Eq, Ord, Show, Read)