diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 0715d1b..81cb63a 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -45,7 +45,7 @@ jobs: with: repository: WildernessLabs/Meadow.Core path: Meadow.Core - ref: ${{ env.GITHUB_REF_NAME }} # match Core branch to this branch + ref: develop token: ${{ secrets.CI_ACCESS_TOKEN }} - name: Checkout Meadow.Foundation uses: actions/checkout@v3 diff --git a/Source/Meadow.ProjectLab/IProjectLabHardware.cs b/Source/Meadow.ProjectLab/IProjectLabHardware.cs index 9120bdc..1a1084c 100644 --- a/Source/Meadow.ProjectLab/IProjectLabHardware.cs +++ b/Source/Meadow.ProjectLab/IProjectLabHardware.cs @@ -27,5 +27,31 @@ public interface IProjectLabHardware public PushButton? DownButton { get; } public string RevisionString { get; } + + public (IPin AN, + IPin RST, + IPin CS, + IPin SCK, + IPin CIPO, + IPin COPI, + IPin PWM, + IPin INT, + IPin RX, + IPin TX, + IPin SCL, + IPin SCA) MikroBus1Pins { get; } + + public (IPin AN, + IPin RST, + IPin CS, + IPin SCK, + IPin CIPO, + IPin COPI, + IPin PWM, + IPin INT, + IPin RX, + IPin TX, + IPin SCL, + IPin SCA) MikroBus2Pins { get; } } } \ No newline at end of file diff --git a/Source/Meadow.ProjectLab/ProjectLab.cs b/Source/Meadow.ProjectLab/ProjectLab.cs index 086b7e3..3e2dd6f 100644 --- a/Source/Meadow.ProjectLab/ProjectLab.cs +++ b/Source/Meadow.ProjectLab/ProjectLab.cs @@ -23,7 +23,7 @@ public static IProjectLabHardware Create() ISpiBus spiBus; // v2+ stuff - Mcp23008? mcp_1 = null; + Mcp23008? mcp1 = null; logger?.Debug("Initializing Project Lab..."); @@ -59,23 +59,27 @@ public static IProjectLabHardware Create() logger?.Debug("I2C Bus instantiated"); + IDigitalInputPort? mcp1Interrupt = null; + IDigitalOutputPort? mcp1Reset = null; + try { // MCP the First - IDigitalInputPort mcp1_int = device.CreateDigitalInputPort( - device.Pins.D09, InterruptMode.EdgeRising, ResistorMode.InternalPullDown); - IDigitalOutputPort mcp_Reset = device.CreateDigitalOutputPort(device.Pins.D14); + mcp1Interrupt = device.CreateDigitalInputPort(device.Pins.D09, InterruptMode.EdgeRising, ResistorMode.InternalPullDown); + mcp1Reset = device.CreateDigitalOutputPort(device.Pins.D14); - mcp_1 = new Mcp23008(i2cBus, address: 0x20, mcp1_int, mcp_Reset); + mcp1 = new Mcp23008(i2cBus, address: 0x20, mcp1Interrupt, mcp1Reset); logger?.Trace("Mcp_1 up"); } catch (Exception e) { logger?.Debug($"Failed to create MCP1: {e.Message}, could be a v1 board"); + mcp1Interrupt?.Dispose(); + mcp1Reset?.Dispose(); } - if (mcp_1 == null) + if (mcp1 == null) { logger?.Debug("Instantiating Project Lab v1 specific hardware"); hardware = new ProjectLabHardwareV1(device, spiBus, i2cBus); @@ -83,7 +87,7 @@ public static IProjectLabHardware Create() else { logger?.Info("Instantiating Project Lab v2 specific hardware"); - hardware = new ProjectLabHardwareV2(device, spiBus, i2cBus, mcp_1); + hardware = new ProjectLabHardwareV2(device, spiBus, i2cBus, mcp1); } return hardware; diff --git a/Source/Meadow.ProjectLab/ProjectLabHardwareBase.cs b/Source/Meadow.ProjectLab/ProjectLabHardwareBase.cs index b043c3c..16d77e6 100644 --- a/Source/Meadow.ProjectLab/ProjectLabHardwareBase.cs +++ b/Source/Meadow.ProjectLab/ProjectLabHardwareBase.cs @@ -16,46 +16,56 @@ namespace Meadow.Devices /// public abstract class ProjectLabHardwareBase : IProjectLabHardware { + /// + /// Get a reference to Meadow Logger + /// protected Logger? Logger { get; } = Resolver.Log; - //==== properties - /// /// Gets the SPI Bus /// public ISpiBus SpiBus { get; } + /// /// Gets the I2C Bus /// public II2cBus I2cBus { get; } + /// /// Gets the BH1750 Light Sensor on the Project Lab board /// public Bh1750? LightSensor { get; } + /// /// Gets the BME688 environmental sensor on the Project Lab board /// public Bme688? EnvironmentalSensor { get; } + /// /// Gets the Piezo noise maker on the Project Lab board /// public PiezoSpeaker? Speaker { get; } + /// /// Gets the BMI inertial movement unit (IMU) on the Project Lab board /// public Bmi270? MotionSensor { get; } + /// /// Gets the ST7789 Display on the Project Lab board /// public abstract St7789? Display { get; } + /// /// Gets the Up PushButton on the Project Lab board /// public abstract PushButton? UpButton { get; } + /// /// Gets the Down PushButton on the Project Lab board /// public abstract PushButton? DownButton { get; } + /// /// Gets the Left PushButton on the Project Lab board /// @@ -64,17 +74,27 @@ public abstract class ProjectLabHardwareBase : IProjectLabHardware /// Gets the Right PushButton on the Project Lab board /// public abstract PushButton? RightButton { get; } + /// /// Gets the ProjectLab board hardware revision /// public virtual string RevisionString { get; set; } = "unknown"; - public ProjectLabHardwareBase(IF7FeatherMeadowDevice device, ISpiBus spiBus, II2cBus i2cBus) + /// + /// Get the ProjectLab pins for mikroBUS header 1 + /// + public abstract (IPin AN, IPin RST, IPin CS, IPin SCK, IPin CIPO, IPin COPI, IPin PWM, IPin INT, IPin RX, IPin TX, IPin SCL, IPin SCA) MikroBus1Pins { get; protected set; } + + /// + /// Get the ProjectLab pins for mikroBUS header 1 + /// + public abstract (IPin AN, IPin RST, IPin CS, IPin SCK, IPin CIPO, IPin COPI, IPin PWM, IPin INT, IPin RX, IPin TX, IPin SCL, IPin SCA) MikroBus2Pins { get; protected set; } + + internal ProjectLabHardwareBase(IF7FeatherMeadowDevice device, ISpiBus spiBus, II2cBus i2cBus) { SpiBus = spiBus; I2cBus = i2cBus; - //==== Initialize the shared/common stuff try { Logger?.Trace("Instantiating light sensor"); @@ -104,7 +124,7 @@ public ProjectLabHardwareBase(IF7FeatherMeadowDevice device, ISpiBus spiBus, II2 try { Logger?.Trace("Instantiating speaker"); - Speaker = new PiezoSpeaker(device, device.Pins.D11); + Speaker = new PiezoSpeaker(device.Pins.D11); Logger?.Trace("Speaker up"); } catch (Exception ex) @@ -122,7 +142,6 @@ public ProjectLabHardwareBase(IF7FeatherMeadowDevice device, ISpiBus spiBus, II2 { Resolver.Log.Error($"Unable to create the BMI270 IMU: {ex.Message}"); } - } /// @@ -139,53 +158,21 @@ public ProjectLabHardwareBase(IF7FeatherMeadowDevice device, ISpiBus spiBus, II2 /// Gets the pin definitions for the Project Lab board /// public static ( - IPin MB1_CS, - IPin MB1_INT, - IPin MB1_PWM, - IPin MB1_AN, - IPin MB1_SO, - IPin MB1_SI, - IPin MB1_SCK, - IPin MB1_SCL, - IPin MB1_SDA, - - IPin MB2_CS, - IPin MB2_INT, - IPin MB2_PWM, - IPin MB2_AN, - IPin MB2_SO, - IPin MB2_SI, - IPin MB2_SCK, - IPin MB2_SCL, - IPin MB2_SDA, - IPin A0, + IPin A1, + IPin A2, IPin D03, - IPin D04 + IPin D04, + IPin D12, + IPin D13 ) Pins = ( - Resolver.Device.GetPin("D14"), - Resolver.Device.GetPin("D03"), - Resolver.Device.GetPin("D04"), Resolver.Device.GetPin("A00"), - Resolver.Device.GetPin("CIPO"), - Resolver.Device.GetPin("COPI"), - Resolver.Device.GetPin("SCK"), - Resolver.Device.GetPin("D08"), - Resolver.Device.GetPin("D07"), - - Resolver.Device.GetPin("A02"), - Resolver.Device.GetPin("D04"), - Resolver.Device.GetPin("D03"), Resolver.Device.GetPin("A01"), - Resolver.Device.GetPin("CIPO"), - Resolver.Device.GetPin("COPI"), - Resolver.Device.GetPin("SCK"), - Resolver.Device.GetPin("D08"), - Resolver.Device.GetPin("D07"), - - Resolver.Device.GetPin("A00"), + Resolver.Device.GetPin("A02"), Resolver.Device.GetPin("D03"), - Resolver.Device.GetPin("D04") + Resolver.Device.GetPin("D04"), + Resolver.Device.GetPin("D12"), + Resolver.Device.GetPin("D13") ); } } \ No newline at end of file diff --git a/Source/Meadow.ProjectLab/ProjectLabHardwareV1.cs b/Source/Meadow.ProjectLab/ProjectLabHardwareV1.cs index b684189..9e35023 100644 --- a/Source/Meadow.ProjectLab/ProjectLabHardwareV1.cs +++ b/Source/Meadow.ProjectLab/ProjectLabHardwareV1.cs @@ -7,7 +7,7 @@ namespace Meadow.Devices { - internal class ProjectLabHardwareV1 : ProjectLabHardwareBase + public class ProjectLabHardwareV1 : ProjectLabHardwareBase { private string revision = "v1.x"; @@ -15,30 +15,43 @@ internal class ProjectLabHardwareV1 : ProjectLabHardwareBase /// Gets the ST7789 Display on the Project Lab board /// public override St7789? Display { get; } + /// /// Gets the Up PushButton on the Project Lab board /// public override PushButton? UpButton { get; } + /// /// Gets the Down PushButton on the Project Lab board /// public override PushButton? DownButton { get; } + /// /// Gets the Left PushButton on the Project Lab board /// public override PushButton? LeftButton { get; } + /// /// Gets the Right PushButton on the Project Lab board /// public override PushButton? RightButton { get; } - public ProjectLabHardwareV1(IF7FeatherMeadowDevice device, ISpiBus spiBus, II2cBus i2cBus) + /// + /// Get the ProjectLab pins for mikroBUS header 1 + /// + public override (IPin AN, IPin RST, IPin CS, IPin SCK, IPin CIPO, IPin COPI, IPin PWM, IPin INT, IPin RX, IPin TX, IPin SCL, IPin SCA) MikroBus1Pins { get; protected set; } + + /// + /// Get the ProjectLab pins for mikroBUS header 2 + /// + public override (IPin AN, IPin RST, IPin CS, IPin SCK, IPin CIPO, IPin COPI, IPin PWM, IPin INT, IPin RX, IPin TX, IPin SCL, IPin SCA) MikroBus2Pins { get; protected set; } + + internal ProjectLabHardwareV1(IF7FeatherMeadowDevice device, ISpiBus spiBus, II2cBus i2cBus) : base(device, spiBus, i2cBus) { //---- create our display Logger?.Trace("Instantiating display"); Display = new St7789( - device: device, spiBus: SpiBus, chipSelectPin: device.Pins.A03, dcPin: device.Pins.A04, @@ -57,25 +70,57 @@ public ProjectLabHardwareV1(IF7FeatherMeadowDevice device, ISpiBus spiBus, II2cB UpButton = GetPushButton(device, device.Pins.D15); DownButton = GetPushButton(device, device.Pins.D02); Logger?.Trace("Buttons up"); + + SetMikroBusPins(); + } + + void SetMikroBusPins() + { + MikroBus1Pins = + (Resolver.Device.GetPin("A00"), + null, + Resolver.Device.GetPin("D14"), + Resolver.Device.GetPin("SCK"), + Resolver.Device.GetPin("CIPO"), + Resolver.Device.GetPin("COPI"), + Resolver.Device.GetPin("D04"), + Resolver.Device.GetPin("D03"), + Resolver.Device.GetPin("D12"), + Resolver.Device.GetPin("D13"), + Resolver.Device.GetPin("D07"), + Resolver.Device.GetPin("D08")); + + MikroBus2Pins = + (Resolver.Device.GetPin("A01"), + null, + Resolver.Device.GetPin("A02"), + Resolver.Device.GetPin("SCK"), + Resolver.Device.GetPin("CIPO"), + Resolver.Device.GetPin("COPI"), + Resolver.Device.GetPin("D03"), + Resolver.Device.GetPin("D04"), + Resolver.Device.GetPin("D12"), + Resolver.Device.GetPin("D13"), + Resolver.Device.GetPin("D07"), + Resolver.Device.GetPin("D08")); } public override string RevisionString => revision; private PushButton GetPushButton(IF7FeatherMeadowDevice device, IPin pin) - => new PushButton(Resolver.Device, pin, ResistorMode.InternalPullDown); + => new PushButton(pin, ResistorMode.InternalPullDown); public override ModbusRtuClient GetModbusRtuClient(int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One) { - if (Resolver.Device is F7FeatherV1 device) + if (Resolver.Device is F7FeatherBase device) { var portName = device.PlatformOS.GetSerialPortName("com4"); var port = device.CreateSerialPort(portName, baudRate, dataBits, parity, stopBits); port.WriteTimeout = port.ReadTimeout = TimeSpan.FromSeconds(5); var serialEnable = device.CreateDigitalOutputPort(device.Pins.D09, false); - return new ModbusRtuClient(port, serialEnable); + return new ProjectLabModbusRtuClient(port, serialEnable); } - // this is v1 instance hardware, so we should never get here throw new NotSupportedException(); } } diff --git a/Source/Meadow.ProjectLab/ProjectLabHardwareV2.cs b/Source/Meadow.ProjectLab/ProjectLabHardwareV2.cs index 1b5e144..529d07d 100644 --- a/Source/Meadow.ProjectLab/ProjectLabHardwareV2.cs +++ b/Source/Meadow.ProjectLab/ProjectLabHardwareV2.cs @@ -9,34 +9,59 @@ namespace Meadow.Devices { - internal class ProjectLabHardwareV2 : ProjectLabHardwareBase + public class ProjectLabHardwareV2 : ProjectLabHardwareBase { + /// + /// The MCP23008 IO expander connected to internal peripherals + /// public Mcp23008 Mcp_1 { get; protected set; } - public Mcp23008 Mcp_2 { get; protected set; } - public Mcp23008? Mcp_Version { get; protected set; } + + /// + /// The MCP23008 IO expander connected to IO headers and terminals on Project Lab + /// + public Mcp23008? Mcp_2 { get; protected set; } + + /// + /// The MCP23008 IO expander that contains the ProjectLab hardware version + /// + Mcp23008? Mcp_Version { get; set; } /// /// Gets the ST7789 Display on the Project Lab board /// public override St7789? Display { get; } + /// /// Gets the Up PushButton on the Project Lab board /// public override PushButton? UpButton { get; } + /// /// Gets the Down PushButton on the Project Lab board /// public override PushButton? DownButton { get; } + /// /// Gets the Left PushButton on the Project Lab board /// public override PushButton? LeftButton { get; } + /// /// Gets the Right PushButton on the Project Lab board /// public override PushButton? RightButton { get; } - public ProjectLabHardwareV2( + /// + /// Get the ProjectLab pins for mikroBUS header 1 + /// + public override (IPin AN, IPin RST, IPin CS, IPin SCK, IPin CIPO, IPin COPI, IPin PWM, IPin INT, IPin RX, IPin TX, IPin SCL, IPin SCA) MikroBus1Pins { get; protected set; } + + /// + /// Get the ProjectLab pins for mikroBUS header 2 + /// + public override (IPin AN, IPin RST, IPin CS, IPin SCK, IPin CIPO, IPin COPI, IPin PWM, IPin INT, IPin RX, IPin TX, IPin SCL, IPin SCA) MikroBus2Pins { get; protected set; } + + internal ProjectLabHardwareV2( IF7FeatherMeadowDevice device, ISpiBus spiBus, II2cBus i2cBus, @@ -105,13 +130,45 @@ Mcp23008 mcp1 var downPort = mcp1.CreateDigitalInputPort(mcp1.Pins.GP3, InterruptMode.EdgeBoth, ResistorMode.InternalPullUp); DownButton = new PushButton(downPort); Logger?.Trace("Buttons up"); + + SetMikroBusPins(); + } + + void SetMikroBusPins() + { + MikroBus1Pins = + (Resolver.Device.GetPin("A02"), + Mcp_2.Pins.GP4, + Mcp_2.Pins.GP5, + Resolver.Device.GetPin("SCK"), + Resolver.Device.GetPin("CIPO"), + Resolver.Device.GetPin("COPI"), + Resolver.Device.GetPin("D03"), + Mcp_2.Pins.GP6, + Resolver.Device.GetPin("D13"), + Resolver.Device.GetPin("D12"), + Resolver.Device.GetPin("D07"), + Resolver.Device.GetPin("D08")); + + MikroBus2Pins = + (Resolver.Device.GetPin("A03"), + Mcp_2.Pins.GP1, + Mcp_2.Pins.GP2, + Resolver.Device.GetPin("SCK"), + Resolver.Device.GetPin("CIPO"), + Resolver.Device.GetPin("COPI"), + Resolver.Device.GetPin("D04"), + Mcp_2.Pins.GP3, + Resolver.Device.GetPin("D13"), + Resolver.Device.GetPin("D12"), + Resolver.Device.GetPin("D07"), + Resolver.Device.GetPin("D08")); } public override string RevisionString { get { - // TODO: figure this out from MCP3? if (revision == null) { if (Mcp_Version == null) @@ -121,28 +178,26 @@ public override string RevisionString else { byte rev = Mcp_Version.ReadFromPorts(Mcp23xxx.PortBank.A); - //mapping? 0 == d2.d? revision = $"v2.{rev}"; } } return revision; } } - protected string? revision; + string? revision; public override ModbusRtuClient GetModbusRtuClient(int baudRate = 19200, int dataBits = 8, Parity parity = Parity.None, StopBits stopBits = StopBits.One) { - if (Resolver.Device is F7FeatherV2 device) + if (Resolver.Device is F7FeatherBase device) { var portName = device.PlatformOS.GetSerialPortName("com4"); var port = device.CreateSerialPort(portName, baudRate, dataBits, parity, stopBits); port.WriteTimeout = port.ReadTimeout = TimeSpan.FromSeconds(5); var serialEnable = Mcp_2.CreateDigitalOutputPort(Mcp_2.Pins.GP0, false); - return new ModbusRtuClient(port, serialEnable); + return new ProjectLabModbusRtuClient(port, serialEnable); } - // this is v2 instance hardware, so we should never get here throw new NotSupportedException(); } } diff --git a/Source/Meadow.ProjectLab/ProjectLabModbusRtuClient.cs b/Source/Meadow.ProjectLab/ProjectLabModbusRtuClient.cs new file mode 100644 index 0000000..e842a66 --- /dev/null +++ b/Source/Meadow.ProjectLab/ProjectLabModbusRtuClient.cs @@ -0,0 +1,24 @@ +using Meadow.Hardware; +using Meadow.Modbus; +using System.Threading; + +namespace Meadow.Devices +{ + public class ProjectLabModbusRtuClient : ModbusRtuClient + { + public ProjectLabModbusRtuClient(ISerialPort port, IDigitalOutputPort enablePort) + : base(port, enablePort) + { + // this forces meadow to compile the serial pipeline. Without it, there's a big delay on sending the first byte + PostOpenAction = () => { port.Write(new byte[] { 0x00 }); }; + + // meadow is not-so-fast, and data will not all get transmitted before the call to the port Write() returns + PostWriteDelayAction = (m) => + { + var delay = (int)((1d / port.BaudRate) * port.DataBits * 1000d * m.Length) + 3; // +3 to add just a little extra for clients who are a little slow to turn off the enable pin + Thread.Sleep(delay); + }; + } + } + +} \ No newline at end of file diff --git a/Source/ProjectLab_Demo/MeadowApp.cs b/Source/ProjectLab_Demo/MeadowApp.cs index f768a1b..469613f 100644 --- a/Source/ProjectLab_Demo/MeadowApp.cs +++ b/Source/ProjectLab_Demo/MeadowApp.cs @@ -1,11 +1,11 @@ -using System; -using System.Threading.Tasks; -using Meadow; +using Meadow; using Meadow.Devices; using Meadow.Foundation; using Meadow.Foundation.Leds; using Meadow.Peripherals.Leds; using Meadow.Units; +using System; +using System.Threading.Tasks; namespace ProjLab_Demo { @@ -24,7 +24,7 @@ public override Task Initialize() //==== RGB LED Resolver.Log.Info("Initializing onboard RGB LED"); - onboardLed = new RgbPwmLed(device: Device, + onboardLed = new RgbPwmLed( redPwmPin: Device.Pins.OnboardLedRed, greenPwmPin: Device.Pins.OnboardLedGreen, bluePwmPin: Device.Pins.OnboardLedBlue,