Code Monkey home page Code Monkey logo

Comments (8)

sidwarkd avatar sidwarkd commented on August 28, 2024

+1 for this issue.

from lightning.

Valks avatar Valks commented on August 28, 2024

I haven't had a chance to try modifying yet but for some reason with the UWP section Exclusive mode is set when creating the device: DmapSupport.cpp#L162

I expected that line to use shareMode instead as I can't see a comment explaining why it is explicitly set.

from lightning.

sidwarkd avatar sidwarkd commented on August 28, 2024

That does resolve it. I tried it a few days ago and confirmed.

from lightning.

Valks avatar Valks commented on August 28, 2024

Interesting to hear that. I just tried changing it to DeviceSharingMode::Sharing which still works fine for one device but as soon as I try to create the second I get a blue screen error.

Would you mind sharing the changes you did to make this work?

from lightning.

sidwarkd avatar sidwarkd commented on August 28, 2024

I literally changed the word "Exclusive" on that line you linked to "Shared". Sounds like there might be something else going on in your case. Could you post some sample code that recreates your specific scenario?

from lightning.

Valks avatar Valks commented on August 28, 2024

Sure hopefully this code snippet will be enough to show what I'm doing at the moment.

I'm registering this class as a service and using it throughout my project (though in this case only one viewmodel is using it).

I have a few INA219 boards so I figured I'd build it as a library for Adafruit components for future use.

It's a simple class to use. To get a device call await _controller.GetDeviceAsync(address, i2cChannel); and it will give back a class which stores the address and channel with a helper function to retrieve the dictionary reference when reading / writing to the device.

After that you use the Read, ReadPartial, Write, WritePartial functions as you would normally to communicate with the devices. This was done because I tried to change the SlaveAddress of a single device to get the desired effect. The class could be restored now to return the I2cDevice instead but for the moment that isn't my problem.

Try calling e.g. await _controller.GetDeviceAsync(address.GetHashCode(), channel); with two different address' and the second one will cause a bluescreen to occur.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.IoT.Lightning.Providers;
using Windows.Devices;
using Windows.Devices.I2c;

namespace Adafruit
{
  public class I2cController : II2cController
  {
    // I2c Controllers
    private Dictionary<int, Windows.Devices.I2c.I2cController> _controllers;
    // I2c Devices
    private Dictionary<Tuple<int, int>, Windows.Devices.I2c.I2cDevice> _devices;

    public I2cController()
    {
      _controllers = new Dictionary<int, Windows.Devices.I2c.I2cController>();
      _devices = new Dictionary<Tuple<int, int>, Windows.Devices.I2c.I2cDevice>();
    }

    /// <summary>
    /// Initialize the I2C Bus
    /// </summary>
    /// <param name="i2cChannel">Channel of i2C output</param>
    /// <returns>True if port opened successfully</returns>
    private async Task InitializeControllerAsync(int i2cChannel = 1)
    {
      if (_controllers.ContainsKey(i2cChannel)) return;

      if (LightningProvider.IsLightningEnabled)
      {
        if (LowLevelDevicesController.DefaultProvider == null)
          LowLevelDevicesController.DefaultProvider = LightningProvider.GetAggregateProvider();

        var controller = (await Windows.Devices.I2c.I2cController.GetControllersAsync(LightningI2cProvider.GetI2cProvider()))[i2cChannel - 1];

        if (controller == null) throw new IndexOutOfRangeException("i2C channel doesn't exist.");
        _controllers.Add(i2cChannel, controller);
      }
    }

    /// <summary>
    /// Try to register and return a device. Will also pass and return the details of the device if it's already registered
    /// </summary>
    /// <param name="address">Address of the device</param>
    /// <returns>I2c device</returns>
    public async Task<I2cDeviceDetails> GetDeviceAsync(int address, int i2cChannel = 1)
    {
      var deviceAddress = new Tuple<int, int>(i2cChannel, address);

      await InitializeControllerAsync(i2cChannel);
      if (_devices.ContainsKey(deviceAddress)) return new I2cDeviceDetails(i2cChannel, address);

      var settings = new I2cConnectionSettings(address) { SharingMode = I2cSharingMode.Shared };

      // Direct Memory Mapped (Lightning) Driver
      if (Microsoft.IoT.Lightning.Providers.LightningProvider.IsLightningEnabled)
      {
        var newDevice = _controllers[i2cChannel].GetDevice(settings);

        if (newDevice == null) throw new ArgumentOutOfRangeException("Failed to get i2C device.");
        _devices.Add(deviceAddress, newDevice);
      }
      // Inbox Driver - not tested
      else
      {
        var aqs = Windows.Devices.I2c.I2cDevice.GetDeviceSelector(string.Format("I2C{0}", i2cChannel));
        var deviceInformation = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs, null);
        settings.SharingMode = I2cSharingMode.Shared;
        var newDevice = await Windows.Devices.I2c.I2cDevice.FromIdAsync(deviceInformation[0].Id, settings);

        if (newDevice == null) throw new ArgumentOutOfRangeException("Failed to get i2C device.");
        _devices.Add(deviceAddress, newDevice);
      }

