由多个应用程序控制的 UWP gpio
UWP gpio controlled by multiple apps
我的问题很简单。我有 win10 和多个 UWP 应用程序的 RPI。我想在任何应用程序遇到问题(抛出异常或其他)时打开红色 LED,并在问题解决后将其关闭。
我可以从应用程序中拉取 up/down 引脚,但是当一个应用程序占用 GPIO 引脚时,另一个应用程序将抛出异常。或者,当一个应用程序解决问题时,led 将关闭,而其他应用程序仍然存在问题。
是否有任何我可以使用的抽象*,或者我可以创建自己的任何方式?
*我所说的抽象是指在后台运行的应用程序,我可以将其称为静态 class。
GPIO 控制器不能跨多个应用域共享,一旦一个应用处理了GPIO 控制器,它将被锁定为当前应用域。我认为这个问题的解决方法是,您可以在设备上创建一个 app service 作为桥 运行,应用程序服务控制 GPIO,您的多个应用程序调用该服务。您可以在应用服务中实现逻辑。
更新:
这是在 windows 物联网核心后台应用程序中托管的应用程序服务。
StartupTask.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using Windows.ApplicationModel.Background;
using Windows.ApplicationModel.AppService;
using Windows.Foundation.Collections;
using Windows.Devices.Gpio;
using System.Threading.Tasks;
using Windows.System.Threading;
// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409
namespace AppErrorCrossDomainMonitorService
{
public sealed class AppErrorCrossDomainMonitorTask : IBackgroundTask
{
IBackgroundTaskInstance _taskInstance = null;
private BackgroundTaskDeferral serviceDeferral;
private AppServiceConnection connection;
private GpioController gpioController;
private static GpioPin ledPin = null;
private GpioOpenStatus pinStatus = GpioOpenStatus.UnknownError;
private const int LED_PIN = 4;
public void Run(IBackgroundTaskInstance taskInstance)
{
//
// TODO: Insert code to perform background work
//
// If you start any asynchronous methods here, prevent the task
// from closing prematurely by using BackgroundTaskDeferral as
// described in http://aka.ms/backgroundtaskdeferral
//
//Take a service deferral so the service isn't terminated
try
{
serviceDeferral = taskInstance.GetDeferral();
taskInstance.Canceled += OnTaskCanceled;
_taskInstance = taskInstance;
pinStatus = GpioOpenStatus.UnknownError;
gpioController = GpioController.GetDefault();
var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
if(details != null)
{
connection = details.AppServiceConnection;
//Listen for incoming app service requests
connection.RequestReceived += OnRequestReceived;
}
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
if (serviceDeferral != null)
{
//Complete the service deferral
serviceDeferral.Complete();
serviceDeferral = null;
}
if (connection != null)
{
connection.Dispose();
connection = null;
}
}
async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
//Get a deferral so we can use an awaitable API to respond to the message
var messageDeferral = args.GetDeferral();
try
{
var input = args.Request.Message;
string appName = input["AppName"].ToString();
string actionName = input["ActionName"].ToString();
//Create the response
var result = new ValueSet();
if (gpioController != null)
{
if(ledPin == null)
{
gpioController.TryOpenPin(LED_PIN, GpioSharingMode.Exclusive, out ledPin, out pinStatus);
if (ledPin != null)
{
ledPin.SetDriveMode(GpioPinDriveMode.Output);
}
}
}
if (actionName == "error")
{
//Open LED
ledPin.Write(GpioPinValue.High);
result.Add("led-status", "ON");
}
if (actionName == "clear")
{
//Close LED
ledPin.Write(GpioPinValue.Low);
result.Add("led-status", "OFF");
}
//Send the response
await args.Request.SendResponseAsync(result);
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
//Complete the message deferral so the platform knows we're done responding
messageDeferral.Complete();
}
}
}
}
Package.appxmanifest
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
IgnorableNamespaces="uap mp iot uap3">
...
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="AppErrorCrossDomainMonitorService.AppErrorCrossDomainMonitorTask">
<BackgroundTasks>
<iot:Task Type="startup" />
</BackgroundTasks>
</Extension>
<uap:Extension Category="windows.appService" EntryPoint="AppErrorCrossDomainMonitorService.AppErrorCrossDomainMonitorTask">
<uap3:AppService Name="com.microsoft.errorcrossdomainmonitor" SupportsRemoteSystems="true"/>
</uap:Extension>
</Extensions>
...
<Capabilities>
<Capability Name="internetClient" />
<DeviceCapability Name="lowLevel" />
</Capabilities>
</Package>
您需要在包清单中添加应用服务的扩展引用。
我的问题很简单。我有 win10 和多个 UWP 应用程序的 RPI。我想在任何应用程序遇到问题(抛出异常或其他)时打开红色 LED,并在问题解决后将其关闭。
我可以从应用程序中拉取 up/down 引脚,但是当一个应用程序占用 GPIO 引脚时,另一个应用程序将抛出异常。或者,当一个应用程序解决问题时,led 将关闭,而其他应用程序仍然存在问题。
是否有任何我可以使用的抽象*,或者我可以创建自己的任何方式?
*我所说的抽象是指在后台运行的应用程序,我可以将其称为静态 class。
GPIO 控制器不能跨多个应用域共享,一旦一个应用处理了GPIO 控制器,它将被锁定为当前应用域。我认为这个问题的解决方法是,您可以在设备上创建一个 app service 作为桥 运行,应用程序服务控制 GPIO,您的多个应用程序调用该服务。您可以在应用服务中实现逻辑。
更新:
这是在 windows 物联网核心后台应用程序中托管的应用程序服务。
StartupTask.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using Windows.ApplicationModel.Background;
using Windows.ApplicationModel.AppService;
using Windows.Foundation.Collections;
using Windows.Devices.Gpio;
using System.Threading.Tasks;
using Windows.System.Threading;
// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409
namespace AppErrorCrossDomainMonitorService
{
public sealed class AppErrorCrossDomainMonitorTask : IBackgroundTask
{
IBackgroundTaskInstance _taskInstance = null;
private BackgroundTaskDeferral serviceDeferral;
private AppServiceConnection connection;
private GpioController gpioController;
private static GpioPin ledPin = null;
private GpioOpenStatus pinStatus = GpioOpenStatus.UnknownError;
private const int LED_PIN = 4;
public void Run(IBackgroundTaskInstance taskInstance)
{
//
// TODO: Insert code to perform background work
//
// If you start any asynchronous methods here, prevent the task
// from closing prematurely by using BackgroundTaskDeferral as
// described in http://aka.ms/backgroundtaskdeferral
//
//Take a service deferral so the service isn't terminated
try
{
serviceDeferral = taskInstance.GetDeferral();
taskInstance.Canceled += OnTaskCanceled;
_taskInstance = taskInstance;
pinStatus = GpioOpenStatus.UnknownError;
gpioController = GpioController.GetDefault();
var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
if(details != null)
{
connection = details.AppServiceConnection;
//Listen for incoming app service requests
connection.RequestReceived += OnRequestReceived;
}
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
private void OnTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
if (serviceDeferral != null)
{
//Complete the service deferral
serviceDeferral.Complete();
serviceDeferral = null;
}
if (connection != null)
{
connection.Dispose();
connection = null;
}
}
async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
//Get a deferral so we can use an awaitable API to respond to the message
var messageDeferral = args.GetDeferral();
try
{
var input = args.Request.Message;
string appName = input["AppName"].ToString();
string actionName = input["ActionName"].ToString();
//Create the response
var result = new ValueSet();
if (gpioController != null)
{
if(ledPin == null)
{
gpioController.TryOpenPin(LED_PIN, GpioSharingMode.Exclusive, out ledPin, out pinStatus);
if (ledPin != null)
{
ledPin.SetDriveMode(GpioPinDriveMode.Output);
}
}
}
if (actionName == "error")
{
//Open LED
ledPin.Write(GpioPinValue.High);
result.Add("led-status", "ON");
}
if (actionName == "clear")
{
//Close LED
ledPin.Write(GpioPinValue.Low);
result.Add("led-status", "OFF");
}
//Send the response
await args.Request.SendResponseAsync(result);
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
//Complete the message deferral so the platform knows we're done responding
messageDeferral.Complete();
}
}
}
}
Package.appxmanifest
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
IgnorableNamespaces="uap mp iot uap3">
...
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="AppErrorCrossDomainMonitorService.AppErrorCrossDomainMonitorTask">
<BackgroundTasks>
<iot:Task Type="startup" />
</BackgroundTasks>
</Extension>
<uap:Extension Category="windows.appService" EntryPoint="AppErrorCrossDomainMonitorService.AppErrorCrossDomainMonitorTask">
<uap3:AppService Name="com.microsoft.errorcrossdomainmonitor" SupportsRemoteSystems="true"/>
</uap:Extension>
</Extensions>
...
<Capabilities>
<Capability Name="internetClient" />
<DeviceCapability Name="lowLevel" />
</Capabilities>
</Package>
您需要在包清单中添加应用服务的扩展引用。