uwp - UWP gpio controlled by multiple apps
问题描述
my problem is pretty simple. I have RPI with win10 and multiple UWP apps. I want to turn on red led when any app comes in trouble (throws exception or whatsoever) and turn it off when problem is solved.
I can pull up/down pins from app, but when one app holds GPIO pin, another one will throw exception. Or, when problem is solved in one app, led will turn off while other apps still have problems.
Is there any abstraction* that I can use, or any way I can create my own?
*By abstraction I mean app that work on background, and I can call it as static class.
解决方案
GPIO controller can not shared across multiple app domain, once an app handles the GPIO controller, it will be locked for current app domain. I think a workaround for this issue is that, you can create an app service as a bridge running on the device, the app service controls the GPIO, your multiple apps call the service. You can implement the logic in the app service.
Update:
Here isn an app service hosted in windows iot core background application.
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>
You need to add the extension reference for app service in package manifest.
推荐阅读
- java - 如何在本地机器上测试 Azure 托管标识连接?
- php - PHP:提前准备繁重的查询和 API 请求(异步)
- c++ - PCL:过滤点云给定 2 线方程
- youtube-api - Youtube api search.list 和 eventType live 没有给出结果
- c - C中二进制文件的运行长度编码
- javascript - 如果文档已经存在,不想覆盖它
- python - 应用 Ostu 阈值和 Skimage 计算图像感兴趣区域的属性
- android - 如何使用 fcm 发送高级通知?
- hugo - Hugo - 使用带有复杂键的索引来获取数据
- c++ - 为什么超出数组边界写入会导致奇怪的行为?