      return new I2cDeviceDetails(i2cChannel, address);
    }

    /// <summary>
    /// Reads data from the inter-integrated circuit (I2C) bus on which the device is
    /// connected into the specified buffer.
    /// </summary>
    /// <param name="device">Device to Write then Read from.</param>
    /// <param name="buffer">
    /// The buffer to which you want to read the data from the I2C bus. The length of
    /// the buffer determines how much data to request from the device.
    /// </param>
    public void Read(I2cDeviceDetails device, [Range(0, int.MaxValue)] byte[] buffer)
    {
      if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));

      _devices[device.GetDeviceAddress()].Read(buffer);
    }

    /// <summary>
    /// Reads data from the inter-integrated circuit (I2C) bus on which the device is
    /// connected into the specified buffer, and returns information about the success
    /// of the operation that you can use for error handling.
    /// </summary>
    /// <param name="device">Device to Write then Read from.</param>
    /// <param name="buffer">
    /// The buffer to which you want to read the data from the I2C bus. The length of
    /// the buffer determines how much data to request from the device.
    /// </param>
    /// <returns>
    /// A structure that contains information about the success of the read operation
    /// and the actual number of bytes that the operation read into the buffer.
    /// </returns>
    public I2cTransferResult ReadPartial(I2cDeviceDetails device, [Range(0, int.MaxValue)] byte[] buffer)
    {
      if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));

      return _devices[device.GetDeviceAddress()].ReadPartial(buffer);
    }

    /// <summary>
    /// Writes data to the inter-integrated circuit (I2C) bus on which the device is
    /// connected, based on the bus address specified in the I2cConnectionSettings object
    /// that you used to create the I2cDevice object.
    /// </summary>
    /// <param name="device">Device to Write then Read from.</param>
    /// <param name="buffer">A buffer that contains the data that you want to write to the I2C device. This
    /// data should not include the bus address.
    /// </param>
    public void Write(I2cDeviceDetails device, byte[] buffer)
    {
      if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));

      _devices[device.GetDeviceAddress()].Write(buffer);
    }

    /// <summary>
    /// Writes data to the inter-integrated circuit (I2C) bus on which the device is
    /// connected, and returns information about the success of the operation that you
    /// can use for error handling.
    /// </summary>
    /// <param name="device">Device to Write then Read from.</param>
    /// <param name="buffer">
    /// A buffer that contains the data that you want to write to the I2C device. This
    /// data should not include the bus address.
    /// </param>
    /// <returns>
    /// A structure that contains information about the success of the write operation
    /// and the actual number of bytes that the operation wrote into the buffer.
    /// </returns>
    public I2cTransferResult WritePartial(I2cDeviceDetails device, byte[] buffer)
    {
      if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));

      return _devices[device.GetDeviceAddress()].WritePartial(buffer);
    }

    /// <summary>
    /// Performs an atomic operation to write data to and then read data from the inter-integrated
    /// circuit (I2C) bus on which the device is connected, and sends a restart condition
    /// between the write and read operations.
    /// </summary>
    /// <param name="device">Device to Write then Read from.</param>
    /// <param name="writeBuffer">
    /// A buffer that contains the data that you want to write to the I2C device. This
    /// data should not include the bus address.
    /// </param>
    /// <param name="readBuffer">
    /// The buffer to which you want to read the data from the I2C bus. The length of
    /// the buffer determines how much data to request from the device.
    /// </param>
    public void WriteRead(I2cDeviceDetails device, byte[] writeBuffer, [Range(0, int.MaxValue)] byte[] readBuffer)
    {
      if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));

      _devices[device.GetDeviceAddress()].WriteRead(writeBuffer, readBuffer);
    }

    /// <summary>
    /// Performs an atomic operation to write data to and then read data from the inter-integrated
    ///  circuit (I2C) bus on which the device is connected, and returns information about
    ///  the success of the operation that you can use for error handling.
    /// </summary>
    /// <param name="device">Device to Write then Read from.</param>
    /// <param name="writeBuffer">
    /// A buffer that contains the data that you want to write to the I2C device. This
    /// data should not include the bus address.
    /// </param>
    /// <param name="readBuffer">
    /// The buffer to which you want to read the data from the I2C bus. The length of
    /// the buffer determines how much data to request from the device.
    /// </param>
    /// <returns>
    /// A structure that contains information about whether both the read and write parts
    /// of the operation succeeded and the sum of the actual number of bytes that the
    /// operation wrote and the actual number of bytes that the operation read.
    /// </returns>
    public I2cTransferResult WriteReadPartial(I2cDeviceDetails device, byte[] writeBuffer, [Range(0, int.MaxValue)] byte[] readBuffer)
    {
      if (!_devices.ContainsKey(device.GetDeviceAddress())) throw new NullReferenceException(string.Format("I2C Controller {0} isn't initialized.", device.Channel));

      return _devices[device.GetDeviceAddress()].WriteReadPartial(writeBuffer, readBuffer);
    }
  }
}

