Skip to content
This repository has been archived by the owner on Jun 14, 2024. It is now read-only.

Add more settings to SPI, and possibly add a Get-SPIDevice #54

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

DanielSSilva
Copy link
Contributor

This is an initial commit so that we can discuss if such changes can make sense.
This comes in sequence of issue #53. In my case, I have the neopixels which I can use to test the SPI, basing my implementation on dotnet IoT binding sample for the WS2812b.

  • Why a Get-SPIDevice - For this binding, they are passing the SPI device as a parameter (which was one of the reasons why I've decided to try an implementation of a Get-SPIDevice). It also seems, as I've pointed on the issue, that "this seems that the SPI device could be created once and used many times", which would make more sense than creating a device for each time we send some data.

  • Why more settings - Again, basing my implementation on their sample, there were some settings that seemed to be mandatory for it to work properly. Because it seems they are not mandatory, they can be created with default values.

Here's an example:

$device = Get-SPIDevice -Frequency 2400000 -Mode Mode0 -DataBitLength 8 -BusId 0 -ChipSelectLine 0
	$neo = [Iot.Device.Ws28xx.Ws2812b]::new($device,1)                              
	$img = $neo.Image
	$img.SetPixel(0,0, [System.Drawing.Color]::DarkRed)
	$neo.Update()    

Comment on lines +45 to +52
var settings = new SpiConnectionSettings(this.BusId, this.ChipSelectLine)
{
ClockFrequency = this.Frequency,
DataBitLength = this.DataBitLength,
Mode = this.Mode,
DataFlow = this.DataFlow,
ChipSelectLineActiveState = this.ChipSelectLineActiveState
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be concerned about overwriting defaults here if they aren't specified via the cmdlet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be concerned because if those fields are not specified, they will have their defaults (0 for int, etc), which already happens with our current version. DataBitLength wasn't specified, hence it was always 0, etc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should Not rely on types' default values.
For defaults we should use values common for SPI communication, so use/copy-paste the defaults from .NET code.
For example, in normal SPI communications default DataBitLength=8.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agree. I was relying on the defaults because from what I saw they seemed to be the .NET defaults. Checking again, I was wrong. I was probably checking the wrong file .
Leaving the SpiSettings here for further reference

internal SpiDevice device = null;
public int BusId { get; set; }

public int ChipSelectLine { get; set; }
Copy link

@iSazonov iSazonov Apr 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these properties be public settable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've followed the same implementation as we have for I2C (here).
From my understanding, it will depend on what we want to do:

What should happen if the user changed their hardware from busId 0 to 1, or the ChipSelectLine? Should he create a new device? Or should we allow to change the busId and ChipSelectLine?

If we want to bind a device to a busId and ChipSelectLine, this should not be settable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High level thinking is that these properties here are for information only / aka readlonly. If people want to use another set of settings, they need to construct another SPIDevice using Get-SPIDevice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, this means that all properties should be readonly, correct?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you consider readonly struct for this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, this means that all properties should be readonly, correct?

Correct.

Do you consider readonly struct for this?

This seems alright.

{
this.BusId = 0;
this.ChipSelectLine = 0;
this.Frequency = 500_000; // 500 KHz default speed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaults for other properties also have to be set here. They can be taken from .NET's SpiDevice code.

public PinValue ChipSelectLineActiveState { get; set; }

[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SwitchParameter Raw { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like this is not used anywhere so can be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't understand from GH interface what property you are referring to. The Raw?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes; Raw.

ChipSelectLineActiveState = this.ChipSelectLineActiveState
};

SpiDevice spiDevice = SpiDevice.Create(settings);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should return our SPIDevice wrapper that has public property of .NET's SpiDevice. This way .NET's SpiDevice object is accessible and can be used for scenarios like neopixels in this PR.

using System.Device.Gpio;
using System.Device.Spi;

public class SPIData : SPIDevice
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SPIData should Not inherit from SPIDevice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just have another SPIDevice-type property

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with best practices for such cases. Why shouldn't it inherit from SPIDevice? I've leveraged from inheritance because SPIData has all the properties that SPIDevice has, plus the Data and Response. Also, because an SPIData requires an SPIDevice

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is very tempting to inherit SPIData from SPIDevice, but semantically the data object is not a subclass of a device object. Inheriting one from another usually brings problems down the road.
For same reason I2CDeviceRegisterData does not inherit from I2CDevice but rather has a property of this type that exposes device configuration data (as well as device object).

internal SpiDevice device = null;
public int BusId { get; set; }

public int ChipSelectLine { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High level thinking is that these properties here are for information only / aka readlonly. If people want to use another set of settings, they need to construct another SPIDevice using Get-SPIDevice.


public class SPIDevice
{
internal SpiDevice device = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a problem if this class just holds 2 public properties:

public SpiDevice device;
public SpiConnectionSettings connectionSettings;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, but it would make sense to "expand" the connectionSettings when they are being displayed, like overriding the ToString

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably be done in a type format file for class SPIDevice.
I also don't have a bug problem with overriding ToString.

src/Microsoft.PowerShell.IoT/SPI/SPIData.cs Show resolved Hide resolved
Comment on lines +45 to +52
var settings = new SpiConnectionSettings(this.BusId, this.ChipSelectLine)
{
ClockFrequency = this.Frequency,
DataBitLength = this.DataBitLength,
Mode = this.Mode,
DataFlow = this.DataFlow,
ChipSelectLineActiveState = this.ChipSelectLineActiveState
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should Not rely on types' default values.
For defaults we should use values common for SPI communication, so use/copy-paste the defaults from .NET code.
For example, in normal SPI communications default DataBitLength=8.

settings.ClockFrequency = this.Frequency;

using(var spiDevice = SpiDevice.Create(settings))
var settings = new SpiConnectionSettings(this.BusId, this.ChipSelectLine)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructing SpiConnectionSettings and SPIDevice can be moved from this cmdlet to Get-SPIDevice

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cmdlet can just take SPIDevice object instead of all settings parameters.

@anmenaga
Copy link
Contributor

Also, a general comment: using SPI for neopixels is a hack that exploits the high-frequency of SPI bus to emulate (relatively)low-frequency of neopixel protocol.
This hack is a valid scenario, but it can't be used as verification that our SPI cmdlets actually work correctly for real SPI communications between devices.

Copy link
Contributor Author

@DanielSSilva DanielSSilva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

general comments regarding feedback. Leaving it here to check later

public PinValue ChipSelectLineActiveState { get; set; }

[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true)]
public SwitchParameter Raw { get; set; }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't understand from GH interface what property you are referring to. The Raw?

src/Microsoft.PowerShell.IoT/SPI/SPIData.cs Show resolved Hide resolved
using System.Device.Gpio;
using System.Device.Spi;

public class SPIData : SPIDevice
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with best practices for such cases. Why shouldn't it inherit from SPIDevice? I've leveraged from inheritance because SPIData has all the properties that SPIDevice has, plus the Data and Response. Also, because an SPIData requires an SPIDevice


public class SPIDevice
{
internal SpiDevice device = null;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, but it would make sense to "expand" the connectionSettings when they are being displayed, like overriding the ToString

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants