diff --git a/README.md b/README.md
index fc64aff6..33f85bae 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@
| nanoFramework.M5Core | [](https://dev.azure.com/nanoframework/nanoFramework.M5Stack/_build/latest?definitionId=52&repoName=nanoframework%2FnanoFramework.M5Stack&branchName=main) | [](https://www.nuget.org/packages/nanoFramework.M5Stack/) |
| nanoFramework.M5Stick | [](https://dev.azure.com/nanoframework/nanoFramework.M5Stack/_build/latest?definitionId=52&repoName=nanoframework%2FnanoFramework.M5Stack&branchName=main) | [](https://www.nuget.org/packages/nanoFramework.M5StickC/) |
| nanoFramework.M5StickCPlus | [](https://dev.azure.com/nanoframework/nanoFramework.M5Stack/_build/latest?definitionId=52&repoName=nanoframework%2FnanoFramework.M5Stack&branchName=main) | [](https://www.nuget.org/packages/nanoFramework.M5StickCPlus/) |
+| nanoFramework.M5StickS3 | [](https://dev.azure.com/nanoframework/nanoFramework.M5Stack/_build/latest?definitionId=52&repoName=nanoframework%2FnanoFramework.M5Stack&branchName=main) | [](https://www.nuget.org/packages/nanoFramework.M5StickS3/) |
| nanoFramework.M5Core2 | [](https://dev.azure.com/nanoframework/nanoFramework.M5Stack/_build/latest?definitionId=52&repoName=nanoframework%2FnanoFramework.M5Stack&branchName=main) | [](https://www.nuget.org/packages/nanoFramework.M5Core2/) |
| nanoFramework.M5CoreS3 | [](https://dev.azure.com/nanoframework/nanoFramework.M5Stack/_build/latest?definitionId=52&repoName=nanoframework%2FnanoFramework.M5Stack&branchName=main) | [](https://www.nuget.org/packages/nanoFramework.M5CoreS3/) |
| nanoFramework.Fire | [](https://dev.azure.com/nanoframework/nanoFramework.M5Stack/_build/latest?definitionId=52&repoName=nanoframework%2FnanoFramework.M5Stack&branchName=main) | [](https://www.nuget.org/packages/nanoFramework.Fire/) |
@@ -28,6 +29,7 @@ These NuGet packages provide a support for M5Stack products:
- [Core (gray) and Basic](https://docs.m5stack.com/en/products?id=core)
- [M5StickC](https://docs.m5stack.com/en/core/m5stickc)
- [M5StickCPlus](https://docs.m5stack.com/en/core/m5stickc_plus)
+- [M5StickS3](https://docs.m5stack.com/en/core/M5StickS3)
- [M5Core2](https://docs.m5stack.com/en/core/core2)
- [CoreS3](https://docs.m5stack.com/en/core/CoreS3)
- [Fire](https://docs.m5stack.com/en/core/fire)
@@ -60,6 +62,12 @@ For the M5StickCPlus:
nanoff --target M5StickCPlus --update --serialport COM3
```
+For the M5StickS3:
+
+```shell
+nanoff --target ESP32_S3_OCTAL --update --serialport COM3
+```
+
For the M5Core2, Tough and Fire:
```shell
diff --git a/Tests/M5StickS3TestApp/M5StickS3TestApp.nfproj b/Tests/M5StickS3TestApp/M5StickS3TestApp.nfproj
new file mode 100644
index 00000000..e97c8458
--- /dev/null
+++ b/Tests/M5StickS3TestApp/M5StickS3TestApp.nfproj
@@ -0,0 +1,113 @@
+
+
+
+ $(MSBuildExtensionsPath)\nanoFramework\v1.0\
+
+
+
+ Debug
+ AnyCPU
+ {11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {3AC12F12-B6DA-414F-8E30-DF57F5334B2D}
+ Exe
+ Properties
+ 512
+ M5StickS3TestApp
+ M5StickS3TestApp
+ v1.0
+
+
+
+
+
+
+
+
+
+
+
+ ..\..\packages\nanoFramework.Iot.Device.Bmm150.1.2.991\lib\Iot.Device.Bmm150.dll
+
+
+ ..\..\packages\nanoFramework.Iot.Device.Button.1.2.1002\lib\Iot.Device.Button.dll
+
+
+ ..\..\packages\nanoFramework.Iot.Device.Common.NumberHelper.1.2.862\lib\Iot.Device.Common.NumberHelper.dll
+
+
+ ..\..\packages\nanoFramework.Iot.Device.Bmi270.1.0.9\lib\Iot.Device.Bmi270.dll
+
+
+ ..\..\packages\nanoFramework.Iot.Device.M5Pm1.1.0.1\lib\Iot.Device.M5Pm1.dll
+
+
+ ..\..\packages\nanoFramework.CoreLibrary.1.17.12\lib\mscorlib.dll
+
+
+ ..\..\packages\nanoFramework.Graphics.1.2.53\lib\nanoFramework.Graphics.dll
+
+
+ ..\..\packages\nanoFramework.Graphics.1.2.53\lib\nanoFramework.Graphics.Core.dll
+
+
+ ..\..\packages\nanoFramework.Hardware.Esp32.1.6.40\lib\nanoFramework.Hardware.Esp32.dll
+
+
+ ..\..\packages\nanoFramework.ResourceManager.1.2.32\lib\nanoFramework.ResourceManager.dll
+
+
+ ..\..\packages\nanoFramework.Runtime.Events.1.11.37\lib\nanoFramework.Runtime.Events.dll
+
+
+ ..\..\packages\nanoFramework.Runtime.Native.1.7.11\lib\nanoFramework.Runtime.Native.dll
+
+
+ ..\..\packages\nanoFramework.System.Collections.1.5.75\lib\nanoFramework.System.Collections.dll
+
+
+ ..\..\packages\nanoFramework.UnitsNet.ElectricPotential.5.76.15\lib\netnano1.0\nanoFramework.UnitsNet.ElectricPotential.dll
+
+
+ ..\..\packages\nanoFramework.UnitsNet.Temperature.5.76.15\lib\netnano1.0\nanoFramework.UnitsNet.Temperature.dll
+
+
+ ..\..\packages\nanoFramework.System.Buffers.Binary.BinaryPrimitives.1.2.862\lib\System.Buffers.Binary.BinaryPrimitives.dll
+
+
+ ..\..\packages\nanoFramework.System.Device.Gpio.1.1.62\lib\System.Device.Gpio.dll
+
+
+ ..\..\packages\nanoFramework.System.Device.I2c.1.1.29\lib\System.Device.I2c.dll
+
+
+ ..\..\packages\nanoFramework.System.Device.Model.1.2.862\lib\System.Device.Model.dll
+
+
+ ..\..\packages\nanoFramework.System.Diagnostics.Stopwatch.1.2.862\lib\System.Diagnostics.Stopwatch.dll
+
+
+ ..\..\packages\nanoFramework.System.Math.1.5.116\lib\System.Math.dll
+
+
+ ..\..\packages\nanoFramework.System.Numerics.1.2.862\lib\System.Numerics.dll
+
+
+ ..\..\packages\nanoFramework.System.Threading.1.1.52\lib\System.Threading.dll
+
+
+ ..\..\packages\UnitsNet.nanoFramework.Temperature.5.75.0\lib\UnitsNet.Temperature.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/M5StickS3TestApp/Program.cs b/Tests/M5StickS3TestApp/Program.cs
new file mode 100644
index 00000000..85905990
--- /dev/null
+++ b/Tests/M5StickS3TestApp/Program.cs
@@ -0,0 +1,287 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using nanoFramework.M5Stack;
+using System.Diagnostics;
+using System.Drawing;
+using System.Threading;
+using UnitsNet;
+using Iot.Device.M5Pm1;
+
+Debug.WriteLine("Hello M5StickS3 from nanoFramework!");
+
+int pmicDeviceId = M5StickS3.Power.GetDeviceId();
+Debug.WriteLine($"M5PM1 device ID: 0x{pmicDeviceId:X4} (expected 0x{M5Pm1.DeviceId:X4}).");
+Debug.WriteLine("M5PM1 initialized. Reporting power telemetry...");
+
+M5StickS3.InitializeScreen();
+
+ushort[] buffer = new ushort[100];
+FillBuffer(buffer, Color.Red.ToBgr565());
+Screen.Write(0, 0, 10, 10, buffer);
+
+FillBuffer(buffer, Color.Green.ToBgr565());
+Screen.Write((ushort)(135 - 10), 0, 10, 10, buffer);
+
+FillBuffer(buffer, Color.Blue.ToBgr565());
+Screen.Write(0, (ushort)(240 - 10), 10, 10, buffer);
+
+FillBuffer(buffer, Color.White.ToBgr565());
+Screen.Write((ushort)(135 - 10), (ushort)(240 - 10), 10, 10, buffer);
+
+bool screenEnabled = true;
+M5StickS3.ButtonA.Press += (s, e) =>
+{
+ screenEnabled = !screenEnabled;
+ Screen.Enabled = screenEnabled;
+ Debug.WriteLine($"Button A pressed, screen enabled: {screenEnabled}");
+};
+
+M5StickS3.ButtonB.Press += (s, e) =>
+{
+ M5StickS3.External5VEnabled = !M5StickS3.External5VEnabled;
+ Debug.WriteLine($"Button B pressed, ext 5V enabled: {M5StickS3.External5VEnabled}");
+};
+
+byte[][] glyphLookup = CreateGlyphLookup();
+const int telemetryWidth = 135;
+ushort[] telemetryLineBuffer = null;
+int telemetryLineBufferHeight = 0;
+
+while (true)
+{
+ var accel = M5StickS3.AccelerometerGyroscope.GetAccelerometer();
+ var gyro = M5StickS3.AccelerometerGyroscope.GetGyroscope();
+ bool isCharging = M5StickS3.IsCharging;
+ ElectricPotential batteryVoltage = M5StickS3.BatteryVoltage;
+ ElectricPotential vbusVoltage = M5StickS3.VBusVoltage;
+ ElectricPotential outputVoltage = M5StickS3.Power.GetOutputVoltage();
+ PowerSource powerSource = M5StickS3.Power.GetPowerSource();
+ bool gpio0 = (bool)M5StickS3.Power.ReadGpio(Pin.Gpio0);
+ int batteryMv = ToMillivolts(batteryVoltage);
+ int vbusMv = ToMillivolts(vbusVoltage);
+ int out5vMv = ToMillivolts(outputVoltage);
+ int batteryPercent = EstimateBatteryPercent(batteryMv, isCharging, vbusMv);
+ string batteryStatusText = batteryPercent >= 0
+ ? $"BAT {batteryPercent,3}% CHG{(isCharging ? "ON" : "OFF")}"
+ : "BAT CHARGING";
+ string batteryVoltageText = $"BATV {batteryMv,4}MV";
+
+ Debug.WriteLine($"Battery : {batteryMv} mV");
+ Debug.WriteLine($"VBUS : {vbusMv} mV");
+ Debug.WriteLine($"5V out : {out5vMv} mV");
+ Debug.WriteLine($"Source : {(int)powerSource}");
+ Debug.WriteLine($"Charging: {isCharging}");
+ Debug.WriteLine($"GPIO0 : {gpio0}");
+ Debug.WriteLine($"Ext5V : {M5StickS3.External5VEnabled}");
+ Debug.WriteLine($"Accel=({accel.X:N2},{accel.Y:N2},{accel.Z:N2})g");
+ Debug.WriteLine($"Gyro =({gyro.X:N2},{gyro.Y:N2},{gyro.Z:N2}) dps");
+
+ const int uiScale = 1;
+ DrawTelemetryLine(12, FitTelemetryText(batteryStatusText), Color.Yellow, Color.Black, uiScale);
+ DrawTelemetryLine(22, FitTelemetryText(batteryVoltageText), Color.Yellow, Color.Black, uiScale);
+ DrawTelemetryLine(32, FitTelemetryText($"AX {FormatSigned(accel.X)}"), Color.Lime, Color.Black, uiScale);
+ DrawTelemetryLine(42, FitTelemetryText($"AY {FormatSigned(accel.Y)}"), Color.Lime, Color.Black, uiScale);
+ DrawTelemetryLine(52, FitTelemetryText($"AZ {FormatSigned(accel.Z)}"), Color.Lime, Color.Black, uiScale);
+ DrawTelemetryLine(62, FitTelemetryText($"GX {FormatSigned(gyro.X)}"), Color.Cyan, Color.Black, uiScale);
+ DrawTelemetryLine(72, FitTelemetryText($"GY {FormatSigned(gyro.Y)}"), Color.Cyan, Color.Black, uiScale);
+ DrawTelemetryLine(82, FitTelemetryText($"GZ {FormatSigned(gyro.Z)}"), Color.Cyan, Color.Black, uiScale);
+
+ Thread.Sleep(1000);
+}
+
+static void FillBuffer(ushort[] buffer, ushort color)
+{
+ for (int i = 0; i < buffer.Length; i++)
+ {
+ buffer[i] = color;
+ }
+}
+
+static int EstimateBatteryPercent(int millivolts, bool isCharging, int vbusMillivolts)
+{
+ const int emptyMv = 3000;
+ const int fullMv = 4200;
+
+ // When USB power is present and charging is active, some PMIC states can report
+ // very low battery voltage transiently. Report "charging" instead of a fake 0%.
+ if (isCharging && vbusMillivolts > 4300 && millivolts < emptyMv)
+ {
+ return -1;
+ }
+
+ if (millivolts <= emptyMv)
+ {
+ return isCharging ? 1 : 0;
+ }
+
+ if (millivolts >= fullMv)
+ {
+ return 100;
+ }
+
+ return (millivolts - emptyMv) * 100 / (fullMv - emptyMv);
+}
+
+static int ToMillivolts(ElectricPotential voltage)
+{
+ int millivolts = (int)voltage.Millivolts;
+ if (millivolts > 0)
+ {
+ return millivolts;
+ }
+
+ return (int)(voltage.Volts * 1000.0);
+}
+
+static string FormatSigned(double value)
+{
+ int scaled = (int)(value * 100);
+ int absScaled = scaled < 0 ? -scaled : scaled;
+ int integer = absScaled / 100;
+ int fraction = absScaled % 100;
+ string sign = scaled >= 0 ? "+" : "-";
+ return $"{sign}{integer}.{fraction:D2}";
+}
+
+static string FitTelemetryText(string text)
+{
+ const int maxChars = 14;
+
+ if (text.Length <= maxChars)
+ {
+ return text;
+ }
+
+ return text.Substring(0, maxChars);
+}
+
+void DrawTelemetryLine(ushort y, string text, Color foreground, Color background, int scale)
+{
+ int width = telemetryWidth;
+ int height = (7 * scale) + 1;
+ int charWidth = (5 * scale) + 1;
+
+ ushort fg = foreground.ToBgr565();
+ ushort bg = background.ToBgr565();
+
+ if (telemetryLineBuffer == null || telemetryLineBufferHeight != height)
+ {
+ telemetryLineBuffer = new ushort[width * height];
+ telemetryLineBufferHeight = height;
+ }
+
+ ushort[] lineBuffer = telemetryLineBuffer;
+
+ for (int i = 0; i < lineBuffer.Length; i++)
+ {
+ lineBuffer[i] = bg;
+ }
+
+ string upper = text.ToUpper();
+ int maxChars = width / charWidth;
+ if (upper.Length > maxChars)
+ {
+ upper = upper.Substring(0, maxChars);
+ }
+
+ for (int c = 0; c < upper.Length; c++)
+ {
+ byte[] glyph = GetGlyph(upper[c]);
+ int xBase = c * charWidth;
+ for (int row = 0; row < 7; row++)
+ {
+ byte bits = glyph[row];
+ for (int col = 0; col < 5; col++)
+ {
+ if ((bits & (1 << (4 - col))) != 0)
+ {
+ int x = xBase + (col * scale);
+ int yBase = row * scale;
+ for (int sy = 0; sy < scale; sy++)
+ {
+ for (int sx = 0; sx < scale; sx++)
+ {
+ int px = x + sx;
+ int py = yBase + sy;
+ int index = py * width + px;
+ if (index >= 0 && index < lineBuffer.Length)
+ {
+ lineBuffer[index] = fg;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Screen.Write(0, y, (ushort)width, (ushort)height, lineBuffer);
+}
+
+byte[] GetGlyph(char c)
+{
+ int index = c;
+ if (index >= 0 && index < glyphLookup.Length)
+ {
+ byte[] glyph = glyphLookup[index];
+ if (glyph != null)
+ {
+ return glyph;
+ }
+ }
+
+ return glyphLookup['?'];
+}
+
+static byte[][] CreateGlyphLookup()
+{
+ byte[][] lookup = new byte[128][];
+
+ lookup['A'] = new byte[] { 0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11 };
+ lookup['B'] = new byte[] { 0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E };
+ lookup['C'] = new byte[] { 0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E };
+ lookup['D'] = new byte[] { 0x1E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1E };
+ lookup['E'] = new byte[] { 0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F };
+ lookup['F'] = new byte[] { 0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10 };
+ lookup['G'] = new byte[] { 0x0E, 0x11, 0x10, 0x13, 0x11, 0x11, 0x0E };
+ lookup['H'] = new byte[] { 0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11 };
+ lookup['I'] = new byte[] { 0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E };
+ lookup['J'] = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x11, 0x11, 0x0E };
+ lookup['K'] = new byte[] { 0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11 };
+ lookup['L'] = new byte[] { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F };
+ lookup['M'] = new byte[] { 0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11 };
+ lookup['N'] = new byte[] { 0x11, 0x19, 0x15, 0x13, 0x11, 0x11, 0x11 };
+ lookup['O'] = new byte[] { 0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E };
+ lookup['P'] = new byte[] { 0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10 };
+ lookup['Q'] = new byte[] { 0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D };
+ lookup['R'] = new byte[] { 0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11 };
+ lookup['S'] = new byte[] { 0x0F, 0x10, 0x10, 0x0E, 0x01, 0x01, 0x1E };
+ lookup['T'] = new byte[] { 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
+ lookup['U'] = new byte[] { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E };
+ lookup['V'] = new byte[] { 0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04 };
+ lookup['W'] = new byte[] { 0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0A };
+ lookup['X'] = new byte[] { 0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11 };
+ lookup['Y'] = new byte[] { 0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04 };
+ lookup['Z'] = new byte[] { 0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F };
+ lookup['0'] = new byte[] { 0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E };
+ lookup['1'] = new byte[] { 0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E };
+ lookup['2'] = new byte[] { 0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F };
+ lookup['3'] = new byte[] { 0x1E, 0x01, 0x01, 0x0E, 0x01, 0x01, 0x1E };
+ lookup['4'] = new byte[] { 0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02 };
+ lookup['5'] = new byte[] { 0x1F, 0x10, 0x10, 0x1E, 0x01, 0x01, 0x1E };
+ lookup['6'] = new byte[] { 0x0E, 0x10, 0x10, 0x1E, 0x11, 0x11, 0x0E };
+ lookup['7'] = new byte[] { 0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08 };
+ lookup['8'] = new byte[] { 0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E };
+ lookup['9'] = new byte[] { 0x0E, 0x11, 0x11, 0x0F, 0x01, 0x01, 0x0E };
+ lookup[':'] = new byte[] { 0x00, 0x04, 0x04, 0x00, 0x04, 0x04, 0x00 };
+ lookup['.'] = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04 };
+ lookup['+'] = new byte[] { 0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00 };
+ lookup['-'] = new byte[] { 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00 };
+ lookup['/'] = new byte[] { 0x01, 0x02, 0x02, 0x04, 0x08, 0x08, 0x10 };
+ lookup['%'] = new byte[] { 0x19, 0x19, 0x02, 0x04, 0x08, 0x13, 0x13 };
+ lookup[' '] = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ lookup['?'] = new byte[] { 0x1F, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04 };
+
+ return lookup;
+}
diff --git a/Tests/M5StickS3TestApp/Properties/AssemblyInfo.cs b/Tests/M5StickS3TestApp/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..d3f4d14c
--- /dev/null
+++ b/Tests/M5StickS3TestApp/Properties/AssemblyInfo.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("M5StickS3TestApp")]
+[assembly: AssemblyDescription("M5StickS3 test application")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("nanoframework")]
+[assembly: AssemblyProduct("M5StickS3TestApp")]
+[assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
diff --git a/Tests/M5StickS3TestApp/packages.config b/Tests/M5StickS3TestApp/packages.config
new file mode 100644
index 00000000..92f64398
--- /dev/null
+++ b/Tests/M5StickS3TestApp/packages.config
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/M5StickS3TestApp/packages.lock.json b/Tests/M5StickS3TestApp/packages.lock.json
new file mode 100644
index 00000000..ddc6878a
--- /dev/null
+++ b/Tests/M5StickS3TestApp/packages.lock.json
@@ -0,0 +1,145 @@
+{
+ "version": 1,
+ "dependencies": {
+ ".NETnanoFramework,Version=v1.0": {
+ "nanoFramework.CoreLibrary": {
+ "type": "Direct",
+ "requested": "[1.17.12, 1.17.12]",
+ "resolved": "1.17.12",
+ "contentHash": "j0fDBm74I7ORpskJTW1R9JgKqlmpgkQaB+ccBbRJcUKD1DGYlPDI1N4/kFwYOZrn8YjHUVFVv6n/1vg822ZSsw=="
+ },
+ "nanoFramework.Graphics": {
+ "type": "Direct",
+ "requested": "[1.2.53, 1.2.53]",
+ "resolved": "1.2.53",
+ "contentHash": "LwXK03HlpMLH37Ol67GxQbjNksNXZE0pIqVZiol9ds+V3698PLyYcP/XayhTmu9pOntcDtmYL64jKuUr2dEu8g=="
+ },
+ "nanoFramework.Hardware.Esp32": {
+ "type": "Direct",
+ "requested": "[1.6.40, 1.6.40]",
+ "resolved": "1.6.40",
+ "contentHash": "jq6wGAXuC5tvkmKaQX1W5NW/IoPLhosASAKbeA5QPDHX35AwOK/l9OZrc8jvgv52DiiXj/WtvKwgPj1W0ocNCQ=="
+ },
+ "nanoFramework.Iot.Device.Bmi270": {
+ "type": "Direct",
+ "requested": "[1.0.9, 1.0.9]",
+ "resolved": "1.0.9",
+ "contentHash": "yG01UK1LH66dHOfic1nMJiQKRR2a7yNi/T9QGPaPpwmRNapIw1tjizCmZv/5pZbIhGtLgIl7EyazYVTbxLzQ6A=="
+ },
+ "nanoFramework.Iot.Device.Bmm150": {
+ "type": "Direct",
+ "requested": "[1.2.991, 1.2.991]",
+ "resolved": "1.2.991",
+ "contentHash": "/xgUJPjbTQMM4ei94cr/s46WvU1+1zBJwGicUnwSQPXNEZBG30iS4osaAnc4J3owc9Y0U2EYkCFX01/0V8HDAg=="
+ },
+ "nanoFramework.Iot.Device.Button": {
+ "type": "Direct",
+ "requested": "[1.2.1002, 1.2.1002]",
+ "resolved": "1.2.1002",
+ "contentHash": "AG4810GRfXKihn97fAdsQOYneHLNQzl+xHuDcS/JQhNJLbjhpkAzl85k9HO8Tjz1ajWtpUACib8lJSo+l4l3AA=="
+ },
+ "nanoFramework.Iot.Device.Common.NumberHelper": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "Ax67ee3vmdfH2NdqtdFYawBzxWH5+KsUIvwnTlGHbXR3ko4t5a4mVelEqB4BheJZETRyNMqKcUGWdWFAbO2byQ=="
+ },
+ "nanoFramework.Iot.Device.M5Pm1": {
+ "type": "Direct",
+ "requested": "[1.0.1, 1.0.1]",
+ "resolved": "1.0.1",
+ "contentHash": "aK4T8ojPfvG7T76s/nN5PzyyBOTKvvbDZ03TeRmRFwluCd+2e1pwj8YO/7o6cX0RJjyMIF02Qyx7O7usC17hEg=="
+ },
+ "nanoFramework.ResourceManager": {
+ "type": "Direct",
+ "requested": "[1.2.32, 1.2.32]",
+ "resolved": "1.2.32",
+ "contentHash": "hpBiZ7yx5AnT/0T37cr2ySQwQDLKP+KaWu+O7ln9J43M/WaKFSCZFVsqXeJGby3/JDfm1cxhfOaQ1MMsevrdiA=="
+ },
+ "nanoFramework.Runtime.Events": {
+ "type": "Direct",
+ "requested": "[1.11.37, 1.11.37]",
+ "resolved": "1.11.37",
+ "contentHash": "whTgEJCGpE8eGK7Z2fI6gTqsVeVrnCzP1KDSqIB2PY0/Jyw7NcnwCFe3s/43ch75DuAZt8/jTX0VJoJtN0Colw=="
+ },
+ "nanoFramework.Runtime.Native": {
+ "type": "Direct",
+ "requested": "[1.7.11, 1.7.11]",
+ "resolved": "1.7.11",
+ "contentHash": "XPSTltZ9KeBruogVmjQpCphi1nLoJH49mpyp2eGBs8BTjKuL5TkMO20MoI8r73F/PW5AppTq49HvIZZavU5nPQ=="
+ },
+ "nanoFramework.System.Buffers.Binary.BinaryPrimitives": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "O+jmbbw2h2cjCTShsvWCzjqn/kmRacJE4Ena9gJt5xF5D7XHyYh/uE/qbZ4LhlmlN6JCZjLRNiEfHyM1YUjyxg=="
+ },
+ "nanoFramework.System.Collections": {
+ "type": "Direct",
+ "requested": "[1.5.75, 1.5.75]",
+ "resolved": "1.5.75",
+ "contentHash": "OiMpKo8RWbjZq1594YjdRnOGNN2aT4nowa+ET7scK0frGCux0a8LGaPkG56mmSfBCKzLlVs13LIlla3XLhXaMA=="
+ },
+ "nanoFramework.System.Device.Gpio": {
+ "type": "Direct",
+ "requested": "[1.1.62, 1.1.62]",
+ "resolved": "1.1.62",
+ "contentHash": "BaSX4efW1WtqVBoqqKs3tb9y3QSZiIPcWyalbxFY7ovQ2FKoyAHI/RzTGjzPtSf3mUwmrvXnPowDida5NY5Urg=="
+ },
+ "nanoFramework.System.Device.I2c": {
+ "type": "Direct",
+ "requested": "[1.1.29, 1.1.29]",
+ "resolved": "1.1.29",
+ "contentHash": "q8duNVWeK3RCiTmTZiO1UWr7s9HMsLnKWm5utxy9OQWeQtlh00l5CoFKxjot42s1NY5zLmfq7p7oWM/fgNEtlA=="
+ },
+ "nanoFramework.System.Device.Model": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "dARhyb8BHkje2P+7VphJpRLynVhMkC0U4pFNecLs6jw8DHRMMJyszcbgo/N0ALeYjilNk9hea+wzBLFrgZpsUQ=="
+ },
+ "nanoFramework.System.Diagnostics.Stopwatch": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "auNXXoJYOJ7mAxPvMPhbxFbDCtfKF/wSdsoBEQiRd8NaQWmLg12JL6YbNiKiNs+fBlxAL6duUorBdhSyPCdayg=="
+ },
+ "nanoFramework.System.Math": {
+ "type": "Direct",
+ "requested": "[1.5.116, 1.5.116]",
+ "resolved": "1.5.116",
+ "contentHash": "0S05UKcoI9Ukz9cMNPC9huFW9vSL42/4gIh4fw8ou8HkcFmTYb0OL8VF2Ah94hEDW5mqcYAVr0ipuGWPzIRqaA=="
+ },
+ "nanoFramework.System.Numerics": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "YdYhLCoj5i77e4f0qw1a45GxDAFYR2F7zLlrUDdUE12JGweBR0kruURKrGJMl4uYWkORfO18PxyqNOXvSqKKCg=="
+ },
+ "nanoFramework.System.Threading": {
+ "type": "Direct",
+ "requested": "[1.1.52, 1.1.52]",
+ "resolved": "1.1.52",
+ "contentHash": "kv+US/+7QKV1iT/snxBh032vwZ+3krJ4vujlSsvmS2nNj/nK64R3bq/ST3bCFquxHDD0mog8irtCBCsFazr4kA=="
+ },
+ "nanoFramework.UnitsNet.ElectricPotential": {
+ "type": "Direct",
+ "requested": "[5.76.15, 5.76.15]",
+ "resolved": "5.76.15",
+ "contentHash": "amhs/PAWNx7+g5JEaG1V3wB/324NJ93RdY8MztR38yXvDppk/qFx+y2Ncno+8GwVRy4GHYskIbMMSHsHqOf9VQ=="
+ },
+ "nanoFramework.UnitsNet.Temperature": {
+ "type": "Direct",
+ "requested": "[5.76.15, 5.76.15]",
+ "resolved": "5.76.15",
+ "contentHash": "rmgtqp2kdwd1LkWCHy/iabt4HFHPgTSllCc8ex8M1xJ/2n3CH+Udng7M/wbtMP5II2yF5zMqxowzQ2iKOaoX/g=="
+ },
+ "UnitsNet.nanoFramework.Temperature": {
+ "type": "Direct",
+ "requested": "[5.75.0, 5.75.0]",
+ "resolved": "5.75.0",
+ "contentHash": "SpA9Z7T1sNaR7YBCYp+L9/ei1bjDkqi8PyPfOWVBjkWInuPSOQaPG9Y7UttIpJ0M2y1GTrCG1kmRCUewGiSFAg=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 7c1d621e..f3bb3ef7 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -78,6 +78,10 @@ steps:
parameters:
nugetPackageName: 'nanoFramework.M5CoreS3'
+- template: azure-pipelines-templates/class-lib-package.yml@templates
+ parameters:
+ nugetPackageName: 'nanoFramework.M5StickS3'
+
- template: azure-pipelines-templates/class-lib-package.yml@templates
parameters:
nugetPackageName: 'nanoFramework.AtomLite'
@@ -117,7 +121,7 @@ steps:
tag: v$(MY_NUGET_VERSION)
title: 'M5Stack Board Support Packages v$(MY_NUGET_VERSION)'
releaseNotesSource: inline
- releaseNotesInline: 'Check the [changelog]($(Build.Repository.Uri)/blob/$(Build.SourceBranchName)/CHANGELOG.md).
Install from NuGet
The following NuGet packages are available for download from this release:
:package: [M5Core](https://www.nuget.org/packages/nanoFramework.M5Core/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [M5Core2](https://www.nuget.org/packages/nanoFramework.M5Core2/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [M5CoreS3](https://www.nuget.org/packages/nanoFramework.M5CoreS3/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [M5StickC](https://www.nuget.org/packages/nanoFramework.M5StickC/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [M5StickCPlus](https://www.nuget.org/packages/nanoFramework.M5StickCPlus/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [M5Stack Fire](https://www.nuget.org/packages/nanoFramework.Fire/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [Atom Lite](https://www.nuget.org/packages/nanoFramework.AtomLite/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [Atom Matrix](https://www.nuget.org/packages/nanoFramework.AtomMatrix/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [Tough](https://www.nuget.org/packages/nanoFramework.Tough/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)'
+ releaseNotesInline: 'Check the [changelog]($(Build.Repository.Uri)/blob/$(Build.SourceBranchName)/CHANGELOG.md).
Install from NuGet
The following NuGet packages are available for download from this release:
:package: [M5Core](https://www.nuget.org/packages/nanoFramework.M5Core/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [M5Core2](https://www.nuget.org/packages/nanoFramework.M5Core2/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [M5CoreS3](https://www.nuget.org/packages/nanoFramework.M5CoreS3/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).
:package: [M5StickC](https://www.nuget.org/packages/nanoFramework.M5StickC/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [M5StickCPlus](https://www.nuget.org/packages/nanoFramework.M5StickCPlus/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [M5StickS3](https://www.nuget.org/packages/nanoFramework.M5StickS3/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [M5Stack Fire](https://www.nuget.org/packages/nanoFramework.Fire/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [Atom Lite](https://www.nuget.org/packages/nanoFramework.AtomLite/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [Atom Matrix](https://www.nuget.org/packages/nanoFramework.AtomMatrix/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)
:package: [Tough](https://www.nuget.org/packages/nanoFramework.Tough/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)'
assets: '$(Build.ArtifactStagingDirectory)/$(nugetPackageName).$(MY_NUGET_VERSION).nupkg'
isPreRelease: false
addChangeLog: false
diff --git a/nanoFramework.M5Stack.sln b/nanoFramework.M5Stack.sln
index 42692411..40b4c21f 100644
--- a/nanoFramework.M5Stack.sln
+++ b/nanoFramework.M5Stack.sln
@@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
nanoFramework.AtomLite.nuspec = nanoFramework.AtomLite.nuspec
nanoFramework.AtomMatrix.nuspec = nanoFramework.AtomMatrix.nuspec
nanoFramework.M5CoreS3.nuspec = nanoFramework.M5CoreS3.nuspec
+ nanoFramework.M5StickS3.nuspec = nanoFramework.M5StickS3.nuspec
nanoFramework.M5Core.nuspec = nanoFramework.M5Core.nuspec
nanoFramework.M5Core2.nuspec = nanoFramework.M5Core2.nuspec
nanoFramework.M5StickC.nuspec = nanoFramework.M5StickC.nuspec
@@ -64,6 +65,10 @@ Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.M5CoreS3", "n
EndProject
Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "M5CoreS3TestApp", "Tests\M5CoreS3TestApp\M5CoreS3TestApp.nfproj", "{B3A0FB0D-44A3-4B09-A9A7-DF8BA963A4C1}"
EndProject
+Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "nanoFramework.M5StickS3", "nanoFramework.M5StickS3\nanoFramework.M5StickS3.nfproj", "{AA95E2BF-4A10-4F9A-8D2D-C7362A8C3562}"
+EndProject
+Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "M5StickS3TestApp", "Tests\M5StickS3TestApp\M5StickS3TestApp.nfproj", "{3AC12F12-B6DA-414F-8E30-DF57F5334B2D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -178,6 +183,18 @@ Global
{B3A0FB0D-44A3-4B09-A9A7-DF8BA963A4C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B3A0FB0D-44A3-4B09-A9A7-DF8BA963A4C1}.Release|Any CPU.Build.0 = Release|Any CPU
{B3A0FB0D-44A3-4B09-A9A7-DF8BA963A4C1}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {AA95E2BF-4A10-4F9A-8D2D-C7362A8C3562}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AA95E2BF-4A10-4F9A-8D2D-C7362A8C3562}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AA95E2BF-4A10-4F9A-8D2D-C7362A8C3562}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {AA95E2BF-4A10-4F9A-8D2D-C7362A8C3562}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AA95E2BF-4A10-4F9A-8D2D-C7362A8C3562}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AA95E2BF-4A10-4F9A-8D2D-C7362A8C3562}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {3AC12F12-B6DA-414F-8E30-DF57F5334B2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3AC12F12-B6DA-414F-8E30-DF57F5334B2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3AC12F12-B6DA-414F-8E30-DF57F5334B2D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {3AC12F12-B6DA-414F-8E30-DF57F5334B2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3AC12F12-B6DA-414F-8E30-DF57F5334B2D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3AC12F12-B6DA-414F-8E30-DF57F5334B2D}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -195,6 +212,7 @@ Global
{5FF00F7C-8ED8-4468-9959-497CE8C5B1AF} = {5972CDE6-43B4-42F0-9276-6B70B7EF6437}
{F5BF3DA4-B92E-46C6-A135-37E6A7E002A1} = {5972CDE6-43B4-42F0-9276-6B70B7EF6437}
{B3A0FB0D-44A3-4B09-A9A7-DF8BA963A4C1} = {5972CDE6-43B4-42F0-9276-6B70B7EF6437}
+ {3AC12F12-B6DA-414F-8E30-DF57F5334B2D} = {5972CDE6-43B4-42F0-9276-6B70B7EF6437}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DD82D7FF-B798-48A4-8506-2FBA0001D32F}
diff --git a/nanoFramework.M5StickS3.nuspec b/nanoFramework.M5StickS3.nuspec
new file mode 100644
index 00000000..3e2576fc
--- /dev/null
+++ b/nanoFramework.M5StickS3.nuspec
@@ -0,0 +1,44 @@
+
+
+
+ nanoFramework.M5StickS3
+ $version$
+ nanoFramework.M5StickS3
+ nanoframework
+ false
+ LICENSE.md
+
+
+ docs\README.md
+ false
+ https://github.com/nanoframework/nanoFramework.M5Stack
+ images\nf-logo.png
+
+ Copyright (c) .NET Foundation and Contributors
+ This package includes the nanoFramework.M5StickS3 assembly for .NET nanoFramework C# projects.
+ nanoFramework C# csharp netmf netnf m5stack M5StickS3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nanoFramework.M5StickS3/M5StickS3.cs b/nanoFramework.M5StickS3/M5StickS3.cs
new file mode 100644
index 00000000..af0d6ce6
--- /dev/null
+++ b/nanoFramework.M5StickS3/M5StickS3.cs
@@ -0,0 +1,220 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Iot.Device.Bmi270;
+using Iot.Device.Button;
+using Iot.Device.M5Pm1;
+using nanoFramework.Hardware.Esp32;
+using nanoFramework.Runtime.Native;
+using System.Device.Gpio;
+using System.Device.I2c;
+using System.Diagnostics;
+using UnitsNet;
+
+namespace nanoFramework.M5Stack
+{
+ ///
+ /// M5StickS3 board support.
+ ///
+ public static class M5StickS3
+ {
+ ///
+ /// The internal I2C bus ID for the PMIC and accelerometer/gyroscope.
+ ///
+ public const int InternalI2cBusId = 1;
+
+ private const int InternalI2cSdaPin = 47;
+ private const int InternalI2cSclPin = 48;
+
+ ///
+ /// The internal I2C bus ID for the Grove connector.
+ ///
+ public const int GroveI2cBusId = 2;
+
+ ///
+ /// The Grove connector SDA pin.
+ ///
+ public const int GroveI2cSdaPin = 9;
+
+ ///
+ /// The Grove connector SCL pin.
+ ///
+ public const int GroveI2cSclPin = 10;
+
+ private const int ButtonAPin = 11;
+ private const int ButtonBPin = 12;
+
+ private static M5Pm1 _pmic;
+ private static GpioController _gpio;
+ private static GpioButton _buttonA;
+ private static GpioButton _buttonB;
+ private static Bmi270AccelerometerGyroscope _accelerometerGyroscope;
+ private static Screen _screen;
+
+ static M5StickS3()
+ {
+ Configuration.SetPinFunction(InternalI2cSdaPin, DeviceFunction.I2C1_DATA);
+ Configuration.SetPinFunction(InternalI2cSclPin, DeviceFunction.I2C1_CLOCK);
+ Configuration.SetPinFunction(GroveI2cSdaPin, DeviceFunction.I2C2_DATA);
+ Configuration.SetPinFunction(GroveI2cSclPin, DeviceFunction.I2C2_CLOCK);
+
+ // M5PM1 requires a 100 kHz I2C bus on M5StickS3.
+ I2cConnectionSettings pmicSettings = new I2cConnectionSettings(InternalI2cBusId, M5Pm1.I2cDefaultAddress, I2cBusSpeed.StandardMode);
+ _pmic = new M5Pm1(new I2cDevice(pmicSettings));
+ int deviceId = _pmic.GetDeviceId();
+ Debug.WriteLine($"M5PM1 device ID: 0x{deviceId:X4} (expected 0x{M5Pm1.DeviceId:X4}).");
+ InitializePmic();
+ }
+
+ ///
+ /// Gets the main GPIO controller.
+ ///
+ public static GpioController GpioController
+ {
+ get
+ {
+ if (_gpio == null)
+ {
+ _gpio = new GpioController();
+ }
+
+ return _gpio;
+ }
+ }
+
+ ///
+ /// Gets the button below the display.
+ ///
+ public static GpioButton ButtonA
+ {
+ get
+ {
+ if (_buttonA == null)
+ {
+ _buttonA = new GpioButton(ButtonAPin, GpioController, false);
+ }
+
+ return _buttonA;
+ }
+ }
+
+ ///
+ /// Gets the side button.
+ ///
+ public static GpioButton ButtonB
+ {
+ get
+ {
+ if (_buttonB == null)
+ {
+ _buttonB = new GpioButton(ButtonBPin, GpioController, false);
+ }
+
+ return _buttonB;
+ }
+ }
+
+ ///
+ /// Gets the onboard accelerometer and gyroscope.
+ ///
+ public static Bmi270AccelerometerGyroscope AccelerometerGyroscope
+ {
+ get
+ {
+ if (_accelerometerGyroscope == null)
+ {
+ // Important: keep standard mode because of the M5PM1
+ _accelerometerGyroscope = new Bmi270AccelerometerGyroscope(
+ new I2cDevice(new I2cConnectionSettings(
+ InternalI2cBusId,
+ Bmi270AccelerometerGyroscope.DefaultI2cAddress,
+ I2cBusSpeed.StandardMode)));
+ }
+
+ return _accelerometerGyroscope;
+ }
+ }
+
+ ///
+ /// Reads the battery voltage in millivolts from the PMIC.
+ ///
+ public static ElectricPotential BatteryVoltage => _pmic.GetBatteryVoltage();
+
+ ///
+ /// Reads the VBUS voltage in millivolts from the PMIC.
+ ///
+ public static ElectricPotential VBusVoltage => _pmic.GetVbusVoltage();
+
+ ///
+ /// Gets whether charging is currently active.
+ ///
+ public static bool IsCharging => _pmic.IsCharging;
+
+ ///
+ /// Gets or sets the 5V output state.
+ ///
+ public static bool External5VEnabled
+ {
+ get => _pmic.ExternalOutputEnabled;
+ set => _pmic.ExternalOutputEnabled = value;
+ }
+
+ ///
+ /// Gets the Power Management device.
+ ///
+ public static M5Pm1 Power => _pmic;
+
+ ///
+ /// Initializes the display.
+ ///
+ /// Bitmap allocation in bytes.
+ public static void InitializeScreen(int memoryBitMapAllocation = Screen.DefaultMemoryAllocationBitmap)
+ {
+ if (_screen == null)
+ {
+ try
+ {
+ // PM1_G2 powers the LCD path.
+ _pmic.SetGpioFunction(Pin.Gpio2, GpioFunction.Gpio);
+ _pmic.SetGpioDrive(Pin.Gpio2, GpioDrive.PushPull);
+ _pmic.SetGpioMode(Pin.Gpio2, PinMode.Output);
+ _pmic.WriteGpio(Pin.Gpio2, PinValue.High);
+ _screen = new Screen(memoryBitMapAllocation);
+ }
+ catch (System.Exception ex)
+ {
+ Debug.WriteLine($"M5StickS3.InitializeScreen failed: {ex}");
+ throw;
+ }
+ }
+ }
+
+ ///
+ /// Gets a device on the internal I2C bus.
+ ///
+ public static I2cDevice GetI2cDevice(int i2cDeviceAddress)
+ => new I2cDevice(new I2cConnectionSettings(InternalI2cBusId, i2cDeviceAddress, I2cBusSpeed.StandardMode));
+
+ ///
+ /// Gets a device on the Grove I2C bus.
+ ///
+ public static I2cDevice GetGrove(int i2cDeviceAddress)
+ => new I2cDevice(new I2cConnectionSettings(GroveI2cBusId, i2cDeviceAddress, I2cBusSpeed.FastMode));
+
+ internal static void SetLcdPower(bool enabled)
+ {
+ _pmic.WriteGpio(Pin.Gpio2, enabled);
+ }
+
+ private static void InitializePmic()
+ {
+ // Constructor wake-up already applies the reliability init (I2C sleep off, watchdog off).
+
+ // PM1_G3 is used by vendor firmware to gate the audio PA.
+ _pmic.SetGpioFunction(Pin.Gpio3, GpioFunction.Gpio);
+ _pmic.SetGpioDrive(Pin.Gpio3, GpioDrive.PushPull);
+ _pmic.SetGpioMode(Pin.Gpio3, PinMode.Output);
+ _pmic.WriteGpio(Pin.Gpio3, PinValue.Low);
+ }
+ }
+}
diff --git a/nanoFramework.M5StickS3/Properties/AssemblyInfo.cs b/nanoFramework.M5StickS3/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..008bc3bd
--- /dev/null
+++ b/nanoFramework.M5StickS3/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("nanoFramework.M5StickS3")]
+[assembly: AssemblyCompany("nanoFramework Contributors")]
+[assembly: AssemblyCopyright("Copyright(c).NET Foundation and Contributors")]
+
+[assembly: ComVisible(false)]
diff --git a/nanoFramework.M5StickS3/Screen.cs b/nanoFramework.M5StickS3/Screen.cs
new file mode 100644
index 00000000..a7796234
--- /dev/null
+++ b/nanoFramework.M5StickS3/Screen.cs
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using nanoFramework.Hardware.Esp32;
+using nanoFramework.UI;
+using System.Device.Gpio;
+using System.Threading;
+
+namespace nanoFramework.M5Stack
+{
+ ///
+ /// M5StickS3 screen support.
+ ///
+ public class Screen : ScreenBase
+ {
+ ///
+ /// Default memory allocation for bitmap in bytes.
+ ///
+ public const int DefaultMemoryAllocationBitmap = 1024;
+
+ private const int SpiBus = 1;
+ private const int ChipSelect = 41;
+ private const int DataCommand = 45;
+ private const int Reset = 21;
+ private const int NoResetInNativeDriver = -1;
+ private const int DummyMisoPin = 42;
+ private const int BackLight = 38;
+ private const int Width = 135;
+ private const int Height = 240;
+ private const int OffsetX = 52;
+ private const int OffsetY = 40;
+ private const int ScreenMosi = 39;
+ private const int ScreenClock = 40;
+
+ private static bool _isInitialized;
+ private static bool _isEnabled;
+
+ ///
+ /// Creates and initializes the screen.
+ ///
+ /// Bitmap allocation in bytes.
+ public Screen(int memoryBitMapAllocation = DefaultMemoryAllocationBitmap)
+ {
+ if (_isInitialized)
+ {
+ return;
+ }
+
+ Configuration.SetPinFunction(ScreenMosi, DeviceFunction.SPI1_MOSI);
+ Configuration.SetPinFunction(ScreenClock, DeviceFunction.SPI1_CLOCK);
+ Configuration.SetPinFunction(DummyMisoPin, DeviceFunction.SPI1_MISO);
+
+ Controller = M5StickS3.GpioController;
+ if (!Controller.IsPinOpen(Reset))
+ {
+ Controller.OpenPin(Reset, PinMode.Output);
+ }
+
+ if (!Controller.IsPinOpen(BackLight))
+ {
+ Controller.OpenPin(BackLight, PinMode.Output);
+ }
+
+ M5StickS3.SetLcdPower(true);
+ Controller.Write(BackLight, PinValue.High);
+ Thread.Sleep(100);
+
+ // Pulse LCD reset explicitly to avoid native reset-path instability on some S3 firmwares.
+ Controller.Write(Reset, PinValue.Low);
+ Thread.Sleep(10);
+ Controller.Write(Reset, PinValue.High);
+ Thread.Sleep(100);
+
+ uint actualBufferSize = DisplayControl.Initialize(
+ new SpiConfiguration(SpiBus, ChipSelect, DataCommand, NoResetInNativeDriver, -1),
+ new ScreenConfiguration(OffsetX, OffsetY, Width, Height, StickS3St7789.GraphicDriver),
+ (uint)memoryBitMapAllocation);
+
+ MemoryAllocationBitmap = (int)actualBufferSize;
+ ScreenBase.BackLightPin = BackLight;
+ Enabled = true;
+ _isInitialized = true;
+ }
+
+ ///
+ /// Enables or disables the screen.
+ ///
+ public new static bool Enabled
+ {
+ get => _isEnabled;
+ set
+ {
+ _isEnabled = value;
+ IsEnabled = value;
+
+ if (value)
+ {
+ M5StickS3.SetLcdPower(true);
+ Controller.Write(BackLight, PinValue.High);
+ Thread.Sleep(100);
+ }
+ else
+ {
+ Thread.Sleep(2);
+ Controller.Write(BackLight, PinValue.Low);
+ M5StickS3.SetLcdPower(false);
+ }
+ }
+ }
+
+ ///
+ /// Sets luminosity in percentage.
+ ///
+ public new static byte LuminosityPercentage
+ {
+ get => (byte)(_isEnabled ? 100 : 0);
+ set => Enabled = value > 0;
+ }
+ }
+}
diff --git a/nanoFramework.M5StickS3/StickS3St7789.cs b/nanoFramework.M5StickS3/StickS3St7789.cs
new file mode 100644
index 00000000..ea6dfa07
--- /dev/null
+++ b/nanoFramework.M5StickS3/StickS3St7789.cs
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using nanoFramework.UI;
+
+namespace nanoFramework.M5Stack
+{
+ ///
+ /// M5StickS3-specific managed ST7789 driver.
+ ///
+ internal static class StickS3St7789
+ {
+ private static GraphicDriver _driver;
+
+ private enum St7789Command : byte
+ {
+ SleepOut = 0x11,
+ DisplayOn = 0x29,
+ ColumnAddressSet = 0x2A,
+ RowAddressSet = 0x2B,
+ MemoryWrite = 0x2C,
+ MemoryAccessControl = 0x36,
+ ColorMode = 0x3A,
+ InversionOn = 0x21,
+ }
+
+ private enum Orientation : byte
+ {
+ My = 0x80,
+ Mx = 0x40,
+ Mv = 0x20,
+ Bgr = 0x08,
+ }
+
+ public static GraphicDriver GraphicDriver
+ {
+ get
+ {
+ if (_driver == null)
+ {
+ _driver = new GraphicDriver()
+ {
+ BitsPerPixel = 16,
+ MemoryWrite = (byte)St7789Command.MemoryWrite,
+ SetColumnAddress = (byte)St7789Command.ColumnAddressSet,
+ SetRowAddress = (byte)St7789Command.RowAddressSet,
+ InitializationSequence = new byte[]
+ {
+ (byte)GraphicDriverCommandType.Command, 2, (byte)St7789Command.ColorMode, 0x55,
+ (byte)GraphicDriverCommandType.Command, 1, (byte)St7789Command.InversionOn,
+ (byte)GraphicDriverCommandType.Command, 1, (byte)St7789Command.SleepOut,
+ (byte)GraphicDriverCommandType.Sleep, 12,
+ (byte)GraphicDriverCommandType.Command, 1, (byte)St7789Command.DisplayOn,
+ },
+ OrientationLandscape = new byte[]
+ {
+ (byte)GraphicDriverCommandType.Command, 2, (byte)St7789Command.MemoryAccessControl, (byte)Orientation.Bgr,
+ },
+ OrientationPortrait = new byte[]
+ {
+ (byte)GraphicDriverCommandType.Command, 2, (byte)St7789Command.MemoryAccessControl, (byte)(Orientation.Mv | Orientation.Bgr),
+ },
+ OrientationLandscape180 = new byte[]
+ {
+ (byte)GraphicDriverCommandType.Command, 2, (byte)St7789Command.MemoryAccessControl, (byte)(Orientation.Mx | Orientation.Bgr),
+ },
+ OrientationPortrait180 = new byte[]
+ {
+ (byte)GraphicDriverCommandType.Command, 2, (byte)St7789Command.MemoryAccessControl, (byte)(Orientation.Mx | Orientation.My | Orientation.Mv | Orientation.Bgr),
+ },
+ DefaultOrientation = DisplayOrientation.Landscape,
+ SetWindowType = SetWindowType.X16bitsY16Bit,
+ };
+ }
+
+ return _driver;
+ }
+ }
+ }
+}
diff --git a/nanoFramework.M5StickS3/nanoFramework.M5StickS3.nfproj b/nanoFramework.M5StickS3/nanoFramework.M5StickS3.nfproj
new file mode 100644
index 00000000..7c0cd5b6
--- /dev/null
+++ b/nanoFramework.M5StickS3/nanoFramework.M5StickS3.nfproj
@@ -0,0 +1,123 @@
+
+
+
+
+ $(MSBuildExtensionsPath)\nanoFramework\v1.0\
+
+
+
+ Debug
+ AnyCPU
+ {11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {AA95E2BF-4A10-4F9A-8D2D-C7362A8C3562}
+ Library
+ Properties
+ 512
+ nanoFramework.M5StickS3
+ nanoFramework.M5StickS3
+ v1.0
+ bin\$(Configuration)\nanoFramework.M5StickS3.xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\packages\nanoFramework.Iot.Device.Bmm150.1.2.991\lib\Iot.Device.Bmm150.dll
+
+
+ ..\packages\nanoFramework.Iot.Device.Button.1.2.1002\lib\Iot.Device.Button.dll
+
+
+ ..\packages\nanoFramework.Iot.Device.Bmi270.1.0.9\lib\Iot.Device.Bmi270.dll
+
+
+ ..\packages\nanoFramework.Iot.Device.Common.NumberHelper.1.2.862\lib\Iot.Device.Common.NumberHelper.dll
+
+
+ ..\packages\nanoFramework.Iot.Device.M5Pm1.1.0.1\lib\Iot.Device.M5Pm1.dll
+
+
+ ..\packages\nanoFramework.CoreLibrary.1.17.12\lib\mscorlib.dll
+
+
+ ..\packages\nanoFramework.Graphics.1.2.53\lib\nanoFramework.Graphics.dll
+
+
+ ..\packages\nanoFramework.Graphics.1.2.53\lib\nanoFramework.Graphics.Core.dll
+
+
+ ..\packages\nanoFramework.Hardware.Esp32.1.6.40\lib\nanoFramework.Hardware.Esp32.dll
+
+
+ ..\packages\nanoFramework.ResourceManager.1.2.32\lib\nanoFramework.ResourceManager.dll
+
+
+ ..\packages\nanoFramework.Runtime.Events.1.11.37\lib\nanoFramework.Runtime.Events.dll
+
+
+ ..\packages\nanoFramework.Runtime.Native.1.7.11\lib\nanoFramework.Runtime.Native.dll
+
+
+ ..\packages\nanoFramework.System.Collections.1.5.75\lib\nanoFramework.System.Collections.dll
+
+
+ ..\packages\nanoFramework.UnitsNet.Temperature.5.76.15\lib\netnano1.0\nanoFramework.UnitsNet.Temperature.dll
+
+
+ ..\packages\nanoFramework.UnitsNet.ElectricPotential.5.76.15\lib\netnano1.0\nanoFramework.UnitsNet.ElectricPotential.dll
+
+
+ ..\packages\nanoFramework.System.Buffers.Binary.BinaryPrimitives.1.2.862\lib\System.Buffers.Binary.BinaryPrimitives.dll
+
+
+ ..\packages\nanoFramework.System.Device.Gpio.1.1.62\lib\System.Device.Gpio.dll
+
+
+ ..\packages\nanoFramework.System.Device.I2c.1.1.29\lib\System.Device.I2c.dll
+
+
+ ..\packages\nanoFramework.System.Device.Model.1.2.862\lib\System.Device.Model.dll
+
+
+ ..\packages\nanoFramework.System.Diagnostics.Stopwatch.1.2.862\lib\System.Diagnostics.Stopwatch.dll
+
+
+ ..\packages\nanoFramework.System.Math.1.5.116\lib\System.Math.dll
+
+
+ ..\packages\nanoFramework.System.Numerics.1.2.862\lib\System.Numerics.dll
+
+
+ ..\packages\nanoFramework.System.Threading.1.1.52\lib\System.Threading.dll
+
+
+ ..\packages\UnitsNet.nanoFramework.Temperature.5.75.0\lib\UnitsNet.Temperature.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/nanoFramework.M5StickS3/packages.config b/nanoFramework.M5StickS3/packages.config
new file mode 100644
index 00000000..73f59b9a
--- /dev/null
+++ b/nanoFramework.M5StickS3/packages.config
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/nanoFramework.M5StickS3/packages.lock.json b/nanoFramework.M5StickS3/packages.lock.json
new file mode 100644
index 00000000..0f14bd8f
--- /dev/null
+++ b/nanoFramework.M5StickS3/packages.lock.json
@@ -0,0 +1,151 @@
+{
+ "version": 1,
+ "dependencies": {
+ ".NETnanoFramework,Version=v1.0": {
+ "nanoFramework.CoreLibrary": {
+ "type": "Direct",
+ "requested": "[1.17.12, 1.17.12]",
+ "resolved": "1.17.12",
+ "contentHash": "j0fDBm74I7ORpskJTW1R9JgKqlmpgkQaB+ccBbRJcUKD1DGYlPDI1N4/kFwYOZrn8YjHUVFVv6n/1vg822ZSsw=="
+ },
+ "nanoFramework.Graphics": {
+ "type": "Direct",
+ "requested": "[1.2.53, 1.2.53]",
+ "resolved": "1.2.53",
+ "contentHash": "LwXK03HlpMLH37Ol67GxQbjNksNXZE0pIqVZiol9ds+V3698PLyYcP/XayhTmu9pOntcDtmYL64jKuUr2dEu8g=="
+ },
+ "nanoFramework.Hardware.Esp32": {
+ "type": "Direct",
+ "requested": "[1.6.40, 1.6.40]",
+ "resolved": "1.6.40",
+ "contentHash": "jq6wGAXuC5tvkmKaQX1W5NW/IoPLhosASAKbeA5QPDHX35AwOK/l9OZrc8jvgv52DiiXj/WtvKwgPj1W0ocNCQ=="
+ },
+ "nanoFramework.Iot.Device.Bmi270": {
+ "type": "Direct",
+ "requested": "[1.0.9, 1.0.9]",
+ "resolved": "1.0.9",
+ "contentHash": "yG01UK1LH66dHOfic1nMJiQKRR2a7yNi/T9QGPaPpwmRNapIw1tjizCmZv/5pZbIhGtLgIl7EyazYVTbxLzQ6A=="
+ },
+ "nanoFramework.Iot.Device.Bmm150": {
+ "type": "Direct",
+ "requested": "[1.2.991, 1.2.991]",
+ "resolved": "1.2.991",
+ "contentHash": "/xgUJPjbTQMM4ei94cr/s46WvU1+1zBJwGicUnwSQPXNEZBG30iS4osaAnc4J3owc9Y0U2EYkCFX01/0V8HDAg=="
+ },
+ "nanoFramework.Iot.Device.Button": {
+ "type": "Direct",
+ "requested": "[1.2.1002, 1.2.1002]",
+ "resolved": "1.2.1002",
+ "contentHash": "AG4810GRfXKihn97fAdsQOYneHLNQzl+xHuDcS/JQhNJLbjhpkAzl85k9HO8Tjz1ajWtpUACib8lJSo+l4l3AA=="
+ },
+ "nanoFramework.Iot.Device.Common.NumberHelper": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "Ax67ee3vmdfH2NdqtdFYawBzxWH5+KsUIvwnTlGHbXR3ko4t5a4mVelEqB4BheJZETRyNMqKcUGWdWFAbO2byQ=="
+ },
+ "nanoFramework.Iot.Device.M5Pm1": {
+ "type": "Direct",
+ "requested": "[1.0.1, 1.0.1]",
+ "resolved": "1.0.1",
+ "contentHash": "aK4T8ojPfvG7T76s/nN5PzyyBOTKvvbDZ03TeRmRFwluCd+2e1pwj8YO/7o6cX0RJjyMIF02Qyx7O7usC17hEg=="
+ },
+ "nanoFramework.ResourceManager": {
+ "type": "Direct",
+ "requested": "[1.2.32, 1.2.32]",
+ "resolved": "1.2.32",
+ "contentHash": "hpBiZ7yx5AnT/0T37cr2ySQwQDLKP+KaWu+O7ln9J43M/WaKFSCZFVsqXeJGby3/JDfm1cxhfOaQ1MMsevrdiA=="
+ },
+ "nanoFramework.Runtime.Events": {
+ "type": "Direct",
+ "requested": "[1.11.37, 1.11.37]",
+ "resolved": "1.11.37",
+ "contentHash": "whTgEJCGpE8eGK7Z2fI6gTqsVeVrnCzP1KDSqIB2PY0/Jyw7NcnwCFe3s/43ch75DuAZt8/jTX0VJoJtN0Colw=="
+ },
+ "nanoFramework.Runtime.Native": {
+ "type": "Direct",
+ "requested": "[1.7.11, 1.7.11]",
+ "resolved": "1.7.11",
+ "contentHash": "XPSTltZ9KeBruogVmjQpCphi1nLoJH49mpyp2eGBs8BTjKuL5TkMO20MoI8r73F/PW5AppTq49HvIZZavU5nPQ=="
+ },
+ "nanoFramework.System.Buffers.Binary.BinaryPrimitives": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "O+jmbbw2h2cjCTShsvWCzjqn/kmRacJE4Ena9gJt5xF5D7XHyYh/uE/qbZ4LhlmlN6JCZjLRNiEfHyM1YUjyxg=="
+ },
+ "nanoFramework.System.Collections": {
+ "type": "Direct",
+ "requested": "[1.5.75, 1.5.75]",
+ "resolved": "1.5.75",
+ "contentHash": "OiMpKo8RWbjZq1594YjdRnOGNN2aT4nowa+ET7scK0frGCux0a8LGaPkG56mmSfBCKzLlVs13LIlla3XLhXaMA=="
+ },
+ "nanoFramework.System.Device.Gpio": {
+ "type": "Direct",
+ "requested": "[1.1.62, 1.1.62]",
+ "resolved": "1.1.62",
+ "contentHash": "BaSX4efW1WtqVBoqqKs3tb9y3QSZiIPcWyalbxFY7ovQ2FKoyAHI/RzTGjzPtSf3mUwmrvXnPowDida5NY5Urg=="
+ },
+ "nanoFramework.System.Device.I2c": {
+ "type": "Direct",
+ "requested": "[1.1.29, 1.1.29]",
+ "resolved": "1.1.29",
+ "contentHash": "q8duNVWeK3RCiTmTZiO1UWr7s9HMsLnKWm5utxy9OQWeQtlh00l5CoFKxjot42s1NY5zLmfq7p7oWM/fgNEtlA=="
+ },
+ "nanoFramework.System.Device.Model": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "dARhyb8BHkje2P+7VphJpRLynVhMkC0U4pFNecLs6jw8DHRMMJyszcbgo/N0ALeYjilNk9hea+wzBLFrgZpsUQ=="
+ },
+ "nanoFramework.System.Diagnostics.Stopwatch": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "auNXXoJYOJ7mAxPvMPhbxFbDCtfKF/wSdsoBEQiRd8NaQWmLg12JL6YbNiKiNs+fBlxAL6duUorBdhSyPCdayg=="
+ },
+ "nanoFramework.System.Math": {
+ "type": "Direct",
+ "requested": "[1.5.116, 1.5.116]",
+ "resolved": "1.5.116",
+ "contentHash": "0S05UKcoI9Ukz9cMNPC9huFW9vSL42/4gIh4fw8ou8HkcFmTYb0OL8VF2Ah94hEDW5mqcYAVr0ipuGWPzIRqaA=="
+ },
+ "nanoFramework.System.Numerics": {
+ "type": "Direct",
+ "requested": "[1.2.862, 1.2.862]",
+ "resolved": "1.2.862",
+ "contentHash": "YdYhLCoj5i77e4f0qw1a45GxDAFYR2F7zLlrUDdUE12JGweBR0kruURKrGJMl4uYWkORfO18PxyqNOXvSqKKCg=="
+ },
+ "nanoFramework.System.Threading": {
+ "type": "Direct",
+ "requested": "[1.1.52, 1.1.52]",
+ "resolved": "1.1.52",
+ "contentHash": "kv+US/+7QKV1iT/snxBh032vwZ+3krJ4vujlSsvmS2nNj/nK64R3bq/ST3bCFquxHDD0mog8irtCBCsFazr4kA=="
+ },
+ "nanoFramework.UnitsNet.ElectricPotential": {
+ "type": "Direct",
+ "requested": "[5.76.15, 5.76.15]",
+ "resolved": "5.76.15",
+ "contentHash": "amhs/PAWNx7+g5JEaG1V3wB/324NJ93RdY8MztR38yXvDppk/qFx+y2Ncno+8GwVRy4GHYskIbMMSHsHqOf9VQ=="
+ },
+ "nanoFramework.UnitsNet.Temperature": {
+ "type": "Direct",
+ "requested": "[5.76.15, 5.76.15]",
+ "resolved": "5.76.15",
+ "contentHash": "rmgtqp2kdwd1LkWCHy/iabt4HFHPgTSllCc8ex8M1xJ/2n3CH+Udng7M/wbtMP5II2yF5zMqxowzQ2iKOaoX/g=="
+ },
+ "Nerdbank.GitVersioning": {
+ "type": "Direct",
+ "requested": "[3.10.85, 3.10.85]",
+ "resolved": "3.10.85",
+ "contentHash": "smhqiTAbnI/6NRn+k7m+a65qKY7nREbnFqFgqxiw3JS8kXiBUOxdCxIZFP9TOpCsoh46DbMlBlcd+dWQYAVVCA=="
+ },
+ "UnitsNet.nanoFramework.Temperature": {
+ "type": "Direct",
+ "requested": "[5.75.0, 5.75.0]",
+ "resolved": "5.75.0",
+ "contentHash": "SpA9Z7T1sNaR7YBCYp+L9/ei1bjDkqi8PyPfOWVBjkWInuPSOQaPG9Y7UttIpJ0M2y1GTrCG1kmRCUewGiSFAg=="
+ }
+ }
+ }
+}
\ No newline at end of file