from lightning.

Valks avatar Valks commented on August 28, 2024

Just to keep things simple using my own local build of the lightning provider which references a local copy of Microsoft.IoT.Lightning and Microsoft.IoT.SDKFromArduino which are fully up to date. The only change done is to the Microsoft.IoT.Lightning to set to Shared.

decimal _flowOne = 0m;
    public decimal FlowOne { get { return _flowOne; } set { Set(ref _flowOne, value); } }
    decimal _flowTwo = 0m;
    public decimal FlowTwo { get { return _flowTwo; } set { Set(ref _flowTwo, value); } }

    private async Task MonitorSensorsAsync()
    {
      if(Microsoft.IoT.Lightning.Providers.LightningProvider.IsLightningEnabled)
      {
        if(Windows.Devices.LowLevelDevicesController.DefaultProvider == null)
        {
          Windows.Devices.LowLevelDevicesController.DefaultProvider = Microsoft.IoT.Lightning.Providers.LightningProvider.GetAggregateProvider();
          var controller = (await Windows.Devices.I2c.I2cController.GetControllersAsync(Microsoft.IoT.Lightning.Providers.LightningI2cProvider.GetI2cProvider()))[0];
          var deviceOne = controller.GetDevice(new Windows.Devices.I2c.I2cConnectionSettings(40) { SharingMode = Windows.Devices.I2c.I2cSharingMode.Shared });
          var deviceTwo = controller.GetDevice(new Windows.Devices.I2c.I2cConnectionSettings(41) { SharingMode = Windows.Devices.I2c.I2cSharingMode.Shared });

          FlowOne = await ReadRegisterAsync(deviceOne, 0x01);
          FlowTwo = await ReadRegisterAsync(deviceTwo, 0x01);
        }
      }
    }

private void WriteRegister(Windows.Devices.I2c.I2cDevice device, byte register, int value)
    {
      device.WritePartial(
        new byte[] {
        register,
        (byte)((value >> 8) & 0xFF),
        (byte)(value & 0xFF)
      });
    }

    private async Task<int> ReadRegisterAsync(Windows.Devices.I2c.I2cDevice device, byte register)
    {
      device.Write(new byte[] { register });
      await Task.Delay(100); // Max 12-bit conversion time is 586us per sample (default 128 samples = 69ms)

      var readBuffer = new byte[2];
      var result = device.ReadPartial(readBuffer);
      return readBuffer[0] << 8 | readBuffer[1];
    }

Still having the same issue when the second device is created using GetDevice it blue screens with "SYSTEM_SERVICE_EXCEPTION"

I'm running into this problem on a Raspberry Pi 2 (with the official display connected). Windows Core is fully up to date.

from lightning.

Valks avatar Valks commented on August 28, 2024

Just to follow up as @sidwarkd said changing that value to Shared works fine. My problem was due to a wiring error.

Thanks for your help.

from lightning.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.