首页 > 解决方案 > 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.

标签: uwpgpiowindows-iot-core-10

解决方案


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.

enter image description here

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.


推荐阅读