未验证 提交 8a6b9cc8 编写于 作者: J Jose Perez Rodriguez 提交者: GitHub

Remove System.Device.Gpio.Native shim (#501)

* Changes to PInvoke directly into libgpiod instead of our native shim.

* Removing all of the Native shim code and build infrastructure

* Interop misc PR feedback.
上级 fcaa4427
......@@ -104,28 +104,6 @@ jobs:
- template: /eng/common/templates/job/job.yml
parameters:
agentOs: Linux
name: Linux_libgpiod
enableTelemetry: $(_enableTelemetry)
helixRepo: dotnet/iot
pool:
name: Hosted Ubuntu 1604
steps:
- script: src/Native/copyLibgpiod.sh
name: CopyLibgpiod
displayName: Copy Libgpiod dependency from container
condition: succeeded()
- task: PublishBuildArtifacts@1
displayName: Publish Libgpiod lib assets
inputs:
pathToPublish: $(Build.SourcesDirectory)/artifacts/libgpiod/
artifactName: Libgpiod
artifactType: container
- template: /eng/common/templates/job/job.yml
parameters:
dependsOn:
- Linux_libgpiod
agentOs: Linux
name: Linux
enableTelemetry: $(_enableTelemetry)
......@@ -141,19 +119,9 @@ jobs:
release_configuration:
_BuildConfig: Release
steps:
- task: DownloadBuildArtifacts@0
displayName: Download Libgpiod assets
inputs:
artifactName: Libgpiod
downloadPath: $(Build.SourcesDirectory)/artifacts/
- script: src/Native/moveLibgpiod.sh
name: MoveLibgpiod
displayName: Move Libgpiod into crossrootfs
condition: succeeded()
- script: ROOTFS_DIR=/crossrootfs/arm ./build.sh --ci
--configuration $(_BuildConfig)
--prepareMachine
/p:BuildNative=true
name: Build
displayName: Build
condition: succeeded()
......@@ -169,13 +137,6 @@ jobs:
condition: succeeded()
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: PublishBuildArtifacts@1
displayName: Publish Linux native assets
inputs:
pathToPublish: $(Build.SourcesDirectory)/artifacts/bin/Native
artifactName: Native
artifactType: container
condition: eq(variables['_BuildConfig'], 'Release')
variables:
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- group: DotNet-HelixApi-Access
......@@ -210,11 +171,6 @@ jobs:
inputs:
artifactName: bin
downloadPath: $(Build.SourcesDirectory)/artifacts
- task: DownloadBuildArtifacts@0
displayName: Download Built Native Assets
inputs:
artifactName: Native
downloadPath: $(Build.SourcesDirectory)/artifacts/bin
- script: build.cmd -ci -sign
-configuration $(_BuildConfig)
-prepareMachine
......
......@@ -22,7 +22,6 @@
$(TargetsForTfmSpecificContentInPackage);
_WalkEachRIDForBuildOutput;
_GetNotSupportedAssemblyForPackage;
_GetNativeAssetsForPackage
</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
......@@ -51,22 +50,6 @@
</ItemGroup>
</Target>
<Target Name="_GetNativeAssetsForPackage">
<ItemGroup>
<_nativeAssetsToPackage Include="$(BaseOutputPath)../Native/Release/*.so" />
<TfmSpecificPackageFile Include="@(_nativeAssetsToPackage)">
<!-- For now, we are only building native assets for linux-arm so we can hardcode the package path.
Once we start producing arm64 native assets then we will have to change this so it is not hardcoded
and instead is calculated depending on where the assets are located. -->
<PackagePath>runtimes/linux-arm/native/</PackagePath>
</TfmSpecificPackageFile>
</ItemGroup>
<!-- During CI or an official build, we should fail if there where no native assets to package -->
<Error Condition="'$(ContinuousIntegrationBuild)' == 'true' And '@(_nativeAssetsToPackage)' == ''"
Text="Unable to find native assets to include in the package" />
</Target>
<Target Name="_GetBuildOutputWithRID" Returns="@(RIDSpecificPackageFile)">
<ItemGroup>
<RIDSpecificPackageFile Include="$(TargetPath)">
......
......@@ -5,14 +5,12 @@
<PropertyGroup>
<BuildRestore Condition="'$(BuildRestore)'==''">true</BuildRestore>
<ProductBuild Condition="'$(ProductBuild)'==''">true</ProductBuild>
<BuildNative Condition="'$(BuildNative)'==''">false</BuildNative>
<ToolsBuild Condition="'$(ToolsBuild)'==''">true</ToolsBuild>
<SampleBuild Condition="'$(SampleBuild)'==''">true</SampleBuild>
<BuildTests Condition="'$(BuildTests)'==''">true</BuildTests>
<BuildPackages Condition="'$(BuildPackages)'==''">false</BuildPackages>
<BuildDependsOn Condition="'$(BuildRestore)'=='true'">$(BuildDependsOn);Restore</BuildDependsOn>
<BuildDependsOn Condition="'$(BuildNative)'=='true'">$(BuildDependsOn);NativeBuild</BuildDependsOn>
<BuildDependsOn Condition="'$(ProductBuild)'=='true'">$(BuildDependsOn);BuildProduct</BuildDependsOn>
<BuildDependsOn Condition="'$(ToolsBuild)'=='true'">$(BuildDependsOn);BuildTools</BuildDependsOn>
<BuildDependsOn Condition="'$(SampleBuild)'=='true'">$(BuildDependsOn);BuildSamples</BuildDependsOn>
......@@ -32,14 +30,6 @@
<MSBuild Projects="@(_BuildProductProjects)" />
</Target>
<Target Name="NativeBuild">
<ItemGroup>
<_NativeBuildProjects Include="$(MSBuildThisFileDirectory)src\Native\build-native.proj" />
</ItemGroup>
<MSBuild Projects="@(_NativeBuildProjects)" />
</Target>
<Target Name="BuildTools">
<ItemGroup>
<_BuildToolProjects Include="$(MSBuildThisFileDirectory)tools\**\*.csproj" />
......
cmake_minimum_required(VERSION 2.8.12)
project (IOT C)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_INSTALL_PREFIX $ENV{__CMakeBinDir})
set(CMAKE_SHARED_LIBRARY_PREFIX "")
add_compile_options(-fPIC)
function(strip_symbols targetName outputFilename)
if(CLR_CMAKE_PLATFORM_UNIX)
if(STRIP_SYMBOLS)
# On the older version of cmake (2.8.12) used on Ubuntu 14.04 the TARGET_FILE
# generator expression doesn't work correctly returning the wrong path and on
# the newer cmake versions the LOCATION property isn't supported anymore.
if(CMAKE_VERSION VERSION_EQUAL 3.0 OR CMAKE_VERSION VERSION_GREATER 3.0)
set(strip_source_file $<TARGET_FILE:${targetName}>)
else()
get_property(strip_source_file TARGET ${targetName} PROPERTY LOCATION)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
set(strip_destination_file ${strip_source_file}.dwarf)
add_custom_command(
TARGET ${targetName}
POST_BUILD
VERBATIM
COMMAND ${DSYMUTIL} --flat --minimize ${strip_source_file}
COMMAND ${STRIP} -u -r ${strip_source_file}
COMMENT Stripping symbols from ${strip_source_file} into file ${strip_destination_file}
)
else(CMAKE_SYSTEM_NAME STREQUAL Darwin)
set(strip_destination_file ${strip_source_file}.dbg)
add_custom_command(
TARGET ${targetName}
POST_BUILD
VERBATIM
COMMAND ${OBJCOPY} --only-keep-debug ${strip_source_file} ${strip_destination_file}
COMMAND ${OBJCOPY} --strip-unneeded ${strip_source_file}
COMMAND ${OBJCOPY} --add-gnu-debuglink=${strip_destination_file} ${strip_source_file}
COMMENT Stripping symbols from ${strip_source_file} into file ${strip_destination_file}
)
endif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
set(${outputFilename} ${strip_destination_file} PARENT_SCOPE)
endif(STRIP_SYMBOLS)
endif(CLR_CMAKE_PLATFORM_UNIX)
endfunction()
function(install_library_and_symbols targetName)
strip_symbols(${targetName} strip_destination_file)
# On the older version of cmake (2.8.12) used on Ubuntu 14.04 the TARGET_FILE
# generator expression doesn't work correctly returning the wrong path and on
# the newer cmake versions the LOCATION property isn't supported anymore.
if(CMAKE_VERSION VERSION_EQUAL 3.0 OR CMAKE_VERSION VERSION_GREATER 3.0)
set(install_source_file $<TARGET_FILE:${targetName}>)
else()
get_property(install_source_file TARGET ${targetName} PROPERTY LOCATION)
endif()
install(PROGRAMS ${install_source_file} DESTINATION .)
if(WIN32)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${targetName}.pdb DESTINATION PDB)
else()
install(FILES ${strip_destination_file} DESTINATION .)
endif()
endfunction()
if(CMAKE_SYSTEM_NAME STREQUAL Linux)
add_subdirectory(System.Device.Gpio.Native)
endif()
project (System.Device.Gpio.Native C)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_library(System.Device.Gpio.Native
SHARED
libgpiod.c
)
set_target_properties(System.Device.Gpio.Native PROPERTIES PREFIX "")
target_link_libraries(System.Device.Gpio.Native LINK_PUBLIC gpiod)
install_library_and_symbols (System.Device.Gpio.Native)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#include <gpiod.h>
/**
* @brief Close a GPIO chip handle and release all allocated resources.
* @param chip The GPIO chip object.
*/
extern void CloseChip(struct gpiod_chip *chip)
{
gpiod_chip_close(chip);
}
/**
* @brief Get the number of GPIO lines exposed by this chip.
* @param chip The GPIO chip object.
* @return Number of GPIO lines.
*/
extern unsigned int GetNumberOfLines(struct gpiod_chip *chip)
{
return gpiod_chip_num_lines(chip);
}
/**
* @brief Get the handle to the GPIO line at given offset.
* @param chip The GPIO chip object.
* @param offset The offset of the GPIO line.
* @return Pointer to the GPIO line handle or NULL if an error occured.
*/
extern struct gpiod_line *GetChipLineByOffset(struct gpiod_chip *chip, unsigned int offset)
{
return gpiod_chip_get_line(chip, offset);
}
/**
* @brief Read the GPIO line direction setting.
* @param line GPIO line object.
* @return Returns GPIOD_DIRECTION_INPUT or GPIOD_DIRECTION_OUTPUT.
*/
extern int GetLineDirection(struct gpiod_line *line)
{
return gpiod_line_direction(line);
}
/**
* @brief Reserve a single line, set the direction to input.
* @param line GPIO line object.
* @param consumer Name of the consumer.
* @return 0 if the line was properly reserved, -1 on failure.
*/
extern int RequestLineInput(struct gpiod_line *line, const char *consumer)
{
return gpiod_line_request_input(line, consumer);
}
/**
* @brief Reserve a single line, set the direction to output.
* @param line GPIO line object.
* @param consumer Name of the consumer.
* @return 0 if the line was properly reserved, -1 on failure.
*/
extern int RequestLineOutput(struct gpiod_line *line, const char *consumer)
{
return gpiod_line_request_output(line, consumer, 0);
}
/**
* @brief Check if the calling user has neither requested ownership of this line nor configured any event notifications.
* @param line GPIO line object.
* @return True if given line is free, false otherwise.
*/
extern bool LineIsFree(struct gpiod_line *line)
{
return gpiod_line_is_free(line);
}
/**
* @brief Release a previously reserved line.
* @param line GPIO line object.
*/
extern void ReleaseGpiodLine(struct gpiod_line *line)
{
gpiod_line_release(line);
}
/**
* @brief Read current value of a single GPIO line.
* @param line GPIO line object.
* @return 0 or 1 if the operation succeeds. On error this routine returns -1
* and sets the last error number.
*/
extern int GetGpiodLineValue(struct gpiod_line *line)
{
return gpiod_line_get_value(line);
}
/**
* @brief Set the value of a single GPIO line.
* @param line GPIO line object.
* @param value New value.
* @return 0 is the operation succeeds. In case of an error this routine
* returns -1 and sets the last error number.
*/
extern int SetGpiodLineValue(struct gpiod_line *line, int value)
{
return gpiod_line_set_value(line, value);
}
/**
* @brief Create a new gpiochip iterator.
* @return Pointer to a new chip iterator object or NULL if an error occurred.
*/
extern struct gpiod_chip_iter * GetChipIterator(void)
{
return gpiod_chip_iter_new();
}
/**
* @brief Release all resources allocated for the gpiochip iterator and close
* the most recently opened gpiochip (if any).
* @param iter The gpiochip iterator object.
*/
extern void FreeChipIterator(struct gpiod_chip_iter *iter)
{
gpiod_chip_iter_free(iter);
}
/**
* @brief Release all resources allocated for the gpiochip iterator but
* don't close the most recently opened gpiochip (if any).
* @param iter The gpiochip iterator object.
*/
extern void FreeChipIteratorNoCloseCurrentChip(struct gpiod_chip_iter *iter)
{
gpiod_chip_iter_free_noclose(iter);
}
/**
* @brief Get the next gpiochip handle.
* @param iter The gpiochip iterator object.
* @return Pointer to the next open gpiochip handle or NULL if no more chips
* are present in the system.
* @note The previous chip handle will be closed.
*/
extern struct gpiod_chip * GetNextChipFromChipIterator(struct gpiod_chip_iter *iter)
{
return gpiod_chip_iter_next(iter);
}
/**
* @brief Request all event type notifications on a single line.
* @param line GPIO line object.
* @param consumer Name of the consumer.
* @return 0 if the operation succeeds, -1 on failure.
*/
extern int RequestBothEdgesEventForLine(struct gpiod_line *line, const char *consumer)
{
return gpiod_line_request_both_edges_events(line, consumer);
}
/**
* @brief Wait for an event on a single line.
* @param line GPIO line object.
* @return 0 if wait timed out, -1 if an error occurred, 1 if an event occurred.
*/
extern int WaitForEventOnLine(struct gpiod_line *line)
{
struct timespec timeout = { 0, 1000000 }; // one millisecond
return gpiod_line_event_wait(line, &timeout);
}
/**
* @brief Read the last event from the GPIO line.
* @param line GPIO line object.
* @return event type if an event was read correctly (1 for rising edge, 2 for falling edge), -1 on error.
* @note This function will block if no event was queued for this line.
*/
extern int ReadEventForLine(struct gpiod_line *line)
{
struct gpiod_line_event event;
int response = gpiod_line_event_read(line, &event);
if (response == 0) { // 0 returned means event read correctly, -1 on error
return event.event_type;
}
return response;
}
/**
* @brief Open a gpiochip by number.
* @return GPIO chip pointer handle or NULL if an error occurred.
*/
extern struct gpiod_chip * OpenChipByNumber(int number)
{
return gpiod_chip_open_by_number(number);
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))" />
<PropertyGroup>
<_BuildNativeArgs>arm $(Configuration)</_BuildNativeArgs>
</PropertyGroup>
<Target Name="BuildNativeUnix"
Condition="'$(OS)' != 'Windows_NT'">
<PropertyGroup>
<!--
MSBuildNodeCount should a good approximation for how many procs to use for native build, if we find that doesn't work
then we should consider calling Environment.ProcessorCount
-->
<_ProcessorCountArg> --numproc $(MSBuildNodeCount)</_ProcessorCountArg>
<_StripSymbolsArg Condition="'$(BuildNativeStripSymbols)' == 'true'"> stripsymbols</_StripSymbolsArg>
<!--
BuildNativeClang is a pass-through argument, to pass an argument to build-native.sh. It is intended to be
used to force a specific clang toolset.
-->
<_BuildNativeClangArg Condition="'$(BuildNativeClang)' != ''"> $(BuildNativeClang)</_BuildNativeClangArg>
<_BuildNativeUnixArgs>$(_BuildNativeArgs)$(_ProcessCountArg)$(_StripSymbolsArg)$(_PortableBuildArg)$(_BuildNativeClangArg)</_BuildNativeUnixArgs>
</PropertyGroup>
<Message Text="$(MSBuildProjectDirectory)/build-native.sh $(_BuildNativeUnixArgs)" Importance="High"/>
<Exec Command="&quot;$(MSBuildProjectDirectory)/build-native.sh&quot; $(_BuildNativeUnixArgs)" IgnoreStandardErrorWarningFormat="true">
<Output TaskParameter="ExitCode" PropertyName="BuildNativeExitCode" />
</Exec>
<Error Condition="'$(BuildNativeExitCode)' != '0'" Text="An error occured when building native project." />
</Target>
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.targets))" />
<!-- Target that builds all the native binaries in the Native folder -->
<Target Name="Build" DependsOnTargets="BuildNativeUnix" />
</Project>
\ No newline at end of file
#!/usr/bin/env bash
usage()
{
echo "Our parameters changed! The parameters: buildArch, buildType, buildOS, numProc"
echo "are passed by the Run Command Tool."
echo "If you plan to only run this script, be sure to pass those parameters."
echo "For more information type build-native.sh -? at the root of the repo."
echo
echo "Usage: $0 [runParameters][-verbose] [-clangx.y] [-cross] [-staticLibLink] [-cmakeargs] [-makeargs]"
echo "runParameters: buildArch, buildType, buildOS, -numProc <numproc value>"
echo "BuildArch can be: -x64, -x86, -arm, -armel, -arm64"
echo "BuildType can be: -debug, -checked, -release"
echo "-verbose - optional argument to enable verbose build output."
echo "-clangx.y - optional argument to build using clang version x.y."
echo "-cross - optional argument to signify cross compilation,"
echo " - will use ROOTFS_DIR environment variable if set."
echo "-staticLibLink - Optional argument to statically link any native library."
echo "-portable - Optional argument to build native libraries portable over GLIBC based Linux distros."
echo "-stripSymbols - Optional argument to strip native symbols during the build."
echo "-skipgenerateversion - Pass this in to skip getting a version on the build output."
echo "-cmakeargs - user-settable additional arguments passed to CMake."
exit 1
}
initHostDistroRid()
{
__HostDistroRid=""
if [ "$__HostOS" == "Linux" ]; then
if [ -e /etc/os-release ]; then
source /etc/os-release
__HostDistroRid="$ID.$VERSION_ID-$__HostArch"
fi
fi
if [ "$__HostDistroRid" == "" ]; then
echo "WARNING: Can not determine runtime id for current distro."
fi
}
initTargetDistroRid()
{
if [ $__CrossBuild == 1 ]; then
if [ "$__BuildOS" == "Linux" ]; then
if [ ! -e $ROOTFS_DIR/etc/os-release ]; then
echo "WARNING: Can not determine runtime id for current distro."
export __DistroRid=""
else
source $ROOTFS_DIR/etc/os-release
export __DistroRid="$ID.$VERSION_ID-$__BuildArch"
fi
fi
else
export __DistroRid="$__HostDistroRid"
fi
}
setup_dirs()
{
echo Setting up directories for build
mkdir -p "$__BinDir"
mkdir -p "$__IntermediatesDir"
}
# Check the system to ensure the right pre-reqs are in place
check_native_prereqs()
{
echo "Checking pre-requisites..."
# Check presence of CMake on the path
hash cmake 2>/dev/null || { echo >&2 "Please install cmake before running this script"; exit 1; }
# Minimum required version of clang is version 3.9 for arm/armel cross build
if [[ $__CrossBuild == 1 && ("$__BuildArch" == "arm") ]]; then
if ! [[ "$__ClangMajorVersion" -gt "3" || ( $__ClangMajorVersion == 3 && $__ClangMinorVersion == 9 ) ]]; then
echo "Please install clang3.9 or latest for arm cross build"; exit 1;
fi
fi
# Check for clang
hash clang-$__ClangMajorVersion.$__ClangMinorVersion 2>/dev/null || hash clang$__ClangMajorVersion$__ClangMinorVersion 2>/dev/null || hash clang 2>/dev/null || { echo >&2 "Please install clang before running this script"; exit 1; }
}
prepare_native_build()
{
# Specify path to be set for CMAKE_INSTALL_PREFIX.
# This is where all built CoreClr libraries will copied to.
export __CMakeBinDir="$__BinDir"
# Configure environment if we are doing a verbose build
if [ $__VerboseBuild == 1 ]; then
export VERBOSE=1
fi
# Generate version.c if specified, else have an empty one.
__versionSourceFile=$__artifactsDir/obj/_version.c
if [ ! -e "${__versionSourceFile}" ]; then
__versionSourceLine="static char sccsid[] __attribute__((used)) = \"@(#)No version information produced\";"
echo "${__versionSourceLine}" > ${__versionSourceFile}
fi
}
build_native()
{
# All set to commence the build
echo "Commencing build of iot native components"
cd "$__IntermediatesDir"
# Regenerate the CMake solution
echo "Invoking cmake with arguments: \"$__scriptpath\" $__CMakeArgs $__CMakeExtraArgs"
"$__scriptpath/gen-buildsys-clang.sh" "$__scriptpath" $__ClangMajorVersion $__ClangMinorVersion $__BuildArch $__CMakeArgs "$__CMakeExtraArgs"
# Check that the makefiles were created.
if [ ! -f "$__IntermediatesDir/Makefile" ]; then
echo "Failed to generate native component build project!"
exit 1
fi
# Build
echo "Executing make install -j $__NumProc $__MakeExtraArgs"
make install -j $__NumProc $__MakeExtraArgs
if [ $? != 0 ]; then
echo "Failed to build iot native components."
exit 1
fi
}
__scriptpath=$(cd "$(dirname "$0")"; pwd -P)
__rootRepo="$__scriptpath/../.."
__artifactsDir="$__rootRepo/artifacts"
# Set the various build properties here so that CMake and MSBuild can pick them up
__CMakeExtraArgs=""
__MakeExtraArgs=""
__BuildArch=x64
__BuildType=Debug
__CMakeArgs=DEBUG
__BuildOS=Linux
__NumProc=1
__UnprocessedBuildArgs=
__CrossBuild=0
__ServerGC=0
__VerboseBuild=false
__ClangMajorVersion=0
__ClangMinorVersion=0
CPUName=$(uname -m)
if [ "$CPUName" == "i686" ]; then
__BuildArch=x86
fi
# Use uname to determine what the OS is.
OSName=$(uname -s)
case $OSName in
Linux)
__BuildOS=Linux
__HostOS=Linux
;;
*)
echo "Unsupported OS $OSName detected, configuring as if for Linux"
__BuildOS=Linux
__HostOS=Linux
;;
esac
while :; do
if [ $# -le 0 ]; then
break
fi
lowerI="$(echo $1 | awk '{print tolower($0)}')"
case $lowerI in
-\?|-h|--help)
usage
exit 1
;;
arm|-arm)
__BuildArch=arm
;;
arm64|-arm64)
__BuildArch=arm64
;;
debug|-debug)
__BuildType=Debug
;;
release|-release)
__BuildType=Release
__CMakeArgs=RELEASE
;;
linux|-linux)
__BuildOS=Linux
;;
stripsymbols|-stripsymbols)
__CMakeExtraArgs="$__CMakeExtraArgs -DSTRIP_SYMBOLS=true"
;;
verbose|-verbose)
__VerboseBuild=1
;;
*)
__UnprocessedBuildArgs="$__UnprocessedBuildArgs $1"
esac
shift
done
# Set cross build
case $CPUName in
i686)
if [ $__BuildArch != x86 ]; then
__CrossBuild=1
echo "Set CrossBuild for $__BuildArch build"
fi
;;
x86_64)
if [ $__BuildArch != x64 ]; then
__CrossBuild=1
echo "Set CrossBuild for $__BuildArch build"
fi
;;
esac
# Set the default clang version if not already set
if [[ $__ClangMajorVersion == 0 && $__ClangMinorVersion == 0 ]]; then
__ClangMajorVersion=3
__ClangMinorVersion=9
fi
# Set the remaining variables based upon the determined build configuration
__IntermediatesDir="$__artifactsDir/obj/Native/$__BuildType"
__BinDir="$__artifactsDir/bin/Native/$__BuildType"
# Make the directories necessary for build if they don't exist
setup_dirs
# Configure environment if we are doing a cross compile.
if [ "$__CrossBuild" == 1 ]; then
export CROSSCOMPILE=1
if ! [[ -n "$ROOTFS_DIR" ]]; then
export ROOTFS_DIR="$__rootRepo/cross/rootfs/$__BuildArch"
fi
fi
# init the host distro name
initHostDistroRid
# init the target distro name
initTargetDistroRid
# Check prereqs.
check_native_prereqs
# Prepare the system
prepare_native_build
# Build the iot native components.
build_native
#!/usr/bin/env bash
__scriptpath=$(cd "$(dirname "$0")"; pwd -P)
__rootRepo="$__scriptpath/../.."
__artifactsDir="$__rootRepo/artifacts"
__libgpiodPath="$__artifactsDir/libgpiod"
mkdir -p "$__libgpiodPath"
docker create --name iot microsoft/dotnet-buildtools-prereqs:debian-iot-arm32v7-be5b37d-20190211200049
docker cp iot:/usr/local/lib "$__libgpiodPath"
if [ $? != 0 ]; then
echo "Failed to extract the libgpiod lib assets."
exit 1
fi
docker cp iot:/usr/local/include "$__libgpiodPath"
if [ $? != 0 ]; then
echo "Failed to extract the libgpiod include assets."
exit 1
fi
docker container rm -f iot
\ No newline at end of file
#!/usr/bin/env bash
#
# This file invokes cmake and generates the build system for Clang.
#
if [ $# -lt 4 -o $# -gt 6 ]
then
echo "Usage..."
echo "gen-buildsys-clang.sh <path to top level CMakeLists.txt> <ClangMajorVersion> <ClangMinorVersion> <Architecture> [build flavor] [cmakeargs]"
echo "Specify the path to the top level CMake file - <iot>/src/Native/Unix"
echo "Specify the clang version to use, split into major and minor version"
echo "Specify the target architecture."
echo "Optionally specify the build configuration (flavor.) Defaults to DEBUG."
echo "Optionally pass additional arguments to CMake call."
exit 1
fi
#Set the root directory of the project
project_root="$1"/../..
# Set up the environment to be used for building with clang.
if which "clang-$2.$3" > /dev/null 2>&1
then
export CC="$(which clang-$2.$3)"
elif which "clang$2$3" > /dev/null 2>&1
then
export CC="$(which clang$2$3)"
elif which clang > /dev/null 2>&1
then
export CC="$(which clang)"
else
echo "Unable to find Clang Compiler"
exit 1
fi
build_arch="$4"
# Possible build types are DEBUG, RELEASE, RELWITHDEBINFO, MINSIZEREL.
# Default to DEBUG
if [ -z "$5" ]
then
echo "Defaulting to DEBUG build."
buildtype="DEBUG"
else
buildtype="$5"
fi
cmake_extra_defines="-DCMAKE_BUILD_TYPE=$buildtype"
if [[ -n "$CROSSCOMPILE" ]]; then
if ! [[ -n "$ROOTFS_DIR" ]]; then
echo "ROOTFS_DIR not set for crosscompile"
exit 1
fi
if [[ -z "$CONFIG_DIR" ]]; then
CONFIG_DIR="$project_root/eng"
fi
export TARGET_BUILD_ARCH=$build_arch
cmake_extra_defines="$cmake_extra_defines -C $CONFIG_DIR/tryrun.cmake"
cmake_extra_defines="$cmake_extra_defines -DCMAKE_TOOLCHAIN_FILE=$CONFIG_DIR/toolchain.cmake"
fi
if [ "$build_arch" == "armel" ]; then
cmake_extra_defines="$cmake_extra_defines -DARM_SOFTFP=1"
fi
__UnprocessedCMakeArgs=""
if [ -z "$6" ]; then
echo "No CMake extra Args specified"
else
__UnprocessedCMakeArgs="$6"
fi
cmake $cmake_extra_defines \
$__UnprocessedCMakeArgs \
$1
#!/usr/bin/env bash
__scriptpath=$(cd "$(dirname "$0")"; pwd -P)
__rootRepo="$__scriptpath/../.."
__artifactsDir="$__rootRepo/artifacts"
__libgpiodPath="$__artifactsDir/Libgpiod"
sudo cp -r "$__libgpiodPath/lib/" /crossrootfs/arm/usr/local/
if [ $? != 0 ]; then
echo "Error copying files to crossrootfs"
exit 1
fi
sudo cp -r "$__libgpiodPath/include/" /crossrootfs/arm/usr/local/
if [ $? != 0 ]; then
echo "Error copying files to crossrootfs"
exit 1
fi
\ No newline at end of file
......@@ -21,16 +21,4 @@
<!--Excluding Linux implementations-->
<Compile Remove="**\*.Linux.cs" />
</ItemGroup>
<!-- Make sure that we copy the native shim to the publish directory before sending the tests to Helix -->
<Target Name="AddNativeShimToCopyToPublishDirectory" Condition="'$(TargetsLinux)' == 'true'" BeforeTargets="_ComputeResolvedFilesToPublishTypes">
<ItemGroup>
<_nativeShimFiles Include="$(ArtifactsBinDir)Native\$(Configuration)\*.*" />
<ResolvedFileToPublish Include="@(_nativeShimFiles)">
<RelativePath>%(_nativeShimFiles.Filename)%(_nativeShimFiles.Extension)</RelativePath>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project>
......@@ -15,10 +15,10 @@ namespace System.Device.Gpio
protected override bool ReleaseHandle()
{
Interop.CloseChip(handle);
Interop.libgpiod.gpiod_chip_close(handle);
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero || handle == Interop.InvalidHandleValue;
public override bool IsInvalid => handle == IntPtr.Zero || handle == Interop.libgpiod.InvalidHandleValue;
}
}
......@@ -15,10 +15,10 @@ namespace System.Device.Gpio
protected override bool ReleaseHandle()
{
Interop.FreeChipIterator(handle);
Interop.libgpiod.gpiod_chip_iter_free(handle);
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero || handle == Interop.InvalidHandleValue;
public override bool IsInvalid => handle == IntPtr.Zero || handle == Interop.libgpiod.InvalidHandleValue;
}
}
......@@ -17,10 +17,10 @@ namespace System.Device.Gpio
protected override bool ReleaseHandle()
{
Interop.ReleaseGpiodLine(handle);
Interop.libgpiod.gpiod_line_release(handle);
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero || handle == Interop.InvalidHandleValue;
public override bool IsInvalid => handle == IntPtr.Zero || handle == Interop.libgpiod.InvalidHandleValue;
}
}
......@@ -5,151 +5,168 @@
using System;
using System.Device.Gpio;
using System.Runtime.InteropServices;
// Since this is only used on Linux, and in C on Linux sizeof(long) == sizeof(void*) this is a valid alias.
using NativeLong = System.IntPtr;
internal partial class Interop
{
private const string LibgpiodLibrary = "System.Device.Gpio.Native";
internal static IntPtr InvalidHandleValue = new IntPtr(-1);
/// <summary>
/// Create a new gpiochip iterator.
/// </summary>
/// <returns>Pointer to a new chip iterator object or <see langword="null" /> if an error occurred.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern SafeChipIteratorHandle GetChipIterator();
/// <summary>
/// Release all resources allocated for the gpiochip iterator and close the most recently opened gpiochip(if any).
/// </summary>
/// <param name="iter">The gpiochip iterator object</param>
[DllImport(LibgpiodLibrary)]
internal static extern void FreeChipIterator(IntPtr iter);
/// <summary>
/// Release all resources allocated for the gpiochip iterator but don't close the most recently opened gpiochip (if any).
/// </summary>
/// <param name="iter">The gpiochip iterator object</param>
[DllImport(LibgpiodLibrary)]
internal static extern void FreeChipIteratorNoCloseCurrentChip(SafeChipIteratorHandle iter);
/// <summary>
/// Get the next gpiochip handle.
/// </summary>
/// <param name="iter">The gpiochip iterator object</param>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern SafeChipHandle GetNextChipFromChipIterator(SafeChipIteratorHandle iter);
/// <summary>
/// Close a GPIO chip handle and release all allocated resources.
/// </summary>
/// <param name="chip">The GPIO chip pointer</param>
[DllImport(LibgpiodLibrary)]
internal static extern void CloseChip(IntPtr chip);
/// <summary>
/// Get the number of GPIO lines exposed by this chip.
/// </summary>
/// <param name="chip">The GPIO chip handle.</param>
/// <returns>Number of GPIO lines.</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int GetNumberOfLines(SafeChipHandle chip);
/// <summary>
/// Get the handle to the GPIO line at given offset.
/// </summary>
/// <param name="chip">The GPIO chip handle</param>
/// <param name="offset">The offset of the GPIO line</param>
/// <returns>Handle to the GPIO line or <see langword="null" /> if an error occured.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern SafeLineHandle GetChipLineByOffset(SafeChipHandle chip, int offset);
/// <summary>
/// Read the GPIO line direction setting.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>1 if INPUT otherwise 2 (OUTPUT).</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int GetLineDirection(SafeLineHandle line);
/// <summary>
/// Reserve a single line, set the direction to input.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <param name="consumer">Name of the consumer.</param>
/// <returns>0 if the line was properly reserved, -1 on failure.</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int RequestLineInput(SafeLineHandle line, string consumer);
/// <summary>
/// Reserve a single line, set the direction to output.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <param name="consumer">Name of the consumer.</param>
/// <returns>0 if the line was properly reserved, -1 on failure.</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int RequestLineOutput(SafeLineHandle line, string consumer);
/// <summary>
/// Set the value of a single GPIO line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <param name="value">New value.</param>
/// <returns>0 if the operation succeeds. In case of an error this routine returns -1 and sets the last error number.</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int SetGpiodLineValue(SafeLineHandle line, int value);
/// <summary>
/// Read current value of a single GPIO line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>0 or 1 if the operation succeeds. On error this routine returns -1 and sets the last error number.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern int GetGpiodLineValue(SafeLineHandle line);
/// <summary>
/// Check if line is no used (not set as Input or Output, not listening events).
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>false if pin is used as Input/Output or Listening an event, true if it is free</returns>
[DllImport(LibgpiodLibrary)]
internal static extern bool LineIsFree(SafeLineHandle line);
/// <summary>
/// Release a previously reserved line.
/// </summary>
/// <param name="line">GPIO line handle</param>
[DllImport(LibgpiodLibrary)]
internal static extern void ReleaseGpiodLine(IntPtr lineHandle);
/// <summary>
/// Request all event type notifications on a single line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <param name="consumer">Name of the consumer.</param>
/// <returns>0 the operation succeeds, -1 on failure.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern int RequestBothEdgesEventForLine(SafeLineHandle line, string consumer);
/// <summary>
/// Wait for an event on a single line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>0 if wait timed out, -1 if an error occurred, 1 if an event occurred.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern WaitEventResult WaitForEventOnLine(SafeLineHandle line);
/// <summary>
/// Read the last event from the GPIO line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>1 if rising edge event occured, 2 on falling edge, -1 on error.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern int ReadEventForLine(SafeLineHandle line);
/// <summary>
/// Open a gpiochip by number.
/// </summary>
/// <returns>GPIO chip pointer handle or NULL if an error occurred.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern SafeChipHandle OpenChipByNumber(int number);
internal partial class libgpiod
{
private const string LibgpiodLibrary = "libgpiod";
internal static IntPtr InvalidHandleValue = new IntPtr(-1);
/// <summary>
/// Create a new gpiochip iterator.
/// </summary>
/// <returns>Pointer to a new chip iterator object or a SafeChipIteratorHandle pointing to 0 which will return <see langword="true" /> for IsInvalid.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern SafeChipIteratorHandle gpiod_chip_iter_new();
/// <summary>
/// Release all resources allocated for the gpiochip iterator and close the most recently opened gpiochip(if any).
/// </summary>
/// <param name="iter">The gpiochip iterator object</param>
[DllImport(LibgpiodLibrary)]
internal static extern void gpiod_chip_iter_free(IntPtr iter);
/// <summary>
/// Release all resources allocated for the gpiochip iterator but don't close the most recently opened gpiochip (if any).
/// </summary>
/// <param name="iter">The gpiochip iterator object</param>
[DllImport(LibgpiodLibrary)]
internal static extern void gpiod_chip_iter_free_noclose(SafeChipIteratorHandle iter);
/// <summary>
/// Get the next gpiochip handle.
/// </summary>
/// <param name="iter">The gpiochip iterator object</param>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern SafeChipHandle gpiod_chip_iter_next(SafeChipIteratorHandle iter);
/// <summary>
/// Close a GPIO chip handle and release all allocated resources.
/// </summary>
/// <param name="chip">The GPIO chip pointer</param>
[DllImport(LibgpiodLibrary)]
internal static extern void gpiod_chip_close(IntPtr chip);
/// <summary>
/// Get the number of GPIO lines exposed by this chip.
/// </summary>
/// <param name="chip">The GPIO chip handle.</param>
/// <returns>Number of GPIO lines.</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int gpiod_chip_num_lines(SafeChipHandle chip);
/// <summary>
/// Get the handle to the GPIO line at given offset.
/// </summary>
/// <param name="chip">The GPIO chip handle</param>
/// <param name="offset">The offset of the GPIO line</param>
/// <returns>Handle to the GPIO line or <see langword="null" /> if an error occured.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern SafeLineHandle gpiod_chip_get_line(SafeChipHandle chip, int offset);
/// <summary>
/// Read the GPIO line direction setting.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>1 if INPUT otherwise 2 (OUTPUT).</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int gpiod_line_direction(SafeLineHandle line);
/// <summary>
/// Reserve a single line, set the direction to input.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <param name="consumer">Name of the consumer.</param>
/// <returns>0 if the line was properly reserved, -1 on failure.</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int gpiod_line_request_input(SafeLineHandle line, string consumer);
/// <summary>
/// Reserve a single line, set the direction to output.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <param name="consumer">Name of the consumer.</param>
/// <returns>0 if the line was properly reserved, -1 on failure.</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int gpiod_line_request_output(SafeLineHandle line, string consumer);
/// <summary>
/// Set the value of a single GPIO line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <param name="value">New value.</param>
/// <returns>0 if the operation succeeds. In case of an error this routine returns -1 and sets the last error number.</returns>
[DllImport(LibgpiodLibrary)]
internal static extern int gpiod_line_set_value(SafeLineHandle line, int value);
/// <summary>
/// Read current value of a single GPIO line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>0 or 1 if the operation succeeds. On error this routine returns -1 and sets the last error number.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern int gpiod_line_get_value(SafeLineHandle line);
/// <summary>
/// Check if line is no used (not set as Input or Output, not listening events).
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>false if pin is used as Input/Output or Listening an event, true if it is free</returns>
[DllImport(LibgpiodLibrary)]
internal static extern bool gpiod_line_is_free(SafeLineHandle line);
/// <summary>
/// Release a previously reserved line.
/// </summary>
/// <param name="line">GPIO line handle</param>
[DllImport(LibgpiodLibrary)]
internal static extern void gpiod_line_release(IntPtr lineHandle);
/// <summary>
/// Request all event type notifications on a single line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <param name="consumer">Name of the consumer.</param>
/// <returns>0 the operation succeeds, -1 on failure.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern int gpiod_line_request_both_edges_events(SafeLineHandle line, string consumer);
/// <summary>
/// Wait for an event on a single line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>0 if wait timed out, -1 if an error occurred, 1 if an event occurred.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern WaitEventResult gpiod_line_event_wait(SafeLineHandle line, ref TimeSpec timeout);
/// <summary>
/// Read the last event from the GPIO line.
/// </summary>
/// <param name="line">GPIO line handle</param>
/// <returns>1 if rising edge event occured, 2 on falling edge, -1 on error.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern int gpiod_line_event_read(SafeLineHandle line, ref GpioLineEvent gpioEvent);
/// <summary>
/// Open a gpiochip by number.
/// </summary>
/// <returns>GPIO chip pointer handle or NULL if an error occurred.</returns>
[DllImport(LibgpiodLibrary, SetLastError = true)]
internal static extern SafeChipHandle gpiod_chip_open_by_number(int number);
}
}
internal struct GpioLineEvent
{
public TimeSpec ts;
public int event_type;
}
internal struct TimeSpec
{
public NativeLong TvSec;
public NativeLong TvNsec;
}
......@@ -17,13 +17,13 @@ namespace System.Device.Gpio.Drivers
private ConcurrentDictionary<int, LibGpiodDriverEventHandler> _pinNumberToEventHandler = new ConcurrentDictionary<int, LibGpiodDriverEventHandler>();
protected internal override int PinCount => Interop.GetNumberOfLines(_chip);
protected internal override int PinCount => Interop.libgpiod.gpiod_chip_num_lines(_chip);
public LibGpiodDriver(int gpioChip = 0)
{
try
{
_chip = Interop.OpenChipByNumber(gpioChip);
_chip = Interop.libgpiod.gpiod_chip_open_by_number(gpioChip);
if (_chip == null)
{
throw ExceptionHelper.GetIOException(ExceptionResource.NoChipFound, Marshal.GetLastWin32Error());
......@@ -61,10 +61,10 @@ namespace System.Device.Gpio.Drivers
{
if (_pinNumberToSafeLineHandle.TryGetValue(pinNumber, out SafeLineHandle pinHandle))
{
if (!Interop.LineIsFree(pinHandle))
if (!Interop.libgpiod.gpiod_line_is_free(pinHandle))
{
pinHandle.Dispose();
pinHandle = Interop.GetChipLineByOffset(_chip, pinNumber);
pinHandle = Interop.libgpiod.gpiod_chip_get_line(_chip, pinNumber);
_pinNumberToSafeLineHandle[pinNumber] = pinHandle;
}
}
......@@ -105,7 +105,7 @@ namespace System.Device.Gpio.Drivers
protected internal override void OpenPin(int pinNumber)
{
SafeLineHandle pinHandle = Interop.GetChipLineByOffset(_chip, pinNumber);
SafeLineHandle pinHandle = Interop.libgpiod.gpiod_chip_get_line(_chip, pinNumber);
if (pinHandle == null)
{
throw ExceptionHelper.GetIOException(ExceptionResource.OpenPinError, Marshal.GetLastWin32Error());
......@@ -118,7 +118,7 @@ namespace System.Device.Gpio.Drivers
{
if (_pinNumberToSafeLineHandle.TryGetValue(pinNumber, out SafeLineHandle pinHandle))
{
int result = Interop.GetGpiodLineValue(pinHandle);
int result = Interop.libgpiod.gpiod_line_get_value(pinHandle);
if (result == -1)
{
throw ExceptionHelper.GetIOException(ExceptionResource.ReadPinError, Marshal.GetLastWin32Error(), pinNumber);
......@@ -155,11 +155,11 @@ namespace System.Device.Gpio.Drivers
string consumer = pinNumber.ToString();
if (mode == PinMode.Input)
{
requestResult = Interop.RequestLineInput(pinHandle, consumer);
requestResult = Interop.libgpiod.gpiod_line_request_input(pinHandle, consumer);
}
else
{
requestResult = Interop.RequestLineOutput(pinHandle, consumer);
requestResult = Interop.libgpiod.gpiod_line_request_output(pinHandle, consumer);
}
pinHandle.PinMode = mode;
......@@ -222,7 +222,7 @@ namespace System.Device.Gpio.Drivers
throw ExceptionHelper.GetInvalidOperationException(ExceptionResource.PinNotOpenedError, pin: pinNumber);
}
Interop.SetGpiodLineValue(pinHandle, (value == PinValue.High) ? 1 : 0);
Interop.libgpiod.gpiod_line_set_value(pinHandle, (value == PinValue.High) ? 1 : 0);
}
protected override void Dispose(bool disposing)
......
......@@ -31,7 +31,7 @@ namespace System.Device.Gpio.Drivers
private void SubscribeForEvent(SafeLineHandle pinHandle)
{
int eventSuccess = Interop.RequestBothEdgesEventForLine(pinHandle, $"Listen {_pinNumber} for both edge event");
int eventSuccess = Interop.libgpiod.gpiod_line_request_both_edges_events(pinHandle, $"Listen {_pinNumber} for both edge event");
if (eventSuccess < 0)
{
......@@ -47,7 +47,13 @@ namespace System.Device.Gpio.Drivers
while (!(token.IsCancellationRequested || _disposing))
{
// WaitEventResult can be TimedOut, EventOccured or Error, in case of TimedOut will continue waiting
WaitEventResult waitResult = Interop.WaitForEventOnLine(pinHandle);
TimeSpec timeout = new TimeSpec
{
TvSec = new IntPtr(0),
TvNsec = new IntPtr(1000000)
};
WaitEventResult waitResult = Interop.libgpiod.gpiod_line_event_wait(pinHandle, ref timeout);
if (waitResult == WaitEventResult.Error)
{
throw ExceptionHelper.GetIOException(ExceptionResource.EventWaitError, Marshal.GetLastWin32Error(), _pinNumber);
......@@ -55,13 +61,14 @@ namespace System.Device.Gpio.Drivers
if (waitResult == WaitEventResult.EventOccured)
{
int readResult = Interop.ReadEventForLine(pinHandle);
if (readResult == -1)
GpioLineEvent eventResult = new GpioLineEvent();
int checkForEvent = Interop.libgpiod.gpiod_line_event_read(pinHandle, ref eventResult);
if (checkForEvent == -1)
{
throw ExceptionHelper.GetIOException(ExceptionResource.EventReadError, Marshal.GetLastWin32Error());
}
PinEventTypes eventType = (readResult == 1) ? PinEventTypes.Rising : PinEventTypes.Falling;
PinEventTypes eventType = (eventResult.event_type == 1) ? PinEventTypes.Rising : PinEventTypes.Falling;
this?.OnPinValueChanged(new PinValueChangedEventArgs(eventType, _pinNumber), eventType);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册